PDA

View Full Version : Temprature conversion --- C to F



Byte_Butcher
- 23rd September 2011, 01:33
--------------------------------------

I have a temperature sensor (MCP9800) that spits out a 12 bit - 2's compliment number that represents degrees C from - 55 C to + 125 C.

5996

12 bits of resolution gives increments of 1/16 degree C and displays to 4 decimal places, like so: 26.1875
I've got it up and running and successfully displaying temperature in degrees C. With this:



'-----------Read and display temperature from MCP9800-----------

checktemp9800:
i2cread sda9800,clk9800,adr_R,[T_MSB,T_LSB] 'read the 2 bytes of temperature data
TempC = abs T_MSB 'all the stuff to the left of the decimal point is in the MSB.
TempCdec = (T_LSB >>4) * 625 'stuff to the right of the decimal point. Side shift out the unused bits and multiply by 625 for 1/16 degree C resolution.

If T_MSB.7 then 'if the sign bit is "1", display a minus sign
signind = "-"
else
signind = "+ "
endif


Lcdout $fe,2, " ", signind, DEC TempC, "." ,DEC4 TempCdec, 223, " C " ' Display the info

return




By I can't for the life of me figure out how to do the conversion from degrees C to degrees F. !!

I have NO problem for temperatures ABOVE 32 F (0 C) You just multiply by 1.8 (or 18/10) and add 32. Simple...

But when the temperature goes BELOW 0 C then my life (and math) falls apart and I can't make it work right. And I'm not even sure what to do when the temp falls even further to less than 0 F.
I'm not sure why my brain won't do this. It seems like it should be simple enough.

I want to end up with degrees F available to at least 1 (preferably 2) decimal places, and it should work right over the whole range of -55 C to + 125C (-67 F to +257F)

Can someone please spin me around and pull the blindfold off?

Oh, and my "device" is a 16F887, so I'm stuck with 16 bit math.

Thanks...

Demon
- 23rd September 2011, 02:27
I haven't touched a PIC in a while, but I vaguely remember a lot of problems with negative math on the 16F family. :D

Wasn't there a thread here somewhere about something like DT's interrupt stuff but about negative math?

(searching...)

Robert

EDIT: Like this thread:
http://www.picbasic.co.uk/forum/showthread.php?t=7777

"...PBP can't multiply or divide negative numbers. (unless you are using PBPL on an 18F) - DT"

Heckler
- 23rd September 2011, 02:52
I feel your pain!! the math was WAY over my head also... luck was in my favor and I stumbled across an INCLUDE file by Darrel Taylor. His routine will convert between C, F, Kelvin and possibly more!!!

Here is my temperature conversion... after reading a DS18B20 one wire temp sensor.

bear in mind that this routine is for a One Wire DS18b20 temp sensor... and the value is a two BYTE value that can be programmed for 9-12 bit resolution and the value is initially read in deg C



'=======TEMPERATURE subroutine======================================== ======
ShowTemp:
while PortA.3=0 : wend
PAUSE 500
OWOUT Comm_Pin, 1, [$CC, $4E, 0, 0, DS18B20_9bit] 'set resolution of sensor
Start_Convert:
OWOUT Comm_Pin, 1, [$CC, $44]' Skip ROM search & do temp conversion

Wait_Up:
OWIN Comm_Pin, 4, [Busy] ' Read busy-bit
IF Busy = 0 THEN Wait_Up ' Still busy..?, Wait_Up..!
OWOUT Comm_Pin, 1, [$CC, $BE]' Skip ROM search & read scratchpad memory
OWIN Comm_Pin, 2, [Raw.LOWBYTE, Raw.HIGHBYTE]' Read two bytes / end comms
Convert_Temp:
Sign="+"
IF Cold_Bit = 1 THEN 'it's below zero Celsius
C=(ABS Raw>>4)*-10 'so shift the ABS value right and mult X -10
ELSE
C=(Raw>>4)*10 'else shift value right and mult X 10
ENDIF

@ CtoF _C, _F ; Convert Celsius to Fahrenheit
'converted value will be X 10, ie. 756=75.6 deg F
'so devide by 10 to get whole degrees

IF f.15=1 THEN Sign="-" 'if converted value is below zero F then sign is "-"
TempF = (ABS f)/10 'take tha ABS value and /10
IF f//10 >4 THEN TempF=TempF+1 'check remainder, if >4 then round up

IF TempF <10 THEN '1 digit value plus "deg F"
len=3
elseif TempF <100 THEN '2 digit value plus "deg F"
len=4
ELSE '3 digit value plus "deg F"
len=5
ENDIF
arraywrite msg,[Sign,DEC TempF,"*"] ' *= lookup for "deg F"
GOSUB Message ' display current temp

