PicBasic Pro, PicBasic, BASIC Stamp, Microchip PIC, 8051, and Remote Control Projects

-- Part 3 --
-- A Simple "High Precision" --
-- 1-Wire Temperature Application  --

A lot of folks have asked how to use the DS18B20 in 12-bit mode, and how to display the results of the DS18B20 temperature readings in °C & °F. Here's a quick code example that displays the temperature in both °C & °F, with 1/16 °C resolution, and ± 0.5°C [0.9°F] accuracy from -10°C to +85°C. The RAW temperature data is shown in 16-bit binary format for verification of the temp conversion calculations.

This is a very simple application, but it uses some of the advanced features of the PicBasic Pro compiler version 2.4 to calculate precise temperatures, and uses the Skip ROM command since we're only using a single 1-wire device.

26.250 °C
(1.8 x 26.250°C) + 32 = 79.25°F

-25.00 °C
(1.8 x -25.00°C) + 32 = -13°F

The conversion calculation from °C to °F shown here works "Full-Range"; from +125°C to -55°C, however, doing this in integer math requires a few tricks. As you'll see, the PicBasic Pro version 2.4 DIV32 function lets us cheat a little.

The code shown below may be confusing until you understand how the DIV32 command works, so spend a little time becoming familiar with this particular command. The DIV32 function allows us to do 16-bit x 16-bit multiplies yielding a 32-bit result. This comes in handy since floating-point math isn't possible using integer math.

Example: The default resolution of the DS18B20 is 0.0625 or 1/16 °C. The compiler & integer math can't understand 0.0625, but it does know what 625 is. By moving the decimal point to the right or the making the number "whole", we can then work with the larger number using integer math. Since the compiler only supports 16-bit variables, other methods have to be used to get results larger than 16-bits. This is where the DIV32 function comes into play.

A temperature reading from the DS18B20 of +25.0625°C or 77.1125°F will look like this: 0000 0001 1001 0001. If you use your calculator, you'll see this 16-bit binary value works out to 401 decimal. Since the resolution of the DS18B20 is in 0.0625 °C, we know that a result of 401 would be; 401 x 0.0625 = 25.0625. The temperature is therefore 25.0625 °C.

Integer math says that we can't use 401 x 0.0625, or get results like 25.0625, but we can use 401 x 625. With the limitations of 16-bit variable storage, 401 x 625 = 250,625 is larger than 65,535, and too big to fit into a 16-bit variable. DIV32 allows us to use these much larger numbers. The only thing left to do after DIV32 is to extract each digit from the result, and place the decimal point where appropriate.

NOTE: 250,625.000 is beyond the 0-4 limitations of the DIG modifier to extract the high digit of 2, so we divide the result by 10 leaving a number we can work with of 25,062. DIG 4 will be the high digit #2. DIG 0 is the lower digit #2, DIG 1 is the #6, etc,,.

The calculation from °C to °F works a little differently. A resolution of 0.0625 °C works out to a resolution of 0.1125 °F, so we use 401 x 1125 / 100 +3200 = 7,711.25 "our modified version of 77.1125 °F". Since 401 x 1125 = 451,125, then 451,125 / 100 = 4,511.25, then 4,511.25 + 3200 = 7,711.25 or 77.11 °F once we have extracted each digit using the DIG function. The larger the number, the greater the precision, hence DIV32 makes this all possible with a minimum of math & effort by allowing us to first make the floating-point number a whole number by increasing the numbers size [moving the decimal point to the right], and work with larger 32-bit results.

The upper 4-bits of the binary value read from the DS18B20 have no significance. The Sign-bit [bit 11] indicates the temperature is either +°C or -°C. The code sample below reads bit 11, and uses this value to decide whether or not to display the negative sign indicator -, or print a + on the LCD for positive temperatures.

You can also remove the routine that displays the temperature value in 16-bit binary format. This was included purely for illustration purposes to show the RAW value being used for the conversion process.

This is a down-&-dirty project showing how to get immediate results with the DS18B20. For more details, including how to identify 1-wire devices, control 1-wire switches, and more, visit the first two article pages here. Reading 1-wire device ROM codes & Communicating with multiple 1-wire devices

The Schematic

PortC.0 is used to communicate with the DS218B20 [as shown above]. PortB.0 is used to send temperature readings to a serial LCD for display. You can easily change the port-pin assignments to any I/O-pins you have available on the PIC microcontroller you're using.

Note: The DS18B20 is referred to as a 12-bit temperature device, but only 11-bits are actually used for the temperature resolution. Bit-11 is the sign-bit, and used to indicate above 0°C "0", and below 0°C "1".

Below is an example of the temperature results read from the DS18B20. The blue-bit "bit-11" is the sign-bit. The remaining red-bits are the actual temperature result. The four high-bits in black are simply ignored, and serve no useful purpose. The example below indicates a temperature of +25.0625°C or 77.1125°F.

The DS18B20 resolution [in 12-bit mode] is 0.0625 or 1/16 °C.

X X X X 0 0 0 1 1 0 0 1 0 0 0 1

This code sample shows how to achieve very precise results using this temperature sensor, and uses several PicBasic Pro tricks for the conversion process like the new DIV32 command, the DEC/DIG modifiers to extract individual temperature digits from the result for displaying on the LCD.

The Code

