跳到主要内容

OLED

微雪 1.5 寸 OLED 模块

OLED(Organic Light-Emitting Diode,有机发光二极管)屏幕的每个像素自行发光,不需要背光。

嵌入式项目中常用的是 0.96~1.5 英寸的小尺寸单色模块:接线简单(I2C 接口仅需两根信号线),功耗低、对比度高,适合显示状态信息,也是入门常用的屏幕。

本章介绍 OLED 的成像原理与常见驱动 IC,并重点讲解单色屏事实上的标准图形库 u8g2

1. 显示原理

OLED 的每个像素是一颗微小的有机发光二极管,通电即发光,亮度随电流变化。这与 LCD 的“背光 + 光阀”结构有本质区别:

LCD 的背光 + 光阀结构与 OLED 像素自发光结构对比

  • 不发光的像素为纯黑。LCD 显示黑色时背光仍在工作、存在漏光,OLED 的黑色像素直接不通电,因此对比度高,黑色纯粹。
  • 功耗取决于画面内容。点亮的像素越多、越亮,功耗越高;深色画面非常省电。

按驱动方式,OLED 分为两类:

  • PMOLED(Passive-Matrix OLED,被动矩阵有机发光二极管):像素按行列共用电极,任一时刻只点亮一行,靠逐行快速扫描配合视觉暂留形成完整画面。行数越多,每行分到的点亮时间越短,要维持亮度就得拉高瞬时电流,因此尺寸和分辨率受限,产品集中在 3 英寸以下的小屏。结构简单、成本低,本章讨论的常见 OLED 模块均属此类。
  • AMOLED(Active-Matrix OLED,有源矩阵有机发光二极管):每个像素配有独立的 TFT(Thin Film Transistor,薄膜晶体管)开关管,可维持发光状态,支持大尺寸、高分辨率和全彩显示,详见 AMOLED 章节

PMOLED 是小尺寸屏幕的默认方案,厂商通常不会专门标注,因此产品页如果没有特别标注 AMOLED,一般即为 PMOLED。

2. 特性与局限

优势:

  • 对比度高,黑色纯粹,小字清晰。
  • 自发光无背光,可视角接近全向。
  • 响应快,无拖影。
  • 显示深色内容时功耗低(黑色像素不耗电)。
  • 模块接口简单,I2C 两根线即可驱动,适合引脚有限的场合。

局限:

  • 尺寸小,产品范围约 0.42~2.42 英寸,主流为 0.96~1.5 英寸;分辨率低,多为 128×64 上下。
  • 以单色(白、蓝、黄)为主,部分为双色或灰度屏,无真彩。
  • 有烧屏风险:有机材料会随累计点亮时间衰减,长期显示固定内容会留下痕迹。长时间运行的设备应避免完全静止的画面(如定期移动内容、降低亮度或熄屏)。
  • 阳光直射下可读性一般。

3. 常见驱动 IC 与接口

驱动 IC分辨率特点常见屏幕
SSD1306128×64最常见、资料最多0.91 / 0.96 英寸
SH1106132×64与 SSD1306 类似,但显存为 132 列(宽 4 列),误用 SSD1306 构造器会导致画面偏移1.3 英寸
SSD1309128×64SSD1306 的大屏版本2.42 英寸
SSD1327128×12816 级灰度1.5 英寸

接口方面,上述驱动 IC 均同时支持 I2C 和 SPI,模块实际引出哪种接口取决于产品设计。部分模块(如微雪 OLED 模块)可通过板上的电阻焊位切换,出厂默认接口请见对应产品页;也有不少模块在出厂时固定为其中一种,不可更改。两种接口的取舍如下:

  • I2C:只需 SDA、SCL 两根线,还可与其他 I2C 器件共享总线,是小屏最常用的接法;缺点是带宽低,整屏刷新率有限。
  • SPI:引脚多(DIN、CLK、CS、DC、RST),但速度显著更快,适合需要流畅动画的场合。

