第三章 LCD驱动芯片手册精读:ILI9341/ST7789关键寄存器与初始化序列分析

做LCD驱动,最怕什么?

怕初始化序列写错了,屏幕死活不亮。怕寄存器配错了,颜色显示一团糟。我见过不少工程师,拿着别人的初始化代码直接复制粘贴,出了问题根本不知道从哪查起。

说白了,驱动芯片手册就是你的地图。看不懂地图,你怎么开车?

这一章,我带你把ILI9341和ST7789这两款最常用的LCD驱动芯片手册,从头到尾捋一遍。重点看关键寄存器、初始化序列,以及那些容易踩坑的地方。

3.1 芯片手册到底看什么?

拿到一份几百页的PDF,别从头读到尾。我个人的习惯是,先看这几个部分:

  • 芯片概述:接口类型、支持分辨率、电压范围
  • 命令表:所有可用的指令码,这是核心
  • 寄存器描述:每个寄存器的位定义,尤其是控制位
  • 初始化序列:官方推荐的启动流程
  • 时序图:SPI通信的时序参数

你想想看,如果连芯片支持什么接口都不清楚,上来就写代码,那不是瞎忙活吗?

我的习惯:先把命令表打印出来,贴在工位上。写代码时随时对照,比翻PDF快多了。

3.2 ILI9341 vs ST7789:核心差异对比

这两款芯片我都用过不少项目。ILI9341是经典款,240x320分辨率,市场占有率极高。ST7789是后起之秀,支持135x240、240x240等多种分辨率,在小尺寸圆形表盘上特别流行。

先看一张对比表,心里有个底:

对比项 ILI9341 ST7789
最大分辨率 240x320 240x320(常见240x240)
接口类型 SPI / 8/16位并口 SPI / 并口
GRAM大小 172800字节 172800字节
典型初始化命令数 约20-30条 约15-25条
写像素速度(SPI) 约15-20MHz 约20-30MHz
常见坑点 复位时序、读ID命令 扫描方向、窗口设置

嗯,这里要注意:ST7789的SPI时钟可以跑到更高,但实际速度还受限于你的MCU和PCB走线。我在一个项目中,ST7789用18MHz SPI刷屏,画面稳定,但换到另一块板子上就花屏了——原来是走线太长,信号质量不行。

3.3 关键寄存器深度解析

不管用哪款芯片,有几个寄存器是必须搞懂的。我挑最重要的几个讲。

3.3.1 软件复位 (0x01)

这个命令很简单,就是让芯片复位到默认状态。但有个细节:复位后需要等待至少5ms,才能发其他命令。我曾经因为延时不够,导致后续配置不生效,查了半天才发现是复位没完成。

// 软件复位示例
void LCD_Reset(void) {
    LCD_WriteCmd(0x01);  // 软件复位
    delay_ms(10);        // 等待复位完成,至少5ms
}

3.3.2 睡眠模式控制 (0x10 / 0x11)

0x10是进入睡眠,0x11是退出睡眠。芯片上电后默认是睡眠状态,必须退出睡眠才能正常显示。这个顺序不能乱:先退出睡眠,再初始化其他寄存器。

注意:退出睡眠后,需要等待120ms才能发其他命令。这是很多新手容易忽略的。

3.3.3 像素格式设置 (0x3A)

这个寄存器决定了每个像素用多少位来表示。常见的有:

  • 0x55:16位色(RGB565),每个像素2字节
  • 0x66:18位色(RGB666),每个像素3字节

我一般用16位色,因为SPI传输效率高,而且人眼基本看不出区别。除非你的应用对色彩精度要求极高,否则没必要用18位。

3.3.4 内存访问控制 (0x36)

这个寄存器控制屏幕的扫描方向、RGB/BGR顺序等。它的每一位都有特定含义:

位 名称 说明
7 MY 行地址翻转(上下翻转)
6 MX 列地址翻转(左右翻转)
5 MV 行列交换(旋转90度)
4 ML 垂直刷新方向
3 BGR 颜色顺序:0=RGB,1=BGR

举个例子:如果你想让屏幕横屏显示,通常需要设置MV=1,同时调整MY和MX。我在做手表项目时,就因为这个寄存器没配好,显示的文字全是倒的,折腾了一下午。

3.3.5 列/页地址设置 (0x2A / 0x2B)

这两个命令用来设置显示窗口。0x2A设置列起始和结束地址,0x2B设置行起始和结束地址。只有在这个窗口内的像素才会被更新。

