CMM2: DS18B20 Temp sensor problem


Author Message
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 3013
Posted: 05:51am 10 Mar 2025      

More playing with Jim's program. Added some comments to help add unknown / non-genuine devices.
'DS18x20 test code by TassyJim
Print
' Input "Type Pin number ",PinNbr
Input "Type PicoMite GPxx number for the DS18B20 (include the GP) "; GPPin$
Dim INTEGER PinNbr = MM.Info(pinno GPPin$)

Print
Print "Family name: ";FamilyName$(PinNbr)
Print "Rom Code:    ";getRomCode$(PinNbr)
Print "ScratchPad:  ";getScratchpad$(PinNbr)

If powerMode(PinNbr) Then
  Print "Power mode   External"
Else
  Print "Power mode   Parasitic"
EndIf

Print
For n = 9 To 12
  Print
  x = setResolution(PinNbr, n)
  Print "ScratchPad:  ";getScratchpad$(PinNbr)
  Timer = 0
  Print "Temperature: ";getTemp(PinNbr);"`C  ";Timer;"mS,";n;" bit"
Next n

Print :t=Timer : Print "Tempr() without Start", TEMPR(PinNbr);" `C",Timer-t;" mS"
TEMPR START PinNbr,0 :t=Timer :ds18=TEMPR(PinNbr):t=Timer-t : Print "Tempr Start pin,0", ds18, t
TEMPR START PinNbr,1 :t=Timer :ds18=TEMPR(PinNbr):t=Timer-t : Print "Tempr Start pin,1", ds18, t
TEMPR START PinNbr,2 :t=Timer :ds18=TEMPR(PinNbr):t=Timer-t : Print "Tempr Start pin,2", ds18, t
TEMPR START PinNbr,3 :t=Timer :ds18=TEMPR(PinNbr):t=Timer-t : Print "Tempr Start pin,3", ds18, t
Print
Print "*** The first RomCode value (a1) can be used to add extra devices to the FamilyName & getTemp functions"
Print "look for *** comments in those functions"
Print
End


Function getRomCode$(PinNbr As INTEGER)
' get ROM Code - useful if you want more than 1 device on wire
'*** The first value returned (a1) can be used to add extra devices to the FamilyName & getTemp functions
'look for *** comments in those functions
Local INTEGER a1,a2,a3,a4,a5,a6,a7,a8
OneWire WRITE PinNbr,1,1,&h33 'read ROM code
OneWire READ PinNbr,0,8,a1,a2,a3,a4,a5,a6,a7,a8
getRomCode$ = Hex$(a1,2)+" "+Hex$(a2,2)+" "+Hex$(a3,2)+" "+Hex$(a4,2)+" "+Hex$(a5,2)+" "+Hex$(a6,2)+" "+Hex$(a7,2)+" "+Hex$(a8
,2)
End Function

Function getScratchpad$(PinNbr As INTEGER)
'ONEWIRE Write PinNbr,1,9,&h55,a1,a2,a3,a4,a5,a6,a7,a8  'read from scratchpad
OneWire WRITE PinNbr,1,2,&hcc,&hbe
OneWire READ PinNbr,0,8,a,b,c,d,e,f,g,h
getScratchpad$ = Hex$(a,2)+" "+Hex$(b,2)+" "+Hex$(c,2)+" "+Hex$(d,2)+" "+Hex$(e,2)+" "+Hex$(f,2)+" "+Hex$(g,2)+" "+Hex$(h,2)
End Function

Function powerMode(PinNbr As INTEGER) As INTEGER
' check whether power external (1) or parasitic (0)
OneWire RESET PinNbr
OneWire WRITE PinNbr, 1,2,&hcc, &hb4
OneWire READ PinNbr,4,1,powerMode
End Function

Function getFamily(PinNbr As INTEGER) As INTEGER
getFamily = Val("&h"+Left$(getRomCode$(PinNbr),2))
End Function

Function FamilyName$(PinNbr As INTEGER)
Local INTEGER fn
fn = getFamily(PinNbr)
Select Case fn
  Case 16  '&H10
    FamilyName$ = "DS1820/DS18S20"
  Case 34  '&H22
    FamilyName$ = "DS18S22"
  Case 40  '&H28
    FamilyName$ = "DS18B20"
  Case 41  '&H29
    FamilyName$ = "a non-genuine DS18B20"
  '*** Add extra cases here using the first value returned by Function getRomCode
  Case Else
    FamilyName$ = "Unknown"
End Select
End Function

Function setResolution(PinNbr As INTEGER,r As INTEGER)
r = r-9
If r < 0 Then r = 0
If r > 3 Then r = 3
r = r*32+31
OneWire WRITE PinNbr, 1,5,&hcc, &h4E, &hFF,&hFF,r
End Function

Function getTemp(PinNbr As INTEGER) As FLOAT
Local INTEGER fn, t, T1, T2, a,b,c,d,e,f,g,h
Local FLOAT Value
fn = getFamily(PinNbr)
power = powerMode(PinNbr)
OneWire RESET PinNbr                        ' reset before command
OneWire WRITE PinNbr, 8, 2, &hcc, &h44      ' start conversion

'read external when b goes high, for parasitic just wait
If power = 0 Then
  Pause 750
Else
  t = Timer
  Do
    If Timer - t > 1000 Then
      Value = 1000
      Print "*** Timeout ***"
      Exit Do
    EndIf
    OneWire READ PinNbr, 4 , 1 , b            ' conversion done?
  Loop Until b = 1
