4. 基本像素写入:写像素命令、行列地址设置、写GRAM、单像素刷新实现
在驱动 ST7789 显示器的过程中,最基础也是最核心的操作就是向指定坐标写入一个像素的颜色值。本章将深入剖析单像素刷新的完整链路,从命令协议到寄存器操作,再到代码实现,帮助您建立对像素级控制的精确理解。
4.1 像素写入的完整流程
向 ST7789 写入一个像素,并非直接发送颜色数据那么简单。控制器内部维护了一个自增的“写指针”,指向当前要写入的 GRAM 地址。因此,写入像素前必须完成以下三个步骤:
- 设置行列地址范围:通过命令
CASET(2Ah) 和RASET(2Bh) 定义目标像素的矩形区域。 - 启动写 GRAM 命令:发送
RAMWR(2Ch) 命令,通知控制器后续数据将写入 GRAM。 - 传输像素颜色数据:按照 RGB565 格式,连续发送 2 字节(或 3 字节,取决于接口模式)的颜色数据。
关键概念: ST7789 的 GRAM 写指针在每次写入后自动递增。即使只写一个像素,也必须先通过 CASET/RASET 将地址范围限定为单个点,否则写指针会继续向后填充,导致非预期区域的像素被修改。
4.2 核心命令详解
下表列出了单像素写入所涉及的三个核心命令及其参数格式:
| 命令名称 | 命令码 | 参数长度 | 参数说明 |
|---|---|---|---|
| CASET (Column Address Set) | 0x2A |
4 字节 | 起始列 (SC) [15:0],结束列 (EC) [15:0] |
| RASET (Row Address Set) | 0x2B |
4 字节 | 起始行 (SR) [15:0],结束行 (ER) [15:0] |
| RAMWR (Memory Write) | 0x2C |
N 字节 | RGB565 颜色数据,每个像素 2 字节 |
4.3 行列地址设置策略
对于单像素写入,行列地址范围必须设置为一个 1x1 的窗口。假设目标坐标为 (x, y),分辨率为 240x240:
- CASET 参数:起始列 = x,结束列 = x
- RASET 参数:起始行 = y,结束行 = y
这种设置方式将 GRAM 写指针锁定在唯一的地址上,确保后续写入的颜色数据只影响该像素。
常见错误: 许多初学者在连续写入多个像素时,忘记重新设置 CASET/RASET,导致写指针溢出到下一行或超出显示区域。务必在每次像素写入前重新定义窗口范围。
4.4 单像素刷新实现代码
以下代码展示了在 4-wire SPI 接口下,使用 MicroPython 实现单像素写入的完整函数。代码中包含了必要的延时和命令序列:
import machine
import time
# 假设已初始化 SPI、DC、CS、RST 引脚
# spi: machine.SPI 对象
# dc: 数据/命令控制引脚
# cs: 片选引脚
def write_cmd(cmd):
"""发送命令字节"""
cs.value(0)
dc.value(0) # 命令模式
spi.write(bytes([cmd]))
cs.value(1)
def write_data(data):
"""发送数据字节"""
cs.value(0)
dc.value(1) # 数据模式
spi.write(bytes([data]))
cs.value(1)
def set_window(x, y):
"""设置单像素窗口"""
# CASET: 列地址范围
write_cmd(0x2A)
write_data(x >> 8) # 起始列高字节
write_data(x & 0xFF) # 起始列低字节
write_data(x >> 8) # 结束列高字节
write_data(x & 0xFF) # 结束列低字节
# RASET: 行地址范围
write_cmd(0x2B)
write_data(y >> 8) # 起始行高字节
write_data(y & 0xFF) # 起始行低字节
write_data(y >> 8) # 结束行高字节
write_data(y & 0xFF) # 结束行低字节
def draw_pixel(x, y, color):
"""在 (x, y) 处绘制一个 RGB565 颜色像素"""
# 1. 设置窗口
set_window(x, y)
# 2. 启动 RAMWR 命令
write_cmd(0x2C)
# 3. 发送颜色数据 (RGB565)
# color 为 16 位整数,例如 0xF800 表示红色
write_data((color >> 8) & 0xFF) # 高字节
write_data(color & 0xFF) # 低字节
# 使用示例:在 (100, 100) 处画一个红色像素
draw_pixel(100, 100, 0xF800)
4.5 像素写入流程可视化
下图展示了从设置地址到数据写入的完整时序与数据流关系:
4.6 性能考量与优化方向
单像素写入虽然简单,但效率极低。每次调用 draw_pixel() 都需要发送 3 条命令和至少 6 字节参数,再加上 2 字节颜色数据。对于 240x240 的屏幕,全屏刷新需要 240×240 = 57,600 次像素写入,总数据传输量巨大。
- 瓶颈分析:命令开销远大于数据开销。每次像素写入的协议开销(命令+参数)约 8 字节,而有效颜色数据仅 2 字节,效率仅为 20%。
- 优化思路:通过设置大窗口(如整行或整块区域),利用 GRAM 写指针自动递增特性,批量发送颜色数据,大幅降低命令发送次数。