// 设置显示窗口示例
void LCD_SetWindow(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
    LCD_WriteCmd(0x2A);  // 列地址
    LCD_WriteData(x1 >> 8);
    LCD_WriteData(x1 & 0xFF);
    LCD_WriteData(x2 >> 8);
    LCD_WriteData(x2 & 0xFF);
    
    LCD_WriteCmd(0x2B);  // 页地址
    LCD_WriteData(y1 >> 8);
    LCD_WriteData(y1 & 0xFF);
    LCD_WriteData(y2 >> 8);
    LCD_WriteData(y2 & 0xFF);
    
    LCD_WriteCmd(0x2C);  // 开始写内存
}

这个函数是刷屏的核心。你想想看,如果窗口设置错了,画面就会偏移或者只显示一部分。

3.4 初始化序列分析

官方手册里通常会给出一个初始化序列。但说实话,那个序列不一定适合你的具体应用。我一般会做两件事:

  1. 精简序列:去掉不必要的命令,只保留必须的
  2. 调整参数:根据屏幕尺寸和方向,修改窗口和扫描方向

下面是一个典型的ILI9341初始化序列,我加了注释:

void ILI9341_Init(void) {
    // 1. 硬件复位
    LCD_RST_LOW();
    delay_ms(10);
    LCD_RST_HIGH();
    delay_ms(120);
    
    // 2. 退出睡眠模式
    LCD_WriteCmd(0x11);
    delay_ms(120);
    
    // 3. 像素格式:16位色
    LCD_WriteCmd(0x3A);
    LCD_WriteData(0x55);
    
    // 4. 内存访问控制:RGB顺序,正常扫描
    LCD_WriteCmd(0x36);
    LCD_WriteData(0x48);  // 0100 1000
    
    // 5. 帧率控制
    LCD_WriteCmd(0xB1);
    LCD_WriteData(0x00);
    LCD_WriteData(0x18);
    
    // 6. 显示开
    LCD_WriteCmd(0x29);
    delay_ms(10);
}

你看,这个序列只有6步,但已经能正常显示了。为什么?因为其他寄存器用默认值就够了。我见过有人把手册里30多步的初始化序列全抄下来,结果屏幕反而显示异常——因为有些命令的默认值就是最优的,你改了反而坏事。

核心原则:初始化序列不是越长越好。只配置那些必须改的寄存器,其他的保持默认。

3.5 知识结构图:初始化流程

下面这张图,把整个初始化流程串起来了。你可以对照着看,每一步都做了什么。

LCD初始化核心流程 1. 上电 2. 硬件复位 3. 退出睡眠 (0x11) 4. 配置寄存器 5. 显示开 (0x29) 关键延时要求 • 硬件复位:≥10ms • 退出睡眠:≥120ms • 显示开:≥10ms • 软件复位:≥5ms • 命令间隔:≥100μs 常见问题 • 复位后直接发命令 → 失败 • 未退出睡眠 → 黑屏 • 窗口设置错误 → 偏移

3.6 避坑指南:我踩过的那些坑

做LCD驱动,有些坑是绕不过去的。我分享几个亲身经历,希望能帮你少走弯路。

坑一:复位时序不对
我曾经在一个项目中,硬件复位只拉了1ms就结束了。结果屏幕偶尔能亮,偶尔不亮。用示波器一看,复位信号毛刺严重。后来改成10ms,问题解决。
教训:复位时间宁长勿短,10ms是安全值。
坑二:读ID命令不响应
有一次我想通过读ID来验证SPI通信是否正常,结果读回来的全是0xFF。查了半天,发现是MISO引脚没接上拉电阻。加上10kΩ上拉后,ID读取正常。
教训:SPI的MISO线在空闲时应该是高阻态,需要外部上拉。
坑三:颜色顺序搞反
显示红色,结果出来的是蓝色。这个问题在ILI9341上特别常见,因为它的默认颜色顺序是RGB,但很多模块厂商改成了BGR。你需要在0x36寄存器里设置BGR位。
教训:拿到新模块,先显示纯色,确认颜色顺序对不对。

3.7 小结

这一章的内容,说白了就是三件事:

  • 看懂手册:知道哪些寄存器是关键,哪些可以忽略
  • 写对序列:初始化步骤不能少,延时不能短
  • 避开坑点:复位、读ID、颜色顺序,这三个地方最容易出问题