if intrpt=1 then SleepNow 'if here by interrupt then return to SleepNow
IF mode=0 THEN Motto 'if here from motto return to motto
GOTO Icon 'else return to icon



Here are most of the variables associated with the temp conversion routine.


'-------------[variables and constants for temperature routine]--------------
DS18B20_9bit CON 011111 ' set resolution on DS18B20 93.75ms, 0.5 C
Comm_Pin VAR PortA.4 ' One-wire Data-Pin "DQ" on PortA.4
Busy VAR BIT ' Busy Status-Bit
Raw VAR WORD ' RAW Temperature readings
TempF VAR WORD ' Temp in deg F
Cold_Bit VAR Raw.BIT11 ' Sign-Bit for +/- Temp. 1 = Below 0 deg C
Sign VAR BYTE ' +/- sign for temp display



Don't forget to add this line to your program...

INCLUDE "Temp_Convert_CtoFonly.pbp"

also you will need to delete the .txt extension off from the attached include file.

I hope this helps... ask questions if you need to.

possibly most if what you need is Darrels (as always excellent) include file.

Heckler
- 23rd September 2011, 03:02
Here is a link to an article that I wrote that describes reading the ONE WIRE DS18b20 temp sensor...


http://www.picbasic.co.uk/forum/content.php?r=374-How-to-read-a-one-wire-DS18B20-temperature-sensor-or-nine-of-them

Byte_Butcher
- 23rd September 2011, 03:17
Thank You Heckler!

That looks like exactly what I need!
I should have known that Darrel had already written something cool to cover it. (Thank You Darrel !!)

I'll have a read through that stuff this evening and report back tomorrow. :)

Normnet
- 23rd September 2011, 03:18
F = C * 9 'DO LESS THE BIT.7 NEG/POS BIT
F = F / 5
IF T_MSB.7 = 1 THEN 'if the sign bit is "1", is minus C
F = 32 - F
else
F = 32 + F
ENDIF

Norm

Normnet
- 23rd September 2011, 03:32
F = C * 9 'DO LESS THE BIT.7 NEG/POS BIT
F = F / 5
IF T_MSB.7 = 1 THEN 'if the sign bit is "1", is minus C
F = 32 - F
else
F = 32 + F
ENDIF

Norm

Try again:
F = C * 9 'DO LESS THE NEG/POS BIT
F = F / 5
IF T_MSB.7 = 1 THEN 'if the sign bit is "1", is minus C
F = F - 32
else
F = F + 32
ENDIF

Heckler
- 23rd September 2011, 15:27
Hey ByteButcher...
bear in mind that my code does NOT result in an actual SIGNED value of the Temperature deg F. You end up with the correct temperature in the variable "tempF" and the sign of that value in the variable "sign". It is sutable for display on an LCD or something like that. But you will have to know the value of the "sign" if you want to do further calculations on the value.

PS. I posted the wrong INCLUDE statement...
YOU would use ...
INCLUDE "Temp_Convert.pbp"
(I tried to modify Darrels code to simplify it to only include the needed code to convert C to F and eliminate the Kelvin part. I was really tight on code space for my project.)


There is some good informaiton about temperature conversion here (towards the bottom of the page)... http://www.rentron.com/PicBasic/one-wire2.htm

@Normnet... is it really that simple to convert degrees C to degrees F? across the whole range of -55C to +125C ??

Normnet
- 24th September 2011, 03:30
@Normnet... is it really that simple to convert degrees C to degrees F? across the whole range of -55C to +125C ??

I was thinking on the run above but the following is complete.
C value is * 1000 to hold 4 places.


C VAR LONG
F VAR LONG
iSIGN VAR BIT

GOTO MAIN

subC_TO_F:
F = C * 9
F = F / 5
IF iSIGN = 1 THEN 'if the sign bit is "1" is minus C
IF F > 320000 THEN
F = F - 320000
SEROUT2 sSEROUT_PIN,cBAUD,[" -",DEC C/10000,".",DEC4 C," C = -",DEC F/10000,".",DEC4 F," F",13]
ELSE
F = 320000 - F
SEROUT2 sSEROUT_PIN,cBAUD,[" -",DEC C/10000,".",DEC4 C," C = ",DEC F/10000,".",DEC4 F," F",13]
ENDIF
ELSE
F = F + 320000
SEROUT2 sSEROUT_PIN,cBAUD,[" ",DEC C/10000,".",DEC4 C," C = ",DEC F/10000,".",DEC4 F," F",13]
ENDIF
RETURN

