显示基础与接口
无论驱动哪种类型的屏幕,像素、色深、帧缓冲、显示方向与坐标系这些基础概念都是通用的;而屏幕与主控之间的数据通路(即显示接口)则直接决定了刷新带宽和引脚开销。本章介绍这两部分内容,作为后续各屏幕章节的基础。以下按 ESP32 生态中的常见方案讲解。
1. 显示的公共概念
1.1 像素与分辨率
屏幕上的画面由一个个像素(Pixel)组成。分辨率描述屏幕横向和纵向各有多少个像素,例如 240×320 表示横向 240 个、纵向 320 个像素。驱动屏幕的本质,是为每个像素指定要显示的颜色。
1.2 色深
色深(Color Depth)指每个像素用多少位(bit)来描述颜色,直接决定了一个像素占用的数据量:
| 色深 | 每像素数据量 | 可表示颜色 | 典型场景 |
|---|---|---|---|
| 1bpp(单色) | 1 bit | 黑 / 白 | 单色 OLED、RLCD、黑白墨水屏 |
| RGB565 | 16 bit(2 字节) | 65536 色 | 嵌入式彩屏的主流格式 |
| RGB888 | 24 bit(3 字节) | 约 1677 万色 | 高色彩要求的场景 |
RGB565 用 5 位表示红色、6 位表示绿色、5 位表示蓝色,在色彩效果和数据量之间取得平衡,是 ESP32 上彩屏开发最常用的格式。
嵌入式 LCD 常用 RGB565,是因为一个像素正好占 16 位(2 字节),比 24 位 RGB888 少占三分之一的显存和传输带宽。对 SPI、I80 等接口而言,少传 1 字节通常能直接降低刷新压力,因此很多中小尺寸 LCD 示例和图形库默认使用 RGB565。
绿色分量占 6 位,是因为人眼对绿色亮度变化更敏感,给 G 多分配 1 位可让亮度过渡更细。这样总位数仍保持 16 位,同时把更多层级留给对视觉亮度影响较大的绿色通道。
由“分辨率 × 色深”可以算出一帧完整画面的数据量:
| 屏幕示例 | 分辨率 | 色深 | 一帧数据量 |
|---|---|---|---|
| 0.96 英寸单色 OLED | 128×64 | 1bpp | 1 KB |
| 1.28 英寸圆形 LCD | 240×240 | RGB565 | 112.5 KB |
| 2.4 英寸 LCD | 240×320 | RGB565 | 150 KB |
| 4.3 英寸 RGB 屏 | 800×480 | RGB565 | 750 KB |
帧数据量直接影响两个关键因素:刷新一帧需要传输多少数据(影响帧率),以及缓存一帧画面需要多少内存(影响内存方案)。
1.3 帧缓冲与显存(GRAM)
对于需要持续扫描刷新的屏幕,当前画面的全部像素数据需要保存在一块内存中,这块内存称为帧缓冲(Frame Buffer)。它可能位于两个位置:
- 屏幕侧:多数 SPI / I80 接口的屏幕,其驱动 IC 内部集成了显存(GRAM)。主控把像素数据写入 GRAM 后,驱动 IC 自行负责持续刷新面板。主控无需保存整帧画面,内存压力小,画面不更新时主控无需执行任何操作。
- 主控侧:RGB 接口的屏幕没有 GRAM,主控必须在自己的内存中维护完整帧缓冲,并按固定时序不间断地向屏幕输出数据。当片内 RAM 不足以容纳完整帧缓冲时,就需要借助片外 PSRAM。以 800×480 RGB565 为例,一帧就需要 750 KB,超出多数 ESP32 型号的片内 RAM,因此这类 RGB 大屏的应用大多需要配备 PSRAM;分辨率较低的 RGB 屏若帧缓冲能放入片内 RAM,则未必需要。
这两类屏幕两种情况都有,取决于驱动 IC 型号和工作模式:部分 QSPI 驱动 IC 内置 GRAM,用法接近 SPI,另一些不带 GRAM,需要主控持续输出画面。ESP32-P4 的 MIPI-DSI 使用 Video Mode,帧缓冲位于主控侧。
这是选择接口时最核心的区别之一:SPI 屏对主控内存要求低,RGB 屏则取决于帧缓冲大小,大尺寸、高分辨率屏通常需要 PSRAM。
1.4 刷新与画面撕裂
屏幕并不会在写入后立即显示对应内容,驱动 IC 会按固定的刷新率(如 60 Hz)周期性地把显存内容扫描到面板上。如果主控写入 GRAM 的过程恰好跨越了一次扫描,屏幕上就会同时出现新旧两帧的内容,称为画面撕裂(Tearing)。
部分带 GRAM 的屏幕引出了 TE (Tearing Effect) 引脚,在两次扫描之间的间隙输出一个同步脉冲。主控可以等待该信号后再开始写入,使写入过程与屏幕扫描保持同步。要完全消除撕裂,还需要写入方向与扫描方向一致、写入速度跟得上扫描速度。主要显示静态内容、只偶尔更新画面的应用,一般无需处理撕裂问题。
有关撕裂的更多讲解,请参考 ESP-IoT-Solution 编程指南 - LCD 屏幕撕裂详解。
1.5 全屏刷新与窗口刷新
带 GRAM 的屏幕支持窗口寻址(Window Addressing):先通过命令指定一个矩形区域,之后写入的像素数据只落在该区域内。因此更新画面时不必重传整帧,只刷新变化的部分即可,这能显著降低传输量。LVGL 等图形库的“局部刷新”就是基于这一机制实现的。
墨水屏的“局刷”是另一个概念,它涉及电泳粒子的驱动波形,详见 E-Paper 章节。
1.6 显示方向与坐标系
屏幕的原生方向由面板和驱动 IC 的行列排列决定。以原生宽度为 W、高度为 H 的屏幕为例,通常将左上角定义为坐标原点 (0, 0),X 轴向右递增,Y 轴向下递增。模组安装到设备后,屏幕的物理方向可能与原生方向不同,因此需要将显示内容旋转到对应方向。
显示方向改变后,图形库使用的逻辑坐标系也会随之改变。以原生画面顺时针旋转为例,原坐标 (x, y) 与旋转后坐标的关系如下:
| 顺时针旋转角度 | 逻辑宽度 × 高度 | 原坐标映射到旋转后坐标 |
|---|---|---|
| 0° | W × H | (x, y) |
| 90° | H × W | (H - 1 - y, x) |
| 180° | W × H | (W - 1 - x, H - 1 - y) |
| 270° | H × W | (y, W - 1 - x) |
实际开发时通常不需要手动计算这些坐标,屏幕驱动或图形库会提供显示方向设置。按照像素转换发生的位置,旋转可分为两种方式:
| 旋转方式 | 实现原理 | 特点 |
|---|---|---|
| 控制器侧旋转(通常称为硬件旋转) | 带 GRAM 的驱动 IC 通过行列交换和轴向翻转改变像素寻址方向,部分驱动 IC 使用 MADCTL 等寄存器控制 | 使用驱动 IC 自身的寻址能力,主控无需重排整帧像素,也不需要增加完整的旋转缓冲区;可用方向取决于驱动 IC |
| 主控侧软件旋转 | CPU、软件画布或 GUI 框架先转换帧缓冲区,再将转换后的像素写入屏幕 | 不依赖驱动 IC 提供完整的旋转能力,但会增加内存占用、数据复制量和计算开销 |
对于 0°、90°、180°、270° 旋转,如果驱动 IC 支持所需方向,应优先使用控制器侧旋转。它直接使用屏幕控制器的寻址功能,配置完成后仍可按旋转后的逻辑坐标绘图。驱动 IC 不支持行列交换,或者应用需要其他角度和图像变换时,再使用主控侧软件旋转。
Arduino_GFX 的 setRotation()、u8g2 构造器中的 U8G2_R0~U8G2_R3 等接口用于设置显示方向。设置后,图形库会按照目标方向调整逻辑坐标和宽高;像素最终由驱动 IC 重新寻址,还是在主控侧完成转换,取决于具体驱动和缓冲方式。
不同图形库对旋转编号和起始方向的定义不完全相同,部分驱动 IC 也只支持轴向翻转,不能完成 90° / 270° 的行列交换。设置方向前,应查阅所用图形库和驱动的说明;设置后,应读取图形库提供的逻辑宽度和高度,并检查四角的图形是否完整。自行编写驱动时,还需确认不同方向下的窗口寻址偏移。
触摸 IC 通常仍按触摸面板的原生方向输出坐标。显示方向改变后,触摸坐标需要执行相同的轴交换和镜像变换,否则触点位置会与画面错位。具体处理方法见 触摸控制的“坐标与显示的对齐”章节。
2. 显示接口对比
屏幕与主控之间常见的接口如下表,核心差异在于数据线数量(决定带宽)、实际占用的 IO 数(决定引脚开销)以及屏端是否带 GRAM(决定主控内存需求)。表中 IO 数为含时钟、片选、命令 / 同步等控制线的大致范围,复位、背光等可选引脚未计入:
| 接口 | 数据线 | 约占用 IO 数 | 典型带宽 | 屏端 GRAM | 典型应用 |
|---|---|---|---|---|---|
| I2C | 1(双向) | 2(与其他 I2C 器件共用) | ≤ 1 Mbps | 有 | 0.96 英寸等小尺寸单色 OLED |
| SPI(4 线) | 1 | 4~5 | 40~80 Mbps | 有 | 3.5 英寸以下彩屏、墨水屏、RLCD |
| QSPI | 4 | 6~7 | 理论峰值为 SPI 的 4 倍 | 取决于驱动 IC | 1~2 英寸高分辨率 AMOLED |
| I80(8080 并口) | 8 / 16 | 11~20 | 较高 | 有 | 中小尺寸 LCD |
| RGB 并口 | 8 / 16 / 18 / 24 | 12~28 | 高 | 无 | 3.5 英寸及以上大屏 |
| MIPI-DSI | 1~2 条数据 Lane,另有 1 条时钟 Lane | 4~6(即 2~3 对差分线) | 很高 | 无(Video Mode) | 高分辨率屏(ESP32-P4) |
2.1 SPI:最常用的接口
SPI 是 ESP32 上最常见的屏幕接口,引脚少、接线简单,几乎所有系列的 ESP32 都支持。典型的 4 线 SPI 屏幕模块引脚如下(与微雪屏幕模块的丝印对应):
| 引脚 | 说明 |
|---|---|
| VCC / GND | 电源 |
| DIN(MOSI) | 数据线,主控 → 屏幕 |
| CLK(SCLK) | 时钟线 |
| CS | 片选,低电平有效 |
| DC | 命令 / 数据选择:低电平表示发送命令,高电平表示发送像素数据 |
| SDO(MISO) | 可选的数据线,屏幕 → 主控,用于读取 ID、状态或显存。多数应用只写不读,可以不连接 |
| RST | 复位,低电平有效。部分模块可以省略,驱动代码中复位引脚参数填 -1 |
| BL | 背光控制(LCD 特有,可接 PWM 调节亮度) |
其中 DC 引脚是显示 SPI 相较普通 SPI 多出的关键信号:屏幕驱动 IC 通过该引脚的电平,区分收到的字节是命令还是数据。RST 能否省略,以模块原理图和驱动要求为准。
2.2 帧率的三个环节
日常所说的“帧率”实际包含三个相互独立的环节,画面的实际流畅度由三者中的最小值决定:
-
渲染帧率:主控生成图像数据的速率。取决于主控性能与画面复杂度(局部更新通常快于全屏更新),是动态变化的。
-
接口帧率:主控连续传输完整画面时,显示接口能达到的速率。由接口带宽与一帧数据量决定:
接口帧率上限 ≈ 接口带宽 ÷ 一帧数据量该式为理论上限,实际会低一些,估算时需要留出余量。
-
屏幕刷新率:驱动 IC 将显存内容扫描到面板的速率(见刷新与画面撕裂)。SPI / I80 屏由驱动 IC 自行决定(可通过命令配置),与主控的传输速率无关;RGB 屏没有这层解耦,主控输出的过程本身就是屏幕扫描的过程。
SPI、QSPI 和 I80 存在命令、事务间隔和 DMA 分块的开销;RGB 和 MIPI-DSI Video Mode 还需要计入有效画面之外的消隐时序。此外,内存和 DMA 带宽也可能成为瓶颈。
接口帧率是选型时最需要估算的环节。以 40 MHz 的 SPI 驱动 240×320 RGB565 屏幕为例:一帧约 1.23 Mbit,接口帧率上限约为 40 Mbps ÷ 1.23 Mbit ≈ 32 帧/秒(实际还有命令与协议开销,会更低一些)。这一估算可以解释几个常见现象:
- SPI 驱动 240×240、240×320 这类中低分辨率屏幕时,通常能满足基础 GUI 的需求;分辨率继续提高后,全屏刷新的带宽很快成为瓶颈。
- ESP32 生态中的小尺寸高分辨率 AMOLED 模组(如 410×502、466×466)多采用 QSPI,以缓解单线 SPI 的带宽压力。
- 800×480 这类大屏一帧 750 KB,用单线 SPI 全屏传输难以达到流畅 GUI 所需的帧率,因此这类屏幕多采用 RGB、QSPI 或 MIPI-DSI 等带宽更高的接口。
若接口帧率估算充足而实际画面仍不流畅,瓶颈通常在渲染帧率,应优化绘制逻辑或降低画面复杂度,而非提高接口时钟。
2.3 各接口小结
- I2C:引脚最少(与其他 I2C 器件共用总线),但带宽最低,只适合小尺寸单色 OLED。
- SPI:只占 4~5 个 GPIO,全系列 ESP32 都支持,是最通用的选择;带宽有限,分辨率提高后需要换用其他接口。
- QSPI:将 SPI 的 1 根数据线扩展为 4 根,像素数据阶段每个时钟最多传输 4 bit,理论峰值为 SPI 的 4 倍,是高分辨率 AMOLED 的主流接口。
- I80:使用 8 位或 16 位并行数据总线,带宽高于单线 SPI,但加上 WR、DC、CS 等控制信号后通常需要 11~20 个 GPIO,在引脚紧张的 ESP32 上使用较少。
- RGB:主控直接输出面板时序,带宽高、成本低,但占用 GPIO 多且必须在主控侧维护整帧缓冲(大屏通常依赖 PSRAM)。
- MIPI-DSI:高分辨率、高刷新率屏幕常用的高速差分串行接口,引脚少带宽高,目前仅 ESP32-P4 支持。
3. ESP32 的显示接口支持
不同系列的 ESP32 支持的显示接口不同,选屏前需要确认主控能力:
| 接口 | 支持的 ESP32 系列 |
|---|---|
| I2C / SPI / QSPI | 全系列(通过通用 I2C / SPI 外设) |
| I80(原生) | ESP32(I2S 的 LCD 模式)、ESP32-S2、ESP32-S3、ESP32-S31、ESP32-P4(专用 LCD 外设) |
| I80(模拟) | ESP32-C5 / C6 / H2 等无原生 I80 外设的型号,可用 Parlio 外设模拟 I80 时序 |
| RGB | ESP32-S3、ESP32-S31、ESP32-P4 |
| MIPI-DSI | ESP32-P4 |
各系列的具体支持情况以 ESP-IoT-Solution:LCD 开发指南 - 支持的接口类型 为准。
按显示接口和应用规模,可参考以下方式选择:
- ESP32-P4 接口最完整,是高分辨率屏幕的首选,但其本身不带无线连接,开发板通常另配 ESP32-C6 等模块提供 Wi-Fi 和 Bluetooth;
- ESP32-S3 凭借专用 LCD 外设和可选的大容量 PSRAM,是目前带屏应用最常用的型号;
- 新推出的 ESP32-S31 支持的接口类型与 ESP32-S3 相同,同规格 RGB 屏的实测帧率更高;
- ESP32-C3 / C6 等主要使用通用 SPI,适合搭配中小尺寸 SPI 屏。
各型号在不同接口和分辨率下的实测帧率,可参考 乐鑫 LCD 应用开发笔记 中的 LVGL Benchmark 数据表。
在 Arduino 生态中,常见的 SPI、QSPI、I80 和 RGB 屏幕差异大多已由图形驱动库封装,常用的库有:
| 库 | 适用范围 |
|---|---|
| GFX Library for Arduino (Arduino_GFX) | 彩屏通用图形库,支持 SPI / QSPI / I80 / RGB 多种总线与大量驱动 IC |
| LovyanGFX | 彩屏图形库,性能优秀,支持触摸与多种总线 |
| TFT_eSPI | 经典 SPI 彩屏图形库,通过配置文件适配屏幕 |
| u8g2 | 单色屏图形库,OLED / RLCD 常用,字体资源丰富 |
| GxEPD2 | 墨水屏驱动库 |
| 微雪示例程序包 | 各开发板 / 屏幕模块的官方驱动与示例,引脚和参数已适配好 |
各类屏幕分别适合用哪个库,在对应章节和 GUI 框架 章节中具体介绍。MIPI-DSI 等较新的接口目前主要依赖 ESP-IDF 及相关显示组件。
使用微雪的带屏开发板(如 ESP32-S3-Touch-LCD 系列)时,屏幕已直连主控,无需接线;官方示例程序包中的引脚定义和初始化参数可直接使用。
4. 带 GRAM 屏幕的通用驱动流程
对于带驱动 IC 和 GRAM 的 SPI、I2C、I80 屏幕,驱动流程通常包括以下步骤,理解该流程有助于阅读后续章节的示例代码:
- 初始化总线:配置 SPI / I2C 等接口的引脚和时钟频率。
- 复位屏幕:拉低 RST 引脚一段时间后释放,使驱动 IC 回到确定状态。
- 发送初始化序列:向驱动 IC 写入一串配置命令,设置电源、扫描方向、像素格式等。这串命令由屏厂针对具体面板调校,一般直接使用微雪示例或驱动库中现成的初始化代码,无需自己编写。
- 设置写入窗口:指定接下来要更新的矩形区域(全屏或局部)。
- 写入像素数据:按选定的像素格式(如 RGB565)连续写入该区域的像素,画面随之显示。
后续更新画面就是重复第 4、5 步。使用 Arduino_GFX、u8g2 这类库时,第 1~3 步由库的 begin() 完成,第 4、5 步则被封装为 drawPixel()、fillRect()、drawBitmap() 等绘图 API。绘图 API 是立即向屏幕传输像素,还是先写入主控侧缓冲区、再由 flush() 或 sendBuffer() 统一传输,取决于所用图形库及其缓冲模式。
其他类型的屏幕在此流程上有所不同:RGB 和 MIPI-DSI Video Mode 屏幕不采用“设置窗口再写入屏端 GRAM”的方式,应用在主控侧帧缓冲中绘制像素,LCD 外设按像素时钟和同步时序把帧缓冲内容持续输出到屏幕;墨水屏写入显示 RAM 后,还需要发送刷新命令并等待 BUSY 信号释放。
5. 延伸阅读
- 乐鑫 ESP-IoT-Solution:LCD 开发指南:官方中文资料,基于 esp_lcd / ESP-IDF,包含各接口的参数对比、典型连接方式与 LCD 术语表,可作为本章的进阶补充。
- 乐鑫 ESP-Techpedia:LCD 应用开发笔记
了解这些公共概念后,即可进入具体屏幕类型的章节。若尚未确定屏幕类型,可回到 显示屏总览 查看选型对比。