Raspberry Pi Pico
TM1637 4 Digit Display
The TM1637 is an LED driver. There are lots of cheap 4 and 6 digit displays that use it. You can pick these up for a a few pounds if you look around. I have had this one for a while now and finally decided to find out how to use it whilst some of my students were doing a long assessment.
This is how the board looks. It came with some male headers pre-soldered meaning it would stand vertically in a breadboard if you didn't use the male to female jumper cables.

Here is a Fritzing diagram showing how to connect the circuit.

from time import sleep_us
from micropython import const
_CMD1 = const(64)
_CMD2 = const(192)
_CMD3 = const(128)
_BIT_DELAY = 10
class TM1637:
def __init__(self, clk, dio):
self.clk = clk
self.dio = dio
self.data = [0, 0, 0, 0]
self.set_brightness(7)
def set_brightness(self, b, on=1):
if b<0 or b>7: return
self.brightness = b + (on * 8)
self.start()
self.write_byte(_CMD3 + self.brightness)
self.stop()
def start(self):
self.dio.value(0)
sleep_us(_BIT_DELAY)
self.clk.value(0)
sleep_us(_BIT_DELAY)
def stop(self):
self.dio.value(0)
sleep_us(_BIT_DELAY)
self.clk.value(1)
sleep_us(_BIT_DELAY)
self.dio.value(1)
def write_byte(self, b):
bits = [b >> i & 1 for i in range(8)]
for b in bits:
self.dio.value(b)
sleep_us(_BIT_DELAY)
self.clk.value(1)
sleep_us(_BIT_DELAY)
self.clk.value(0)
sleep_us(_BIT_DELAY)
self.clk.value(0)
sleep_us(_BIT_DELAY)
self.clk.value(1)
sleep_us(_BIT_DELAY)
self.clk.value(0)
sleep_us(_BIT_DELAY)
def write_digits(self, colon=True):
seg_data = [0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D,
0x07, 0x7F, 0x6F]
bitdata = [seg_data[d] for d in self.data]
if colon:
bitdata[1] |= 128
self.start()
self.write_byte(_CMD1)
self.stop()
self.start()
self.write_byte(_CMD2)
for digit in bitdata:
self.write_byte(digit)
self.stop()
self.start()
self.write_byte(_CMD3 + self.brightness)
self.stop()
# write a list of 4 binary values
def write_raw(self, digits):
self.data = digits
self.start()
self.write_byte(_CMD1)
self.stop()
self.start()
self.write_byte(_CMD2)
for digit in digits:
self.write_byte(digit)
self.stop()
self.start()
self.write_byte(_CMD3 + self.brightness)
self.stop()
def display_number(self, num, colon = True):
if num < 0 or num > 9999:
return
sdig = '{:04d}'.format(num)
self.data = [int(x) for x in sdig]
self.write_digits(colon)
Here is the test code I used,
from machine import Pin
from time import sleep
from tm1637 import TM1637
clk = Pin(17, Pin.OUT)
dio = Pin(16, Pin.OUT)
t = TM1637(clk, dio)
t.write_raw([127, 255, 127, 127])
for i in range(8):
t.set_brightness(7 - i)
sleep(1)
t.set_brightness(7)
sleep(1)
# off and on again
t.set_brightness(7, False)
sleep(1)
t.set_brightness(7, True)
sleep(1)
for i in range(10000):
t.display_number(i, False)
sleep(0.1)
When I finally got this to work, I was reasonably impressed with it. It can use any pins you like because it has a custom protocol and these displays are really cheap. There is no decimal point on my display and I find the colon to be a little cramped. It's still good enough to get across some numbers or the time when you need it to. I suspect I will find myself using this a lot in the future.