MAIN:

SEROUT2 sSEROUT_PIN,cBAUD,[" ",13]
SEROUT2 sSEROUT_PIN,cBAUD,["START",13]

iSIGN = 1 'NEG
FOR C = 100 TO 0 STEP -1 '-.0100 C TO 0 C
GOSUB subC_TO_F
NEXT

iSIGN = 0 'POS
FOR C = 0 TO 100 STEP 1 '0 C TO .0100 C
GOSUB subC_TO_F
NEXT


iSIGN = 1
FOR C = 550000 TO 0 STEP -10000 '-55.0000 C TO 0 C 'DO STEP -1 FOR COMPLETE BUT FOREVER
GOSUB subC_TO_F
NEXT

iSIGN = 0
FOR C = 0 TO 1250000 STEP 10000 '0 C TO 125.0000 C 'DO STEP 1 FOR COMPLETE BUT FOREVER
GOSUB subC_TO_F
NEXT

STOP

END

Norm

Normnet
- 24th September 2011, 04:14
Now displays 4 decimals with round up.

Norm


C VAR LONG
F VAR LONG
iSIGN VAR BIT

GOTO MAIN

subC_TO_F:
F = C * 10
F = F * 9
F = F / 5
IF iSIGN = 1 THEN 'if the sign bit is "1" is minus C
IF F > 3200000 THEN
F = F - 3200000
F = F + 5
F = F / 10
SEROUT2 sSEROUT_PIN,cBAUD,[" -",DEC C/10000,".",DEC4 C," C = -",DEC F/10000,".",DEC4 F," F",13]
ELSE
F = 3200000 - F
F = F + 5
F = F / 10
SEROUT2 sSEROUT_PIN,cBAUD,[" -",DEC C/10000,".",DEC4 C," C = ",DEC F/10000,".",DEC4 F," F",13]
ENDIF
ELSE
F = F + 3200000
F = F + 5
F = F / 10
SEROUT2 sSEROUT_PIN,cBAUD,[" ",DEC C/10000,".",DEC4 C," C = ",DEC F/10000,".",DEC4 F," F",13]
ENDIF
RETURN

MAIN:
SEROUT2 sSEROUT_PIN,cBAUD,[" ",13]
SEROUT2 sSEROUT_PIN,cBAUD,["START",13]

iSIGN = 1
FOR C = 100 TO 0 STEP -1 '-.0100 C TO 0 C
GOSUB subC_TO_F
NEXT

iSIGN = 0
FOR C = 0 TO 100 STEP 1 '0 C TO .0100 C
GOSUB subC_TO_F
NEXT


iSIGN = 1
FOR C = 550000 TO 0 STEP -10000 '-55.0000 C TO 0 C 'DO STEP -1 FOR COMPLETE BUT FOREVER
GOSUB subC_TO_F
NEXT

iSIGN = 0
FOR C = 0 TO 1250000 STEP 10000 '0 C TO 125.0000 C 'DO STEP 1 FOR COMPLETE BUT FOREVER
GOSUB subC_TO_F
NEXT

STOP

END

Byte_Butcher
- 25th September 2011, 16:34
Well, I got lost in a world of fire wood this week and haven't had a chance to look through all these great suggestions. But THANKS to everyone for the input so far. Hopefully in the next day or 2 I'll get a chance to try again.

Norm, you're killing me with those "Longs".... that's going to be tough to implement with my 16F887! :)

Normnet
- 25th September 2011, 17:44
Well, I got lost in a world of fire wood this week and haven't had a chance to look through all these great suggestions. But THANKS to everyone for the input so far. Hopefully in the next day or 2 I'll get a chance to try again.

Norm, you're killing me with those "Longs".... that's going to be tough to implement with my 16F887! :)

No longs, 2 decimals. no round.
Enter C value 124.56 as 12456

Norm


C VAR WORD
F VAR WORD
iSIGN VAR BIT

GOTO MAIN

subC_TO_F:
DISABLE ' Necessary if On Interrupt used
F = C * 9
F = DIV32 5
ENABLE ' Necessary if On Interrupt used

IF iSIGN = 1 THEN 'if the sign bit is "1" is minus C
IF F > 3200 THEN
F = F - 3200
SEROUT2 sSEROUT_PIN,cBAUD,[" -",DEC C/100,".",DEC2 C," C = -",DEC F/100,".",DEC2 F," F",13]
ELSE
F = 3200 - F
SEROUT2 sSEROUT_PIN,cBAUD,[" -",DEC C/100,".",DEC2 C," C = ",DEC F/100,".",DEC2 F," F",13]
ENDIF
ELSE
F = F + 3200
SEROUT2 sSEROUT_PIN,cBAUD,[" ",DEC C/100,".",DEC2 C," C = ",DEC F/100,".",DEC2 F," F",13]
ENDIF
RETURN

