Scalling the temprtature below freezing

Ga-Retired

New Member
Hi everyone,just a question on the scalling of the DS18B20 below 32*F.I'm using the 08m2+ to gather the DS18B20 Temp. using variable W1 and displaying on a 4 digit CC LED display driven by the Max7219.This project has been working just great when the temperature is above 0* C or in my case 32* F which I used forum members Marks conversion formula of:Temperature = Temperature +880 **7373 -67 being capable of reading 0*F to 257*F in whole numbers.Using the current scalling of:Thous = Temperature /Base/Base/base
Hundr = Temperature /Base/Base//Base
Tens = Temperature / Base // Base
Units = Temperature // Base
Base being = decimal10.All is well down to 32*F and then it comes up with random numbers.I've been trying to figuire this problem out myself, but to my dismay, haven't been able to solve the problem.I'm wanting to display a temperature from say around 15*F to above 100*F which Marks conversion covers this range nicely.(Thanks Marks!)Any help or solutions on this is always appreicated.
my best,Ga-Retired
 

eggdweather

Senior Member
So the 18B20 returns Celsius result, examples:

+125°C / 0000 0111 1101 0000 / 07D0h
+85°C / 0000 0101 0101 0000 / 0550h*
+25.0625°C / 0000 0001 1001 0001 / 0191h
+10.125°C / 0000 0000 1010 0010 / 00A2h
+0.5°C / 0000 0000 0000 1000 / 0008h
0°C / 0000 0000 0000 0000 / 0000h
-0.5°C / 1111 1111 1111 1000 / FFF8h
-10.125°C / 1111 1111 0101 1110 / FF5Eh
-25.0625°C / 1111 1110 0110 1111 / FF6Fh
-55°C / 1111 1100 1001 0000 / FC90h

Things to check, how are you converting from deg-C to deg-F, the 32F is significant as the sign changes, so check/post your code please. Your partial post looks wrong to me, what is happening is (say the temp = 0) then the MSB was 0000, but when e.g. -0.5'C becomes 1111 now put that number into your formula and your calculations overflow.
You need to test for that condition, complement the bits, then set a flag to denote the result is now negative to then print the minus sign, if that makes sense.

Noting what +10 binary is and the same for -10 goes like this:
+10.125°C / 0000 0000 1010 0010 / 00A2h
-10.125°C / 1111 1111 0101 1110 / FF5Eh

Complement the bytes of -10 becomes:
0000 0000 1010 0001 or 10.125

Take a reading, then check if MSBit is 1, if so then set a flag to denote the result is negative say negative_value = TRUE, then complement (invert all the bits) of the reading, then print a "-" then use the same formula as above to print the (negative now positive) result.

Make sense?
 
Last edited:

AllyCat

Senior Member
Hi,

I'm not sure if you're using readtemp or readtemp12. Strictly you should be using readtemp12 for accurate integer degrees F (because there are almost 2 for each degree C). But let's start with readtemp:

PICaxe Basic can't (easily) scale (i.e. multiply or divide) negative numbers, so the easisest solution is not to work with negative numbers! For temperature calculations, using minus 40 degrees (assuming you won't encounter lower values) as a "base" is a useful trick, because it's the same temperature in C and F.

However, Manual 2 implies that readtemp does NOT return a two's complement value (as shown by eggdweather) so I think it needs to be converted, and to be safe we should also "sign extend" the value to 16 bits, e.g.:

IF readtempvalue > $7F THEN : readtempvalue = 127 - readtempvalue OR $FF00 : ENDIF

Then add 40 to the (sign extended) value received. Now you can scale to F by multiplying by 9 / 5 and then subtract 40 .

That calculation will truncate the result (e.g. "60.9" degrees becomes 60) so you can round to the nearest integer by adding half the divisor before division. Thus the calculation becomes:

TempF = (converted)readtempvalue + 40 * 9 + 2 / 5 - 40

With readtemp12, you'd need to modify the sign extension formula and introduce division by 16 to get to integer degrees.

Cheers, Alan.
 

marks

Senior Member
Hi Ga-Retired,
I would think the code should work find
It does sound like it could be a hardware problem
at lower temperatures it needs a bit more power for conversion
an unstable supply could cause erratic readings .if you sensor cable is long
perhaps try a 1uf cap at the sensor end where the pullup should be also try a 2.2k pullup



Code:
SYMBOL Ds18b20      = C.0
SYMBOL Temperature  = W0 
SYMBOL units        = b4 
SYMBOL tens         = b5 
SYMBOL hunds        = b6 
SYMBOL thous        = b7

