DS18b20 temperature values format



  • Hello everyone,
    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[0] == 0x10 or rom[0] == 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[0]
            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[0], 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[0]
            temp_msb = data[1]
            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[6]
                count_per_c = data[7]
                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))
    


  • @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.



  • I also replaced the read_temp() function by the read_temps() one. Then I get printed : [2275] for the temperature for example, but then it says : IndexError : list index out of range.


Log in to reply
 

Pycom on Twitter