1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

One Wire Temperature sensor (DS1820) to PC interface.

Discussion in 'Electronic Projects' started by Pommie, Jan 10, 2009.

Thread Status:
Not open for further replies.
  1. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    Very ingenious, may I suggest you do a multiply by 5 routine (shift left twice and add to original) and call it 3 times as this will keep it in two bytes. I have a Double Dabble routine that will convert it to BCD without the need to do the final multiply by 8. I may have a go at that tomorrow if I get time. The biggest hurdle is RAM.

    I had a play with your code and got rid of the sending the ROM serial twice by checking the "conversion complete" flag in the PowerBus code. I had to clear the DataBit but the result was the same length code as the send cr was two location anyway.

    BTW, I'm sure you need to subtract 4 (¼°) from your extended result.

    Mike.
     
  2. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    You mentioned that before and the '1820 Data Sheet also mentions subtracting 0.25 but I haven't quite figured out why.

    Printing the rom ID once is a much better way to do it. Let me study that to see if there's a way to reclaim a byte (grin).

    Your 3 x 5 x Celsius idea is genius but the product will still require 3 bytes, won't it? I'm starting out with a 12 bit number.

    Double-dabble? Sounds familiar. Must check google (grin)...

    Mike
     
    Last edited: Jan 22, 2009
  3. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    I think we can still save one byte while printing the rom ID only once. Program size is now 165 bytes.

    Send the <cr> and <lf> newline character pair during the "OwConvert" pass after the OwPowerBus function instead of at the end of the OwMatch code section and print the rom serial number in the OwWriteBuffer function only during the "OwReadScratch" pass.

    Code (text):
    ;       bcf     BitMask,3       ; do "convert" (BitMask=00000001)
    OwMatch
            [COLOR=Blue]OwReset[/COLOR]                 ; reset all 1-wire devices
            [COLOR=Blue]OwWrite[/COLOR](OwMatchRom)     ; send "match rom" command
            [COLOR=Blue]OwWriteBuffer[/COLOR]           ; send + print rom serial number
            btfsc   BitMask,3       ; conversion complete?
            goto    OwScratch       ; yes, branch, else
            [COLOR=Blue]OwWrite[/COLOR](OwConvert)      ; send "convert" command
            [COLOR=Blue]OwPowerBus[/COLOR]              ; power OW pin during conversion
            [COLOR=Blue]Send232[/COLOR](0x0D)           ; send <cr> char
            [COLOR=Blue]Send232[/COLOR](0x0A)           ; send <lf> char
            bsf     BitMask,3       ; indicate conversion complete
            goto    OwMatch         ; do "match rom" for OwScratch
    OwScratch
            [COLOR=Blue]OwWrite[/COLOR](OwReadScratch)  ; send "read scratchpad" command
            [COLOR=Blue]Send232[/COLOR](' ')            ; send space char
    ;       movlw   9               ; instructions not needed
    ;       movwf   BitMask         ; BitMask = 9 already from above
    RdLoop  [COLOR=Blue]OwReadByte[/COLOR]              ; read + print scratchpad byte
            decfsz  BitMask,F       ; all 9 bytes read + printed?
            goto    RdLoop          ; no, branch, else
            goto    OwSearchNext    ; search and process next device
     
    Code (text):
    OwWriteBuffer   macro
            local   loop
            bcf     FSR,3           ; reset FSR = &RomBuffer (0x10)
    loop    movf    INDF,W          ;
            call    Ow.WriteByte    ; send rom serial number byte
            btfsc   BitMask,3       ; OwConvert pass? yes, skip, else
            call    PutHex          ; print rom ID byte as hex
            incf    FSR,F           ;
            btfss   FSR,3           ;
            goto    loop            ;
            endm
     
     
    Last edited: Jan 22, 2009
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE

    Forget the Double Dabble stuff, I realized that the fractional part can be done by multiplying by 10 and taking the high nibble.

    So, calling this 4 times prints the fraction part,
    Code (text):

    FracDigit
        movlw   0x0f
        andwf   TempFrac,F
        clrc
        rlf TempFrac,W  ;*2
        movwf   temp
        rlf temp,W      ;*4
        addwf   TempFrac,F  ;*5
        rlf TempFrac,F  ;*10
        swapf   TempFrac,W
        goto    PutNybble
     
    Mike.
     
    Last edited: Jan 23, 2009
  6. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    That routine works extremely well. Bravo!

    So, we just need to do an ABS() function, process and print the 3 digit whole number (-55..125), suppress leading zeros (?), print a decimal point, then process and print and the 4 digit fraction. Correct?

    Can we do all that with 91 free bytes of memory and our limited RAM resources?
     
  7. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    I have not seen this sort of byte hording since collage days. Nice work.
     
  8. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    It's Pommie's fault (grin). He posted this fascinating and clever example of what you can do with only 256 words of program memory and 16 bytes of RAM...
     
    Last edited: Jan 23, 2009
  9. 3v0

    3v0 Coop Build Coordinator Forum Supporter

    Joined:
    Jul 14, 2006
    Messages:
    9,404
    Likes:
    227
    Location:
    OKLAHOMA USA
    Hey, I love to watch this. :) I may build a few when you get it sorted out.

    I have a friend who would like to do some control work but is too tied down with work to get back in to uC's. I would like to drop one of these on his desk and see what happens.

    3v0
     
    Last edited: Jan 23, 2009
  10. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    I've quite enjoyed this little exercise in optimization. When I first wrote this I was just pleased to get the code in 256 words and then Mike came along and demonstrated just how lax I had been with optimization:D. Along the way I've learnt some very interesting techniques, although they are probably more academic than useful.

    Anyway, enough of my ramblings, here's a first go at the full decimal part (7 digits :eek:) with absolute and leading zero suppression,
    Code (text):

    OwMatch
            OwReset         ; reset all 1-wire devices
            OwWrite(OwMatchRom)     ; send "match rom" command
            OwWriteBuffer       ; send + print rom serial number
            btfsc   BitMask,2   ; conversion complete?
            goto    OwScratch   ; yes, branch, else
            OwWrite(OwConvert)  ; send "convert" command
            OwPowerBus      ; power OW pin during conversion
            bcf DataBit
            bsf BitMask,2   ; indicate conversion complete
            goto    OwMatch     ; do "match rom" for OwScratch
    OwScratch
            Send232(' ')        ; send <space> char
            OwWrite(OwReadScratch)  ; send "read scratchpad" command
            OwReadByte
            movfw   OwByte
            movwf   TempLo
            OwReadByte
            movfw   OwByte
            movwf   TempHi
    ReadLoop
            OwReadByte
            decfsz  BitMask,F
            goto    ReadLoop

            movf    RomBuffer,W ; get Family ID byte
            xorlw   0x28        ; is it 12 bit DS18B20?
            bz  OwTemperature   ; yes, branch, else
            rlf TempLo,F    ;                                 |
            rlf TempHi,F    ;
            rlf TempLo,F    ;
            rlf TempHi,F    ;
            rlf TempLo,F    ;
            rlf TempHi,F    ;
            movlw   0xF0        ;
            andwf   TempLo,F    ;
            movlw   16      ;
            movwf   temp        ;
            movf    OwByte,W    ; Count_Remain
            subwf   temp,W      ;
            iorwf   TempLo,F    ; now DS18B20 12 bit format
            movlw   4
            subwf   TempLo,F
            skpc
            decf    TempHi,F
    OwTemperature
            OwReadByte
            OwReadByte

            Send232 " "
            btfss   TempHi,7    ;is it negative
            goto    NoNegate
            Send232 '-'     ;Send minus sign
            comf    TempLo,F    ;and negate temperature
            comf    TempHi,F
            incfsz  TempLo,F
            goto    NoNegate
            incf    TempHi,F
    NoNegate
            movfw   TempLo      ;keep fraction part
            movwf   TempFrac    ;and move it to seperate var
            movlw   0x0f
            andwf   TempHi,F    ;move nibbles around so
            swapf   TempLo,F    ;that the temperature is
            andwf   TempLo,F    ;contained in TempLo
            swapf   TempHi,W
            iorwf   TempLo,F

            clrf    TempHi      ;will contain tens digit
            movlw   0x100-.100
            addwf   TempLo,W
            bnc NoHundreds
            movwf   TempLo
            Send232 '1'
            bsf BitMask,0   ;no longer suppressing zeros
    NoHundreds
            movlw   .10
            subwf   TempLo,F
            incf    TempHi,F
            bc  NoHundreds
            decfsz  TempHi,F    ;is it zero
            goto    PrintIt     ;no so print it
            btfss   BitMask,0   ;are we suppressing zeros
            goto    SkipZero    ;yes so skip it
    PrintIt     movlw   '0'
            addwf   TempHi,W    ;print 10s digit
            call    Put232
    SkipZero    movlw   '0'+10
            addwf   TempLo,W
            call    Put232      ;always print units digit
            Send232 '.'
            call    FracDigit
            call    FracDigit
            call    FracDigit
            call    FracDigit

            Send232(0x0D)       ; send <cr> char
            Send232(0x0A)       ; send <lf> char
            goto    OwSearchNext    ; search and process next device

    FracDigit
            movlw   0x0f
            andwf   TempFrac,F
            clrc
            rlf TempFrac,W  ;*2
            movwf   temp
            rlf temp,W      ;*4
            addwf   TempFrac,F  ;*5
            rlf TempFrac,F  ;*10
            swapf   TempFrac,W
            goto    PutNybble

     
    It now occupies 254 words so we have a full word free:D.

    Mike.
    P.S. this is what I see in Hyperterminal,
    [​IMG]
    You can see where I hit them (3 sensors) with a freezing spray.
     
    Last edited: Jan 23, 2009
  11. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    Excellent work! Incredible work!

    I found some 10F206 samples in PDIP-8 package. Can't wait to try this but would like to print leading spaces to align the decimal points.

    Mike
     
  12. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    Hey Mike,

    I wonder if this revised sequence would work? If so, I think there's a one word savings over the way we're doing it now and it eliminates our double "match rom" operation.

    Code (text):
    OwMatch
            [COLOR=Blue]OwReset[/COLOR]                 ; reset all 1-wire devices
            [COLOR=Blue]OwWrite[/COLOR](OwSkipRom)      ; send "skip rom" command
            [COLOR=Blue]OwWrite[/COLOR](OwConvert)      ; send "convert" command
            [COLOR=Blue]OwPowerBus[/COLOR]              ; power OW pin during conversion
            [COLOR=Blue]Send232[/COLOR](0x0D)           ; send <cr>
            [COLOR=Blue]Send232[/COLOR](0x0A)           ; send <lf>
            [COLOR=Blue]OwReset[/COLOR]                 ; reset all 1-wire devices
            [COLOR=Blue]OwWrite[/COLOR](OwMatchRom)     ; send "match rom" command
            [COLOR=Blue]OwWriteBuffer[/COLOR]           ; send and print rom serial number
            [COLOR=Blue]OwWrite[/COLOR](OwReadScratch)  ; send "read scratchpad" command
     
     
  13. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    Hi Mike,

    My only worry about using the SkipRom command is that all devices would draw power at the same time and possibly overload the (very dodgy) RS232 power scheme. But it may work. I got rid of the double ROM id write with a bit test in OwWriteBuffer. As for the leading spaces, you're just never satisfied are you.:D I might play with that tomorrow.

    BTW, if you use a 10F206 then you need to turn off the comparator. It was in the original code but got optimized.:rolleyes:

    Mike.
     
  14. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    The serial port on my Dell Latitude D800 notebook cannot supply more than a couple hundred microamps so I dismissed the idea of powering this device from the serial port early on and completely forgot that's what you're doing. Sorry. We definitely need to keep your original double "matchrom" method to keep current manageable.

    I just though it would be nice if the Host application on the PC could always find the nine character temperature string in the same place; str[x+0] == " " or "-", str[x+1] == " " or "1" (hundreds), str[x+2] == " " or "n" (tens), str[x+3] == "n" (ones), str[x+4] == ".", etc.

    Your original program occupies a place of honor in my work folder and so I have easy access to it and I see the reference for turning off the comparator. Thank you.

    I apologize for my style changes to your excellent program. Those movfw instructions drive me crazy and I prefer using the STATUS "branch" and "skip" pseudo opcodes to the more traditional bit test instructions because they seem much more intuitive (to me). I'm sure you probably cringe at some of my preferences (grin). I suspect my preferences have changed over time as I've become more familiar with some of the C implementations.

    Later, Mike
     
  15. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    Hi Mike,

    My comment "but got optimized" was in no way a criticism. I hold your optimization skills in high esteem and I like your programming style. So, no need to apologize, please just carry on as was.

    As for the leading zeros, in VB you would simply do Temperature=Val(mid(record,36)) to get the full floating point number, I hadn't considered how you would do it in C. Isn't there a atof (ascii to float) type instruction?

    Anyway, you find me a few more words and I'll sort out the spaces problem.:D

    Mike.
     
  16. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    Just kickin' around some ideas here so bear with me. I was thinking that we should only have up to 12 "tens" for temperature readings up to 125° so why not just count up and print the number of "tens" as two digits?

    I just typed this code into the post window so I haven't tested it but I think it's the same size as the code it would replace and I believe it will give me my decimal point alignment and my leading zero suppression. I wonder if there's a better way to do it that produces even smaller tighter code?

    I'll test later and get back.

    Mike

    Code (text):

    [COLOR=DarkOrchid] [COLOR=Blue]       clrf    TempHi          ; will contain tens digit
            bsf     BitMask,5       ; BitMask = 0x20 = " "
    Bin2Dec                         ; print values "  0".."125"
            movlw   10              ;
            subwf   TempLo,F        ;
            incf    TempHi,F        ;
            bc      Bin2Dec         ;
            addwf   TempLo,F        ; fix "ones", 0x00..0x09
            decf    TempHi,F        ; fix "tens", 0x00..0x0C
            movlw   6               ;
            addwf   TempHi,W        ; packed BCD, 0x00..0x09?
            skpndc                  ; yes, skip, no digit carry, else
            movwf   TempHi          ; packed BCD, 0x10..0x12
            swapf   TempHi,W        ; get hundreds digit
            call    PutDigit        ; prints " " or "1"
            movf    TempHi,W        ; get tens digit
            call    PutDigit        ; prints " " or "0".."9"
            movf    TempLo,W        ; get ones digit
            call    PutOnes         ; always print ones, "0".."9"[/COLOR][/COLOR]
            Send232 '.'             ;
            call    PutFraction     ;
            call    PutFraction     ;
            call    PutFraction     ;
            call    PutFraction     ;
            [COLOR=Black]Send232[/COLOR](0x0D)           ; send <cr> char
            [COLOR=Black]Send232[/COLOR](0x0A)           ; send <lf> char
            goto    OwSearchNext    ; search and process next device

    [COLOR=Blue]PutDigit
            andlw   0x0F            ;
            skpz                    ; zero? yes, skip, else
    PutOnes bsf     BitMask,4       ; BitMask = 0x30 = "0"
            iorwf   BitMask,W       ; " " or "0".."9"
            goto    Put232          ; print digit[/COLOR]
    ;
     
     
    Last edited: Jan 26, 2009
  17. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    That works well but there is a slight problem with negative numbers. Here is how the alignment works at the moment,
    Code (text):

    123.1234 < no space
     12.1234
      1.1234
    -  1.1234
     
    This will stop the use of Val in basic. I can correct it but it ends up 5 words too long.

    I'm assuming the preferred alignment would be,
    Code (text):

     123.1234 < leading space
      12.1234
       1.1234
      -1.1234
     

    BTW, making BitMask 0x20 or 0x30 is brilliant.

    Mike.
     
  18. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    Thank you for the nice comment. I suspect there are better ways to do it though.

    There's a bit of code I didn't show that goes in front of the section I posted that prints a " " or "-" sign so right now it's doing this;

    Code (text):

     123.1234
      12.1234
       0.1234
    -  0.1234
    -  1.1234
    - 12.1234
     
    I think I would prefer to print it one of the following ways;
    Code (text):

     123.1234°C      123.1234°C
      12.1234°C       12.1234°C
       1.1234°C        1.1234°C
      -1.1234°C      - 1.1234°C
     -12.1234°C      -12.1234°C
     
    With a couple other structure changes and the new code sections (abs, putfraction, etc) the program is 249 bytes long.

    Mike
     
    Last edited: Jan 26, 2009
  19. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,637
    Likes:
    109
    Location:
    Michigan, USA
    We can save another couple words in your genius PutFraction subroutine with a subtle change in your x10 code and by letting the routine fall into the PutDigit subroutine;

    Code (text):
    PutFraction
            movlw   0x0F            ;
            andwf   TempLo,F        ; toss integer, leave remainder
    [COLOR=Blue]        movf    TempLo,W        ;
            addwf   TempLo,F        ; *2, C=0
            rlf     TempLo,F        ; *4, C=0
            addwf   TempLo,F        ; *5, C=0
            rlf     TempLo,F        ; *10
    [/COLOR]        swapf   TempLo,W        ; integer portion in lo nybble
    PutDigit
            andlw   0x0F            ;
            skpz                    ; zero? yes, skip, else
    PutOnes bsf     BitMask,4       ; BitMask = 0x30 = "0"
            iorwf   BitMask,W       ; " " or "0".."9"
            goto    Put232          ; print digit
     
    I've included the code that subtracts 1/4° from the sign extended two's complement temperature value for DS1820/DS18S20 devices but I'm still not convinced it's necessary. This effectively adds 1/4° to a negative temperature or subtracts 1/4° from a positive temperature. Why would this be necessary? Is it because the 1/2° bit in the original 9-bit temperature value is "rounded up" or "rounded down" based on the value in the Count_Remain byte? I'm not using the 1/2° bit, just the 4 bit Count_Remain value, so do you think it's still necessary to subtract 1/4°?

    The program is 255 bytes long in its current form (256 bytes with the clrf CMCON0 instruction for my 10F206) and should print out something like this;

    Code (text):

    10SSSSSSSSSSSSCC TTTTTTTTTTTTTTTTCC  125.0000°C
    28SSSSSSSSSSSSCC TTTTTTTTTTTTTTTTCC   23.1234°C
    28SSSSSSSSSSSSCC TTTTTTTTTTTTTTTTCC    0.1234°C
    10SSSSSSSSSSSSCC TTTTTTTTTTTTTTTTCC -  4.1234°C
    10SSSSSSSSSSSSCC TTTTTTTTTTTTTTTTCC - 24.1234°C
     
     
    Last edited: Jan 27, 2009
  20. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,024
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    The code always subtracts 1/4° because it is done before the absolute function. However, I understand the confusion but assume that the data sheet should be taken literally. The only code I could find on the internet is DS1820.asm which does do the subtraction. (you should study that code - it has a full stack based 16 bit maths system on a 12F509 :eek: ).

    Anyway, I implemented your optimizations and I had another play with swapping things around. After much head scratching I finally managed to implement the space before minus solution. I removed the earlier print space and minus sign and made Put232 return 0x0a. The final 2 words I found were the initial write to the tris register.

    Code (text):

    FracDigit
            movlw   0x0f
            andwf   TempFrac,F
            movf    TempFrac,W
            addwf   TempFrac,F  ;*2 C=0
            rlf TempFrac,F  ;*4
            addwf   TempFrac,F  ;*5
            rlf TempFrac,F  ;*10
            swapf   TempFrac,W

    PutDigit    bsf BitMask,5   ; BitMask = 0x20 = " "
            andlw   0x0F        ;
            skpnz           ; zero? yes, skip, else
            goto    PutIt      
    PutOnes     btfsc   BitMask,4   ;done leading zeros
            goto    PutIt       ;yes so just print it      
            movwf   FSR     ;skip zeros over - keep copy of W
            movlw   '-'     ;print minus maybe
            btfss   STATUS,7    ;was it minus
            movlw   ' '     ;No, so print space instead
            call    Put232
            movfw   FSR    
            andlw   0x0F        ;and out top bits from FSR
            bsf BitMask,4   ; BitMask = 0x30 = "0"
    PutIt       iorwf   BitMask,W   ; " " or "0".."9"
            goto    Put232      ; print digit
     
    The code ended up 0xfd long and so we have 0xfe free again.:D

    If you can find 1 more word I can reinstate the space between the ROMid and the Scratchpad.

    <edit> I mistakenly thought we could corrupt the RomBuffer after it had been used but have just noticed it is reading chips in a random order. I changed it to use FSR and so now there are zero words free</edit>

    <edit2> I just realised that we can corrupt the last byte of the ROMid (the CRC) as by the time the algorithm has reached that point only one device can be answering. </edit2>

    Mike.
    This is the output in Hyperterminal. Again with freezer spray.
    [​IMG]
     
    Last edited: Jan 27, 2009
  21. jagdish_1449

    jagdish_1449 New Member

    Joined:
    Feb 12, 2008
    Messages:
    1
    Likes:
    0
    nice job good thanks
     
Thread Status:
Not open for further replies.

Share This Page