Continue to Site

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.

  • 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.

Temperature Sensor DS18B20 Display Fahrenhiet

Status
Not open for further replies.
Hi everyone.

I continue being asked if my DS18B20 Temp Sensor can be changed to display Fahrenheit instead of Celsius.
I say 'Yes, but I'm not sure how'..

I need some pointers in regard to some PIC math to adapt to my DS18B20 Temperature Sensor project found here:

I need to take the 16 bit signed number, X 1.8 + 32
Where do i start?
 
Last edited:
Your temperature is multiplied by 16 and is in the form ssssnnnn nnnn.ffff (sign,number,fraction). So dividing by 8 (shift right 3 times) and adding the original number will be 18 times the value. If you now add 320 you will have the temperature in Fahrenheit times ten. Print it out with a decimal point before the last digit and you have your result.

EG,
20°C = 00000001 01000000 = 320 decimal
320/8 = 40
320+40 = 360
360+320 = 680
printed = 68.0°F

Mike.
 
Pommie, I've just been thinking, and trying to work out;
How are the negative temperatures handled.

Say for instance the 2's complemented -25.125c (= -13.225 F)
1111 1110 0110 1110
 
Exactly the same way,

1111 1110 0110 1110 = -402
-402/8 = -50
-402+-50 = -452
-452+320 = -132
Printed = -13.2

Note, to do the divide by eight you have to set the top three bits after the shift.

Mike.
 
Pommie, woudln't dividing by eight lose data?

If the application is in C it should be easy enough to do *18 /10 (or *9 /5) which will preserve the data.

If possible I would do *18, +5, /10 to give closest rounding up or down.
 
As he is working in assembler I thought it best to avoid both multiply and divide. The above uses just shifts and addition.

Mike.
 
Just out of curiosity.. how do you do multiply and divide with assembler?

Or how do you do it in C, and what is the result in assembler after it is compiled?
 
For a complete list of maths functions go to .

In C you simply do,
Code:
    Farenheit = Centigrade*9/5+32;
and the compiler will produce very similar code to the PicList versions.

Mike.
 
Ok so i'm finally sitting down to convert my DS18B20 temp sensor to display fahrenheit.

Taking pommie's idea of ((C/8)x10) = (Cx18) + 320 = F x 10 i've started with this.

Code:
;TEMPHI_C & TEMPLO_C hold temperature data in celsius from the DS18B20 which has already been obtained.
;TEMPHI_F & TEMPLO_F will be used to hold the Fahrenheit x 10 conversion.

; FLAGS, 1  = Temperature Negative Flag (0 = False 1 = True)
first routines to divide by 8

Code:
DISPLAY_FAHRENHEIT   ; Displays Temperature in Fahrenheit Format 
        MOVF    TEMPLO_C, W             ; Copy Celsius Temperature Data into Fahrenheit Registers for conversion
        MOVWF   TEMPLO_F                ; 
        MOVF    TEMPHI_C, W             ; 
        MOVWF   TEMPHI_F                ; 

DIVIDE_BY_8
        RRF     TEMPHI_F, F             ; Divide 16 bit number by 8 by shifting right 3 times
        RRF     TEMPLO_F, F             ; / 2
        RRF     TEMPHI_F, F             ; 
        RRF     TEMPLO_F, F             ; / 4
        RRF     TEMPHI_F, F             ; 
        RRF     TEMPLO_F, F             ; / 8
        
        BTFSS   TEMPHI_C, 7             ; Is temp negative?
        GOTO    $+D'4'                  ; No
        MOVLW   B'11100000'             ; Set upper 3 bits if temperature negative
        IORWF   TEMPHI_F, F             ; 
        GOTO    $+D'3'
        MOVLW   B'00011111'             ; Clear upper 3 bits if temperature positive
        ANDWF   TEMPHI_F, F             ; 

CONTINUE

