tempr not working


Author Message
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 3321
Posted: 01:09pm 05 Jun 2026      

Yet another tweak.
As before many DS18x20s can be on the OneWire bus if the unique ROM code of each is provided.
If no ROM code is provided it assumes there is only one device on the bus and reads the temperature and its unique ROM code.
The ROM code is then available in a integer variable with an initial value of 0 in place of the second parameter, The Family Code can be obtained from that by down shifting 56.

Eg, reading 2 individual devices on pins 9 and 10.
> code%=0 : ? "Temp.";ds18x20(10,code%);"`C",,"ROM Code ="; code%, "Family =";code%>>56
Temp. 19.6875`C       ROM Code = 2909716863767585976  Family = 40
>
> code%=0 : ? "Temp.";ds18x20(9,code%);"`C","ROM Code ="; code%, "Family =";code%>>56
Temp. 20.0625`C       ROM Code = 2900111825584602189  Family = 40
>


For 2 or more on the same pin:-
> clear : PinNo = mm.info(pinno GP6)
> ? ds18x20(PinNo, 2900111825584602189), :pause 500 :? ds18x20(PinNo, 2909716863767585976)
21.375       21.4375
>

Family ROM codes - 16 = DS1820/DS18S20, 34 = DS18S22, 40 = DS18B20
Function DS18x20(PinNbr As INTEGER, ROM As INTEGER) As FLOAT
' Adapted from DS18x20 test code by TassyJim
' This version for MMbasic v6.03.00RC15 with array and string support for OneWire
  Local INTEGER  done, T(7), Fam, ROM1
  Local ROMcode$ = Bin2str$(Uint64,ROM,big) 'convert ROM code to string
  DS18x20 = 1000'                            standard error code

  OneWire READ PinNbr, 4, 1, done'           is conversion finished?
  If Not done Then Exit Function '           if not return to program

  If ROM Then
    Fam = ROM >> 56 '                        extract "family" from ROM code
    OneWire WRITE PinNbr, 1, 1, &h55 '       reset then match ROM Code command
    OneWire WRITE PinNbr, 0, 8, ROMcode$ '   send ROM Code to the DS18x20
    OneWire WRITE PinNbr,0,1,&hBE  '         read scratchpad command
   Else
    OneWire WRITE PinNbr, 1, 1, &h33 'If no ROM code given assume only one DS18x20 connected
    OneWire READ PinNbr, 0, 8, ROMcode$ '      read the ROM code
    OneWire WRITE PinNbr, 1, 2, &hCC, &hBE '   read scratchpad command
    ROM1 = Str2bin(Uint64,ROMcode$,big) '      Output the ROM code to a variable% if it's value was 0
    Fam = ROM1 >> 56 '                         extract "family" from ROM code
  EndIf
  OneWire READ PinNbr, 2, 8, T() ' : Math V_Print T()' get the temperature data

' process the data, Family ROM codes - 16=DS1820/DS18S20, 34=DS18S22, 40=DS18B20
  If Fam = 16 Then Value = Str2bin(int16,Chr$(T(0))+Chr$(T(1)))\2 -0.25+(T(7)-T(6))/T(7)
  If Fam = 40 Or Fam = 34 Then Value = Str2bin(int16,Chr$(T(0))+Chr$(T(1)))/16
  If Fam = 0 Then Value = 1001
  DS18x20 = Value

' Start conversion, ready for next read
  If ROM Then
    OneWire WRITE PinNbr, 1, 1, &h55  'reset then match ROM Code command
    OneWire WRITE PinNbr, 0, 8, ROMcode$   'send ROM Code
    OneWire WRITE PinNbr, 8, 1, &h44  'Master issues Convert Temp. command
   Else
    OneWire RESET PinNbr'                      ' reset before command
    OneWire WRITE PinNbr, 8, 2, &hCC, &h44'    ' start conversion
  EndIf
  ROM = ROM1 '                                : Print "conversion started"
End Function

The code above has been edited to improve a couple of minor items.



Checking for a genuine DS18B20 vs. non-genuine.

Genuine units retain the Last Temperature (bytes 0 & 1), High Alarm (byte 2), Low Alarm (byte 3) and Resolution (byte 4) of Scratchpad memory in EEPROM.
On power-up they are restored. Non-genuine ones don't appear to have EEPROM so are in a Factory Fresh state when powered up.

This command-line program shows the difference.
> clear : Dim integer S(8) :  Pin% = MM.Info(pinno gp6)
> 'Genuine DS18B20
> OneWire WRITE Pin%, 1, 2, &hCC, &hBE : OneWire READ Pin%, 2, 9, S() : Math V_Print S()
144, 1, 85, 5, 127, 165, 165, 102, 180  
> 'Last_Temp = Byte0 / 16 + Byte1 * 16, High_Alarm = Byte2, Low_Alarm = Byte3, Resolution = Byte4 >> 5, CRC value - Byte8
> 'the alarm temperatures have a fixed resolution of 1.0`C
>
> 'Non_genuine DS18B20
> OneWire WRITE Pin%, 1, 2, &hCC, &hBE : OneWire READ Pin%, 2, 9, S() : Math V_Print S()
80, 5, 255, 255, 127, 255, 255, 255, 31
> 'Default_Temp = 85`C = Byte0 / 16 + Byte1 * 16, High_Alarm = Byte2, Low_Alarm = Byte3, Resolution = Byte4 >> 5 These only have resolution 3 so this byte must be 127.
> 'the alarm temperatures have fixed a resolution of 1.0`C
>