MAIN:
SEROUT2 sSEROUT_PIN,cBAUD,[" ",13]
SEROUT2 sSEROUT_PIN,cBAUD,["START",13]


iSIGN = 1
FOR C = 100 TO 0 STEP -1 '-1.00 C TO 0 C
GOSUB subC_TO_F
NEXT

iSIGN = 0
FOR C = 0 TO 100 STEP 1 '0 C TO 1.00 C
GOSUB subC_TO_F
NEXT


iSIGN = 1
FOR C = 5500 TO 0 STEP -100 '-55.00 C TO 0 C 'DO STEP -1 FOR COMPLETE BUT FOREVER
GOSUB subC_TO_F
NEXT

'12500 IS 125.00 * 100 TO HOLD 2 DECIMAL PLACES
iSIGN = 0
FOR C = 0 TO 12500 STEP 100 '0 C TO 125.00 C 'DO STEP 1 FOR COMPLETE BUT FOREVER
GOSUB subC_TO_F
NEXT

STOP

END

Byte_Butcher
- 25th September 2011, 22:20
NORM!
This works great!
I tested it with my circuit and it works perfect down to at least -20C (-4F) which is as cold as my freezer goes. :)
So that should cover the full range of temperature now.

I really appreciate the help from all of you.
I've pondered the problem several times over the last few years but never came up with code that worked over the full range of positive and negative temps.

This is very cool :D
THANKS! THANKS! THANKS!


subC_TO_F:
F = C * 9
F = DIV32 5

IF C_sign = 1 THEN 'if the sign bit is "1" is minus C
IF F > 3200 THEN
F = F - 3200
lcdout $fe,$2," C = -",DEC C/100,".",DEC2 C,$fe,$c0," F = -",DEC F/100,".",DEC2 F," "
ELSE
F = 3200 - F
lcdout $fe,$2," C = -",DEC C/100,".",DEC2 C,$fe,$c0," F = ",DEC F/100,".",DEC2 F," "
ENDIF
ELSE
F = F + 3200
lcdout $fe,$2," C = ",DEC C/100,".",DEC2 C,$fe,$c0," F = ",DEC F/100,".",DEC2 F," "
ENDIF
pause 200
RETURN


Oh, and this is the first time that I've played with "DIV32". Very handy that is....

Normnet
- 26th September 2011, 06:04
Now with round up, No longs, 2 decimal places.
Enter C value 124.56 as 12456

Norm


C VAR WORD
F VAR WORD
iSIGN VAR BIT

GOTO MAIN

subC_TO_F:
F = C * 2
F = F * 9
F = DIV32 5
F = F + 1 'ROUND UP
F = F / 2
IF iSIGN = 1 THEN 'if the sign bit is "1" is minus C
IF F > 3200 THEN
F = F - 3200
SEROUT2 sSEROUT_PIN,cBAUD,[" -",DEC C/100,".",DEC2 C," C = -",DEC F/100,".",DEC2 F," F",13]
ELSE
F = 3200 - F
SEROUT2 sSEROUT_PIN,cBAUD,[" -",DEC C/100,".",DEC2 C," C = ",DEC F/100,".",DEC2 F," F",13]
ENDIF
ELSE
F = F + 3200
SEROUT2 sSEROUT_PIN,cBAUD,[" ",DEC C/100,".",DEC2 C," C = ",DEC F/100,".",DEC2 F," F",13]
ENDIF
RETURN

MAIN:
SEROUT2 sSEROUT_PIN,cBAUD,[" ",13]
SEROUT2 sSEROUT_PIN,cBAUD,["START",13]

iSIGN = 1
FOR C = 100 TO 0 STEP -1 '-1.00 C TO 0 C
GOSUB subC_TO_F
NEXT

iSIGN = 0
FOR C = 0 TO 100 STEP 1 '0 C TO 1.00 C
GOSUB subC_TO_F
NEXT


iSIGN = 1
FOR C = 5500 TO 0 STEP -100 '-55.00 C TO 0 C 'DO STEP -1 FOR COMPLETE BUT FOREVER
GOSUB subC_TO_F
NEXT

'12500 IS 125.00 * 100 TO HOLD 2 DECIMAL PLACES
iSIGN = 0
FOR C = 0 TO 12500 STEP 100 '0 C TO 125.00 C 'DO STEP 1 FOR COMPLETE BUT FOREVER
GOSUB subC_TO_F
NEXT

STOP

END