News:

;) This forum is the property of Proton software developers

Main Menu

Need some DS18B20 Temp sensor help

Started by JohnB, Jul 11, 2022, 11:17 AM

Previous topic - Next topic

JohnB

I cannot make any sense of the numbers coming out of the 18B20 temperature sensor.
Attached is the library file I have created for the 18B20.
From my main loop I call Acquire once every 2 seconds and ReadTemperature on the alternate second.

As I understand it I don't need to adjust the temperature output if I am working at the highest resolution

The numbers I am getting keep changing despite a constant temperature are pretty random and don't relate to any real temperature.

I have the device powered (i.e. not parasitic) and 4.7K on the output

Any suggestions gratefully received.
JohnB

david

#1
John,
I brushed the cobwebs off some old files of mine that I think uses the same device.  My code is reading two sensors for a differential measurement so just ignore the second read.

Device 16F628 'high resolution temp readout
Declare Xtal 4
Symbol DQ2=PORTA.4    'Data in port with 4.7k pullup
Symbol DQ1=PORTA.3
CMCON=7
Dim temp As Word
Dim crm As Byte    'counts remaining
Dim cperd As Byte 'counts per degree
Cls
start: OWrite DQ2,1,[$CC,$44]
   Repeat
   DelayMS 25
   ORead DQ2,4,[crm]
   Until crm<>0
   OWrite DQ2,1,[$CC,$BE]
   ORead DQ2,2,[temp.LowByte,temp.HighByte,crm,crm,crm,crm,crm,cperd]
   temp=(((temp>>1)*100)-25)+(((cperd-crm)*100)/cperd)
   Print At 1,1, Dec temp/100,".",Dec2 temp,223,"C "
   
   OWrite DQ1,1,[$CC,$44]
   Repeat
   DelayMS 25
   ORead DQ1,4,[crm]
   Until crm<>0
   OWrite DQ1,1,[$CC,$BE]
   ORead DQ1,2,[temp.LowByte,temp.HighByte,crm,crm,crm,crm,crm,cperd]
   temp=(((temp>>1)*100)-25)+(((cperd-crm)*100)/cperd)
   Print At 2,1, Dec temp/100,".",Dec2 temp,223,"C "
       
   DelayMS 500
   GoTo start
End
I'm about to head off to bed so I'll leave you to play spot the difference with your code.

Cheers,
David

keytapper

I studied how the 16 bits are defined to get the temperature.
Proc GetDegree(), SDword
    ' Read the DS18S20 chip
    ' DQ_Pin is the pin connected to the sensor
    Dim wTemperature As Word       ' Holds the temperature value
    Dim bCounts As Byte             ' Holds the counts remaining value
    Dim negative As wTemperature.15 ' the sign bit
    Dim tmpVal As Dword
    Dim negate As Bit               ' the sign bit
    OWrite DQ_Pin, 1, [$CC, $BE]    ' Send a Read ScratchPad command
    ORead DQ_Pin, 2,[wTemperature.LowByte, wTemperature.HighByte]
    ' Calculate the temperature in degrees Centigrade
    If negative = 1 Then
        wTemperature = ~wTemperature + 1
        Set negate
    Else
        Clear negate
    End If
    tmpVal = (wTemperature >> 4) * 10000
    tmpVal = tmpVal + (wTemperature & $000f) * 625
    Result = tmpVal / 10
    If negate = 1 Then
        Result = -Result
    End If
EndProc
So the first 4 least significant bits are the decimal part of the temperature, thus they are expressed in 1/16.
From the 12th to the 5th bit is expressed the degree units (maximum is 127°). For negative result the first 4 bits will be at 1.
Ignorance comes with a cost

top204

Below is a demo program listing that contains a procedure to read a DS18B20 temperature sensing device at its full 12-bit resolution, so the temperatures returned have a higher resolution. The DS18B20_Read procedure returns the floating point temperature in either Celsius or Fahrenheit, depending on the value in its parameter.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Read a DS18B20 temperature sensor with a 12-bit resolution
' And display the temperatures in Celsius and Fahrenheit on a serial terminal
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F26K22                                       ' Tell the compiler what device to compile for
    Declare Xtal = 64                                       ' Tell the compiler what frequency the device is operating at
    Declare Float_Display_Type = Fast                       ' Use the faster, and more accurate, Float to ASCII library routine
