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

