【MicroPython ESP32】ST7735 TFT中文显示实战:从固件烧录到多色文本绘制
1. 准备工作:硬件与固件选择
玩转MicroPython和ESP32的第一步,就是准备好合适的硬件和固件。我刚开始接触这块1.8寸ST7735屏幕时,也踩过不少坑,现在把这些经验都分享给你。首先你需要一块ESP32开发板,我用的是ESP32 DevKit,市面上常见的型号基本都能用。屏幕方面,合宙的1.8寸TFT性价比不错,分辨率128x160,SPI接口,带背光控制。
重点来了:必须选择带中文字库的MicroPython固件。普通固件显示中文会很麻烦,需要自己处理字库。我推荐使用kaixindelele维护的固件,这个固件内置了GB2312标准字库,支持12x12和16x16两种常用中文字体。下载地址在GitHub上搜索"ssd1306-MicroPython-ESP32-Chinese"就能找到。
烧录固件推荐使用esptool.py工具,这是最稳定的方法。具体命令如下:
esptool.py --chip esp32 --port COM3 --baud 460800 write_flash -z 0x1000 firmware.bin注意把COM3换成你的实际串口号,firmware.bin换成下载的固件文件名。烧录完成后,建议先用PuTTY或者Thonny连接测试下,确保固件正常运行。
2. 硬件连接与SPI配置
接线是很多新手容易出错的地方,我刚开始就接反过SCK和MOSI,结果屏幕死活不亮。ST7735的SPI接口有6个关键引脚:
- SCK(SCL):时钟信号,接ESP32的GPIO18
- MOSI(SDA):数据输出,接GPIO23
- DC:数据/命令选择,接GPIO21
- CS:片选,接GPIO16
- RST:复位,接GPIO22
- BL:背光控制,可接3.3V或PWM引脚调节亮度
这里有个小技巧:背光引脚如果不接,屏幕也能工作但会非常暗。建议接到3.3V上,或者接一个PWM引脚实现亮度调节。我的实际接线是这样的:
# 接线对应表 接线图 = { "SCK": 18, "MOSI": 23, "DC": 21, "CS": 16, "RST": 22, "BL": "3.3V" # 可选 }SPI配置要注意波特率设置。ST7735最高支持26MHz,但实际使用中20MHz就很稳定了。初始化代码如下:
from machine import Pin, SPI spi = SPI(2, baudrate=20000000, polarity=0, phase=0, sck=Pin(18), mosi=Pin(23))这里SPI(2)表示使用ESP32的HSPI接口,polarity和phase通常设为0就能正常工作。如果屏幕显示花屏,可以尝试调整这两个参数。
3. ST7735驱动实现详解
驱动代码是核心部分,我花了整整两天才调通所有功能。ST7735的驱动主要做三件事:初始化屏幕、实现帧缓冲区、提供绘图API。下面拆解关键部分:
寄存器定义:ST7735有一堆控制命令,比如0x11是唤醒屏幕,0x29是开启显示。这些常量定义在代码开头:
NOP = const(0x00) # 空操作 SWRESET = const(0x01) # 软件复位 SLPIN = const(0x10) # 睡眠模式 SLPOUT = const(0x11) # 退出睡眠 DISPON = const(0x29) # 开启显示初始化流程特别重要,顺序错了屏幕可能不工作。标准流程是:复位→退出睡眠→设置颜色模式→设置内存访问控制→开启显示。我的初始化代码是这样的:
def __init__(self, width, height, spi, dc, rst, cs, rot=0, bgr=0): # 引脚初始化 dc.init(dc.OUT, value=0) cs.init(cs.OUT, value=1) if rst: rst.init(rst.OUT, value=1) # 帧缓冲区 self.buffer = bytearray(height * width * 2) super().__init__(self.buffer, width, height, framebuf.RGB565SW) # 屏幕初始化 self.reset() self._write(SLPOUT) time.sleep_ms(120) self._write(COLMOD, b"\x05") # 16位色 self._write(DISPON)显示方向控制是个实用功能,通过rot参数可以旋转0°、90°、180°、270°。原理是修改MADCTL寄存器的值:
if rot == 0: madctl = 0x00 elif rot == 1: madctl = 0xA0 elif rot == 2: madctl = 0xC0 else: madctl = 0x60 self._write(MADCTL, pack('>B', madctl))4. 中文显示实战技巧
终于到最激动人心的部分了!显示中文需要三个关键步骤:加载字体、设置颜色、调用text方法。我用的固件已经内置了GB2312字库,所以直接加载就行:
lcd.font_load('./GB2312-12.fon') # 12x12字体颜色设置采用RGB565格式,16位色。我整理了几个常用颜色的对应值:
| 颜色 | RGB565值 |
|---|---|
| 红色 | 0xF800 |
| 绿色 | 0x07E0 |
| 蓝色 | 0x001F |
| 黄色 | 0xFFE0 |
| 白色 | 0xFFFF |
显示多行文本的示例代码:
lcd.text("MicroPython学习", 2, 5, 0xF800) # 红色标题 lcd.text("作者: 张三", 16, 25, 0x07E0) # 绿色 lcd.text("日期: 2023", 16, 45, 0x001F) # 蓝色 lcd.show() # 刷新显示常见问题排查:
- 如果中文显示乱码,检查是否加载了正确字库
- 文字位置不对,调整坐标参数
- 屏幕闪烁,尝试降低SPI波特率
- 颜色异常,检查RGB565值是否正确
5. 高级功能与性能优化
基础功能调通后,可以尝试更酷炫的效果。比如多语言混合显示,英文用内置字体,中文用外挂字库:
lcd.text("Hello 世界!", 10, 50, 0xFFFF)滚动显示实现起来也不复杂,原理是定期更新文本位置:
for i in range(160): lcd.fill(0) # 清屏 lcd.text("滚动文本", 10, i, 0x07E0) lcd.show() time.sleep_ms(50)性能优化方面,有几点心得:
- 减少lcd.show()调用次数,批量更新
- 使用fill_rect局部刷新替代全屏刷新
- 复杂界面可以考虑预渲染到缓冲区
- 静态内容可以不用每次循环都重绘
最后分享一个实用技巧:如何保存自定义字体。如果你需要显示特殊字体,可以用PCtoLCD等工具生成字模,然后按照固件要求的格式保存为.fon文件。我通常会把常用字做成一个子集,减少存储空间占用。
