![]() | ![]() | ![]() |
| | #1 |
|
Here is a project I worked on a while ago that I’ve finally got around to documenting. It interfaces Dallas One Wire (OW) temperature devices to a PC using the smallest Pic chip available, the 10f200. The 10f200 can hold 256 instructions and has 16 bytes of RAM so fitting the OW search algorithm in it was rather challenging. It can also use a 12F509. What the device actually does is to interrogate the Dallas chips one at a time, find their ROM IDs, do a conversion and send a string to the PC containing all the information. It is powered from the RS232 port and works with the 2 USB to RS232 converters that I have. Here it is with 3 DS13S20s attached. You can attach as many as you like in theory but you will probably have to add an external power supply. ![]() And a closer look, ![]() The Schematic, ![]() Parts list, A preprogrammed 10F200 or 12F509. 2 x 1K resistors 2 X 10uF electrolitic capacitors 2 x 0.1uF capacitors 1 x 1N4148 diode. 1 x 78L05 voltage regulator The board, ![]() I've attached a monochrome image. See below. If you run hyperterminal you will get this, ![]() Not very useful and so I’ve written a little VB application to demonstrate how to extract the ROM and temperature information. See below. (anyone familiar with the Dallas devices will recognize the above as the ROM ID followed by the scratch pad area.) This is what the VB app does. This is the 3 ROM Ids and temperatures. ![]() The code is rather hard to follow as it uses every trick in the book to minimize ROM and RAM usage. But here it is anyway, Code: ;******************************************************************* ; Title One Wire temperature reader ; Author Mike Webb ; Date 10th January 2009 ; Pic 10F200 or 12F509 ;******************************************************************* errorlevel -302,-224 radix dec #ifdef __12F509 include "p12f509.inc" __CONFIG _MCLRE_ON & _CP_OFF & _WDT_ON & _IntRC_OSC OW_Bit equ 4 RS_Bit equ 2 #define DataLow b'11111111' - (1<<OW_Bit) - (1<<RS_Bit) #define DataHigh b'11111111' - (1<<RS_Bit) #define DataBit GPIO,OW_Bit #define b_RS232Out GPIO,RS_Bit cblock 0x10 RomBuffer:8 ;must be on 16 byte boundary temp OwByte:0 Discrepency OutByte OwCount OwFlags BitIndex OwTemp LastDiscrepency endc endif #ifdef __10F200 include "p10f200.inc" __CONFIG _MCLRE_OFF & _CP_OFF & _WDT_ON OW_Bit equ 2 RS_Bit equ 0 #define DataLow b'11111111' - (1<<OW_Bit) - (1<<RS_Bit) #define DataHigh b'11111111' - (1<<RS_Bit) #define DataBit GPIO,OW_Bit #define b_RS232Out GPIO,RS_Bit cblock 0x10 RomBuffer:8 ;must be on 16 byte boundary temp OwByte:0 ;shares same location as Discrepency Discrepency OutByte OwCount OwFlags BitIndex OwTemp LastDiscrepency endc endif #define OwSkipRom 0xcc #define OwConvert 0x44 #define OwReadScratchPad 0xbe #define OwSearchRom 0xf0 #define OwMatchRom 0x55 #define b_OwPresent OwFlags,7 #define b_ClrBit OwFlags,6 #define b_Done OwFlags,5 #define b_IsGetBit OwFlags,4 #define b_SendRom OwFlags,3 org 0 movwf OSCCAL clrf 7 ;turn of comparators (10f204/6) start movlw DataHigh ;release line tris GPIO movlw 0xdf ;make GPIO2 I/O option First clrf LastDiscrepency ;restart search rom bcf b_Done Next bcf DataBit btfsc b_Done ;Have we completed list goto start ;Yes so restart clrf BitIndex ;start at first bit call OwReset movlw OwSearchRom ;Send search rom command call OwWriteByte clrf Discrepency GetBits clrf OwFlags ;clear all bit variables call OwReadBit ;get bit A rlf OwFlags,f call OwReadBit ;get bit B rlf OwFlags,f movlw 0x03 xorwf OwFlags,w ;If A=1 && B=1 then no devices present btfsc STATUS,Z goto start ;Restart xorlw 0x03 btfss STATUS,Z goto Not00 ;A=0 and B=0 movfw BitIndex subwf LastDiscrepency,w btfsc STATUS,Z goto RomIndexEqualLD btfss STATUS,C goto RomIndexGTLD call GetBit ;RomIndex < LastDiscrepency btfss STATUS,C goto SetMarker goto SendRomBit Not00 btfsc OwFlags,1 ;set ROM bit to match Bit A call SetBit btfss OwFlags,1 call ClrBit goto SendRomBit RomIndexGTLD call ClrBit ;RomIndex > LastDiscrepency SetMarker movfw BitIndex movwf Discrepency goto SendRomBit RomIndexEqualLD call SetBit ;RomIndex = LastDiscrepency SendRomBit call GetBit call OwSendCarry incf BitIndex,f btfss BitIndex,6 goto GetBits movfw Discrepency movwf LastDiscrepency btfsc STATUS,Z bsf b_Done bsf b_SendRom ;this was a subroutine but due to lack of OwMatch call OwReset ;stack space it was put in line and a flag movlw OwMatchRom ;used to indicate the return address call OwWriteByte movlw RomBuffer ;=0x10 = 0001 0000 movwf FSR SendRom movfw INDF call OwWriteByte incf FSR,F btfss FSR,3 ;bodgey, FSR=0x18 goto SendRom btfss b_SendRom goto Continue ;taken 2nd time around movlw OwConvert call OwWriteByte bcf b_SendRom bsf DataBit ;drive data line high by movlw DataLow ;setting to output for tris GPIO ;parasitic power devices call Delay1 ;wait for conversion movlw DataHigh ;release data line tris GPIO ;by setting to input SendSerial decf FSR,F ;FSR=0x18 when entering btfss FSR,4 ;will be clear when FSR=0x0f goto OwMatch swapf INDF,W call SendNibble movfw INDF call SendNibble goto SendSerial Continue movlw OwReadScratchPad call OwWriteByte call SendSpace movlw 0x100-9 movwf FSR ;very dodgey - relies on unused bits being 1 ReadLoop call OwReadByte ;but no choice as out of RAM!! swapf OwByte,W call SendNibble movfw OwByte call SendNibble incfsz FSR,F goto ReadLoop movlw 0x0d ;send cr/lf call Send movlw 0x0a call Send goto Next ;go get next rom ID GetBit bsf b_IsGetBit ;Get bit RomBuffer[BitIndex] goto DoBit ClrBit bsf b_ClrBit ;Clear bit RomBuffer[BitIndex] btfss b_ClrBit SetBit bcf b_ClrBit ;Set bit RomBuffer[BitIndex] bcf b_IsGetBit DoBit rrf BitIndex,W movwf OwTemp rrf OwTemp,f rrf OwTemp,W andlw 0x07 iorlw RomBuffer movwf FSR movfw BitIndex andlw 0x07 clrf OwTemp movwf OwCount bsf STATUS,C GetBitLoop rlf OwTemp,f ;will clear the carry bit decf OwCount,F btfss OwCount,7 goto GetBitLoop movfw OwTemp btfsc b_IsGetBit goto DoGetBit ;carry must be clear btfsc b_ClrBit goto IsClrBit iorwf INDF,f retlw 0 IsClrBit xorlw 0xff andwf INDF,f retlw 0 DoGetBit andwf INDF,w btfss STATUS,Z bsf STATUS,C retlw 0 OwReset movlw DataLow ;pull line low tris GPIO movlw .750/4 ;delay 750uS movwf temp decfsz temp,W goto $-2 movlw DataHigh ;release line tris GPIO ; movlw .68/4 ;delay 68uS ; movwf temp ; decfsz temp,W ; goto $-2 ; bcf b_OwPresent ; btfss DataBit ;pulled low? ; bsf b_OwPresent ;yes so chip present ; movlw .480/4 ;delay 480uS movlw .548/4 ;combined times ExitDelay movwf temp decfsz temp,W goto $-2 retlw 0 OwWriteByte movwf OwByte ;store byte to write movlw .8 ;send 8 bits movwf OwCount OwWriteLoop rrf OwByte,f ;move bit to carry call OwSendCarry ;send it decfsz OwCount,F ;sent all bits goto OwWriteLoop ;no, so loop retlw 0 OwReadByte movlw .8 ;get 8 bits movwf OwCount OwReadByteLoop call OwReadBit ;returns bit in carry rrf OwByte,F ;move carry into byte decfsz OwCount,F ;finished? goto OwReadByteLoop ;no, so carry on retlw 0 OwSendCarry btfss STATUS,C ;is carry clear goto OwSend0 ;yes, so goto send zero OwSend1 movlw DataLow ;pull line low tris GPIO goto $+1 ;wait 4uS goto $+1 movlw DataHigh ;release line tris GPIO Exit60 movlw .60/4 ;wait 60uS goto ExitDelay OwSend0 movlw DataLow ;pull line low tris GPIO movlw .60/4 ;wait 60uS movwf temp decfsz temp,W goto $-2 movlw DataHigh ;release line tris GPIO movlw .4/4 goto ExitDelay OwReadBit movlw DataLow ;pull line low tris GPIO goto $+1 ;wait 4uS goto $+1 movlw DataHigh ;release line tris GPIO movlw .12/4 ;Wait 12uS movwf temp decfsz temp,W goto $-2 bcf STATUS,C btfsc DataBit bsf STATUS,C ; movlw .60/4 ;Wait 60uS goto Exit60 ;Delay SendSpace movlw ' ' ;0x20 goto Send SendNibble andlw 0fh ;keep lower nibble movwf temp ;save for later movlw 0x100-10 ;test if greater addwf temp,W ;than 10 movlw "0" ;add "0" btfsc STATUS,C ;or, if greater than 10 movlw "0"+7 ;add "A"-10 addwf temp,W ;do add and fall through to send it Send movwf OutByte ;sends data inverted so no MAX232 needed bsf b_RS232Out ;start bit call BitDelay bsf STATUS,C ;will be first stop bit SendLoop rrf OutByte,F ;move bit to carry bsf b_RS232Out btfsc STATUS,C bcf b_RS232Out call BitDelay bcf STATUS,C ;ensure 0 shifted into outbyte movfw OutByte ;will be zero when 8 bits + 1 stop bit sent btfss STATUS,Z goto SendLoop bcf DataBit ;ensure data line is low ;fall through for second stop bit. ; at 1 meg instructions and 9600 baud ; delay is 1,000,000/9600 = 104 cc ; the calling loop and the call/return = 13 ; therefore delay needs to be 91 cycles BitDelay movlw .30 movwf temp DelayLoop decfsz temp,F; (3*30)-1 = 89 + 2 = 91 goto DelayLoop clrwdt ;kick the dog retlw 0 Delay1 clrf OwTemp ;approx 1 second delay movlw .40 movwf OwCount del call BitDelay decfsz OwTemp,F goto del decfsz OwCount,F goto del retlw 0 if ($>0xff) messg "Memory Overflow" endif end The attachments are the VB files, Hex files and board image. Mike. | |
| |
| | #2 |
|
Nice project and execptional post. A demo of how handy the little pics can be, and your asm skill too
__________________ Please post questions to the forums. PM's are for personal communication. BCHS/3v0's Tutorials Junebug USB PIC programmer kit., USB Bit Whacker, The 15 Minute Printed Circuit Board! (+drill time) | |
| |
| | #3 |
|
Hi Mike, A very impressive effort. Thank you for sharing. I've not implemented the ROM Search algorithm and so I'm looking forward to studying your code. Regards, Mike | |
| |
| | #4 |
|
Hi Mike, Maxim have a very good explanation of the search ROM algorithm in this document. My implementation above is very convoluted (spaghetti like) mainly due to the stack limitations. I also gave up trying to comment the search part as it really needs a whole paragraph per 4 lines of code and it's easier to refer people to the document (which I forgot to do). Anyway, have fun trying to untangle that web of code. ![]() Mike. | |
| |
| | #5 |
|
Really nice, thanks for sharing Mike! Isn't documentation always the tough part. ![]() Well done! | |
| |
| | #6 |
|
Great job!! Fully documented projects like yours are such a rare commodity, Thanks. There's a lot going on for such a little device. By coincidence, there are a couple of 10F's from Newark coming my way very soon. Now, to put on my assembly deciphering hat. | |
| |
| | #7 |
|
Very nice job.Power also from serial port, thats nice too......... | |
| |
| | #8 |
|
Mike (Pommie), Thank you again for sharing your project. I think (hope) I'm getting a handle on the search algorithm thanks to your example and the Maxim application note and I'm taking a stab at optimizing the code a bit and organizing it in a way that's more intuitive for me. If you get a chance could you take a peek at the following excerpt and tell me if it makes sense? The program is about 45 bytes smaller so far and I was able to eliminate the OwFlags variable and its flag bits as well as the GetBit, SetBit, and ClrBit routines. Thanks. Take care. Mike Code: First
clrf LastDiscrepency ; restart search rom
Next
bcf DataBit ; clear 1-wire port latch
clrf BitIndex ; start at first bit
clrf LastZero ;
movlw RomBuffer ;
movwf FSR ; FSR = &RomBuffer
movlw 1 ;
movwf BitMask ; reset rom array bit mask
call OwReset ;
OwSend (OwSearchRom) ; send "search rom" command
GetBits
clrf OwTemp ;
call OwReadBit ; get bit A
rlf OwTemp,F ; F = -------A
call OwReadBit ; get bit B
rlf OwTemp,W ; W = ------AB
xorlw 0x03 ; AB == 11, no devices present?
bz start ; yes, branch (restart), else
xorlw 0x03 ; AB == 00, discrepency?
bnz SendRomBit ; no, branch (use 'A' bit), else
Discrepency
bsf OwTemp,0 ; set 'A' bit to '1'
movf BitIndex,W ; 0..63
subwf LastDiscrepency,W
bnc IndexGTLD ;
bz SendRomBit ; set rom bit to '1'
IndexLTLD
movf BitMask,W ; get ROM bit
andwf INDF,W ; is ROM bit '0'?
bnz SendRomBit ; no, branch, use '1', else
IndexGTLD
bcf OwTemp,0 ; set 'A' bit to '0'
movf BitIndex,W ;
movwf LastZero ; update LastZero
SendRomBit
rrf OwTemp,F ; put 'A' bit into Carry
movf BitMask,W ; set ROM bit to bit 'A'
iorwf INDF,F ; set ROM bit (unconditionally)
skpc ; is bit a '1'? yes, skip, else
xorwf INDF,F ; clr ROM bit
call OwSendCarry ; send direction/qualifier bit
rlf BitMask,W ;
rlf BitMask,F ; advance rom array bit mask
skpnc ; all 8 bits done? no, skip, else
incf FSR,F ; bump RomBuffer array address
incf BitIndex,F ; bump bit index, 0..63
btfss BitIndex,6 ; BitIndex = 64? yes, skip, else
goto GetBits ; do next bit
movf LastZero,W ;
movwf LastDiscrepency ; update last discrepency
;
; we now have a qualified 64 bit ROM serial number
;
OwMatch
Last edited by Mike, K8LH; 13th January 2009 at 03:25 AM. | |
| |
| | #9 |
|
That looks like it should work. I like the way you've kept FSR current rather than recalculating it each bit. I don't have the equipment setup at the moment to test it but can probably try it later. Are you able to test it? I'm looking forward to seeing the complete code. Edit, Did you realise that Discrepancy (LastZero) and OWByte share the same RAM location hence why I cleared Discrepancy after sending OWSearchRom. Mike. Last edited by Pommie; 13th January 2009 at 03:15 AM. | |
| |
| | #10 |
|
I won't be able to test it for a few days but then I'm still workin' on it. There are lots of changes like the SendCarry routine below. Yes, I think I figured out your local and global variables. I changed them around a bit to fit the new structure. I can't tell you how geeked I am to try this routine on a couple projects. Thank you, thank you, thank you... Mike Code: OwSendCarry
movlw DataLow ;
tris GPIO ; initiate write slot
skpnc ; send 0 bit
movlw DataHigh ; send 1 bit
tris GPIO ;
movlw .60/4 ; finish 60 usec slot
movwf temp ;
decfsz temp,W ;
goto $-2 ;
movlw DataHigh ;
tris GPIO ; release bus
retlw 0 ;
Last edited by Mike, K8LH; 13th January 2009 at 04:05 AM. | |
| |
| | #11 |
|
I still had the breadboard with a SOT-23 10F200 on it and just incorporated your code. It worked first time and occupies 0xc4 locations - less than 200. Mike. | |
| |
| | #12 |
|
Hi Mike (Pommie), I attached my crude unpolished 168 byte version of your program below just in case you might be interested. It's probably a reasonably good example of optimization and the problems that the subtle dependencies may cause. Here's my version of your OwMatch code section. I used some macros to hide detail and hopefully make it easier to follow the logic and program flow. I used your flag method to reuse the MatchRom code for both the "Convert" and "Read Scratchpad" operations but I used my BitMask variable for the flag since BitMask always equals '00000001' when we fall out of the "OwSearch" code into the "OwMatch" code. Code: ; bsf BitMask,0 ; do "convert" (bit = 1 already)
OwMatch
OwReset ; reset all 1-wire devices
OwWrite(OwMatchRom) ; send "match rom" command
OwWriteBuffer ; send + print rom serial number
Send232(' ') ; send <space> char
btfss BitMask,0 ; conversion complete?
goto OwScratch ; yes, branch, else
OwWrite(OwConvert) ; send "convert" command
OwPowerBus ; power OW pin during conversion
Send232(0x0D) ; send <cr> char (htab 0)
bcf BitMask,0 ; indicate conversion complete
goto OwMatch ; do "match rom" for OwScratch
OwScratch
OwWrite(OwReadScratch) ; send "read scratchpad" command
movlw -9 ;
movwf FSR ; use FSR as byte counter
RdLoop OwReadByte ; read + print scratchpad byte
incfsz FSR,F ; all 9 bytes read + printed?
goto RdLoop ; no, branch, else
Send232(0x0D) ; send <cr> char
Send232(0x0A) ; send <lf> char
goto OwSearchNext ; search and process next device
One program difference worth mentioning is that the OwWriteBuffer code also sends each byte to the serial port. This results in the rom serial number being printed twice but I send a <cr> character after the "OwConvert" operation so the second instance of the rom serial number printout should print on top of the first instance. This should work fine for Hyperterminal but if you're using an application then it will need to ignore the first 17 characters after detecting each <newline> (<cr>+<lf>) sequence. Now I'm wondering if 88 bytes of free memory might be enough for adding code to print the temperature as a decimal number? Regards, Mike Last edited by Mike, K8LH; 22nd January 2009 at 10:45 AM. | |
| |
| | #13 |
|
Hi Mike, I've been playing with your code but I can't get it working. I had to add an extra stop bit to the RS232 routine to get sensible data but I don't seem to be getting a correct ROM address. This is what I'm getting in Hyperterminal, Code: 0100000000000080 000000000000000000 0100000000000040 000000000000000000 01000000000000C0 000000000000000000 0100000000000020 000000000000000000 01000000000000A0 000000000000000000 0100000000000060 000000000000000000 01000000000000E0 000000000000000000 0100000000000010 000000000000000000 0100000000000090 000000000000000000 0100000000000050 000000000000000000 Also, I found a problem in the OwScratch routine, FSR has to be -9 and incremented as the unused bits of FSR are set to 1. I'l have another play later and see if I can figure anything out. Do you have hardware to test this? Did it work? Have you any ideas why I'm getting strange results? BTW, some great code saving ideas there. I'm not sure the decimal part will be possible but look forward to trying. Mike. | |
| |
| | #14 |
|
Thanks for checking it out Mike. I'll keep working on the code and look for those errors. Did you notice my serial code was 19200 baud instead of 9600 baud? I wonder if there's a problem with my modified OwReadBit routine? I don't have hardware to test this code yet. Mike Last edited by Mike, K8LH; 21st January 2009 at 05:31 AM. | |
| |
| | #15 |
|
Mike, For a sanity check I just reverted to the code from the first post and I'm getting the same results so I suspect my hardware is at fault. <edit> one of the outer pins (DS1820) had shorted to the middle pin. No wonder I couldn't get any sense out of it. I'll try your code again and get let you know.</edit> <edit2> You code works with the mod to OwScratch and the extra stop bit. Extremely nice piece of code. Now for the decimal bit!!</edit2> Mike. Last edited by Pommie; 24th January 2009 at 06:47 AM. | |
| |
|
| Tags |
| ds1820, interface, sensor, temperature, wire |
| Thread Tools | |
| Display Modes | |
| |
Similar | ||||
| Title | Starter | Forum | Replies | Latest |
| 74LS174 2-wire LCD interface | futz | Micro Controllers | 30 | 29th August 2009 08:49 AM |
| DS1820 Temp.sensor | alpish | Micro Controllers | 4 | 27th October 2007 07:47 PM |
| circuit ideas on isolated two wire temperature transmitter | madhusudan | Electronic Projects Design/Ideas/Reviews | 1 | 11th September 2004 11:59 AM |
| PIC code Error checking help (DS1820 temp sensor) | NewGeek | Micro Controllers | 11 | 10th September 2004 08:42 PM |
| temperature sensor Dallas DS1820 | electricano | Micro Controllers | 0 | 30th December 2003 03:13 PM |