2. 像素与颜色格式:RGB565颜色编码、像素排列、显存映射、16位色深详解

在驱动ST7789这类TFT-LCD时,理解像素的颜色编码方式与显存映射关系是进行高效刷新的基础。本章将深入剖析RGB565颜色格式、像素在显存中的排列规律以及16位色深的实际含义,为后续双缓冲与DMA优化打下坚实的理论基础。

2.1 16位色深与RGB565编码

ST7789支持16位色深(即每像素占用2字节),采用RGB565格式。这种格式在色彩表现力与存储/传输带宽之间取得了良好平衡,是嵌入式小尺寸LCD最主流的颜色编码方案。

颜色分量 位宽 取值范围 权重
红色 (R) 5 bit 0 ~ 31 高位
绿色 (G) 6 bit 0 ~ 63 中间位
蓝色 (B) 5 bit 0 ~ 31 低位

RGB565 数据排列(大端模式,MCU常用):

字节0 (高字节)         字节1 (低字节)
┌───┬───┬───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┬───┬───┐
│ R4│ R3│ R2│ R1│ R0│ G5│ G4│ G3│ │ G2│ G1│ G0│ B4│ B3│ B2│ B1│ B0│
└───┴───┴───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┴───┴───┘

颜色转换示例:将24位RGB(128, 64, 32)转换为RGB565

R = 128 >> 3 = 16 (0b10000)
G = 64  >> 2 = 16 (0b100000)
B = 32  >> 3 = 4  (0b00100)

RGB565 = (R << 11) | (G << 5) | B
       = (16 << 11) | (16 << 5) | 4
       = 0x8414
实战提示:在C语言中,常用宏定义进行RGB888到RGB565的快速转换:
#define RGB565(r, g, b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3))

2.2 像素排列与显存映射

ST7789的显存(GRAM)以行优先方式组织。每个像素对应一个16位RGB565值,显存地址按从左到右、从上到下的顺序递增。

显存映射公式:
对于坐标 (x, y),显存地址偏移 = (y × 宽度 + x) × 2 字节

关键参数(以240×240分辨率为例):

  • 总像素数:240 × 240 = 57,600 像素
  • 显存总大小:57,600 × 2 = 115,200 字节 ≈ 112.5 KB
  • 每行字节数:240 × 2 = 480 字节
ST7789显存映射与像素排列结构 ST7789 显存映射与像素排列结构 GRAM 地址空间 (115,200 字节) 行 0: 像素(0,0) | 像素(1,0) | 像素(2,0) | ... | 像素(239,0) 行 1: 像素(0,1) | 像素(1,1) | 像素(2,1) | ... | 像素(239,1) ... 中间行省略 ... 行 239: 像素(0,239) | 像素(1,239) | 像素(2,239) | ... | 像素(239,239) 地址偏移 = (y × 240 + x) × 2 字节 例: 像素(10,5) 偏移 = (5×240+10)×2 = 2420 字节 像素 (x, y) 存储格式 高字节: R[4:0] | G[5:3] 低字节: G[2:0] | B[4:0]

2.3 像素数据在SPI总线上的传输顺序

ST7789通过SPI接口接收像素数据时,遵循先高字节后低字节的传输顺序。当使用9位SPI模式(8位数据+1位DCX)时,每个像素需要2次传输。

传输序号 DCX电平 数据内容 说明
第1次 高 (数据) RGB565 高字节 R[4:0] + G[5:3]
第2次 高 (数据) RGB565 低字节 G[2:0] + B[4:0]
常见错误:字节序混淆是导致颜色显示异常的首要原因。如果屏幕出现颜色通道错位(如红色变蓝色),请检查MCU端发送数据时是否使用了小端模式,以及SPI的MSB/LSB优先设置是否与ST7789匹配。

2.4 颜色深度对比:16位 vs 18位 vs 24位

虽然ST7789硬件支持18位色深(通过3字节/像素的RGB666格式),但在实际嵌入式应用中,16位RGB565是性能和画质的最佳平衡点。

色深 每像素字节数 总颜色数 240×240显存占用 适用场景
16位 (RGB565) 2 65,536 112.5 KB 通用GUI、图标、文字
18位 (RGB666) 3 262,144 168.75 KB 照片、渐变、图像显示
24位 (RGB888) 3(需转换) 16,777,216 168.75 KB(模拟) 上位机预处理后下传
性能调优要点:在双缓冲方案中,使用RGB565格式可使帧缓冲区大小减半,从而:
  • 减少SRAM占用,为其他任务留出空间
  • 降低DMA传输量,提升刷新帧率
  • 加快像素填充与拷贝操作(16位对齐访问)

2.5 像素坐标与窗口设置

ST7789通过CASET(列地址设置)和RASET(行地址设置)命令定义像素写入窗口。理解窗口与显存映射的关系,是实现局部刷新和区域裁剪的前提。

窗口设置与显存区域映射 窗口设置与显存区域映射 全屏区域 (0,0) ~ (239,239) CASET = 0, 239 RASET = 0, 239 窗口区域 (50,50) ~ (189,169) CASET = 50, 189 RASET = 50, 169 显存地址空间 窗口对应显存块 起始地址偏移 = (50×240+50)×2 结束地址偏移 = (169×240+189)×2 总像素数 = 140 × 120 = 16,800

2.6 颜色格式转换实战

在实际项目中,经常需要将图像数据从RGB888转换为RGB565。以下是一个高效的C语言转换函数示例:

/**
 * @brief 将RGB888像素转换为RGB565格式
 * @param r 红色分量 (0-255)
 * @param g 绿色分量 (0-255)
 * @param b 蓝色分量 (0-255)
 * @return 16位RGB565颜色值
 */
uint16_t rgb888_to_rgb565(uint8_t r, uint8_t g, uint8_t b) {
    return ((r >> 3) << 11) |   // R: 5位
           ((g >> 2) << 5)  |   // G: 6位
           (b >> 3);             // B: 5位
}

/**
 * @brief 批量转换RGB888缓冲区到RGB565
 * @param src RGB888源数据 (每像素3字节)
 * @param dst RGB565目标数据 (每像素2字节)
 * @param pixel_count 像素数量
 */
void rgb888_batch_to_rgb565(const uint8_t *src, uint16_t *dst, uint32_t pixel_count) {
    for (uint32_t i = 0; i < pixel_count; i++) {
        uint8_t r = src[i * 3 + 0];
        uint8_t g = src[i * 3 + 1];
        uint8_t b = src[i * 3 + 2];
        dst[i] = rgb888_to_rgb565(r, g, b);
    }
}
优化建议:在批量转换时,可以使用查表法(LUT)将8位R/B分量预计算为5位值,将8位G分量预计算为6位值,从而将每次转换从移位+或运算简化为三次查表+一次或运算,在无硬件乘法器的MCU上可提升30%以上性能。

2.7 本章小结

  • RGB565是ST7789最常用的颜色格式,5-6-5位分配兼顾色彩与效率。
  • 显存采用行优先线性映射,地址偏移 = (y × 宽度 + x) × 2。
  • SPI传输时先高字节后低字节,字节序错误会导致颜色通道错乱。
  • 16位色深相比18/24位在存储占用和传输带宽上优势明显,是双缓冲方案的首选。
  • 窗口设置(CASET/RASET)与显存映射配合,可实现高效的局部刷新。