4. 像素格式不匹配:RGB565 vs RGB888 的坑

说实话,像素格式这个问题,我见过太多人栽跟头了。我自己刚用LVGL那会儿,也在这上面折腾了两天。屏幕能亮,能显示,但颜色就是不对——红色变紫色,蓝色变绿色,整个画面像开了个奇怪的滤镜。

为什么会这样?说白了,就是你的屏幕硬件和LVGL配置用的像素格式不一样。一个用RGB565,一个用RGB888,颜色数据对不上,花屏就来了。

4.1 两种格式的本质区别

先搞清楚这两个东西是什么。

  • RGB565:每个像素用16位表示。红色5位,绿色6位,蓝色5位。总共能显示2^16 = 65536种颜色。
  • RGB888:每个像素用24位(或32位)表示。红绿蓝各8位。总共能显示2^24 = 1600多万种颜色。

你想想看,一个像素占2个字节,另一个占3个甚至4个字节。显存里的数据排列方式完全不同。LVGL往显存里写数据时,如果格式没对上,那颜色数据就被解释错了。

特性 RGB565 RGB888
每像素位数 16位 24位(或32位带Alpha)
颜色深度 65536色 1670万色
显存占用 2字节/像素 3或4字节/像素
常见场景 低成本MCU、小屏 高性能MCU、大屏
颜色精度 有损失,尤其蓝色 精度高,色彩平滑

核心要点:LVGL内部默认使用RGB565。如果你用的屏幕驱动芯片支持RGB888,但LVGL配置没改,那就会出问题。反过来也一样。

4.2 配置在哪里?怎么改?

LVGL的像素格式配置,主要在 lv_conf.h 里。我记得第一次找这个配置项,翻了好几遍才找到。

/* Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888) */
#define LV_COLOR_DEPTH 16

这里填16就是RGB565,填32就是ARGB8888。注意,LVGL没有单独的RGB888选项,32位是带Alpha通道的ARGB8888。

还有一个关键配置:

/* Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit port */
#define LV_COLOR_16_SWAP 0

这个 LV_COLOR_16_SWAP 是专门给RGB565用的。如果你的屏幕数据线是8位的,需要高低字节交换,就得把这个打开。我在一个项目里遇到过,屏幕颜色偏蓝偏紫,折腾半天,最后发现是这个没开。

4.3 屏幕驱动芯片的格式设置

光改LVGL还不够。你的屏幕驱动芯片(比如ILI9341、ST7789、NT35510)也有自己的像素格式寄存器。你得通过SPI或并行接口,给芯片发命令,告诉它你准备用什么格式传数据。

以ILI9341为例,它的 0x3A 寄存器控制像素格式:

// 设置像素格式为 RGB565
void lcd_set_pixel_format(void) {
    uint8_t data = 0x55;  // 0x55 = RGB565, 0x66 = RGB666, 0x77 = RGB888
    lcd_write_cmd(0x3A);
    lcd_write_data(data);
}

这里 0x55 对应RGB565,0x77 对应RGB888。你LVGL配了16位,屏幕芯片也得配成16位,两边才能对上。

注意:有些屏幕驱动芯片支持RGB666(18位),但LVGL不支持。如果你遇到这种情况,要么降级到RGB565,要么用RGB888模拟。我个人建议直接上RGB565,省心。

4.4 颜色转换的精度损失

就算格式配对了,从RGB888到RGB565的转换也会有精度损失。LVGL内部做这个转换时,会丢掉低位数据。比如红色从8位变成5位,最低3位就没了。

我做过一个测试:用一张渐变图,在RGB565和RGB888下分别显示。RGB565下,蓝色渐变有明显的色带,一块一块的,不平滑。RGB888就好很多。

如果你对色彩要求高,比如做图像显示或UI特效,建议用RGB888。如果只是普通按钮、文字、图标,RGB565完全够用。

4.5 实战排查步骤

遇到花屏,怎么判断是不是像素格式的问题?我总结了一套排查流程:

  1. 看颜色偏移方向:红色变紫色?蓝色变绿色?大概率是格式不匹配。
  2. 检查 lv_conf.h:确认 LV_COLOR_DEPTH 的值。
  3. 检查屏幕驱动初始化代码:确认像素格式寄存器的值。
  4. 检查 LV_COLOR_16_SWAP:如果颜色整体偏蓝或偏红,试试打开或关闭这个。
  5. 用纯色测试:显示纯红、纯绿、纯蓝,看实际显示的颜色对不对。

小技巧:我习惯在初始化完成后,先显示一个纯红色的矩形。如果红色显示正常,那格式基本没问题。如果红色偏紫,那肯定是格式错了。

4.6 一个典型的错误案例

我曾经帮一个朋友调试过。他的屏幕能亮,但所有颜色都偏蓝。他用的屏幕是ST7789,支持RGB565和RGB666。他LVGL配了16位,但屏幕初始化代码里没设置像素格式寄存器,默认是RGB666。

LVGL往显存里写RGB565数据,屏幕芯片按RGB666去解释,结果就是颜色错位。改了屏幕初始化代码,加上 0x3A = 0x55,问题就解决了。

嗯,这里要注意:有些屏幕驱动芯片的默认像素格式不是RGB565。你拿到一个新屏幕,一定要先看数据手册,确认默认值。

4.7 知识体系图

下面这张图,把像素格式不匹配的整个逻辑串起来了。从LVGL配置到屏幕芯片,再到实际显示,每一步都可能出问题。

像素格式不匹配排查流程图 屏幕花屏 颜色偏移?红色变紫色? 检查 lv_conf.h 配置 LV_COLOR_DEPTH = 16 LV_COLOR_DEPTH = 32 检查屏幕驱动寄存器 检查屏幕驱动寄存器 设置 0x3A = 0x55 设置 0x3A = 0x77 常见症状 颜色整体偏蓝/偏紫 红色显示为紫色 绿色显示为青色

4.8 避坑指南

最后,分享几个我踩过的坑:

  • 不要默认屏幕是RGB565:有些屏幕默认是RGB666或RGB888,一定要看数据手册。
  • 注意字节序:RGB565在内存里是低字节在前还是高字节在前?不同MCU可能不一样。如果颜色整体不对,试试 LV_COLOR_16_SWAP。
  • DMA传输时也要注意:如果用DMA刷屏,数据宽度要跟像素格式匹配。16位像素用16位DMA,32位像素用32位DMA。宽度不对,数据会错位。
  • 双缓冲区的格式要一致:如果你用了双缓冲区,两个缓冲区的像素格式必须一样。我曾经犯过这个错,一个缓冲区是RGB565,另一个是ARGB8888,结果画面闪烁加花屏。

一句话总结:像素格式不匹配,是LVGL花屏最常见的原因之一。排查时先看LVGL配置,再看屏幕驱动寄存器,两边对上了,颜色就对了。