'   Print Timer-t;" mS conversion time",
EndIf
If Value = 0 Then ' we have not timed out yet
  OneWire WRITE PinNbr, 1, 2, &hcc, &hbe      ' command read data
  OneWire READ PinNbr, 2, 2, T1, T2           ' get the data
  OneWire RESET PinNbr
  Select Case fn
    Case 16 'DS18S20 or DS1820
      OneWire WRITE PinNbr,1,2,&hcc,&hbe
      OneWire READ PinNbr,0,8,a,b,c,d,e,f,g,h
      If T2 And &h80 Then       'if MSB of T2=1 then negative
        'Read 12bit resolution and adjust
        'truncate 0.5deg value (or use integer division \)
        T1 = T1 And &hFE
        T1=T1 / 2                   'make whole degrees
        'add compensation values read from scratchpad
        T1=T1*16                  'make lsb 1/16 degree
        T1 = T1 -4 +(16 - g)    'add 12 bit value
        'take 2s complement
        T1 = (T1 Xor &hFF) + 1
        Value = -T1/16                'make decimal value in degrees
      Else                              'positive temp
        Value = T1 / 2                '9bit value
        'Read 12bit resolution and adjust
        T1 = T1 And &hFE      'truncate 0.5deg(or use integer division \)
        Value = T1/2- 0.25 + (16 - g) /16   '12 bit value
      EndIf
    Case 34, 40 ' DS18S22 or DS18B20
      If T2 And &b1000 Then       'negative temp
        'make 2s complement (1s complement+1)
        T2 = (T2 Xor &hFF)
        T1 = (T1 Xor &hFF)+1
        If T1=1 Then T2=T2+1        'add the carry if required
        Value = -((T2 And &b111) * 256 + T1) / 16
      Else                            'positive temp
        Value = ((T2 And &b111) * 256 + T1) / 16
      EndIf
    Case 41 '&H29, a non genuine DS18B20
      If T2 And &b1000 Then       'negative temp
        'make 2s complement (1s complement+1)
        T2 = (T2 Xor &hFF)
        T1 = (T1 Xor &hFF)+1
        If T1=1 Then T2=T2+1        'add the carry if required
        Value = -((T2 And &b111) * 256 + T1) / 16
      Else                            'positive temp
        Value = ((T2 And &b111) * 256 + T1) / 16
      EndIf
    '*** Add extra cases here using the first value returned by Function getRomCode
    Case Else 'Unknown device
       ' *** use the output of this to create the scale factor of the unknown device
      'Value = 1000
      If T2 And &b1000 Then       'negative temp
        'make 2s complement (1s complement+1)
        T2 = (T2 Xor &hFF)
        T1 = (T1 Xor &hFF)+1
        If T1=1 Then T2=T2+1        'add the carry if required
        Value = -((T2 And &b111) * 256 + T1) / 1'<-This is where you put the scale factor
      Else                            'positive temp
        Value = ((T2 And &b111) * 256 + T1) / 1'<-This is where you put the scale factor
      EndIf
  End Select
EndIf
getTemp= Value
End Function

Example output. This one always reads 85° until after a Tempr Start pin,2 or 3 command then is ok till next power cycle.
> RUN

Type PicoMite GPxx number for the DS18B20 (include the GP) ? gp6

Family name: a non-genuine DS18B20
Rom Code:    29 61 64 12 3D D4 A4 B8
ScratchPad:  51 05 FF FF 7F FF FF FF
Power mode   External


ScratchPad:  FF FF FF FF FF FF FF FF
Temperature:  85.0625`C   17.934mS, 9 bit

ScratchPad:  FF FF FF FF FF FF FF FF
Temperature:  85.0625`C   17.951mS, 10 bit

ScratchPad:  A8 82 FF FF AF FF FF FF
Temperature:  680`C   17.91mS, 11 bit

ScratchPad:  51 05 FF FF 7F FF FF FF
Temperature:  85.0625`C   17.935mS, 12 bit

Tempr() without Start    85 `C   210.435 mS
Tempr Start pin,0        85      103.408
Tempr Start pin,1        85      203.84
Tempr Start pin,2        27.875  403.835
Tempr Start pin,3        27.875  803.819

*** The first RomCode value (a1) can be used to add extra devices to the FamilyName & getTemp functions
look for *** comments in those functions

> RUN

Type PicoMite GPxx number for the DS18B20 (include the GP) ? gp6

Family name: a non-genuine DS18B20
Rom Code:    29 61 64 12 3D D4 A4 B8
ScratchPad:  BF 01 FF FF 7B FF FF FF
Power mode   External


ScratchPad:  FF FF FF FF FF FF FF FF
Temperature:  27.9375`C   17.964mS, 9 bit

ScratchPad:  FF FF FF FF FF FF FF FF
Temperature:  27.9375`C   17.942mS, 10 bit

ScratchPad:  DF 80 FF FF AF FF FF FF
Temperature:  223`C   17.93mS, 11 bit

ScratchPad:  BF 01 FF FF 7F FF FF FF
Temperature:  27.9375`C   17.942mS, 12 bit

Tempr() without Start    27.875 `C       210.452 mS
Tempr Start pin,0        27.875  104.167
Tempr Start pin,1        27.875  203.82
Tempr Start pin,2        27.6875         403.821
Tempr Start pin,3        27.6875         803.819

*** The first RomCode value (a1) can be used to add extra devices to the FamilyName & getTemp functions
look for *** comments in those functions

Edit.
Prompted by Volhout's mention of the RP2350 pin issue I reduced the pullup resistor from 10k to 1.2k. Now the Rom Code value of a1 is &H28, as it should be. Was &H29.
It no longer reads 85°C in Jim's program but still requires an initial Tempr Start to get Tempr() to read correctly.
Edited 2025-03-10 20:08 by phil99