3、显示驱动原理:TFT-LCD与OLED工作原理、像素与分辨率概念、RGB与灰度颜色模型、帧缓冲(FrameBuffer)机制

好,咱们这一章来聊聊显示驱动里最核心的几个概念。说实话,很多做单片机开发的朋友,一开始接触屏幕驱动时,最头疼的就是搞不清这些底层原理。你调通了SPI或者8080时序,能点亮屏幕了,但为什么有些颜色显示不对?为什么刷新率上不去?为什么OLED和TFT-LCD的驱动方式不一样?

这些问题,其实都藏在这一章的内容里。我个人习惯是,不管用什么屏,先把它的工作原理吃透,后面写驱动才心里有底。

3.1 TFT-LCD与OLED:两种主流屏幕的工作原理

先说说TFT-LCD。这玩意儿我们太熟了,手机、显示器、开发板上的小屏幕,到处都是。TFT-LCD的全称是薄膜晶体管液晶显示器。名字很长,但核心就两样东西:液晶和背光。

液晶本身不发光。它像一扇扇小百叶窗,通过电压控制扭转角度,让背光模组的光线透过来。TFT(薄膜晶体管)就是控制每个小百叶窗的开关。每个像素背后都有一个TFT,所以叫有源矩阵。我最早用51单片机驱动一个12864的LCD时,那还是无源的,刷新慢得要命。后来换成TFT屏,感觉就像从拨号上网换成了光纤。

OLED就不一样了。它是有机发光二极管,每个像素自己就能发光。不需要背光模组。所以OLED屏幕可以做得非常薄,而且黑色是真的黑——因为不发光嘛。我在项目中用过一次0.96寸的OLED,128x64分辨率,驱动起来比TFT-LCD简单不少,因为不需要处理背光控制。

核心区别一句话总结:

  • TFT-LCD:背光 + 液晶光阀。需要背光一直亮着,黑色其实也是漏光的。
  • OLED:自发光。黑色像素直接关掉,对比度极高,但长时间显示静态画面容易烧屏。

嗯,这里要注意。OLED虽然显示效果好,但寿命和亮度衰减问题在工业产品里是个大坑。我曾经在一个手持设备上用过OLED,客户反馈用了半年屏幕变暗了。后来查资料才发现,OLED的蓝色像素衰减最快。所以如果你做的是需要长期显示固定界面的产品,比如仪器仪表,我个人建议还是优先考虑TFT-LCD。

3.2 像素与分辨率:屏幕的“细胞”与“网格”

像素,就是屏幕上最小的显示单元。每个像素能独立控制颜色。分辨率,就是横向和纵向有多少个像素。比如320x240,就是横向320个像素,纵向240个像素。

你想想看,驱动一个屏幕,本质上就是告诉每个像素该显示什么颜色。分辨率越高,需要控制的像素就越多,数据量就越大。我在用STM32驱动一个480x272的屏幕时,光刷一帧全屏数据就要将近500KB(按16位色深算)。这对于单片机来说,压力不小。

分辨率 像素总数 16位色深一帧数据量 典型应用
128x64 8192 16KB 小OLED、字符屏
320x240 76800 150KB 常见TFT彩屏
480x272 130560 255KB 工控屏、MP4
800x480 384000 750KB 智能家居面板

这里有个容易忽略的点:分辨率不等于物理尺寸。同样320x240的分辨率,2.4寸屏和3.5寸屏的像素密度(PPI)完全不同。PPI越高,显示越细腻。但驱动代码是一样的,因为像素数量没变。

3.3 RGB与灰度颜色模型:颜色是怎么来的

说到颜色,就绕不开RGB模型。说白了,就是用红、绿、蓝三种基色,按不同比例混合出所有颜色。每个颜色分量用多少位来表示,决定了色深。

  • 1位:每个颜色分量要么0要么1,总共8种颜色。早期单色屏常用。
  • 16位:RGB565格式,R用5位,G用6位,B用5位。总共65536种颜色。这是单片机驱动彩屏最常用的格式。为什么G多一位?因为人眼对绿色最敏感。
  • 18位:RGB666,每个分量6位。总共26万色。有些TFT屏支持。
  • 24位:RGB888,每个分量8位。总共1677万色。真彩色,但数据量大,单片机很少用。

避坑指南:

我曾经在项目里犯过一个低级错误。屏幕驱动IC支持RGB565格式,但我用上位机生成的图片是RGB888的。直接丢给屏幕显示,颜色全乱了。后来才意识到,需要把24位颜色转换成16位。转换公式很简单:

// RGB888 转 RGB565
uint16_t rgb565 = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);

记住,高位对齐,低位舍弃。

灰度模型呢?其实就是单色显示。每个像素只有一个亮度值,从0(黑)到255(白)。在单片机里,灰度显示通常通过PWM或者抖动算法来实现。比如一个1位的单色屏,想显示灰度,就得靠帧率控制或者空间抖动。我在做墨水屏驱动时,对灰度处理就特别头疼,因为刷新一次要好几秒,没法用PWM。

3.4 帧缓冲(FrameBuffer)机制:显示驱动的“画板”

帧缓冲,说白了就是在内存里开辟一块区域,专门用来存放一帧画面的像素数据。CPU往这块区域里写数据,然后显示控制器(或者DMA)定期把这块区域的数据刷到屏幕上。

为什么需要帧缓冲?因为屏幕刷新是持续的,每秒60帧甚至更高。如果CPU每画一个像素都要直接操作屏幕,那CPU就被占死了,啥也干不了。有了帧缓冲,CPU只管往内存里写数据,显示刷新由硬件自动完成。

帧缓冲的工作流程:

  1. 在内存中分配一块连续空间,大小 = 分辨率 × 每个像素字节数。
  2. CPU或GPU将绘制内容写入帧缓冲。
  3. 显示控制器(如LTDC、DSI、SPI DMA)从帧缓冲读取数据。
  4. 数据通过接口(RGB、SPI、8080等)发送到屏幕。
  5. 屏幕逐行扫描显示。

在LVGL里,帧缓冲是核心机制。LVGL的绘制引擎会把所有控件、文字、图形渲染到帧缓冲里,然后一次性刷新到屏幕。LVGL支持单缓冲、双缓冲甚至三缓冲。

注意:

单片机的RAM通常很有限。一个480x272的屏幕,用RGB565格式,帧缓冲需要255KB。很多STM32的RAM才128KB或256KB,根本放不下。这时候怎么办?

  • 部分刷新:只刷新变化区域,不刷全屏。
  • 外部SRAM或SDRAM:把帧缓冲放在外部内存。
  • 单缓冲+行缓冲:LVGL支持只分配一小块行缓冲,逐行绘制。

我记得有一次,客户要求用STM32F103驱动一个320x240的TFT屏,还要跑LVGL。F103的RAM只有64KB,全屏帧缓冲就要150KB,根本不够。最后我用了LVGL的“单缓冲+部分刷新”模式,帧缓冲只分配了20KB,虽然刷新率降到了20帧左右,但UI交互完全够用。这就是灵活运用帧缓冲机制的好处。

最后总结一下。显示驱动原理,说白了就是三件事:理解屏幕怎么发光(TFT vs OLED)、知道每个像素怎么表示(RGB/灰度)、学会用内存管理画面(帧缓冲)。这三件事搞明白了,后面不管是调SPI驱动、配置LTDC控制器,还是优化LVGL刷新性能,你都会觉得顺理成章。

下一章,咱们就进入实战,聊聊怎么用STM32的LTDC外设直接驱动RGB接口的屏幕。那又是另一番天地了。