这是 STM32 入门笔记专栏的第 02 篇。在能点亮 LED 之后,下一步通常是把 OLED 显示屏接上,单片机把数据 / 文字显示出来,能让调试过程直观得多。

一、OLED 是什么

OLED(Organic Light-Emitting Diode,有机发光二极管)是一种自发光显示技术,每个像素都能自己发光,不需要背光。在嵌入式领域常见的是 0.96 寸 128×64 单色 OLED 屏,通常用 SSD1306 这颗驱动芯片,支持 I²C 或 SPI 两种通信接口(看型号后缀,4 针的几乎都是 I²C)。

特点:

  • 薄、轻、功耗低——适合手持 / 可穿戴设备;
  • 对比度高——黑的真黑,亮字清晰;
  • 每个像素独立发光——理论上响应时间比 LCD 快;
  • 寿命有限——蓝色像素老化得最快,长时间高亮度全亮会烧屏;
  • 接口简单——4 根线(VCC / GND / SCL / SDA)就能用 I²C 驱动。

二、4 针 I²C OLED 的引脚定义

江科大最小系统板上常见的是 0.96 寸 4 针 I²C 模块,引脚定义如下:

引脚 名称 说明
VCC 电源 接 3.3V(绝对不能接 5V,会烧 OLED)
GND 地 接板子 GND
SCL 串行时钟 接 STM32 任一 GPIO,推荐带硬件 I²C 外设的引脚(如 PB10 / PB11 对应 I2C2)
SDA 串行数据 接 STM32 任一 GPIO,与 SCL 一对

也可以用「软件 I²C」(自己用 GPIO 模拟 SCL / SDA 的时序),任意两个 GPIO 引脚都行——教学场景更推荐这种,因为不用抢 I²C 外设,对照示波器调时序也方便。

三、最常踩的硬件坑:杜邦线太长

原文里有句话非常关键,但容易被新手忽略——

⚠️ OLED 显示屏如果跳线(杜邦线)太长可能导致显示不成功

I²C 是开漏 + 上拉的同步通信协议,时钟频率一般 100 kHz ~ 400 kHz。杜邦线本身有几个问题:

  1. 线太长(≥ 20 cm):导线分布电容变大,信号边沿变缓,SCL / SDA 上升时间变长,主机还没等到从机释放总线就开始采数据,读到错误值;
  2. 杜邦线质量参差不齐:接触电阻大、容易松动,时不时出现「能显示一行乱码」的现象;
  3. 没接上拉电阻:4 针 OLED 模块板子上已经板载了上拉电阻,但如果你用的是裸屏 SSD1306 模块,SDA / SCL 必须外接 4.7 kΩ 上拉到 3.3V,否则高电平根本拉不起来。

实测经验:

  • 线长 ≤ 10 cm:基本没问题;
  • 10 ~ 20 cm:偶尔出现错位,可以把 I²C 时钟降到 100 kHz 以下;
  • ≥ 30 cm:强烈建议改用硬件 I²C + 中继器,或者干脆把 OLED 用排针直接焊到板子上。

四、软件层面的最小演示

驱动 OLED 通常不自己手写 SSD1306 命令,而是用江科大 / 野火 / 立创开发板配套的 OLED 库。下面是「基于软件 I²C 发送 1 字节」的最小片段,演示数据怎么从 STM32 走到 OLED:

1
2
3
4
5
6
7
8
9
10
// 软件 I²C 写 1 字节(OLED 驱动库里最底层的一个函数)
void OLED_I2C_WriteByte(uint8_t addr, uint8_t data)
{
I2C_Start(); // 主机发出 SCL 高、SDA 下降沿的「起始位」
I2C_WriteByte(addr); // 发送从机地址 + 写位(OLED 通常是 0x78)
I2C_WaitAck(); // 等待从机 ACK(拉低 SDA)
I2C_WriteByte(data); // 发送 1 字节数据
I2C_WaitAck(); // 再次等 ACK
I2C_Stop(); // 主机发出 SCL 高、SDA 上升沿的「停止位」
}

OLED 驱动库对上层暴露的是这种接口:

1
2
3
4
5
6
OLED_Init();            // 初始化:发一系列 SSD1306 配置命令(设置页地址、对比度、开显示…)
OLED_Clear(); // 清空显存(全部置 0)
OLED_ShowChar(1, 1, 'A'); // 在第 1 行第 1 列显示字符 'A'
OLED_ShowString(1, 1, "Hello!"); // 显示字符串
OLED_ShowNum(2, 1, 123, 3); // 显示数字(指定位数 3)
OLED_ShowChinese(3, 1, 0); // 显示汉字(需要字模)

写库的时候通常把数据先写到一块 显存 buffer(也是 128×64 / 8 = 1024 字节),再整体 OLED_Refresh() 推到屏幕。这样可以做到「在内存里画好一次性刷出去」,避免边画边闪烁。

五、本篇小结

本篇没写完整 OLED 驱动(要写完得 300 行 +),重点是让你在接 OLED 之前知道三件事:

  1. 认准 4 针 I²C 接口(VCC / GND / SCL / SDA),VCC 只能接 3.3V;
  2. 杜邦线不要太长,否则会出现「不显示 / 显示乱码」;
  3. OLED 驱动库 + 软件 I²C 是入门阶段最友好的组合,硬件 I²C 等之后学 I²C 总线再回头看。

下两篇我们会讲 EXTI 外部中断 和 旋转编码器,把「按键计数」「旋转触发」也玩起来,再回过头把 OLED 接到旋钮上做菜单之类的应用。

六、易错点清单

  1. OLED 接 5V 烧屏:模块板上一般印了 3.3V 和 5V 两个丝印,但 I²C 版本绝大多数只接 3.3V。接 5V 短期可能正常,长期或部分批次直接烧 SSD1306。
  2. 没看清 4 针 / 7 针就焊:7 针的是 SPI 版本(GPIO 引脚定义完全不同)。看清楚丝印和模块上的字「IIC」/「SPI」再选库。
  3. 杜邦线方向插反:模块上 G / V 紧挨着,看反了插反,VCC 接 GND 不一定烧(OLED 抗反接做得不错),但 G 接反会让程序里的低电平 / 高电平与硬件约定反过来——表现是「明明写了 1 但屏幕没反应」。
  4. 想用硬件 I²C 但忘了 remap 引脚:STM32F103 默认 I2C1 是 PB6 / PB7,I2C2 是 PB10 / PB11;如果你的板子把它们 remap 到别的脚,必须先开 AFIO 时钟再 GPIO_PinRemapConfig()。
  5. 不调用 OLED_Clear() 直接显示:上一次显示的内容会留在屏幕上。要么记得刷新前清,要么在 OLED_Refresh() 里覆盖到全 0。
  6. 字模没烧进 flash:想显示汉字需要字模数据(C 文件格式),库没自带时要自己加。PCtoLCD2002 是常用的字模提取工具。

下一篇:03 EXTI 外部中断——原理 + 对射式红外计次