ONEWIRE

Compatible with:
DOS Maximite CMM MM150 MM170 MM+ MMX Picromite ArmiteL4 Armite F4 ArmiteH7 CMM2

Syntax:
ONEWIRE READ pin, flag, length, data [, data ...]
ONEWIRE WRITE pin, flag, length, data [, data…]

ONEWIRE RESET pin

Description:

The 1-Wire protocol was developed by Dallas Semiconductor to communicate with chips using a single signalling line.

 There are three commands that you can use: 
ONEWIRE RESET pin Reset the 1-Wire bus 
ONEWIRE WRITE pin, flag, length, data [, data…] Send a number of bytes 
ONEWIRE READ pin, flag, length, data [, data…] Get a number of bytes 

Where: 
pin - The I/O pin (located in the rear connector) to use. It can be any pin capable of digital I/O. 
flag - A combination of the following options: 
1 - Send reset before command 
2 - Send reset after command 
4 - Only send/recv a bit instead of a byte of data 
8 - Invoke a strong pullup after the command (the pin will be set high and open drain disabled) 
length - Length of data to send or receive 
data - Data to send or variable to receive. The number of data items must agree with the length parameter. 

The automatic variable MM.ONEWIRE returns true if a device was found

After the command is executed, the I/O pin will be set to the not configured state unless flag option 8 is used. 
When a reset is requested the automatic variable MM.ONEWIRE will return true if a device was found. 
This will occur with the ONEWIRE RESET command and the ONEWIRE READ and ONEWIRE WRITE commands if a reset was requested (flag = 1 or 2). 

The 1-Wire protocol is often used in communicating with the DS18B20 temperature measuring sensor and to help in that regard MMBasic includes the TEMPR() function which provides a convenient method of directly reading the temperature of a DS18B20 without using these functions.

This program will communicate with most DS18xx variants as well as situations where there are multiple devices on the one pin.

 ' one-wire search and read mutiple devices on one pin
 ' also should read DS18S20 and DS1820 as well as DS18B20
 ' tested on CMM2 and micromite
 ' TassyJim August2020
 ' search based on code by jman and maximite source code
 '
 OPTION EXPLICIT
 DIM NextRomCode$
 DIM INTEGER t,b, pinN = 42
 DIM FLOAT tp

 PRINT
 PRINT TEMPR(pinN)
 PRINT ow_Tempr(pinN)
 PRINT
 DO
   NextRomCode$ = ow_search(PinN)
   IF NextRomCode$<>"" THEN
     FOR b = 9 TO 12
       t = TIMER
       tp = ow_Tempr(PinN,b,NextRomCode$)
       PRINT NextRomCode$;"  ";INT(TIMER-t-30);" ";tp
     NEXT b
   ENDIF
   PRINT
 LOOP UNTIL NextRomCode$ = ""
 
 ' ow_search() given pin number, returns all onewire devices found one at a time,
 ' as a string. After the last device, the next call will return an empty string.
 ' If there are no devices found "None found" is returned.
 ' Anything other than zero for the second parameter will cause the counter to reset,
 ' retrieving the first device
FUNCTION ow_search(PinNbr AS INTEGER,f%) AS STRING
 LOCAL INTEGER i, RomNum, rom_byte_mask, id_bit, cmp_id_bit, Last_zero
 LOCAL INTEGER search_direction, id_bit_number
 LOCAL RomCode$
 STATIC INTEGER LastDeviceFlag, LastDiscrepancy, last_RomNum
 
 IF f% <> 0 THEN ' reset for a new search
   last_RomNum = 0
   LastDeviceFlag = 0
   LastDiscrepancy = 0
   'LastFamilyDiscrepancy = 0
 ENDIF
 
 ONEWIRE RESET PinNbr
 
 IF LastDeviceFlag = 1 THEN
   RomCode$ = ""
   last_RomNum = 0
   LastDeviceFlag = 0
   LastDiscrepancy = 0
   'LastFamilyDiscrepancy = 0
 ELSE
   RomNum = 0
   id_bit_number = 1
   rom_byte_mask = 1
   last_zero = 0
   
   ONEWIRE WRITE PinNbr,1,1,&HF0 'Send the Search ROM command (FO)
   DO
     ONEWIRE READ PinNbr, 4 , 2, id_bit, cmp_id_bit 'Get response from device
     IF (id_bit = 1 AND cmp_id_bit = 1) THEN ' shouldn't happen
       LastDeviceFlag = -1
       EXIT DO
     ENDIF
     IF id_bit <> cmp_id_bit THEN search_direction = id_bit ' no conflict
     IF ((id_bit = 0) AND (cmp_id_bit = 0)) THEN ' conflict
       IF id_bit_number = LastDiscrepancy THEN
         'id_bit_number = LastDiscrepancy then take "1" path
         search_direction = 1
       ELSEIF id_bit_number > LastDiscrepancy THEN
         'id_bit_number > LastDiscrepancy then take the "0" path
         search_direction = 0
       ELSE
         ' id_bit_number < LastDiscrepancy then take same path as last time
         IF (last_RomNum AND rom_byte_mask) > 0 THEN
           search_direction = 1
         ELSE
           search_direction = 0
         ENDIF
       ENDIF
       IF search_direction = 0 THEN
         Last_zero = id_bit_number
         'If last_zero < 9 Then LastFamilyDiscrepancy = last_zero
       ENDIF
     ENDIF
     
     ' add bit to rom code or leave at zero if search_direction = 0
     IF search_direction = 1 THEN RomNum = RomNum OR rom_byte_mask
     
     ONEWIRE WRITE PinNbr,4,1,search_direction ' send 1 or 0 as search direction
     id_bit_number = id_bit_number+1 ' increment id_bit_number
     rom_byte_mask = rom_byte_mask << 1
     
   LOOP UNTIL id_bit_number > 64 'Check for next bit
   
   IF LastDeviceFlag = -1 THEN
     LastDeviceFlag = 1
     RomCode$ = "None found"
   ELSE
     LastDiscrepancy = last_zero
     IF LastDiscrepancy = 0 THEN LastDeviceFlag = 1
     last_RomNum = RomNum
     
     RomCode$ = ""
     FOR i = 1 TO 8
       RomCode$ = RomCode$ + HEX$((RomNum AND &hFF),2)
       RomNum = RomNum>>8
     NEXT i
   ENDIF
 ENDIF
 ow_search = RomCode$