'****************************************************************
'*  Name    : Temp.BAS                                          *
'*  Author  : Bruce Reynolds                                    *
'*  Notice  : Copyright (c) 2003 Reynolds Electronics           *
'*          : All Rights Reserved                               *
'*  Date    : 7/28/2003                                         *
'*  Version : 1.0                                               *
'*  Notes   :                                                   *
'*          :                                                   *
'****************************************************************
DEFINE      LOADER_USED 1   ' Boot-Loader is being used
DEFINE      OSC 20          ' We're using a 20MHz oscillator
Comm_Pin    VAR	PortC.0     ' One-wire Data-Pin "DQ" on PortC.0
Busy        VAR BIT         ' Busy Status-Bit
R_Temp      VAR	WORD        ' RAW Temperature readings
TempC       VAR WORD        ' Temp in deg C
TempF       VAR WORD        ' Temp in deg F
Float       VAR WORD        ' Holds remainder for + temp C display
Cold_Bit    VAR R_Temp.Bit11' Sign-Bit for +/- Temp. 1 = Below 0 deg C
Real_Cold   CON 1           ' Define Real_Cold = 1
BAUD        CON 16468       ' N9600 for serial LCD
DISP        VAR PortB.0     ' Pin to drive serial LCD
Deg         CON 223         ' Data to display Deg ° symbol
CLR         CON 1           ' CLR LCD command
LINE1       CON 128         ' LCD line #1
LINE2       CON 192         ' LCD line #2
LINE3       CON 148         ' LCD line #3
LINE4       CON 212         ' LCD line #4
INS         CON 254         ' LCD command mode parameter
Sign        VAR BYTE        ' +/- sign for temp display
Dummy       VAR BYTE        ' Dummy for Div32

    SEROUT2 DISP,BAUD, [INS,CLR]
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, [R_Temp.Lowbyte, R_Temp.Highbyte]' Read two bytes / end comms
    GOSUB   Convert_Temp
    GOTO    Start_Convert
    
Convert_Temp:                 ' +32.0 to +257 F 
    IF      Cold_Bit = Real_Cold THEN Yikes ' If Cold_Bit = 1, it's below "0" deg C
    Sign  = "+"
    Dummy = 625 * R_Temp      ' Multiply to load internal registers with 32-bit value
    TempC = DIV32 10          ' Use Div32 value to calculate precise deg C
    Dummy = 1125 * R_Temp
    TempF = DIV32 100
    IF TempF >6795 THEN ' Over 99.5 deg F..?
       TempF = TempF + 3200
       SEROUT2 DISP,BAUD, [INS,LINE1, " TempF = ",Sign,DEC TempF DIG 4,_
       DEC TempF DIG 3,DEC TempF DIG 2,".",DEC2 TempF,Deg,"F "]
    ELSE
       TempF = TempF + 3200
       SEROUT2 DISP,BAUD, [INS,LINE1, " TempF = ",Sign,DEC TempF DIG 3,_
       DEC TempF DIG 2,".",DEC2 TempF,Deg,"F "]
    ENDIF
    TempC  = (R_Temp & $0FF0) >> 4 ' Mask middle 8-bits, shift into lower byte
    Float = ((R_Temp.Lowbyte & $0F) * 625) ' Lower 4-bits of result * 625
    SEROUT2 DISP,BAUD, [INS,LINE2, " TempC = ",Sign,DEC TempC,".",DEC Float,Deg,"C "]
    SEROUT2 DISP,BAUD, [INS,LINE4, "Raw", IBIN16 R_Temp]
    RETURN

Yikes:                      ' Display full range -C to -F conversion
    Sign   = "-"            ' Display - symbol for negative temp
    Dummy  = 625 * ~R_Temp+1' Multiply to load internal registers with 32-bit value
    TempC  = DIV32 10       ' Use Div32 value to calculate precise deg C
    TempF  = ~R_Temp / 16   ' Begin conversion from -C to deg +/-F
    IF TempF >=18 THEN      ' Check for -degrees F "-18 C = -0.4 F"
       TempF   = ((((TempF + 50) * 9) /5) -122) ' -C to -F below -17 deg C
       SEROUT2 DISP,BAUD, [INS,LINE1, " TempF = ",Sign, DEC TempF,Deg,"F     "]
       SEROUT2 DISP,BAUD, [INS,LINE2, " TempC = ",Sign,DEC TempC DIG 4,_
       DEC TempC DIG 3,".",DEC3 TempC,Deg,"C "]
       SEROUT2 DISP,BAUD, [INS,LINE4, "Raw", IBIN16 R_Temp]
    ELSE                    ' Else result = +deg F
       TempF   = ((((-TempF + 50) * 9) /5) -58)' -C to +F below 32.0 deg F to -17 deg C
       SEROUT2 DISP,BAUD, [INS,LINE1, " TempF = ","+",DEC TempF,Deg,"F     "]
       SEROUT2 DISP,BAUD, [INS,LINE2, " TempC = ",Sign,DEC TempC DIG 4,_
       DEC TempC DIG 3,".",DEC3 TempC,Deg,"C "]
       SEROUT2 DISP,BAUD, [INS,LINE4, "Raw", IBIN16 R_Temp]
    ENDIF
    RETURN
    
    END
Until the next project - have fun & and play safe...;o]
Best regards,
-Bruce

  BASIC Stamp, Microchip PIC, 8051, and Remote Control Mailing-List"Micro-News"BASIC Stamp, Microchip PIC, 8051, and Remote Control Mailing-List
   Micro-Mailing-List

Copyright © 1999-2008 Reynolds Electronics