But this code is flawed.
lets take -25.125 c like in pommies example (post #5)
or -402

Code:
;        MOVLW   B'11111110'              ; Load Dummy Temperature
;        MOVWF   TEMPHI_C                 ; Decimal = -402
;        MOVLW   B'01101110'              ; C = -25.125
;        MOVWF   TEMPLO_C                 ; F = -13.2

-402 / 8 = -50
but shifting 3 places right gives -51

I could work around this by INCF'ing TEMPLO_F, but it mess's up other temperatures that work correctly.
any ideas?
 
Due to the fact that shifting, by it's nature, will always round down (-51 is less than -50) the way around this is to add 4 to the number so it rounds correctly.

So, do ((Num+4)>>3)+Num+320
-402
+4 = -398
>>3 = -50
+-402 = -452
+320 = -132
print -13.2

Mike.
 
Last edited:
Yes, I realised what I'd done and edited it. It should make sense now.

Mike.
 
Ok, so we only want to add 4 to negative 2's complemented temperature becasue positive temperatures round correctly.

becasue this is 16-bit math with an 8-bit processor, is there a better way to do this add 4 routine than what i have come up with. (below)

For example...
if we have -2 (11111111 11111110) and we add 4.. the upper regsister must overflow too.

here's what I have:
Code:
        BCF     STATUS, Z
        INCF    TEMPLO_C, F
        BTFSC   STATUS, Z
        INCF    TEMPHI_C, F

        INCF    TEMPLO_C, F
        BTFSC   STATUS, Z
        INCF    TEMPHI_C, F

        INCF    TEMPLO_C, F
        BTFSC   STATUS, Z
        INCF    TEMPHI_C, F

        INCF    TEMPLO_C, F
        BTFSC   STATUS, Z
        INCF    TEMPHI_C, F

There's got to be a better way.
 
Last edited:
You always add 4 so it rounds correctly.

To add 4 do,
Code:
	movlw	4			;add 4
        addf    TEMPLO_C, W             ; Copy Celsius Temperature Data into Fahrenheit Registers for conversion
	andlw	b'11111000'		;ensure carry stays clear later
        MOVWF   TEMPLO_F                ; 
        MOVF    TEMPHI_C, W             ; 
	btfsc	STATUS,C
	incf	TEMPHI_C,W		; allow for carry
        MOVWF   TEMPHI_F                ; 

	bcf	STATUS,C		;do divide
	rrf	TEMPH_F,f
	rrf	TEMPL_F,f
	rrf	TEMPH_F,f
	rrf	TEMPL_F,f
	rrf	TEMPH_F,f
	rrf	TEMPL_F,f

	movlw	b'11100000'		;do sign extend
	btfsc	TEMPH_C,7
	iorwf	TEMPHI_F,f

	movfw	TEMPL_C			;add original temp
	addwf	TEMPL_F,f
	btfsc	STATUS,C
	incf	TEMPH_F,f
	movfw	TEMPH_C
	addwf	TEMPH_F,f

	movlw	low(.320)		;add 320
	addwf	TEMPL_F,f
	btfss	STATUS,C
	incf	TEMPH_F,f
	movlw	high (.320)
	addwf	TEMPH_F,f

Got carried away and did all the operations.

Mike.
 
Ok I've got it working.
Mike I couldnt get your ADD_4 routine to work, nor could I interpret what your block of instructions was doing to fix it.
I have reverted back to my simple, but long, routine just to get it working for now..
I've simulated a series of Dummy Temperature and it works.

After my BIN_TO_DEC routine I have my "look up table jump pointers" stored in 4 registers;
THOUS holds amount of thousands (i.e. 0000 0001 = 1x1000)
HUNS holds amount of hundreds (i.e. 0000 0010 = 2x100)
TENS holds amount of tens (i.e. 0000 0010 = 2x10)
ONES holds amount of ones (i.e. 0000 0101 = 5x1)

These registers are used in the ISR for loading each of the 4 digits on the 7 seg display..

For example: I load B'11111110 01101110' D'-402' (-25.125 C = -13.2 F)
My routines output
THOUS 0
HUNS 1
TENS 3
ONES 2

Then I print this on the display to the corresponding segments with a decimal between the ones and tens to make it appear as 13.2 (F)

Code:
DUMMY_LOAD
; DUMMY TEMPERATURES ;------------------------------------------------------       
;        MOVLW   B'00000111'              ; Load Dummy Temperature
;        MOVWF   TEMPHI_C                 ; Decimal =  2000
;        MOVLW   B'11010000'              ; C = 125.0
;        MOVWF   TEMPLO_C                 ; F = 257.0

;        MOVLW   B'00000101'              ; Load Dummy Temperature
;        MOVWF   TEMPHI_C                 ; Decimal =  1360
;        MOVLW   B'01010000'              ; C = 85.0
;        MOVWF   TEMPLO_C                 ; F = 185.0

;        MOVLW   B'00000011'              ; Load Dummy Temperature
;        MOVWF   TEMPHI_C                 ; Decimal =  913
;        MOVLW   B'10010001'              ; C = 57.0625
;        MOVWF   TEMPLO_C                 ; F = 134.7

;        MOVLW   B'00000001'              ; Load Dummy Temperature
;        MOVWF   TEMPHI_C                 ; Decimal = 401
;        MOVLW   B'10010001'              ; C = 25.0625
;        MOVWF   TEMPLO_C                 ; F = 77.1

;        MOVLW   B'11111111'              ; Load Dummy Temperature
;        MOVWF   TEMPHI_C                 ; Decimal = -2
;        MOVLW   B'11111110'              ; C = -0.125
;        MOVWF   TEMPLO_C                 ; F = 31.8

;        MOVLW   B'11111111'              ; Load Dummy Temperature
;        MOVWF   TEMPHI_C                 ; Decimal = -10
;        MOVLW   B'11110110'              ; C = -0.625
;        MOVWF   TEMPLO_C                 ; F = 30.9

;        MOVLW   B'11111111'              ; Load Dummy Temperature
;        MOVWF   TEMPHI_C                 ; Decimal = -162
;        MOVLW   B'01011110'              ; C = -10.125
;        MOVWF   TEMPLO_C                 ; F = 13.8

        MOVLW   B'11111110'              ; Load Dummy Temperature
        MOVWF   TEMPHI_C                 ; Decimal = -402
        MOVLW   B'01101110'              ; C = -25.125
        MOVWF   TEMPLO_C                 ; F = -13.2

;        MOVLW   B'11111100'              ; Load Dummy Temperature
;        MOVWF   TEMPHI_C                 ; Decimal = -880
;        MOVLW   B'10010000'              ; C = -55.0
;        MOVWF   TEMPLO_C                 ; F = -67.0
; DUMMY TEMPERATURES ;------------------------------------------------------
        
DISPLAY_TEMP
TEST_IF_NEGATIVE 		
        BCF     FLAGS, 1                ; Clear Negative Flag
        BTFSS   TEMPHI_C, 7             ; Test if Temperature is negative (2's complement format)
        GOTO    COPY                    ; NOT Negative, skip "UNDO_2SCOMPLEMENT"
        BSF     FLAGS, 1                ; Set Negative Flag; used later
        
COPY
        MOVF    TEMPLO_C, W             ; Copy Celsius Temperature Data into Fahrenheit Registers for conversion
        MOVWF   TEMPLO_F                ; 
        MOVF    TEMPHI_C, W             ; 
        MOVWF   TEMPHI_F                ; 
        
        
 ; The following 3 routines convert the Celsius Temperature Data into Fahrenheit * 10.
 ; This is acheived by dividing by 8 and adding the original number, which gives 18 times the value. 
 ; If you now add 320 you will have the temperature in Fahrenheit times ten.
 ; After the conversion it is simply a matter of displaying the data with the decimal shifted one place to the right.
 ; Example 
 ; 25 Degrees C  =  B'0000000110010000'  =  D'400' 
 ; 400 / 8   =  50
 ;  50 + 400 = 450
 ; 450 + 320 = 770
 ; 770 /  10 = 77 Degrees Fahrenheit
ADD_4  ; Adding 4 ensures number is correctly rounded after DIVIDE_BY_8 routine
        BCF     STATUS, Z
        INCF    TEMPLO_F, F
        BTFSC   STATUS, Z
        INCF    TEMPHI_F, F
 
        INCF    TEMPLO_F, F
        BTFSC   STATUS, Z
        INCF    TEMPHI_F, F
 
        INCF    TEMPLO_F, F
        BTFSC   STATUS, Z
        INCF    TEMPHI_F, F
 
        INCF    TEMPLO_F, F
        BTFSC   STATUS, Z
        INCF    TEMPHI_F, F
        
DIVIDE_BY_8
        RRF     TEMPHI_F, F             ; Divide 16 bit number by 8 by shifting right 3 times
        RRF     TEMPLO_F, F             ; / 2
        RRF     TEMPHI_F, F             ; 
        RRF     TEMPLO_F, F             ; / 4
        RRF     TEMPHI_F, F             ; 
        RRF     TEMPLO_F, F             ; / 8
        
MASK_BITS  ; This routine sets or clear the upper 3 bits of TEMPHI_F depending on weather or not the temp is negative or positive        
        BTFSS   TEMPHI_C, 7             ; Is temp negative?
        GOTO    $+D'7'                  ; No
        MOVF    TEMPLO_F, F             ; Temperature may be negative but result after ADD_4 may have caused TEMPLO_F to overflow
        BTFSC   STATUS, Z               ; Did TEMPLO_F overflow?
        GOTO    $+D'4'                  ; Yes, clear upper 3 bits of TEMPHI_F
        MOVLW   B'11100000'             ; 
        IORWF   TEMPHI_F, F             ; No, Set upper 3 bits
        GOTO    $+D'3'                  ;
        MOVLW   B'00011111'             ; Clear upper 3 bits
        ANDWF   TEMPHI_F, F             ; 
        
ADD_ORIGINAL
        BCF     STATUS, C               ; Add original number 
        MOVF    TEMPLO_C, W             ; 
        ADDWF   TEMPLO_F, F             ; 
        BTFSC   STATUS, C               ;
        INCF    TEMPHI_C, F             ;
        MOVF    TEMPHI_C, W             ; 
        ADDWF   TEMPHI_F, F             ; Temperature is now 18 x the value
        
ADD_320
        MOVLW   B'01000000'             ; 
        ADDWF   TEMPLO_F, F             ;
        BTFSC   STATUS, C               ;
        INCF    TEMPHI_F, F             ;
        MOVLW   B'00000001'             ; 
        ADDWF   TEMPHI_F, F             ; Result is now C x 18 + 320 (= F x 10)
        
        BTFSS   TEMPHI_F, 7             ; Test if number negative (2's complemented)
        GOTO    BIN_TO_DEC_F            ; No, skip undo 2's complement
        
        COMF    TEMPLO_F, F             ; Invert TEMPLO 
        COMF    TEMPHI_F, F             ; Invert TEMPHI
        INCFSZ  TEMPLO_F, F             ; Increment TEMPLO once; After inverting the data, add one to acheive equivalent positive number (see 2's complement)
        GOTO    $+D'2'                  ; No overflow skip next instruction
        INCF    TEMPHI_F, F             ; Overflow occured, increment upper byte
        
        
BIN_TO_DEC_F  ; This routine converts a 16-bit number held in TEMPHI_F:TEMPLO_F to Decimal and stores it in 4 GPR's; THOUS, HUNS, TENS & ONES
 ; Example 1225;
 ; THOUS holds amount of thousands (i.e. 0000 0001 = 1x1000)
 ; HUNS holds amount of hundreds (i.e. 0000 0010 = 2x100)
 ; TENS holds amount of tens (i.e. 0000 0010 = 2x10)
 ; ONES holds amount of ones (i.e. 0000 0101 = 5x1)
 ; These registers are then used as jump pointers when calling digits to display
        
        INCF    TEMPLO_F                ; Preload TEMPHI + 1
        INCF    TEMPHI_F                ; Preload TEMPHI + 1
        CLRF    THOUS                   ; HUNS = 0000 0000
 
        MOVLW   D'246'                  ; MOVE Decimal '246' to W
        MOVWF   HUNS                    ; ONES GPR = 1111 0101
        MOVWF   TENS                    ; TENS GPR = 1111 0101
        MOVWF   ONES                    ; ONES GPR = 1111 0101
        DECFSZ  TEMPLO_F, F             ; Decement TEMPHI register
        GOTO    $+D'4'                  ; NOT 0, skip next instruction
        DECFSZ  TEMPHI_F, F             ; Decement TEMPHI register
        GOTO    $+D'2'                  ; NOT 0, skip next instruction
        GOTO    $+D'9'                  ; NOT 0, skip next instruction
        INCFSZ  ONES, F                 ; Increment ONES register, skip if 0
        GOTO    $-D'6'                  ; NOT 0, GOTO here - 4 instructions
        INCFSZ  TENS, F                 ; IS 0, Increment TENS register skip if 0
        GOTO    $-D'9'                  ; GOTO here - 7 instructions & reset the ONES register to D'246'
        INCFSZ  HUNS, F                 ; TENS overflowed, Increment HUNS
        GOTO    $-D'12'                 ; GOTO here - 10 instructions & reset the ONES and TENS registers to D'246'
        INCF    THOUS, F                ; TENS overflowed, Increment HUNS
        GOTO    $-D'15'                 ; GOTO here - 10 instructions & reset the ONES and TENS registers to D'246'
 
        SUBWF   HUNS, F                 ; W still holds D'246 so subract it from TENS register to determine how many 'TENS'
        SUBWF   TENS, F                 ; W still holds D'246 so subract it from TENS register to determine how many 'TENS'
        SUBWF   ONES, F                 ; W still holds D'246 so subract it from ONES register to determine how many 'ONES'

SO, before I begin code optimization and disscussing better way to do various things (becasue I know there is room for improvments with the methods I have used) I need to do one more thing...

I need to creat a flag for when the temp is negative..
But not negative Celsius, Negative Fahrenheit..
In other words I want to Set 'FLAGS, 2' if Fahrenheit < 0
OR
DS18B20 output < -285
OR
IF DS18B20 = -285 to -880, FLAGS, 2 = 1
ELSE FLAGS, 2 = 0

any ideas?

Then I will use the flag in this routine:
Code:
  ; Leading zero suppression & minus (-) sign if Temperature Negative
        MOVF    THOUS, W                ; Does HUNS equal 1 or 2? MOVF instruction affects Z bit of STATUS register 
        BTFSC   STATUS, Z               ; Test Z bit of STATUS register to see if HUNS = 0000 0000
        MOVLW   B'00001010'             ; Jump Pointer for blank arrangement
 
        BTFSC   FLAGS, 2                ; Is Temperature Negative?
        MOVLW   B'00001011'             ; YES, Jump Pointer for - arrangement
        MOVWF   THOUS                   ; 
 
        BTFSS   STATUS, Z               ; Test Z bit of STATUS register to see if THOUS = 0000 0000
        GOTO    $+D'5'                  ; THOUS is not, therefore do not blank HUNS
        MOVF    HUNS, W                 ; Does TENS equal 0?
        BTFSC   STATUS, Z               ; Test Z bit of STATUS register to see if last instruction = 0000 0000
        MOVLW   B'00001010'             ; Jump Pointer for blank arrangement
        MOVWF   HUNS                    ;
 
If you are dividing a two's complement number by shifting, you have to preserve the msb.

I think that the simplest way is:-

Code:
	rlf	TEMPH_F, w		
	rrf	TEMPH_F,f
	rrf	TEMPL_F,f

The first line puts the msb of TEMPH_F into the carry bit, but does nothing to TEMPH_F. The contents of w are never used.

The following line will bring that bit in to indicate a negative if required.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top