DS18b20 temperature values format
brossingo last edited by robert-hh
I am currently working on a project which consists in reading temperature values using a DS18b20 sensor and a 1-Wire. In my code which you can find below, I used both Micropython libraries and my main.py does return some values. However, the values I have are not suitable I guess. For example, I have values like 2293 printed, whereas I would like for example 23.5 (degrees celsius). If I try to use the convert_temp function which, I think, is supposed to do the convertion, I get the following error message : TypeError: 'int' object is not subscriptable. I think there is the problem with the rom I defined which is : [bytearray(b'(\xffI\xd8 \x17\x048')]. From what I have read on the internet, it is probably because I am trying to index/use it as a list or a table, which is not its type. If I decide not to use, I get the 4-number value as I said before. How can I fix this and get a proper value ?
Thanks for helping
import time import machine from machine import Pin class OneWire: CMD_SEARCHROM = const(0xf0) CMD_READROM = const(0x33) CMD_MATCHROM = const(0x55) CMD_SKIPROM = const(0xcc) def __init__(self, pin): self.pin = pin self.pin.init(pin.OPEN_DRAIN, pin.PULL_UP) def reset(self): """ Perform the onewire reset function. Returns True if a device asserted a presence pulse, False otherwise. """ sleep_us = time.sleep_us disable_irq = machine.disable_irq enable_irq = machine.enable_irq pin = self.pin pin(0) sleep_us(480) i = disable_irq() pin(1) sleep_us(60) status = not pin() enable_irq(i) sleep_us(420) return status def read_bit(self): sleep_us = time.sleep_us enable_irq = machine.enable_irq pin = self.pin pin(1) # half of the devices don't match CRC without this line i = machine.disable_irq() pin(0) sleep_us(1) pin(1) sleep_us(1) value = pin() enable_irq(i) sleep_us(40) return value def read_byte(self): value = 0 for i in range(8): value |= self.read_bit() << i return value def read_bytes(self, count): buf = bytearray(count) for i in range(count): buf[i] = self.read_byte() return buf def write_bit(self, value): sleep_us = time.sleep_us pin = self.pin i = machine.disable_irq() pin(0) sleep_us(1) pin(value) sleep_us(60) pin(1) sleep_us(1) machine.enable_irq(i) def write_byte(self, value): for i in range(8): self.write_bit(value & 1) value >>= 1 def write_bytes(self, buf): for b in buf: self.write_byte(b) def select_rom(self, rom): """ Select a specific device to talk to. Pass in rom as a bytearray (8 bytes). """ self.reset() self.write_byte(CMD_MATCHROM) self.write_bytes(rom) def crc8(self, data): """ Compute CRC """ crc = 0 for i in range(len(data)): byte = data[i] for b in range(8): fb_bit = (crc ^ byte) & 0x01 if fb_bit == 0x01: crc = crc ^ 0x18 crc = (crc >> 1) & 0x7f if fb_bit == 0x01: crc = crc | 0x80 byte = byte >> 1 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.write_byte(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.read_bit() if self.read_bit(): 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.write_bit(b) if b: r_b |= 1 << bit i -= 1 rom[byte] = r_b return rom, next_diff class Ds(object): def __init__(self, onewire): self.ow = onewire self.roms = [rom for rom in self.ow.scan() if rom == 0x10 or rom == 0x28] def read_temp(self, rom=None): """ Read and return the temperature of one DS18x20 device. Pass the 8-byte bytes object with the ROM of the specific device you want to read. If only one DS18x20 device is attached to the bus you may omit the rom parameter. """ rom = rom or self.roms ow = self.ow ow.reset() ow.select_rom(rom) ow.write_byte(0x44) # Convert Temp while True: if ow.read_bit(): break ow.reset() ow.select_rom(rom) ow.write_byte(0xbe) # Read scratch data = ow.read_bytes(9) return self.convert_temp(rom, data) def read_temps(self): """ Read and return the temperatures of all attached DS18x20 devices. """ temps =  for rom in self.roms: temps.append(self.read_temp(rom)) return temps def convert_temp(self, rom0, data): """ Convert the raw temperature data into degrees celsius and return as a fixed point with 2 decimal places. """ temp_lsb = data temp_msb = data if rom0 == 0x10: if temp_msb != 0: # convert negative number temp_read = temp_lsb >> 1 | 0x80 # truncate bit 0 by shifting, fill high bit with 1. temp_read = -((~temp_read + 1) & 0xff) # now convert from two's complement else: temp_read = temp_lsb >> 1 # truncate bit 0 by shifting count_remain = data count_per_c = data temp = 100 * temp_read - 25 + (count_per_c - count_remain) // count_per_c return temp elif rom0 == 0x28: return (temp_msb << 8 | temp_lsb) * 100 // 16 else: assert False ow = OneWire(Pin('P23',mode=Pin.IN,pull=Pin.PULL_UP)) temp = Ds(ow) rom=ow.scan() t=temp.read_temp() print(t) print(temp.convert_temp(rom,t))
robert-hh last edited by
@brossingo I'm using this lib for Pycom devices: https://github.com/pycom/pycom-libraries/tree/master/examples/DS18X20
It works well. I tested it only with a single device on the bus, but there is also support for multiple devices.
brossingo last edited by brossingo
I also replaced the read_temp() function by the read_temps() one. Then I get printed :  for the temperature for example, but then it says : IndexError : list index out of range.