树莓派 Pico 与 TM1637 数码管模块:从零开始的实战教程
这篇教程将带你一步步掌握如何在树莓派 Pico(或 Pico W)上驱动 TM1637 4 位数码管模块,最终实现数字、文字、甚至滚动消息的显示。别担心接线和代码,我们从头说起。
所需组件
- 树莓派 Pico 或 Pico W
- TM1637 4 位数码管模块
- 面包板和跳线
- microUSB 数据线
认识 TM1637 模块
TM1637 是一颗非常实用的 LED 驱动控制芯片,内部集成了 MCU 数字接口、数据锁存器、高压驱动和键盘扫描电路。这类数码管模块之所以受欢迎,是因为它只用了 4 个引脚(两个电源、两个控制)就能搞定 4 位 7 段显示,接线简单到令人感动。

- CLK:时钟引脚,负责与微控制器保持同步脉冲。
- DIO:数据引脚,用于发送和接收数据。
- GND:接地。
- VCC:电源输入,支持 3.3V~5V。
树莓派 Pico 的 I2C 引脚分配
RP2040 芯片提供了两个 I2C 控制器,每个控制器都可以通过多个 GPIO 引脚灵活配置。下面这张表就是它们的映射关系——你完全可以按自己手头的接线来选。
| I2C 控制器 | 功能 | 可选 GPIO 引脚 |
|---|---|---|
| I2C0 | SDA | GP0/GP4/GP8/GP12/GP16/GP20 |
| I2C0 | SCL | GP1/GP5/GP9/GP13/GP17/GP21 |
| I2C1 | SDA | GP2/GP6/GP10/GP14/GP18/GP26 |
| I2C1 | SCL | GP3/GP7/GP11/GP15/GP19/GP27 |
实际连接非常简单:我们直接把 CLK 接到 GP26,DIO 接到 GP27 就行。当然你也可以用表里其他 SDA/SCL 组合,只要软件里配置一致即可。

安装 TM1637 库
要驱动这个模块,我们需要一个干净的 MicroPython 库。下面的代码就是完整的 tm1637.py,直接复制到 Thonny 中,保存到 Pico 的根目录或 lib 文件夹即可。
from micropython import const
from machine import Pin
from time import sleep_us, sleep_ms
TM1637_CMD1 = const(64) # 0x40 data command
TM1637_CMD2 = const(192) # 0xC0 address command
TM1637_CMD3 = const(128) # 0x80 display control command
TM1637_DSP_ON = const(8) # 0x08 display on
TM1637_DELAY = const(10) # 10us delay between clk/dio pulses
TM1637_MSB = const(128) # msb is the decimal point or the colon depending on your display
# 0-9, a-z, blank, dash, star
_SEGMENTS = bytearray(b'x3Fx06x5Bx4Fx66x6Dx7Dx07x7Fx6Fx77x7Cx39x5Ex79x71x3Dx76x06x1Ex76x38x55x54x3Fx73x67x50x6Dx78x3Ex1Cx2Ax76x6Ex5Bx00x40x63')
class TM1637(object):
"""Library for quad 7-segment LED modules based on the TM1637 LED driver."""
def __init__(self, clk, dio, brightness=7):
self.clk = clk
self.dio = dio
if not 0 <= brightness <= 7:
raise ValueError("Brightness out of range")
self._brightness = brightness
self.clk.init(Pin.OUT, value=0)
self.dio.init(Pin.OUT, value=0)
sleep_us(TM1637_DELAY)
self._write_data_cmd()
self._write_dsp_ctrl()
def _start(self):
self.dio(0)
sleep_us(TM1637_DELAY)
self.clk(0)
sleep_us(TM1637_DELAY)
def _stop(self):
self.dio(0)
sleep_us(TM1637_DELAY)
self.clk(1)
sleep_us(TM1637_DELAY)
self.dio(1)
def _write_data_cmd(self):
# automatic address increment, normal mode
self._start()
self._write_byte(TM1637_CMD1)
self._stop()
def _write_dsp_ctrl(self):
# display on, set brightness
self._start()
self._write_byte(TM1637_CMD3 | TM1637_DSP_ON | self._brightness)
self._stop()
def _write_byte(self, b):
for i in range(8):
self.dio((b >> i) & 1)
sleep_us(TM1637_DELAY)
self.clk(1)
sleep_us(TM1637_DELAY)
self.clk(0)
sleep_us(TM1637_DELAY)
self.clk(0)
sleep_us(TM1637_DELAY)
self.clk(1)
sleep_us(TM1637_DELAY)
self.clk(0)
sleep_us(TM1637_DELAY)
def brightness(self, val=None):
"""Set the display brightness 0-7."""
if val is None:
return self._brightness
if not 0 <= val <= 7:
raise ValueError("Brightness out of range")
self._brightness = val
self._write_data_cmd()
self._write_dsp_ctrl()
def write(self, segments, pos=0):
"""Display up to 6 segments moving right from a given position."""
if not 0 <= pos <= 5:
raise ValueError("Position out of range")
self._write_data_cmd()
self._start()
self._write_byte(TM1637_CMD2 | pos)
for seg in segments:
self._write_byte(seg)
self._stop()
self._write_dsp_ctrl()
def encode_digit(self, digit):
return _SEGMENTS[digit & 0x0f]
def encode_string(self, string):
segments = bytearray(len(string))
for i in range(len(string)):
segments[i] = self.encode_char(string[i])
return segments
def encode_char(self, char):
o = ord(char)
if o == 32:
return _SEGMENTS[36] # space
if o == 42:
return _SEGMENTS[38] # star/degrees
if o == 45:
return _SEGMENTS[37] # dash
if o >= 65 and o <= 90:
return _SEGMENTS[o-55] # uppercase A-Z
if o >= 97 and o <= 122:
return _SEGMENTS[o-87] # lowercase a-z
if o >= 48 and o <= 57:
return _SEGMENTS[o-48] # 0-9
raise ValueError("Character out of range: {:d} '{:s}'".format(o, chr(o)))
def hex(self, val):
string = '{:04x}'.format(val & 0xffff)
self.write(self.encode_string(string))
def number(self, num):
num = max(-999, min(num, 9999))
string = '{0: >4d}'.format(num)
self.write(self.encode_string(string))
def numbers(self, num1, num2, colon=True):
num1 = max(-9, min(num1, 99))
num2 = max(-9, min(num2, 99))
segments = self.encode_string('{0:0>2d}{1:0>2d}'.format(num1, num2))
if colon:
segments[1] |= 0x80 # colon on
self.write(segments)
def temperature(self, num):
if num < -9:
self.show('lo')
elif num > 99:
self.show('hi')
else:
string = '{0: >2d}'.format(num)
self.write(self.encode_string(string))
self.write([_SEGMENTS[38], _SEGMENTS[12]], 2) # degrees C
def show(self, string, colon=False):
segments = self.encode_string(string)
if len(segments) > 1 and colon:
segments[1] |= 128
self.write(segments[:4])
def scroll(self, string, delay=250):
segments = string if isinstance(string, list) else self.encode_string(string)
data = [0] * 8
data[4:0] = list(segments)
for i in range(len(segments) + 5):
self.write(data[0+i:4+i])
sleep_ms(delay)
class TM1637Decimal(TM1637):
"""For modules with decimal points after each digit."""
def encode_string(self, string):
segments = bytearray(len(string.replace('.','')))
j = 0
for i in range(len(string)):
if string[i] == '.' and j > 0:
segments[j-1] |= TM1637_MSB
continue
segments[j] = self.encode_char(string[i])
j += 1
return segments
库文件就绪后,就可以进入真正的实战阶段了。
树莓派 Pico MicroPython:TM1637 示例代码
首先确保你的 Pico 已经刷入了 MicroPython(如果不清楚,可以参考之前的入门教程)。按上图完成硬件连接,然后用 USB 线连上电脑。打开 Thonny,新建一个文件,粘贴下面的代码:
import tm1637
from machine import Pin
import time
tm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))
# 设置亮度(0-7)
tm.brightness(5)
# 显示 "10:24"
tm.numbers(10, 24, colon=True)
time.sleep(2)
# 显示单词
tm.show("AbCd", colon=False)
time.sleep(2)
# 直接通过位段显示 "COOL"
tm.write([0b00111001, 0b00111111, 0b00111111, 0b00111000])
time.sleep(2)
# 清屏
tm.show(" ")
time.sleep(2)
# 显示十六进制 "bEEF"
tm.hex(0xbeef)
time.sleep(2)
# 显示负数 "-123"
tm.number(-123)
time.sleep(2)
# 显示温度 "24*C"
tm.temperature(24)
time.sleep(2)
# 滚动显示长文本
tm.scroll('RPI-ICU', delay=250)
点击 Thonny 的“运行”按钮(或按 F5),然后将脚本保存到 Pico 中(比如命名为 main.py 或任意 .py 文件)。上传成功后,你会看到数码管依次切换显示各种内容,每次显示停留约 2 秒。