'
' Setup USART1
'   
    Declare Hserial1_Baud = 9600                            ' Setup the Baud rate of USART1
    Declare HRSOut1_Pin = PORTC.6                           ' Setup the pin used for USART1 TX

    Symbol DQ_Pin = PORTC.0                                 ' Setup the data pin (DQ) for the DS18B20 device
'
' Create some constants and variables for the demo
'
    Symbol cCelsius = 0                                     ' Tell the DS18B20_Read procedure to return the temperature in Celcius
    Symbol cFahrenheit = 1                                  ' Tell the DS18B20_Read procedure to return the temperature in Fahrenheit
   
    Dim fTemperature As Float                               ' Holds the temperature returned from the DS18B20_Read procedure
  
'-------------------------------------------------------------------------------
' The main program starts here
' Read a DS18B20 device and transmit the temperature in Fahrenheit and Celsius to a serial terminal
'
Main:
    Internal_Osc_64MHz()                                    ' Set the internal oscillator to operate at 64MHz

    Do                                                      ' Create a loop
        fTemperature = DS18B20_Read(cCelsius)               ' Read the temperature (in Celsius) from the DS18B20 device into fTemperature
        HRSOutLn "Temperature = ", Dec1 fTemperature, " C"  ' Transmit the temperature value to a serial terminal
       
        fTemperature = DS18B20_Read(cFahrenheit)            ' Read the temperature (in Fahrenheit) from the DS18B20 device into fTemperature
        HRSOutLn "Temperature = ", Dec1 fTemperature, " F"  ' Transmit the temperature value to a serial terminal
    Loop                                                    ' Do it forever
 
'-------------------------------------------------------------------------------
' Read a DS18B20 device with its default 12-bit resolution
' Input     : pCorF is 1 if the return is to be Fahrenheit, 0 for Celsius
' Output    : Returns the floating point temperature value
'           : If the device cannot be read, the value returned is $FFFFFFFF
' Notes     : None
'
Proc DS18B20_Read(pCorF As Bit), Float   
    Dim bData[9]  As Byte                                   ' Holds the data read from the DS18B20 device
    Dim bTimeOut  As Byte At bData#0 = $FF                  ' A timeout for the conversion wait loop
    Dim bRawTemp  As bData#0                                ' \ Array elements 0 and 1 hold the raw temperature value
    Dim bRawTempH As bData#1                                ' /
    Dim wRawTemp  As bRawTemp.SWord                         ' Combine them into a signed word variable
 
    OWrite DQ_Pin, 1, [$CC, $44]                            ' Start a temperature conversion
'
' Wait until the conversion is complete
'
    Repeat                                                  ' Create a loop
        If ORead DQ_Pin, 4 = 1 Then ReadTemp                ' Exit the loop if the conversion is complete
        DelayMS 10                                          ' A small delay within the loop
        Dec bTimeOut                                        ' Decrement the timeout counter
    Until STATUSbits_Z = 1                                  ' Finish the loop when it reaches zero
    Result = $FFFFFFFF                                      ' Return $FFFFFFFF because the loop completed
    ExitProc                                                ' Exit the procedure prematurely because it timed out
ReadTemp:
    OWrite DQ_Pin, 1, [$CC, $BE]                            ' Set to read the temperature
    ORead DQ_Pin, 0, [Str bData\9]                          ' Read 9 bytes into array bData
'
' Convert the data held in wRawTemp to a temperature value
'  
    Result = wRawTemp / 16.0                                ' Convert to Celsius
    If pCorF = 1 Then                                       ' Is the temperature returned to be Fahrenheit?
        Result = (Result * 1.8) + 32.0                      ' Yes. So do the conversion from Celsius to Fahrenheit
    EndIf
EndProc
 