Main:
Readtemp12 Ds18b20,Temperature 
 
  Convert:                                             
  Temperature = Temperature +880 **7373 -67             'Fahrenheit (0F to 257F)
        units = temperature  //10  
        tens  = temperature   /10 //10
       hunds  = temperature  /100 //10
     
 SERTXD (CR, LF, "Temperature ",#hunds,#tens,#units," degrees F", CR, LF) 
 GOTO Main
 

hippy

Ex-Staff (retired)
Using READTEMP12 the returned number is a 16 bit two's complement value, the most significant 12 bits the integer temperature in Centigrade, the least significant 4 bits the fractional temperature.

To convert that to the same in Fahrenheit ( 512 = 32*16, 32.0 with a 4 bit fractional ) -

Code:
ConvertCtoF:
  If Centigrade < $8000 Then
    Fahrenheit  = Centigrade * 9 / 5 + 512
  Else
    Fahrenheit  = -Centigrade * 9 / 5
    Fahrenheit  = -Fahrenheit + 512
  End If
  Return
By keeping the Centigrade and Fahrenheit formats the same it means a single 'print signed temperature' routine can be used to display both.

A full demonstration / test program below -

Code:
#Picaxe 08M2
#Terminal 4800

Pause 2000

Do

  w0 = $07D0 : Gosub Show ; +125      / 0000 0111 1101 0000 / 07D0
  w0 = $0550 : Gosub Show ;  +85      / 0000 0101 0101 0000 / 0550
  w0 = $0191 : Gosub Show ;  +25.0625 / 0000 0001 1001 0001 / 0191
  w0 = $00A2 : Gosub Show ;  +10.125  / 0000 0000 1010 0010 / 00A2
  w0 = $0008 : Gosub Show ;   +0.5    / 0000 0000 0000 1000 / 0008
  w0 = $0000 : Gosub Show ;    0      / 0000 0000 0000 0000 / 0000
  w0 = $FFF8 : Gosub Show ;   -0.5    / 1111 1111 1111 1000 / FFF8
  w0 = $FF5E : Gosub Show ;  -10.125  / 1111 1111 0101 1110 / FF5E
  w0 = $FE6F : Gosub Show ;  -25.0625 / 1111 1110 0110 1111 / FE6F
  w0 = $FC90 : Gosub Show ;  -55      / 1111 1100 1001 0000 / FC90

  SerTxd( CR, LF )

  w0 = $FCE0 : Gosub Show ; -50 C  -58.0 F
  w0 = $FD80 : Gosub Show ; -40 C  -40.0 F
  w0 = $FE20 : Gosub Show ; -30 C  -22.0 F
  w0 = $FEC0 : Gosub Show ; -20 C   -4.0 F
  w0 = $FF60 : Gosub Show ; -10 C   14.0 F
  w0 = $0000 : Gosub Show ;   0 C   32.0 F
  w0 = $00A0 : Gosub Show ;  10 C   50.0 F
  w0 = $0140 : Gosub Show ;  20 C   68.0 F
  w0 = $01E0 : Gosub Show ;  30 C   86.0 F
  w0 = $0280 : Gosub Show ;  40 C  104.0 F
  w0 = $0320 : Gosub Show ;  50 C  122.0 F

  Pause 10000

  SerTxd( CR, LF, "===", CR, LF )

Loop

Show:
  Gosub PrintHexWord
  SerTxd( 9 )
  Gosub PrintSignedTemperature ; w0 in C
  SerTxd( "C", 9 )
  Gosub ConvertCtoF            ; w0 in C -> w0 in F
  Gosub PrintSignedTemperature ; w0 in F
  SerTxd( "F", CR, LF )
  Return

ConvertCtoF:
  If w0 < $8000 Then
    w0 = w0 * 9 / 5 + 512
  Else
    w0 = -w0 * 9 / 5
    w0 = -w0 + 512
  End If
  Return

PrintHexWord:
  SerTxd( "$" )
  b11 = w0 / $1000 : Gosub PrintHexNibble 
  b11 = w0 / $100  : Gosub PrintHexNibble 
  b11 = w0 / $10   : Gosub PrintHexNibble 
  b11 = w0         : Gosub PrintHexNibble 
  Return

PrintHexNibble:
  b11 = b11 & 15 + "0"
  If b11 > "9" Then
    b11 = b11 + 7
  End If
  SerTxd( b11 )
  Return

PrintSignedTemperature:
  If w0 < $8000 Then
    SerTxd( "+" )
    w2 = w0
  Else
    SerTxd( "-" )
    w2 = -w0
  End If
  w3 = w2 & 15 * 625
  BinToAscii w3, b15,b14,b13,b12,b11
  w3 = w2 / 16
  SerTxd( #w3, ".", b14,b13,b12,b11 )
  Return
That should produce the results as follows -

Code:
$07D0	+125.0000C	+257.0000F
$0550	+85.0000C	+185.0000F
$0191	+25.0625C	+77.0625F
$00A2	+10.1250C	+50.1875F
$0008	+0.5000C	+32.8750F
$0000	+0.0000C	+32.0000F
$FFF8	-0.5000C	+31.1250F
$FF5E	-10.1250C	+13.8125F
$FE6F	-25.0625C	-13.0625F
$FC90	-55.0000C	-67.0000F

$FCE0	-50.0000C	-58.0000F
$FD80	-40.0000C	-40.0000F
$FE20	-30.0000C	-22.0000F
$FEC0	-20.0000C	-4.0000F
$FF60	-10.0000C	+14.0000F
$0000	+0.0000C	+32.0000F
$00A0	+10.0000C	+50.0000F
$0140	+20.0000C	+68.0000F
$01E0	+30.0000C	+86.0000F
$0280	+40.0000C	+104.0000F
$0320	+50.0000C	+122.0000F
 

AllyCat

Senior Member
Hi,

Yes, it does sound like a hardware issue, because marks' code should work fine (also for negative temperatures) except that pin C.0 cannot be used with a 08M2.

The "magic numbers" are rather more confusing, the "base" temperature appears to be -55 degrees C (i.e. 880 = 55 * 16) and the ** 7373 is 65536 * 9 / 5 / 16 (equals 7372.8). Then subtracting "67" is the -40 ("common" temperature) plus the extra -15 degrees C = -15 * 9 / 5 = -27 F .

Cheers, Alan.
 

Ga-Retired

New Member
Thanks everyone for your response,sorry for the delay in getting back.
Hippy and eggdweather:Thanks guys for your very detailed info and as I still consider myself a 'Noobie" at this programming thing its way above my knowledge base at this time.However,I'm learning more of this "Math" stuff each time I encounter these problems.So thank you guys for your efforts, I just need some low level bascic information that I can get my "Noobie" head wrapped around.
Allycat,Marks:To answer your inquiry about the possability of a hardware setup problem,this project has been running both wireless and on a proto board with 1 degree accuracy all the way down to 32* F where I encounter this changeover problem,which BTW,I think I know where I went astray.So back to the shop to test the info you provided to me.
Marks: your *F conversion (Temperature = Temperature +880 **7373 -67 'Fahrenheit (0F to 257F)
does it require any "sign" conversion like - (minus) or is it taken care of in the formula above? Just to verify I'm using "readtemp12" on this project.
I don't want to make this to long a reply, (TLDR),so I'll take any and all help please!I love the Picaxe,its the best I think at learning to work with MCU's.
Thanks once again as always guys,my best,Ga-Retired
 

marks

Senior Member
Hi Ga-Retired,
the conversion code shown is all that is required for the range of 0F to 257F as shown in brackets.

the sensors raw output is -880 to 2000 which is (-67F to 257F)
because we have added 880 there are no negative numbers to deal with

earlier mention of random numbers ,this is more likely caused from the ds18b20 having an unstable source
it requires a good pullup voltage to do a proper tempconversion and then sends the data to your picaxe.
So check your project has adequate decoupling which needs to be determined for load and devices.
any picaxe should have a minimum of a 22uF and 0.1uF
and the led led display may likely need its own decoupling.

a bad connection will probably cause it to just display 32F (raw value 0) when unplugged
 

Ga-Retired

New Member
Hi Marks,I'll look into the power situation and make sure its well filtered and capable of handeling the load of the Max7219.The 08M2 has a 104 right across the pwr pins and the 7219 has its 10uf & 104 decoulping caps.So the power source could very well be the problem,but is reading 5.1 volts across the rails.Thanks for the reminder about your code NOT needing any further manipulation for negative numbers,that helps ....... alot! I finally got the Max7219 fiquired out so if I can solve this problem I'll be a very happy guy.Got some 3 digit displays coming and will want to get this project changed over to them,the fun never stops does it. Thanks again my friend,I'll get back with the results soon.
 
Top