SSD1306、SH1106 等 1bpp(1 bit per pixel,每像素 1 位,即单色)驱动 IC 的显存按页寻址组织:每页为 8 行像素,一个字节对应一列中垂直排列的 8 个点。SSD1327 这类灰度屏则不同,显存为 4bpp(4 bits per pixel,每像素 4 位),一个字节存放相邻两个像素的灰度值。无论哪种布局,直接操作显存都需要按对应格式组织字节,较为繁琐,这也是使用 u8g2 等图形库的原因:库在内存中维护常规布局的缓冲区,绘图后统一转换并发送,无需关心显存细节。

单色 OLED 显存的页寻址组织方式(以 SSD1306 为例)

4. Arduino + u8g2 驱动示例

u8g2 是开源社区维护的单色屏图形库,支持 SSD1306、SH1106、SSD1327 等几乎所有常见单色驱动 IC,内置数百套字体,是 Arduino 下驱动 OLED 的首选。RLCD 章节 中微雪官方示例同样基于 u8g2。

关于模块的兼容性

本节以 微雪 1.5 寸 OLED 模块 为例,该模块驱动 IC 为 SSD1327,分辨率 128×128,16 级灰度,通过 I2C 接线,可搭配任意 ESP32 开发板使用。如果使用其他 OLED 模块,只需替换引脚定义和对应的构造器即可。

4.1 构造器与缓冲模式

u8g2 通过构造器类名选择驱动 IC、屏幕型号、缓冲模式和接口,命名规则为:

U8G2_<驱动IC>_<屏幕型号>_<缓冲模式>_<接口>

例如 U8G2_SSD1327_WS_128X128_F_HW_I2C 表示:SSD1327 驱动 IC、微雪(WS)128×128 屏、全缓冲(F)、硬件 I2C。构造器必须与屏幕完全对应,这是 u8g2 使用中最关键的一步,完整列表见 u8g2 官方文档

缓冲模式决定内存占用与绘图方式:

模式代号内存占用(128×64 为例)绘图方式
全缓冲F整帧 1 KB任意绘制,sendBuffer() 一次刷新,简单直观
页缓冲1 / 2128 / 256 字节firstPage()/nextPage() 循环中重复绘制,省内存但代码受约束

页缓冲是为内存极小的单片机(如 AVR)设计的;ESP32 内存充足,使用全缓冲(F)即可

u8g2 不支持逐像素灰度

u8g2 本质是 1bpp(单色)图形库,drawStr()drawBox() 等绘图 API 只区分“亮”与“灭”,不提供逐像素设置灰度值的接口。SSD1327 虽然支持 16 级灰度(4bpp 显存),但 u8g2 在其上仍固定将“亮”像素映射为最大灰度,因此画面只会呈现全亮或全黑,不会有中间深浅。真正需要利用 SSD1327 的 16 级灰度(灰阶渐变、抗锯齿字体等)时,需要绕开 u8g2 的绘图层直接操作 4bpp 显存,或改用支持灰度缓冲区的其他库。

4.2 安装库

在库管理器(工具 > 管理库)中搜索 U8g2 并安装,其他安装方式参考 Arduino 库管理教程

4.3 确认引脚

本节接线以 微雪 ESP32-S3-Zero 迷你开发板 为例,与 Arduino 教程第 7 节 I2C 通信 相同:

开发板引脚OLED 模块说明
GPIO 1DIN(SDA)I2C 数据线
GPIO 2CLK(SCL)I2C 时钟线
3.3VVCC电源正极
GNDGND电源负极

使用其他 ESP32 开发板时,请选择该板可用的 I2C 引脚,并同步修改代码中的 SDA_PIN / SCL_PIN;注意部分引脚在某些板型上有默认功能(如 UART、ADC),不宜占用。

使用其他 OLED 模块时只需更换对应构造器,其余代码不变。

4.4 示例代码