'-------------------------------------------------------------------------------
' Set the PIC18F26K22's internal oscillator to operate at 64MHz
' Input     : None
' Output    : None
' Notes     : Waits for the internal oscillator to become stable
'
Proc Internal_Osc_64MHz()
    OSCCON  = %01110000
    OSCCON2 = %10000100
    Repeat : Until OSCCONbits_HFIOFS = 1                    ' Keep looping until the oscillator is stable
    Set OSCTUNEbits_PLLEN                                   ' Enable the 4xPLL
EndProc
 
'-------------------------------------------------------------------------------
' Setup the configuration fuses for 64MHz operation using the internal oscillator on a PIC18F26K22 device
'
Config_Start
    FOSC = INTIO67      ' Internal oscillator block. Port function on RA6 and RA7
    PLLCFG = On         ' Oscillator not multiplied by 4
    PRICLKEN = Off      ' Primary clock disabled
    IESO = Off          ' Oscillator Switchover mode disabled
    Debug = Off         ' Background debugger disabled. RB6 and RB7 Configured as general purpose I/O pins
    WDTEN = Off         ' WDT disabled (Control is placed on SWDTEN bit)
    XINST = Off         ' Standard mnemonic mode enabled
    FCMEN = On          ' Fail-Safe Clock Monitor enabled
    PWRTEN = On         ' PWRT enabled
    BOREN = On          ' Brown-out Reset enabled and Controlled by software (SBOREN is enabled)
    BORV = 190          ' VBOR set to 1.9 V nominal
    WDTPS = 128         ' Watchdog prescaler set to 1:128
    MCLRE = EXTMCLR     ' MCLR pin enabled, RE3 input pin disabled
    HFOFST = Off        ' The system clock is held Off until the HF-INTOSC is stable.
    PBADEN = Off        ' PORTB<4:0> pins are Configured as digital I/O on Reset
    CCP2MX = PORTC1     ' CCP2 input/output is multiplexed with RC1
    CCP3MX = PORTB5     ' P3A/CCP3 input/output is multiplexed with RB5
    T3CMX = PORTC0      ' T3CKI is on RC0
    P2BMX = PORTB5      ' P2B is on RB5
    STVREN = On         ' Stack full/underflow will cause Reset
    LVP = Off           ' Single-Supply ICSP disabled
    Cp0 = Off           ' Block 0 ($000800 - $001FFF) not code-protected
    CP1 = Off           ' Block 1 ($002000 - $003FFF) not code-protected
    CPB = Off           ' Boot block ($000000 - $0007FF) not code-protected
    CPD = Off           ' Data EEPROM not code-protected
    WRT0 = Off          ' Block 0 ($000800 - $001FFF) not write-protected
    WRT1 = Off          ' Block 1 ($002000 - $003FFF) not write-protected
    WRTB = Off          ' Boot block ($000000 - $0007FF) not write-protected
    WRTC = Off          ' Configuration registers ($300000 - $3000FF) not write-protected
    WRTD = Off          ' Data EEPROM not write-protected
    EBTR0 = Off         ' Block 0 ($000800 - $001FFF) not protected from table reads executed in other blocks
    EBTR1 = Off         ' Block 1 ($002000 - $003FFF) not protected from table reads executed in other blocks
    EBTRB = Off         ' Boot block ($000000 - $0007FF) not protected from table reads executed in other blocks
Config_End

Below is a screenshot of the above demo program operating inside a simulator:

Positron8 - DS18B20 Read.jpg


top204

After some twiddling, I came up with the program listing below that reads a DS18B20 temperature sensor using integer only calculations, but still gives a resolution of 0.1 degrees Celsius. This means the code and RAM usage are a lot, lot smaller, but the temperatures read and displayed are just as good as the floating point version, listed above.

