import time
import machine
from micropython import const
from machine import Pin
#class OneWire.py
#
class OneWire:
CMD_SEARCHROM = 0xf0
CMD_READROM = 0x33
CMD_MATCHROM = 0x55
CMD_SKIPROM = 0xcc
PULLUP_ON = 1
def __init__(self, pin):
self.pin = pin
self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP)
self.disable_irq = machine.disable_irq
self.enable_irq = machine.enable_irq
self.crctab1 = (b"\x00\x5E\xBC\xE2\x61\x3F\xDD\x83"
b"\xC2\x9C\x7E\x20\xA3\xFD\x1F\x41")
self.crctab2 = (b"\x00\x9D\x23\xBE\x46\xDB\x65\xF8"
b"\x8C\x11\xAF\x32\xCA\x57\xE9\x74")
def reset(self, required=False):
"""
Perform the onewire reset function.
Returns True if a device asserted a presence pulse, False otherwise.
"""
sleep_us = time.sleep_us
pin = self.pin
pin(0)
sleep_us(480)
i = self.disable_irq()
pin(1)
sleep_us(60)
status = not pin()
self.enable_irq(i)
sleep_us(420)
assert status is True or required is False, "Onewire device missing"
return status
def readbit(self):
sleep_us = time.sleep_us
pin = self.pin
pin(1) # half of the devices don't match CRC without this line
i = self.disable_irq()
pin(0)
# skip sleep_us(1) here, results in a 2 us pulse.
pin(1)
sleep_us(5) # 8 us delay in total
value = pin()
self.enable_irq(i)
sleep_us(40)
return value
def readbyte(self):
value = 0
for i in range(8):
value |= self.readbit() << i
return value
def readbytes(self, count):
buf = bytearray(count)
for i in range(count):
buf[i] = self.readbyte()
return buf
def readinto(self, buf):
for i in range(len(buf)):
buf[i] = self.readbyte()
def writebit(self, value, powerpin=None):
sleep_us = time.sleep_us
pin = self.pin
i = self.disable_irq()
pin(0)
# sleep_us(1) # dropped for shorter pulses
pin(value)
sleep_us(60)
if powerpin:
pin(1)
powerpin(self.PULLUP_ON)
else:
pin(1)
self.enable_irq(i)
def writebyte(self, value, powerpin=None):
for i in range(7):
self.writebit(value & 1)
value >>= 1
self.writebit(value & 1, powerpin)
def write(self, buf):
for b in buf:
self.writebyte(b)
def select_rom(self, rom):
"""
Select a specific device to talk to. Pass in rom as a bytearray (8 bytes).
"""
self.reset()
self.writebyte(self.CMD_MATCHROM)
self.write(rom)
def crc8(self, data):
"""
Compute CRC, based on tables
"""
crc = 0
for i in range(len(data)):
crc ^= data[i] ## just re-using crc as intermediate
crc = (self.crctab1[crc & 0x0f] ^
self.crctab2[(crc >> 4) & 0x0f])
return crc
def scan(self):
"""
Return a list of ROMs for all attached devices.
Each ROM is returned as a bytes object of 8 bytes.
"""
devices = []
diff = 65
rom = False
for i in range(0xff):
rom, diff = self._search_rom(rom, diff)
if rom:
devices += [rom]
if diff == 0:
break
return devices
def _search_rom(self, l_rom, diff):
if not self.reset():
return None, 0
self.writebyte(self.CMD_SEARCHROM)
if not l_rom:
l_rom = bytearray(8)
rom = bytearray(8)
next_diff = 0
i = 64
for byte in range(8):
r_b = 0
for bit in range(8):
b = self.readbit()
if self.readbit():
if b: # there are no devices or there is an error on the bus
return None, 0
else:
if not b: # collision, two devices with different bit meaning
if diff > i or ((l_rom[byte] & (1 << bit)) and diff != i):
b = 1
next_diff = i
self.writebit(b)
if b:
r_b |= 1 << bit
i -= 1
rom[byte] = r_b
return rom, next_diff
#class DS18X20.py
CMD_CONVERT = const(0x44)
CMD_RDSCRATCH = const(0xbe)
CMD_WRSCRATCH = const(0x4e)
CMD_RDPOWER = const(0xb4)
PULLUP_ON = const(1)
PULLUP_OFF = const(0)
class DS18X20:
def __init__(self, onewire):
self.ow = onewire
self.buf = bytearray(9)
self.config = bytearray(3)
self.power = 1 # strong power supply by default
self.powerpin = None
def powermode(self, powerpin=None):
if self.powerpin is not None: # deassert strong pull-up
self.powerpin(PULLUP_OFF)
self.ow.writebyte(self.ow.CMD_SKIPROM)
self.ow.writebyte(CMD_RDPOWER)
self.power = self.ow.readbit()
if powerpin is not None:
assert type(powerpin) is Pin, "Parameter must be a Pin object"
self.powerpin = powerpin
self.powerpin.init(mode=Pin.OUT, value=0)
return self.power
def scan(self):
if self.powerpin is not None: # deassert strong pull-up
self.powerpin(PULLUP_OFF)
return [rom for rom in self.ow.scan() if rom[0] in (0x10, 0x22, 0x28)]
def convert_temp(self, rom=None):
if self.powerpin is not None: # deassert strong pull-up
self.powerpin(PULLUP_OFF)
self.ow.reset()
if rom is None:
self.ow.writebyte(self.ow.CMD_SKIPROM)
else:
self.ow.select_rom(rom)
self.ow.writebyte(CMD_CONVERT, self.powerpin)
def read_scratch(self, rom):
if self.powerpin is not None: # deassert strong pull-up
self.powerpin(PULLUP_OFF)
self.ow.reset()
self.ow.select_rom(rom)
self.ow.writebyte(CMD_RDSCRATCH)
self.ow.readinto(self.buf)
assert self.ow.crc8(self.buf) == 0, 'CRC error'
return self.buf
def write_scratch(self, rom, buf):
if self.powerpin is not None: # deassert strong pull-up
self.powerpin(PULLUP_OFF)
self.ow.reset()
self.ow.select_rom(rom)
self.ow.writebyte(CMD_WRSCRATCH)
self.ow.write(buf)
def read_temp(self, rom):
try:
buf = self.read_scratch(rom)
if rom[0] == 0x10:
if buf[1]:
t = buf[0] >> 1 | 0x80
t = -((~t + 1) & 0xff)
else:
t = buf[0] >> 1
return t - 0.25 + (buf[7] - buf[6]) / buf[7]
elif rom[0] in (0x22, 0x28):
t = buf[1] << 8 | buf[0]
if t & 0x8000: # sign bit set
t = -((t ^ 0xffff) + 1)
return t / 16
else:
return None
except AssertionError:
return None
def resolution(self, rom, bits=None):
if bits is not None and 9 <= bits <= 12:
self.config[2] = ((bits - 9) << 5) | 0x1f
self.write_scratch(rom, self.config)
return bits
else:
data = self.read_scratch(rom)
return ((data[4] >> 5) & 0x03) + 9
def fahrenheit(self, celsius):
return celsius * 1.8 + 32 if celsius is not None else None
def kelvin(self, celsius):
return celsius + 273.15 if celsius is not None else None
#DS18B20 data line connected to pin P10
ow = OneWire(Pin(2, Pin.OPEN_DRAIN))
temp = DS18X20(ow)
print("Powermode = ", temp.powermode())
roms = temp.scan()
print(roms)
temp.resolution(roms[0], bits=9)
print("Resolution", temp.resolution(roms[0]))
temp.convert_temp()
while True:
time.sleep(1)
for rom in roms:
print(temp.read_temp(rom), end=" ")
print()
temp.convert_temp()