#include <U8g2lib.h>

#define SDA_PIN 1
#define SCL_PIN 2

// 1. 构造器:SSD1327、微雪 128×128 屏、全缓冲、硬件 I2C
// U8G2_R0 表示不旋转;ESP32 可在构造器中直接指定 I2C 引脚
U8G2_SSD1327_WS_128X128_F_HW_I2C u8g2(U8G2_R0, /* reset= */ U8X8_PIN_NONE,
/* clock= */ SCL_PIN, /* data= */ SDA_PIN);

void setup() {
// 2. 模块默认 I2C 地址为 0x3D,u8g2 使用左移一位后的 8 位地址
u8g2.setI2CAddress(0x3D << 1);
u8g2.begin();

// 3. 清空缓冲区
u8g2.clearBuffer();

// 4. 顶部居中显示标题:字体较窄,按实际文字宽度居中,避免超出屏宽
u8g2.setFont(u8g2_font_7x14B_tr);
const char *title = "Hello, OLED!";
int titleW = u8g2.getStrWidth(title);
u8g2.drawStr((128 - titleW) / 2, 13, title);

// 5. 标题下方左右并排绘制空心矩形与空心圆,二者顶部对齐、互不重叠
u8g2.drawFrame(8, 24, 50, 50);
u8g2.drawCircle(94, 49, 25);

// 6. 底部绘制实心矩形
u8g2.drawBox(28, 90, 72, 24);

// 7. 把缓冲区内容刷新到屏幕
u8g2.sendBuffer();
}

void loop() {
// 静态画面,无需重复刷新
}

烧录后屏幕自上而下依次显示居中标题、一行空心矩形与空心圆、底部一个实心矩形,四者间留有间距。几个关键点:

  • 先绘制、后 sendBuffer():所有绘图 API 只修改内存缓冲区,调用 sendBuffer() 才真正通过 I2C 发送到屏幕显存。更新画面的固定流程为 clearBuffer() → 绘制 → sendBuffer()
  • 字体决定文字大小,且不会自动换行或缩放u8g2_font_7x14B_tr 中的 7x14 即字符宽、高的像素数,选择字体时需自行估算文字总宽度是否超出屏幕,例如本例中 128 像素宽的屏幕最多能容纳 128÷7≈18 个该字体的字符。更多字体见 官方字体列表
  • getStrWidth() 计算实际宽度再居中:不同字符宽度可能不同(非等宽字体尤其明显),绘制前调用 getStrWidth() 获取像素宽度,再据此计算起始坐标,才能保证居中精确、不超出屏幕边界。
  • 图形之间预留间距drawFrame()drawCircle()drawBox() 等只按给定坐标绘制,彼此及与文字是否重叠完全由坐标决定,规划布局时应逐一核算各元素的边界范围。
  • I2C 地址:微雪 1.5 寸模块默认地址为 0x3D。如果初始化后无显示,可先用 I2C 扫描程序 确认设备地址。
  • 本例为演示用的静态画面:实际长期运行的产品应避免长时间显示完全静止的内容,以降低烧屏风险(见特性与局限)。

4.5 常见问题

现象常见原因处理
屏幕无显示I2C 地址不符;接线错误用 I2C 扫描程序确认地址;核对 SDA/SCL
画面整体偏移 2 像素、边缘有噪点1.3 英寸屏误用 SSD1306 构造器SH1106 屏必须使用 SH1106 构造器
只显示了一部分内容页缓冲模式下没有使用 firstPage/nextPage 循环改用全缓冲(F)构造器
文字不显示绘制后未调用 sendBuffer();字体未设置确认已调用 setFont();检查 clearBuffer → 绘制 → sendBuffer 流程
文字超出屏幕或与图形重叠未按字体实际宽高计算坐标getStrWidth() 取宽度居中,并核算各元素边界留出间距
长期使用后有残像烧屏避免长时间显示完全静止的内容