# ONEWIRE

Compatible with:
DOS Maximite CMM MM150 MM170 MM+ MMX Picromite ArmiteL4 Armite F4 ArmiteH7 Picomite 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