3、LCD驱动芯片:驱动芯片的作用、常见驱动IC(ILI9341/ST7789/SSD1306)、驱动芯片内部架构
好,咱们进入第三讲。前面聊了LCD的物理原理和接口,说白了,那些都是“怎么把信号送进去”。但真正干活的是谁?是驱动芯片。
驱动芯片,你可以把它想象成LCD屏幕的“翻译官”和“管家”。MCU(主控芯片)说“我要在坐标(100,50)显示一个红色像素”,但MCU的IO口不可能直接去控制每个液晶分子的偏转角度。这时候驱动芯片就登场了——它接收MCU发来的指令和数据,然后转换成液晶面板需要的扫描信号、灰度电压、时序控制信号。
我个人习惯把驱动芯片比作“画师”。MCU告诉它“画一朵红花”,它就知道怎么调色、怎么下笔、怎么一笔一笔把整幅画填满。没有它,MCU得自己一根一根线去点,那效率低得可怕。
驱动芯片到底干了哪些活?
说白了,驱动芯片的核心任务就三件:
- 接收并解析指令:MCU通过SPI、I2C或并行接口发过来的数据,驱动芯片得读懂。是写寄存器?还是刷显存?还是设置窗口?
- 管理显存(GRAM):驱动芯片内部有一块SRAM,叫图形显存(Graphic RAM)。你发给它的像素数据,它先存到GRAM里。然后它自己定时从GRAM里读数据,刷新到屏幕上。这就像你写作业,先写在草稿纸上,再誊到正式本子上。
- 生成驱动波形:这是最硬核的部分。驱动芯片要根据GRAM里的数据,生成COM(公共电极)和SEG(段电极)的扫描时序,还要产生VCOM(公共电压)、灰度伽马电压等。这些电压和时序稍有偏差,屏幕就会出现闪烁、偏色、残影。
避坑指南:我曾经在一个项目里,屏幕初始化后一直闪烁。查了三天,最后发现是驱动芯片的VCOM电压设置不对。那个寄存器默认值是0x20,但我的屏幕模组需要0x28。就差了这么一点,整个画面都在抖。所以,拿到一个新屏幕,第一件事就是仔细看数据手册里的初始化序列和电压配置。
常见驱动IC:ILI9341、ST7789、SSD1306
市面上驱动芯片很多,但有三款你一定会遇到。我按使用场景给你捋一捋。
| 驱动IC | 类型 | 分辨率 | 接口 | 典型应用 |
|---|---|---|---|---|
| ILI9341 | TFT-LCD(彩色) | 240×320(QVGA) | SPI / 8/16位并行 | 2.8寸~3.5寸彩屏,Arduino屏、STM32开发板屏 |
| ST7789 | TFT-LCD(彩色) | 240×240 / 240×320 | SPI / QSPI | 1.3寸~1.8寸小圆屏、手表屏、低成本彩屏 |
| SSD1306 | OLED(单色/双色) | 128×64 / 128×32 | I2C / SPI | 0.96寸OLED、小尺寸字符/图形显示 |
ILI9341:彩屏界的“老大哥”
这芯片我用了好多年。它支持262K色(RGB 6-6-6),内部有172800字节的GRAM(240×320×18bit)。为什么是18bit?因为每个像素用6位红、6位绿、6位蓝表示。你想想看,这精度已经能显示很细腻的照片了。
它最常用的接口是16位并行,一次传2个字节,刷屏速度很快。但如果你用SPI,虽然引脚少,刷屏速度会慢不少。我在一个项目里为了省引脚,用了SPI模式,结果刷一帧要50ms,肉眼可见的刷新。后来改回并行接口,刷一帧只要8ms,流畅多了。
ST7789:小尺寸彩屏的“新宠”
ST7789是近几年很火的驱动IC。它和ILI9341类似,但更省电、更便宜,而且支持240×240这种正方形分辨率,很适合做圆形表盘(配合圆形屏幕切割)。
它有个特点:内部GRAM是240×320的,但你可以通过设置窗口只显示一部分。比如你用一个1.3寸圆屏,实际显示区域只有240×240,剩下的区域就“黑着”。
嗯,这里要注意:ST7789的初始化序列和ILI9341完全不同。我见过有人直接把ILI9341的代码搬过来用,结果屏幕一片白。千万别偷懒,一定要看数据手册里的初始化命令表。
SSD1306:OLED界的“常青树”
SSD1306是单色OLED驱动芯片。它内部有128×64个像素点,每个像素只有亮或不亮(1bit)。所以它的GRAM只有128×64/8 = 1024字节。很小,对吧?
它支持页寻址模式,说白了就是把屏幕分成8页,每页8个像素高。你写数据时,先选页,再选列,然后连续写8个像素。我刚开始用的时候,总觉得这个寻址方式很别扭,后来习惯了反而觉得挺高效——因为刷字符时,一个字符正好占一页的宽度。
个人经验:如果你做低功耗项目,SSD1306是首选。它休眠电流只有几微安。我曾经在一个电池供电的温湿度计里用SSD1306,一节CR2032电池用了半年。但要注意,OLED屏幕长时间显示静态画面会烧屏,所以记得加屏幕保护逻辑。
驱动芯片内部架构长什么样?
咱们以ILI9341为例,看看它内部到底是怎么组织的。我画了一张简化的架构图,你一看就明白。
你看这张图,数据从左边进来,经过接口模块,被解析成命令或数据。命令会配置控制寄存器,数据则写入GRAM。然后显示控制模块定时从GRAM里读数据,结合伽马校正生成的灰度电压,通过行/列驱动输出到屏幕。
这里有个关键点:GRAM是双缓冲的吗? 大部分LCD驱动芯片不是。你写GRAM的同时,显示控制也在读GRAM。如果你在刷屏过程中修改了GRAM,可能会出现“撕裂”现象——屏幕上半部分是旧画面,下半部分是新画面。解决办法是:要么等垂直消隐期再写,要么用双缓冲(但驱动芯片内部一般没有,需要MCU自己做)。
我曾经踩过的坑:在一个需要快速刷新的项目中,我直接往GRAM里写数据,结果画面撕裂严重。后来我加了一个“帧同步”逻辑:先读取驱动芯片的状态寄存器,等它显示完当前帧,再开始写下一帧。虽然牺牲了一点刷新率,但画面完美了。
驱动芯片的“隐藏技能”
除了基本的显示功能,这些驱动芯片还有一些你可能不知道的功能:
- 窗口裁剪:你可以设置一个矩形区域,后续的写GRAM操作只影响这个区域。这在局部刷新时非常有用,不用全屏重绘。
- 滚动显示:驱动芯片内部支持硬件滚动,你只需要设置起始地址和滚动方向,它自己会滚动显示。MCU不用干预,省CPU资源。
- 休眠模式:大部分驱动芯片有休眠指令,进入后功耗极低。唤醒时只需要重新初始化即可。
- 伽马曲线调整:你可以通过寄存器调整伽马曲线,说白了就是调整屏幕的对比度和色彩饱和度。不同批次的屏幕,伽马曲线可能略有差异,需要微调。
嗯,说到伽马曲线,我再啰嗦一句。LCD的亮度响应不是线性的,人眼对暗部更敏感。所以驱动芯片内部有伽马校正电路,把数字信号映射成非线性的电压。如果你发现屏幕颜色发白或者暗部细节丢失,多半是伽马曲线没调好。
好了,这一讲就到这里。驱动芯片是LCD系统的核心,理解了它的内部架构,你就能更好地理解为什么初始化序列要那样写,为什么刷屏速度有上限,为什么会出现撕裂。下一讲咱们会深入代码层面,看看怎么用MCU去控制这些驱动芯片。