'
'   /\\\\\\\\\
'  /\\\///////\\\
'  \/\\\     \/\\\                                                 /\\\          /\\\
'   \/\\\\\\\\\\\/        /\\\\\     /\\\\\\\\\\     /\\\\\\\\   /\\\\\\\\\\\  /\\\\\\\\\\\  /\\\\\\\\\
'    \/\\\//////\\\      /\\\///\\\  \/\\\//////    /\\\/////\\\ \////\\\////  \////\\\////  \////////\\\
'     \/\\\    \//\\\    /\\\  \//\\\ \/\\\\\\\\\\  /\\\\\\\\\\\     \/\\\         \/\\\        /\\\\\\\\\\
'      \/\\\     \//\\\  \//\\\  /\\\  \////////\\\ \//\\///////      \/\\\ /\\     \/\\\ /\\   /\\\/////\\\
'       \/\\\      \//\\\  \///\\\\\/    /\\\\\\\\\\  \//\\\\\\\\\\    \//\\\\\      \//\\\\\   \//\\\\\\\\/\\
'        \///        \///     \/////     \//////////    \//////////      \/////        \/////     \////////\//
'                                  Let's find out together what makes a PIC Tick!
'
' Read a DS18B20 temperature sensor with a 12-bit resolution
' And display the temperature in Celsius on a serial terminal
' This version uses integers only for the calculations, but still gives a 0.1 degree temperature resolution.
'
' Written for the Positron8 compiler by Les Johnson.
'
    Device = 18F26K22                                       ' Tell the compiler what device to compile for
    Declare Xtal = 64                                       ' Tell the compiler what frequency the device is operating at
'
' Setup USART1
'
    Declare Hserial1_Baud = 9600                            ' Setup the Baud rate of USART1
    Declare HRSOut1_Pin = PORTC.6                           ' Setup the pin used for USART1 TX

    Symbol DQ_Pin = PORTC.0                                 ' Set the data pin (DQ) for the DS18B20 device
'
' Create a variable for the demo
'
    Dim wTemperature As SWord                               ' Holds the temperature returned from the DS18B20_Read procedure

'------------------------------------------------------------------
' The main program starts here
' Read a DS18B20 device and transmit the temperature in Celsius to a serial terminal
'
Main:
    Internal_Osc_64MHz()                                        ' Set the internal oscillator to operate at 64MHz

    Do                                                          ' Create a loop
        wTemperature = DS18B20_Read()                           ' Read the temperature from the DS18B20 device
        If wTemperature <> 32767 Then                           ' Was the temperature read?
            HRSOutLn "Temperature = ", SDec wTemperature / 10,  ' \
                     ".", SDec wTemperature // 10, " C"         ' / Yes. So transmit the temperature value to a serial terminal
        EndIf
    Loop                                                        ' Do it forever

'-------------------------------------------------------------------
' Read a DS18B20 device with its default 12-bit resolution
' Input     : None
' Output    : Returns the integer temperature value x10, in Celsius
'           : If the device cannot be read, the value returned is 32767
' Notes     : Uses integer calculations, so the temperature returned will need to be divided
'             for the whole and fraction numbers to be displayed
'           : Because the CRC value is not being used from the DS18B20 device,
'             there is no need to read all 9 data bytes from it
'
Proc DS18B20_Read(), SWord
    Dim bTimeOut As Result.Byte0  = $FF                     ' A timeout for the conversion wait loop
    OWrite DQ_Pin, 1, [$CC, $44]                            ' Start a temperature conversion
'
' Wait until the conversion is complete
'
    Repeat                                                  ' Create a loop
        If ORead DQ_Pin, 4 = 1 Then ReadTemp                ' Exit the loop if the conversion is complete
        DelayMS 10                                          ' A small delay within the loop
        Dec bTimeOut                                        ' Decrement the timeout counter
    Until STATUSbits_Z = 1                                  ' Finish the loop when it reaches zero
    Result = 32767                                          ' Return 32767 because the loop completed
    ExitProc                                                ' Exit the procedure prematurely because it timed out
ReadTemp:
    OWrite DQ_Pin, 1, [$CC, $BE]                            ' Set to read the temperature
    ORead DQ_Pin, 0, [Result.Byte0, Result.Byte1]           ' Read the temperature data only from the DS18B20 device
    Result = Result * 10                                    ' Multiply the raw temperature value by 10
    Result = Result / 16                                    ' Convert to Celsius
