LED 点阵屏
LED 点阵屏由大量独立封装的 RGB LED 灯珠按行列排布组成,每颗灯珠构成一个像素。与将像素结构集成在面板内部的 LCD、OLED 不同,常见的 HUB75 点阵模组使用尺寸较大的独立灯珠,像素之间通常有清晰可见的间距(点距)。它亮度高、便于模块化拼接,常见于广告屏、信息屏、比分牌等远距离观看的场合。
嵌入式领域常用的是 HUB75 接口的全彩 LED 点阵屏。本章介绍点阵屏的成像原理与 HUB75 的行扫描机制,并以微雪 RGB-Matrix-P2.5-64x64 点阵屏搭配 ESP32-S3-RGB-Matrix 驱动板为例讲解驱动方法。
1. 显示原理
一块全彩点阵屏是一个 M×N 的 LED 灯珠阵列,每个像素是一颗灯珠,封装内含红、绿、蓝三颗发光芯片(1R1G1B),通过混色显示全彩。
像素数量很大,无法为每个像素单独布线(一块 64×64 屏就有 4096 个像素、12288 颗发光芯片),因此点阵屏采用行列扫描 + 移位寄存器的方式驱动,这也是 HUB75 接口的工作原理:
- 列数据靠移位寄存器串行送入:屏幕在垂直方向被分为上下两半。
R1/G1/B1是三条并行的数据线,对应上半屏的红、绿、蓝三条独立移位链,每个CLK时钟三条链同时各移入 1 位,恰好是同一像素的三个颜色位;一行有多少列,就需要多少个时钟移满整行。R2/G2/B2以同样的方式送入下半屏当前行的数据。 - 地址线选通当前扫描行:
A/B/C/D/E是行地址线,经译码后决定当前选中哪一对扫描行(上下半屏各一行)。 - 锁存与使能:一行数据移入完成后,
LAT将移位寄存器的内容锁存输出,OE(Output Enable,低电平有效)控制这一行是否点亮。
任一时刻每半屏只有一行在发光,屏幕靠高速逐行扫描配合视觉暂留形成完整画面。这个"扫描"过程需要主控持续不断地运行,一旦停止,画面便无法维持。因此点阵屏与 SPI 屏不同:SPI 屏的驱动 IC 自带显存,主控写入一帧后显示即可自行维持;点阵屏则需要由主控高频率地反复刷屏。ESP32 借助 I2S 或 LCD 并行外设配合 DMA(Direct Memory Access,直接存储器访问),在后台自动完成这一持续刷新,无需 CPU 逐行干预,这是它能流畅驱动点阵屏的关键。
另一个关键点是灰度的来源。数据线上每种颜色只有 1 位,单次扫描中每颗芯片非亮即灭,直接显示只能得到 2³=8 种颜色。更丰富的色彩由 BCM(Binary Code Modulation,二进制编码调制) 调光实现:驱动程序把颜色值拆成多个位平面(Bitplane),逐个位平面反复扫描,点亮时长按位的权重分配,人眼混合后即呈现连续灰度。
屏幕的扫描方式决定用到几根地址线。RGB-Matrix-P2.5-64x64 为 1/32 扫描:64 行分为上下两半、各 32 行,需要 5 根地址线(A/B/C/D/E,2⁵=32)。而分辨率较低的 64×32 屏为 1/16 扫描,只用 4 根地址线(A/B/C/D,2⁴=16),不接 E。
接口命名上,只用 A~D 的接口称 HUB75,增加 E 线的常被称为 HUB75E,两者同为 16 针排线。各厂商的命名并不统一,本章统称 HUB75。
点距(Pitch) 指相邻像素中心的间距,是点阵屏的关键参数。P2.5 表示点距 2.5 mm,数字越小像素越密(同为 64×64,P2.5 屏为 160×160 mm,P3 屏则为 192×192 mm)。点阵屏的原生分辨率由物理灯珠数量决定,而独立封装的灯珠在封装尺寸、布线和散热间距上都有下限,因此像素密度明显低于同尺寸的 LCD 或 OLED 面板。
2. 特性与局限
优势:
- 可实现很高的显示亮度,适合远距离观看和明亮环境。
- 模块化设计,可通过 HUB75 级联接口按整数倍拼接成更大尺寸的屏,单块模组也便于安装、更换和维护。
- 全彩自发光,可视角度大(≥140°)。
- 部分型号采用 GOB (Glue On Board) 灌胶工艺,可提升抗冲击、防潮、防尘能力。
局限:
- 点距大,近距离观看颗粒感明显、亮度刺眼,需要一定的观看距离才能获得良好观感。
- 单像素是独立封装的灯珠,分辨率和像素密度低,不适合显示精细的文字和图形。
- 画面依赖持续高速刷新,DMA 缓冲区占用较多内部 RAM(分辨率、色深越高占用越大,64×64 单块即需数十 KB)。
- 功耗和电流大。全彩全亮时电流可达数安培(RGB-Matrix-P2.5-64x64 为 5 V / 4 A、≤20 W),需要独立的 5 V 电源供电。
- 需要专用的 HUB75 驱动方案,接线和供电比小屏复杂。
3. 接口与驱动方案
HUB75 接口 是全彩 LED 点阵屏的事实标准,为 16 针(2×8)排线,主要信号如下:
| 信号 | 含义 |
|---|---|
| R1 / G1 / B1 | 上半屏的红/绿/蓝数据 |
| R2 / G2 / B2 | 下半屏的红/绿/蓝数据 |
| A / B / C / D / E | 行地址线(E 仅 1/32 扫描屏使用,即 HUB75E 接口) |
| CLK | 移位时钟 |
| LAT(STB) | 锁存 |
| OE | 输出使能(低电平有效) |
| GND | 地 |
HUB75 排线传输控制信号和地参考,不为灯珠提供 5 V 工作电源。点阵屏必须通过屏体或驱动板上专门的 5 V 电源接口(如 RGB-Matrix-P2.5-64x64 的 VH4 接口)供电,且电源要满足屏的额定电流,切勿从主控的 GPIO、3.3 V 引脚或普通开发板的 5 V 引脚获取灯珠的工作电流。
驱动方案:如显示原理一节所述,点阵屏需要主控持续高频刷新,ESP32 系列通过高速并行外设配合 DMA 在后台自动完成:
- 经典 ESP32 使用 I2S 外设的 LCD 并行模式。
- ESP32-S3 使用 LCD 并行外设 + GDMA(通用 DMA 控制器,见《ESP32-S3 技术参考手册》),性能更好。
微雪 ESP32-S3-RGB-Matrix 驱动板将 ESP32-S3 主控、HUB75 排线座和屏的供电接口集成在一起,直接插上点阵屏即可使用,省去了自行接线和供电设计的工作,本章示例即基于该驱动板。
4. Arduino + ESP32-HUB75-MatrixPanel-DMA 驱动示例
ESP32-HUB75-MatrixPanel-DMA 是社区维护的 HUB75 点阵屏驱动库,利用 ESP32 的并行外设 + DMA 在后台自动刷屏,是 Arduino 下驱动这类屏幕的流行选择。库的头文件与类名中的 I2S 字样沿用自早期基于经典 ESP32 I2S 外设的实现,属历史命名,在 ESP32-S3 上实际使用的是 LCD 并行外设。它的绘图 API 继承自 Adafruit GFX,drawRect()、drawCircle()、print() 等接口与常见图形库一致。
本节以微雪 ESP32-S3-RGB-Matrix 驱动板搭配 RGB-Matrix-P2.5-64x64 点阵屏为例,屏幕分辨率 64×64、1/32 扫描,采用普通移位寄存器型驱动 IC、上下两路并行扫描。换用其他常规的 1/16 或 1/32 扫描屏时,通常只需调整分辨率、级联数量和引脚配置;部分面板采用特殊的行译码方式、像素映射或带内部 PWM 的驱动 IC,还需要修改驱动类型或改用 VirtualMatrixPanel。
4.1 安装库
在库管理器(工具 > 管理库)中搜索 ESP32 HUB75 LED MATRIX PANEL DMA Display 并安装,安装时如提示需要安装依赖库,也一并安装。其他安装方式参考 Arduino 库管理教程。
4.2 确认引脚
ESP32-S3-RGB-Matrix 驱动板的 HUB75 引脚已在板上固定连接,对应的 ESP32-S3 GPIO 如下:
| HUB75 信号 | GPIO | HUB75 信号 | GPIO |
|---|---|---|---|
| R1 | 4 | R2 | 7 |
| G1 | 5 | G2 | 15 |
| B1 | 6 | B2 | 16 |
| A | 18 | B | 8 |
| C | 3 | D | 42 |
| E | 9 | CLK | 41 |
| LAT | 40 | OE | 2 |
使用该驱动板时无需自行接线,直接把点阵屏的 HUB75 排线插到驱动板对应座子,并给屏接好 5 V 电源即可;屏与主控已通过板上线路和 HUB75 接口共地,无需额外连接地线。库在 ESP32-S3 上的默认引脚恰好与本驱动板一致(E 除外),但示例代码仍将全部引脚显式写出,以演示手动指定引脚的写法和各信号的排列顺序。使用其他开发板自行接线时,按实际连接修改示例代码中的 pins 即可。
4.3 示例代码
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
// 1. 屏幕参数:单块 64×64,未级联
#define PANEL_RES_X 64 // 单块屏宽(像素)
#define PANEL_RES_Y 64 // 单块屏高(像素)
#define PANEL_CHAIN 1 // 级联的屏数量
MatrixPanel_I2S_DMA *dma_display = nullptr;
// 2. 渐变取色:输入 0-255,返回沿绿→红→蓝循环渐变的颜色
uint16_t colorWheel(uint8_t pos) {
if (pos < 85) {
return dma_display->color565(pos * 3, 255 - pos * 3, 0);
} else if (pos < 170) {
pos -= 85;
return dma_display->color565(255 - pos * 3, 0, pos * 3);
} else {
pos -= 170;
return dma_display->color565(0, pos * 3, 255 - pos * 3);
}
}
void setup() {
Serial.begin(115200);
// 3. HUB75 引脚:按 ESP32-S3-RGB-Matrix 驱动板的实际连接逐一列出
HUB75_I2S_CFG::i2s_pins pins = {
4, 5, 6, // R1, G1, B1
7, 15, 16, // R2, G2, B2
18, 8, 3, 42, // A, B, C, D
9, // E:1/32 扫描屏必须配置
40, 2, 41 // LAT, OE, CLK
};
// 4. 构造配置:屏宽、屏高、级联数量、引脚
HUB75_I2S_CFG mxconfig(PANEL_RES_X, PANEL_RES_Y, PANEL_CHAIN, pins);
// 本屏使用普通移位寄存器型列驱动
mxconfig.driver = HUB75_I2S_CFG::SHIFTREG;
// 切换时钟采样边沿:本屏保持库默认值会使画面整体横向偏移一个像素
mxconfig.clkphase = false;
// 5. 初始化并设置亮度(0-255),亮度越高电流越大
dma_display = new MatrixPanel_I2S_DMA(mxconfig);
if (!dma_display->begin()) {
Serial.println("HUB75 DMA buffer allocation failed.");
while (true) {
delay(1000);
}
}
dma_display->setBrightness8(90);
dma_display->clearScreen();
// 6. 白色外框,沿屏幕边缘一圈
dma_display->drawRect(0, 0, PANEL_RES_X, PANEL_RES_Y,
dma_display->color565(255, 255, 255));
// 7. 顶部居中显示标题:字号 2 时每字符占 12 像素宽,
// "LED" 共 36 像素,起始 x = (64 - 36) / 2 = 14
dma_display->setTextSize(2);
dma_display->setTextColor(dma_display->color565(255, 255, 0));
dma_display->setCursor(14, 8);
dma_display->print("LED");
// 8. 中部三原色色块:12×12,等间距排布,左右留边对称
dma_display->fillRect( 8, 30, 12, 12, dma_display->color565(255, 0, 0));
dma_display->fillRect(26, 30, 12, 12, dma_display->color565(0, 255, 0));
dma_display->fillRect(44, 30, 12, 12, dma_display->color565(0, 0, 255));
// 9. 底部彩虹渐变条:逐列取色绘制竖线,展示全彩平滑渐变
for (int x = 4; x < 60; x++) {
uint8_t pos = (x - 4) * 255 / 55;
dma_display->drawFastVLine(x, 48, 8, colorWheel(pos));
}
}
void loop() {
// 静态画面,DMA 在后台持续刷新,无需在 loop 中重复绘制
}
烧录后屏幕自上而下依次显示:居中的黄色标题 LED、红绿蓝三个色块、一条彩虹渐变条,四周为白色边框。三原色色块可一并检验 R/G/B 通道接线是否正确,渐变条则直观展示全彩渐变能力。几个关键点:
- 屏幕参数必须与实际屏一致:
PANEL_RES_X、PANEL_RES_Y是单块屏的分辨率,PANEL_CHAIN是同一条 HUB75 数据链上横向级联的屏数量(单块填 1),例如两块 64×64 会形成 128×64 的逻辑画布。若把面板排成 2×2、蛇形等二维结构,则需要使用VirtualMatrixPanel完成坐标映射。 - 引脚配置对应驱动板:
pins中的 14 个引脚按R1/G1/B1、R2/G2/B2、A/B/C/D、E、LAT/OE/CLK的固定顺序排列,不可调换。本屏为 1/32 扫描,E地址线必须配置,漏配会导致画面只显示一半或错乱。driver和clkphase不是引脚:driver = SHIFTREG表示列驱动为普通移位寄存器,也是库的默认值,写出来只是让配置更明确;clkphase控制数据的时钟采样边沿,库默认为true,而本屏必须设为false:保持默认值时整幅画面会横向偏移一个像素,表现为一侧边框缺失、另一侧多出一列。换用其他面板时若出现类似的横向错位或重影,也可从这个参数入手。 - 应检查
begin()的返回值:该函数在 DMA 缓冲区分配失败时返回false。提高分辨率、增加级联数量、调大色深或启用双缓冲后,内部 RAM 可能不足以分配缓冲区,此时屏幕不会有任何显示,检查返回值可以直接从串口定位问题。 - 亮度直接影响电流:
setBrightness8()取值 0-255,亮度越高、点亮的像素越多,电流越大,务必确保 5 V 电源能提供足够电流。另外该库通过显示原理中介绍的 BCM 调光实现灰度,亮度设得过低会损失灰度层次。 - 本例使用 RGB565 颜色值:Adafruit GFX 兼容接口以 16 位 RGB565 表示颜色,
color565(R, G, B)接收三个 0-255 的通道值并转换为 RGB565。库同时提供drawPixelRGB888()等直接接收 RGB888 数据的接口,色深本身也可配置,条件允许时最高可输出每通道 8 位。colorWheel()把 0-255 的位置值映射为绿→红→蓝的循环渐变色,是点阵屏演示中常用的取色方法,也适合做流动的彩虹动画。 - 低分辨率下布局需按像素精确规划:64×64 的画布上没有多少余量,各元素的坐标和尺寸应逐一核算。Adafruit GFX 默认字体在字号 1 时每字符占 6×8 像素、字号 2 时加倍为 12×16,本例标题即按 3 字符 × 12 像素 = 36 像素计算居中起点;色块与渐变条的留边也按同样方式推算,保证互不重叠、左右对称。
- 绘图 API 与 Adafruit GFX 一致:
drawRect()、fillRect()、drawFastVLine()、setCursor()、print()等用法与其他基于 Adafruit GFX 的库相同。 - 无需在
loop()中反复刷新:绘图 API 直接写入 DMA 缓冲区,硬件在后台持续把缓冲区刷到屏上。要实现动画,在loop()中更新缓冲区内容即可;若动画出现闪烁或撕裂,可启用双缓冲(mxconfig.double_buff = true,每帧绘制完调用flipDMABuffer()切换)。
4.4 常见问题
| 现象 | 常见原因 | 处理 |
|---|---|---|
| 屏幕完全不亮 | 屏未接 5 V 电源;HUB75 排线未插好或方向反;begin() 返回 false | 确认屏的 5 V 供电;检查排线插接与方向;查看串口是否报缓冲区分配失败 |
| 画面偏暗、闪烁、颜色发红 | 5 V 电源电流不足,或供电线材压降大 | 换用更大电流的 5 V 电源或降低亮度;改用更粗的供电线 |
| 上下半屏内容错位或颜色错乱 | 扫描方式或引脚配置与屏不符 | 核对屏的扫描方式;确认 PANEL_RES_Y 与各引脚配置 |
| 画面整体错位、显示不全 | PANEL_RES_X/Y 或级联数量填错 | 按实际屏参数修正分辨率与 PANEL_CHAIN |
| 部分行不亮 | 地址线(A/B/C/D/E)接线或配置错误 | 检查地址线;本例 64×64、1/32 扫描屏必须配置 E |
| 像素横向偏移或重影 | 时钟相位不匹配;锁存切换时消隐不足 | 切换 mxconfig.clkphase(本例的屏需设为 false);必要时用 setLatBlanking() 调整消隐 |
| 颜色偏色但图形正常 | R/G/B 引脚顺序接错 | 核对 R1/G1/B1、R2/G2/B2 的引脚 |