4. 初始化序列编写:从数据手册提取初始化命令、SPI/8080时序实现、初始化代码实战
说实话,LCD驱动这块,很多人一上来就怼着刷屏代码调,结果画面花屏、闪烁、颜色不对,折腾半天发现是初始化没写好。我早期做项目时就吃过这个亏——一块ST7789的屏,怎么调都偏色,最后拿示波器一抓,发现初始化序列里少发了一条命令。
初始化序列,说白了就是告诉LCD芯片:「我要开始用你了,请按我的规矩来」。这一步做扎实了,后面刷屏才稳。今天咱们就手把手把这事捋清楚。
4.1 数据手册里的初始化命令怎么找?
拿到一块新屏,第一件事不是写代码,是翻数据手册。我习惯先看这几个地方:
- Command Table:命令列表,一般在手册后半部分
- Initial Sequence:有些厂商会直接给一段推荐的初始化流程
- Power On Sequence:上电时序,这个漏了屏直接不亮
以常见的ILI9341为例,它的初始化命令大概长这样:
| 命令 | 参数 | 说明 |
|---|---|---|
| 0x01 | 无 | 软件复位 |
| 0x11 | 无 | 退出睡眠模式 |
| 0x36 | 1字节 | 存储访问控制(决定扫描方向) |
| 0x3A | 1字节 | 像素格式(16位/18位) |
| 0x29 | 无 | 打开显示 |
我的小技巧: 把数据手册里的命令表截图存下来,写代码时对照着看,比来回翻PDF快得多。我一般还会在命令旁边手写备注,比如「这条不加会花屏」之类的。
4.2 SPI与8080时序,到底选哪个?
这个问题我经常被问到。其实选择很简单:
- SPI:引脚少(4线或3线),适合引脚紧张的MCU,但速度上限低
- 8080并口:引脚多(至少8条数据线+控制线),但速度快,适合大屏高刷
我个人的经验是:320×240以下的小屏,SPI完全够用;再往上,尤其要跑动画或视频的,老老实实上8080。
来看SPI的时序实现。以写命令为例:
// SPI写命令(DC=0表示命令,DC=1表示数据)
void LCD_WriteCmd(uint8_t cmd) {
DC_LOW(); // 命令模式
CS_LOW(); // 片选使能
SPI_TransferByte(cmd);
CS_HIGH(); // 片选释放
}
8080并口稍微复杂一点,但核心逻辑一样:
// 8080写命令
void LCD_WriteCmd(uint8_t cmd) {
DC_LOW(); // 命令
RD_HIGH(); // 读禁止
WR_LOW(); // 写使能
DATA_PORT = cmd; // 数据总线
WR_HIGH(); // 锁存数据
}
注意: 8080时序里,WR的上升沿才是数据锁存时刻。我曾经因为WR拉高太快,数据还没稳定就锁存了,结果屏上全是乱码。后来在WR上升沿前加了100ns的延时才解决。
4.3 初始化代码实战:一步一步来
好,理论说完了,咱们直接上代码。下面是一份完整的ILI9341初始化序列,我把它拆成了几个步骤:
- 硬件复位:拉低RST引脚至少10ms
- 软件复位:发0x01命令
- 退出睡眠:发0x11,然后等120ms
- 配置参数:发0x36、0x3A等
- 打开显示:发0x29
void LCD_Init(void) {
// 1. 硬件复位
RST_LOW();
delay_ms(10);
RST_HIGH();
delay_ms(120); // 等内部晶振稳定
// 2. 软件复位
LCD_WriteCmd(0x01);
delay_ms(120);
// 3. 退出睡眠模式
LCD_WriteCmd(0x11);
delay_ms(120);
// 4. 设置像素格式为16位
LCD_WriteCmd(0x3A);
LCD_WriteData(0x55); // 0x55 = 16位色
// 5. 设置扫描方向(根据你的屏安装方向调整)
LCD_WriteCmd(0x36);
LCD_WriteData(0x48); // 竖屏模式
// 6. 打开显示
LCD_WriteCmd(0x29);
// 7. 清屏
LCD_Fill(0x0000); // 黑色
}
关键点: 每条命令之间的延时不是随便写的。数据手册里会写「Exit Sleep」后需要等120ms,这个时间不能省。我见过有人为了省这120ms把延时改成10ms,结果屏一直闪。
4.4 初始化流程的SVG结构图
下面这张图把整个初始化流程串起来了,方便你对照着写代码:
4.5 避坑指南:我踩过的几个坑
写初始化代码这么多年,有些坑我至今记忆犹新:
- 坑一:复位后不等够时间——屏内部晶振还没稳定,发命令它不理你
- 坑二:命令和数据搞混——DC引脚电平反了,屏把数据当命令解析,画面直接崩
- 坑三:参数写错位——比如0x3A的参数应该是0x55,写成0x5A,颜色就全乱了
- 坑四:初始化顺序不对——有些屏必须先配参数再开显示,顺序反了直接黑屏
我的调试习惯: 每次发完一条命令,用示波器抓一下DC和SCLK的波形,确认时序对不对。尤其是刚开始调新屏的时候,这一步能省下大半天排查时间。
嗯,初始化这块其实不难,但细节特别多。你只要把数据手册啃透,时序写对,代码一步步来,基本不会出大问题。下次咱们聊聊刷新率优化,那个才是真正考验功夫的地方。