EndProc

'------------------------------------------------------------------
' Set the PIC18F26K22's internal oscillator to operate at 64MHz
' Input     : None
' Output    : None
' Notes     : Waits for the internal oscillator to become stable
'
Proc Internal_Osc_64MHz()
    OSCCON  = %01110000
    OSCCON2 = %10000100
    Repeat : Until OSCCONbits_HFIOFS = 1        ' Keep looping until the oscillator is stable
    Set OSCTUNEbits_PLLEN                       ' Enable the 4xPLL
EndProc

'------------------------------------------------------------------
' Setup the configuration fuses for 64MHz operation using the internal oscillator for a PIC18F26K22 device
'
Config_Start
    FOSC = INTIO67      ' Internal oscillator block. Port function on RA6 and RA7
    PLLCFG = On         ' Oscillator not multiplied by 4
    PRICLKEN = Off      ' Primary clock disabled
    IESO = Off          ' Oscillator Switchover mode disabled
    Debug = Off         ' Background debugger disabled. RB6 and RB7 Configured as general purpose I/O pins
    WDTEN = Off         ' WDT disabled (Control is placed on SWDTEN bit)
    XINST = Off         ' Standard mnemonic mode enabled
    FCMEN = On          ' Fail-Safe Clock Monitor enabled
    PWRTEN = On         ' PWRT enabled
    BOREN = On          ' Brown-out Reset enabled and Controlled by software (SBOREN is enabled)
    BORV = 190          ' VBOR set to 1.9 V nominal
    WDTPS = 128         ' Watchdog prescaler set to 1:128
    MCLRE = EXTMCLR     ' MCLR pin enabled, RE3 input pin disabled
    HFOFST = Off        ' The system clock is held Off until the HF-INTOSC is stable.
    PBADEN = Off        ' PORTB<4:0> pins are Configured as digital I/O on Reset
    CCP2MX = PORTC1     ' CCP2 input/output is multiplexed with RC1
    CCP3MX = PORTB5     ' P3A/CCP3 input/output is multiplexed with RB5
    T3CMX = PORTC0      ' T3CKI is on RC0
    P2BMX = PORTB5      ' P2B is on RB5
    STVREN = On         ' Stack full/underflow will cause Reset
    LVP = Off           ' Single-Supply ICSP disabled
    Cp0 = Off           ' Block 0 ($000800 - $001FFF) not code-protected
    CP1 = Off           ' Block 1 ($002000 - $003FFF) not code-protected
    CPB = Off           ' Boot block ($000000 - $0007FF) not code-protected
    CPD = Off           ' Data EEPROM not code-protected
    WRT0 = Off          ' Block 0 ($000800 - $001FFF) not write-protected
    WRT1 = Off          ' Block 1 ($002000 - $003FFF) not write-protected
    WRTB = Off          ' Boot block ($000000 - $0007FF) not write-protected
    WRTC = Off          ' Configuration registers ($300000 - $3000FF) not write-protected
    WRTD = Off          ' Data EEPROM not write-protected
    EBTR0 = Off         ' Block 0 ($000800 - $001FFF) not protected from table reads executed in other blocks
    EBTR1 = Off         ' Block 1 ($002000 - $003FFF) not protected from table reads executed in other blocks
    EBTRB = Off         ' Boot block ($000000 - $0007FF) not protected from table reads executed in other blocks
Config_End

Notice that the DS18B20_Read() procedure does not use any new local variables, because it can use the Result variable for them. Try doing that in C or C++ with code that actually makes sense to read! LOL. Also, notice that because the CRC value is not being used from the DS18B20 device, there is no need to read the full 9 data bytes from it, so just the raw temperature values are read.

Below is a screenshot of the program above operating in a simulator:

DS18B20 Integer Read.jpg


keytapper

I forgot to mention that my procedure returns a value 1000 times higher, but it's for maintaining the use of integers.
Ignorance comes with a cost