代码逐段解析
先看导入部分:import tm1637 是我们的核心驱动,Pin 用于控制 GPIO,time 负责延时。
import tm1637
from machine import Pin
import time
tm = tm1637.TM1637(clk=Pin(0), dio=Pin(1))
这里实例化了一个 TM1637 对象,指定 CLK 接 GP0,DIO 接 GP1。
tm.brightness(5)
亮度范围 1~7,数字越大越亮。
tm.numbers(10, 24, colon=True)
numbers() 函数在冒号两侧各显示两个数字,前导会自动补零。如果不想显示冒号,把 colon 设为 False 即可。
tm.write([0b00111001, 0b00111111, 0b00111111, 0b00111000])
这是最底层的控制方式——直接指定每个段的状态。每个 8 位二进制数对应一个数码管的 a~g 和 DP 段。比如 0b00111001 点亮了 a、d、e、f 段,正好显示字母 'c'。熟悉 7 段显示原理的话,这个写法会格外顺手。
__2__
| |
1 | | 3
|__7__|
| |
6 | | 4
|__5__| DP
对照上面的段位图,0b00111001 = 二进制位的 0~7 分别对应 a、b、c、d、e、f、g、DP。最低位是 a,最高位是 DP。所以 0b00111001 点亮 a、d、e、f,拼出 'c'。同理,0b00111111 点亮 a、b、c、d、e、f,拼出 'o';0b00111000 点亮 a、d、e 和 g,拼出 'l'。
tm.show('heya', colon=False)
tm.hex(0xbeef)
tm.number(-123)
这些是更高级的封装函数:show() 直接显示字符串,hex() 显示 4 位十六进制数,number() 显示 -999 到 9999 范围内的整数,数字自动右对齐。
tm.scroll('scrolling', delay=250)
当内容超过 4 位时,scroll() 可以滚动显示。参数 delay 是每个字符在屏幕上停留的毫秒数。
最后
上传代码后,TM1637 数码管模块就会依次展示数字、文字、十六进制值、温度符号和滚动消息。整个过程直观且易于调试,非常适合作为树莓派 Pico 的入门显示项目。有问题的话,不妨先核对接线和库的版本,再检查一下代码中的引脚号是否与实物一致。