END FUNCTION
 
 ' bit (9-12) is optional and defaults to 10
 ' probe$ is optional if only one probe attached
 ' probe$ format = "2862D8F105000018"
 ' time taken is ~30mS plus conversion time
 ' passive power sensors use a 750mS delay for all conversions.
FUNCTION ow_Tempr(PinNbr AS INTEGER, bit AS INTEGER, probe$) AS FLOAT
 LOCAL FLOAT T1
 LOCAL INTEGER t, n, power, romcode, Tconv
 LOCAL INTEGER c1,c2,c3,c4,c5,c6,c7,c8
 LOCAL INTEGER d1,d2,d3,d4,d5,d6,d7,d8
 
 IF bit = 0 THEN
   bit = 10
 ELSEIF bit < 9 THEN
   bit = 9
 ELSEIF bit > 12 THEN
   bit = 12
 ENDIF
 
 Tconv=750
 ONEWIRE RESET PinNbr
 IF MM.ONEWIRE = 0 THEN                 ' no device
   T1 = 1000
 ELSE
   
   ONEWIRE WRITE PinNbr, 1,2,&hcc, &hb4
   ONEWIRE READ PinNbr,4,1,power
   
   IF probe$ = "" THEN ' romcode not specified so go get it.
     ONEWIRE WRITE PinNbr,1,1,&h33 'read ROM code
     ONEWIRE READ PinNbr,0,8,c1,c2,c3,c4,c5,c6,c7,c8
   ELSE
     romcode = VAL("&h"+probe$)
     c8 = romcode AND &hFF
     romcode = romcode >> 8
     c7 = romcode AND &hFF
     romcode = romcode >> 8
     c6 = romcode AND &hFF
     romcode = romcode >> 8
     c5 = romcode AND &hFF
     romcode = romcode >> 8
     c4 = romcode AND &hFF
     romcode = romcode >> 8
     c3 = romcode AND &hFF
     romcode = romcode >> 8
     c2 = romcode AND &hFF
     romcode = romcode >> 8
     c1 = romcode AND &hFF
   ENDIF
   IF c1=34 OR c1=40 THEN
     n = ((bit-9)<< 5) + 31           ' set resolution config byte
     ONEWIRE WRITE PinNbr,1,9,&h55,c1,c2,c3,c4,c5,c6,c7,c8
     ONEWIRE WRITE PinNbr,0,4, &h4e , &hFF,&hFF,n
   ENDIF
   ONEWIRE WRITE PinNbr,1,9,&h55,c1,c2,c3,c4,c5,c6,c7,c8
   IF power = 0 THEN
     ONEWIRE WRITE PinNbr,8,1, &h44   'apply strong pullup for passive
   ELSE
     ONEWIRE WRITE PinNbr,0,1, &h44
   ENDIF
   'read external when bit goes hi, for parasitic just wait
   IF power = 0 THEN
     PAUSE Tconv
   ELSE
     t = TIMER
     DO
       IF TIMER - t > 1000 THEN
         T1 = 1001
         EXIT DO
       ENDIF
       ONEWIRE READ PinNbr, 4, 1, n   ' conversion done?
     LOOP UNTIL n = 1
     'print int(timer - t);" ";
   ENDIF
 ENDIF
 
 IF T1 < 1000 THEN
   'read scratchpad
   ONEWIRE WRITE PinNbr,1,9,&h55,c1,c2,c3,c4,c5,c6,c7,c8
   ONEWIRE WRITE PinNbr,0,1,&hbe     ' command read data
   ONEWIRE READ PinNbr,2,8,d1,d2,d3,d4,d5,d6,d7,d8
   
   IF c1=34 OR c1=40 THEN            ' DS18S22 or DS18B20
     t= d1+(d2<<8)
     t = t AND (&hFFFF <<(12-bit))
     IF t > 32767 THEN t = t - 65536
     T1 = t/16
   ELSEIF c1=16 THEN                 ' DS18S20 or DS1820
     t= d1+(d2<<8)
     IF t > 32767 THEN t = t - 65536
     ' T1 = t/2 ' 9 bit
     T1 = (t>>1) - 0.25 + (d8-d7)/d8 ' using extended precision data
   ELSE
     T1 = 1002
   ENDIF
 ENDIF
 ow_Tempr = T1
END FUNCTION

Last edited: 29 September, 2020