Setting temperature alarm levels and reading the alarm status.

While the temperature of all units on the bus is within their set limits the status is 1
If the temperature any of the units on the bus goes high or low the status is 0.
They do not read the temp. unless instructed and there is no provision for triggering an interrupt.
So your main loop needs to trigger a bus-wide read and poll the status periodically to see if a 0 is returned.

If that returns 0 you can read each unit to find which one is out of its limits.

If your program is regularly reading all temperatures none of this is necessary as you can compare the temperatures with ones set in the program.
Either hard coded or from VAR SAVE / RESTORE.
MMBAsic makes life easier.

This Function sets the alarm limits and resolution and returns the ROM code.
It will work with just one on the bus, in which case you don't need to supply a ROM code.
If more than one you must supply the ROM code of the one you are setting the limits and resolution on.
The temperature resolution format is the same as the TEMPR START command.
0 = 0.5°C, 1 = 0.25°C, 2 = 0.125°C and 3 = 0.0625°C
The alarm setting resolution is fixed at 1°C

Function AlarmSet(Pin%, TH, TL, Res%, ROM%) As Integer
  'Set the high temp alarm (TH), low temp alarm (TL) and resolution (Res%) of DS18S20 and DS18B20.
  Local integer TD(7), done
  Local ROMcode$, t
  TH = Cint(TH) And 255 : TL = Cint(TL) And 255 : Res% = ((Res% And 3) << 5) + 31 'prepare the data

  t=Timer                    'Start conversion on all units on the bus and wait for the slowest to finish.
  OneWire WRITE Pin%, 1, 2, &hCC,&h44
  Do
    OneWire READ Pin%, 4, 1, done
  Loop Until done Or Timer - t > 1100 '        : Print Timer-t;"uS conversion time"

  If ROM% Then '                                1 or more devices on 1Wire bus, ROM Code supplied
    ROMcode$ = Bin2str$(Uint64,ROM%,big) '      convert ROM code to string
    OneWire WRITE Pin%, 1, 1, &h55 '            reset then match ROM Code command
    OneWire WRITE Pin%, 0, 8, ROMcode$ '        send ROM Code
    OneWire WRITE Pin%, 0, 1, &hBE '            Read data command (to to check for non-genuine DS18B20)
    OneWire READ Pin%, 0, 8, TD() ': Print "TD() = "; :Math V_Print TD()' read back the scratchpad data
    If TD(7) = 255 Then Res% = 127 '            Non-Genuine DS18B20 use resolution 3 only
    OneWire WRITE Pin%, 1, 1, &h55 '            reset then match ROM Code command
    OneWire WRITE Pin%, 0, 8, ROMcode$ '        send ROM Code
    OneWire WRITE Pin%, 0, 1, &h4E '            Write data command
    OneWire WRITE Pin%, 0, 3, TH, TL, Res% '    send 3 bytes
    OneWire WRITE Pin%, 0, 1, &h48 'transfer the TH, TL and Res data from the scratchpad to EEPROM
  Else '                                        Only 1 device on the bus and ROM Code not supplied
    OneWire WRITE Pin%, 1, 1, &h33 '            reset then read the ROM code command
    OneWire READ Pin%, 0, 8, ROMcode$ '         Get the 8 byte ROM code
    ROM% = Str2bin(Uint64,ROMcode$,big) '       Output the ROM code to variable ROM% (if ROM% was 0)
    OneWire WRITE Pin%, 1, 2, &hCC, &hBE '      Read data command (to to check for non-genuine DS18B20)
    OneWire READ Pin%, 2, 8, TD() ': Print "TD() = "; :Math V_Print TD()' read back the scratchpad data then reset
    If TD(7) = 255 Then Res% = 127 '            Non-Genuine DS18B20 use resolution 3 only
    OneWire WRITE Pin%, 1, 2, &hCC, &h4E '      reset then write data to scratchpad command
    OneWire WRITE Pin%, 0, 3, TH, TL, Res% '    send 3 bytes
    OneWire WRITE Pin%, 1, 2, &hCC, &h48 '      reset then transfer the TH, TL and Res from scratchpad to EEPROM
  EndIf

  AlarmSet = ROM%
End Function

Reading the alarm status.
t = Timer + 2001 'An example of reading the temperature alarm status of all units on the bus.
Do   'Your main loop
     
    If Timer - t > 2000 Then       'Start conversion on all units at 2 Sec intervals
       OneWire WRITE Pin%, 1, 2, &hCC,&h44
       t = Timer
    EndIf

    OneWire READ Pin%, 4, 1, done                   ' and wait for the slowest to finish.
    If done then
      OneWire WRITE Pin, 1, 11, &hEC : OneWire READ Pin, 4, 1, alarm ': ? a 'Alarm Search then read all alarm flags
      If alarm = 0 then
        Print "A temperature is out of limits"
        'now read each unit individually to find the culprit
      EndIf
    EndIf
Loop

Edited 2026-07-18 16:35 by phil99