Raspberry Pi Pico
DS18B20 Digital Thermometer
I picked up a digital temperature sensor breakout board for £2.50. It was a DS18B20 sensor that you communicate with using the OneWire protocol. Handily, MicroPython comes with a module for the protocol and for the family of sensors that this one is from. I thought I'd put together a quick project to show the temperature on one of Adafruit's 4x7 segment displays using the HT16K33 backpack.
Here is a photo of what I ended up with. The display is way brighter than my photo shows and is really easy to read.
Here is a Fritzing diagram showing the equivalent circuit. Notice that there is a pull-up resistor on the signal line. This is a 4.7K resistor as advised in the MicroPython documentation.
I started by doing a quick tidy of the library code I had previously written for the display. I wanted to make it so you passed the I2C connection to the class when you instantiate it.
class backpack: ADDRESS = 0x70 BLINK_CMD = 0x80 CMD_BRIGHTNESS = 0xE0 # Digits 0 - F NUMS = [0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71] def __init__(self, i2c): self.buffer = bytearray([0]*16) self.i2c= i2c self.i2c.writeto(self.ADDRESS,b'\x21') # 0 to 3 self.blink_rate(0) # 0 to 15 self.set_brightness(15) self.update_display() def set_brightness(self,b): self.i2c.writeto(self.ADDRESS,bytes([self.CMD_BRIGHTNESS | b])) def blink_rate(self, b): self.i2c.writeto(self.ADDRESS,bytes([self.BLINK_CMD | 1 | (b << 1)])) def write_digit(self, position, digit, dot=False): # skip the colon offset = 0 if position < 2 else 1 pos = offset + position self.buffer[pos*2] = self.NUMS[digit] & 0xFF if dot: self.buffer[pos*2] |= 0x80 def update_display(self): data = bytearray([0]) + self.buffer self.i2c.writeto(self.ADDRESS,data) def print(self,value): if value<0 or value>9999: return sdig = '{:04d}'.format(value) dts = [int(x) for x in sdig] for i,d in enumerate(dts): self.write_digit(i,d) def set_decimal(self, position, dot=True): # skip the colon offset = 0 if position < 2 else 1 pos = offset + position if dot: self.buffer[pos*2] |= 0x80 else: self.buffer[pos*2] &= 0x7F def clear(self): self.buffer = bytearray([0]*16) self.update_display() def set_colon(self, colon=True): if colon: self.buffer[4] |= 0x02 else: self.buffer[4] &= 0xFD
The rest of the code is not too special. It shows how to interact with the sensor and how I prepared the reading to get it onto the display as easily as possible.
from machine import Pin, I2C from time import sleep from onewire import OneWire from ds18x20 import DS18X20 from ht16k33 import backpack # set up temperature sensor with onewire ow = OneWire(Pin(22)) ds = DS18X20(ow) r = ds.scan()[0] # set up i2c and display i2c = I2C(1, sda=Pin(14), scl=Pin(15)) display = backpack(i2c) while True: ds.convert_temp() sleep(0.75) t = round(ds.read_temp(r), 2) print(t) # do the whole number part w = int(t * 100) display.print(w) # set the decimal point display.set_decimal(1) # do the fractional part w = w % 100 display.write_digit(2, w // 10) display.write_digit(3, w % 10) display.update_display() sleep(5)
I was really impressed with the temperature sensor and how easy it was to get a plausible reading with the built-in library. Given the price and the apparent accuracy, I would be reaching for this sensor again, perhaps to draw a nice thermometer on an LCD...