|
| 1 | +""" |
| 2 | +DS18x20 temperature sensor driver for MicroPython. |
| 3 | +
|
| 4 | +This driver uses the OneWire driver to control DS18S20 and DS18B20 |
| 5 | +temperature sensors. It supports multiple devices on the same 1-wire bus. |
| 6 | +
|
| 7 | +The following example assumes the ground of your DS18x20 is connected to |
| 8 | +Y11, vcc is connected to Y9 and the data pin is connected to Y10. |
| 9 | +
|
| 10 | +>>> gnd = Pin('Y11') |
| 11 | +>>> gnd.init(Pin.OUT_PP) |
| 12 | +>>> gnd.low() |
| 13 | + |
| 14 | +>>> vcc = Pin('Y9') |
| 15 | +>>> vcc.init(Pin.OUT_PP) |
| 16 | +>>> vcc.high() |
| 17 | +
|
| 18 | +>>> d = DS18X20(Pin('Y10')) |
| 19 | +
|
| 20 | +Call read_temps to read all sensors: |
| 21 | +
|
| 22 | +>>> result = d.read_temps() |
| 23 | +>>> print(result) |
| 24 | +[20.875, 20.8125] |
| 25 | +
|
| 26 | +Call read_temp to read the temperature of a specific sensor: |
| 27 | +
|
| 28 | +>>> result = d.read_temp(d.roms[0]) |
| 29 | +>>> print(result) |
| 30 | +20.25 |
| 31 | +
|
| 32 | +If only one DS18x20 is attached to the bus, then you don't need to |
| 33 | +pass a ROM to read_temp: |
| 34 | +
|
| 35 | +>>> result = d.read_temp() |
| 36 | +>>> print(result) |
| 37 | +20.25 |
| 38 | +
|
| 39 | +""" |
| 40 | + |
| 41 | +from onewire import OneWire |
| 42 | + |
| 43 | +class DS18X20(object): |
| 44 | + def __init__(self, pin): |
| 45 | + self.ow = OneWire(pin) |
| 46 | + # Scan the 1-wire devices, but only keep those which have the |
| 47 | + # correct # first byte in their rom for a DS18x20 device. |
| 48 | + self.roms = [rom for rom in self.ow.scan() if rom[0] == 0x10 or rom[0] == 0x28] |
| 49 | + |
| 50 | + def _select_rom(self, rom): |
| 51 | + if rom: |
| 52 | + self.ow.select_rom(rom) |
| 53 | + else: |
| 54 | + self.ow.skip_rom() |
| 55 | + |
| 56 | + def read_temp(self, rom=None): |
| 57 | + """ |
| 58 | + Read and return the temperature of one DS18x20 device. |
| 59 | + Pass the 8-byte bytes object with the ROM of the specific device you want to read. |
| 60 | + If only one DS18x20 device is attached to the bus you may omit the rom parameter. |
| 61 | + """ |
| 62 | + ow = self.ow |
| 63 | + ow.reset() |
| 64 | + self._select_rom(rom) |
| 65 | + ow.write_byte(0x44) # Convert Temp |
| 66 | + while True: |
| 67 | + if ow.read_bit(): |
| 68 | + break |
| 69 | + ow.reset() |
| 70 | + self._select_rom(rom) |
| 71 | + ow.write_byte(0xbe) # Read scratch |
| 72 | + data = ow.read_bytes(9) |
| 73 | + return self.convert_temp(rom[0], data) |
| 74 | + |
| 75 | + def read_temps(self): |
| 76 | + """ |
| 77 | + Read and return the temperatures of all attached DS18x20 devices. |
| 78 | + """ |
| 79 | + temps = [] |
| 80 | + for rom in self.roms: |
| 81 | + temps.append(self.read_temp(rom)) |
| 82 | + return temps |
| 83 | + |
| 84 | + def convert_temp(self, rom0, data): |
| 85 | + """ |
| 86 | + Convert the raw temperature data into degrees celsius and return as a float. |
| 87 | + """ |
| 88 | + temp_lsb = data[0] |
| 89 | + temp_msb = data[1] |
| 90 | + if rom0 == 0x10: |
| 91 | + if temp_msb != 0: |
| 92 | + # convert negative number |
| 93 | + temp_read = temp_lsb >> 1 | 0x80 # truncate bit 0 by shifting, fill high bit with 1. |
| 94 | + temp_read = -((~temp_read + 1) & 0xff) # now convert from two's complement |
| 95 | + else: |
| 96 | + temp_read = temp_lsb >> 1 # truncate bit 0 by shifting |
| 97 | + count_remain = data[6] |
| 98 | + count_per_c = data[7] |
| 99 | + temp = temp_read - 0.25 + (count_per_c - count_remain) / count_per_c |
| 100 | + return temp |
| 101 | + elif rom0 == 0x28: |
| 102 | + return (temp_msb << 8 | temp_lsb) / 16 |
| 103 | + else: |
| 104 | + assert False |
0 commit comments