STM32HAL 快速入门(十二):OLED 屏的使用与显示控制
摘要:本文介绍了STM32通过I2C接口驱动OLED显示屏的实现方法。硬件方面详细说明了4针OLED屏的引脚定义和连接方式,重点讲解了I2C通信协议的基本原理。软件配置部分包含CubeMX中的I2C外设设置、驱动程序的集成与修改,以及解决上拉电阻等常见问题。实战部分展示了静态字符显示、字符串拼接和动态计数功能的具体实现,并提供了示例代码。最后总结了OLED不显示、字符乱码等常见问题的解决方法,为后
前言
大家好,这里是 Hello_Embed。前面我们通过 GPIO 实现了按键、传感器的输入输出控制,本篇将引入 OLED 屏 —— 作为常用的显示外设,它能直观呈现数据(如传感器数值、系统状态)。我们将从硬件连接、CubeMX 配置到驱动使用,一步步实现 OLED 的静态显示与动态计数功能,为后续更复杂的信息展示打基础。下一篇会讲解 “定时器消抖”,进一步优化输入信号处理。
一、OLED 硬件连接与原理
本次使用的是 4 针脚 IIC 通信 OLED 屏(GND、VCC、SCL、SDA),通过 IIC 协议与 STM32 通信,硬件连接需注意引脚分配和电源供给。
1. 引脚定义与连接
- OLED 屏引脚(从左至右):GND(地)、VCC(电源,3.3V)、SCL(时钟线)、SDA(数据线);
- 连接方案:
- SCL 接 PB6,SDA 接 PB7(复用为 IIC1 的时钟线和数据线);
- 额外使用 PB4 接 GND、PB5 接 VCC,通过电阻激活面包板电源轨(方便其他外设供电);
- 整体连接图:

2. IIC 通信简介
IIC(Inter-Integrated Circuit)是一种两线制同步通信协议,通过 SCL(时钟)和 SDA(数据)实现主从设备间的通信。OLED 屏作为从设备,STM32 作为主设备,通过 IIC 协议发送指令和数据,控制 OLED 显示内容。
二、CubeMX 配置 IIC 外设
为使 STM32 的 PB6、PB7 作为 IIC1 接口与 OLED 通信,需在 CubeMX 中配置 IIC 外设:
- 使能 IIC1:
进入 “Connectivity”→“I2C1”,选择 “Mode” 为 “I2C”(标准 IIC 模式);
- 引脚复用配置:
IIC1 默认自动分配 PB6(SCL)和 PB7(SDA),模式为 “Alternate Function Open Drain”(复用开漏)——IIC 协议要求总线使用开漏模式,配合上拉电阻确保电平稳定。 - 生成代码:
配置完成后生成工程,会自动生成 IIC 初始化函数MX_I2C1_Init(),并在main.c中调用。
三、OLED 驱动程序的集成与修改
OLED 的显示逻辑由驱动程序实现,我们直接使用韦东山的 OLED 驱动代码(包含初始化、字符 / 字符串显示等功能),需注意适配硬件和解决编译问题。
1. 驱动文件集成
- 驱动文件:
driver_oled.c、driver_oled.h及字模文件(如oled_font.h),复制到工程的Drivers文件夹下新建的OLED目录; - 在 Keil 中添加文件:
新建 “OLED_Driver” 组,将driver_oled.c添加到组中(其内部会引用其他文件,无需重复添加);
2. 解决上拉电阻问题
IIC 总线需要上拉电阻才能正常工作,但 CubeMX 配置复用开漏模式时默认关闭上下拉,需手动在代码中添加:
在i2c.c的HAL_I2C_MspInit函数中,修改 GPIO 初始化结构体:
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; // PB6(SCL)、PB7(SDA)
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; // 复用开漏模式
GPIO_InitStruct.Pull = GPIO_PULLUP; // 添加上拉电阻(关键)
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
3. 处理代码冲突(可选)
若使用韦东山原版驱动代码出现编译错误(如函数重定义),需修改冲突部分(例如重命名与 HAL 库重复的函数名),确保编译无报错。这里我会将修改后我能够正常使用的驱动文件上传。
四、OLED 显示功能实战
通过驱动程序提供的 API,实现字符、字符串的静态显示,以及动态计数值的展示。
1. 静态显示:字符与字符串
调用OLED_PutChar(显示单个字符)和OLED_PrintString(显示字符串)函数,代码示例:
void OLED_Test(void)
{
OLED_Init(); // 初始化OLED
OLED_Clear(); // 清屏
while (1)
{
// 在(0, 0)位置显示字符'A'(x=0列,y=0行)
OLED_PutChar(0, 0, 'A');
// 在(1, 0)位置显示字符'Y'(x=1列,y=0行)
OLED_PutChar(1, 0, 'Y');
// 在(0, 2)位置显示字符串"Hello World!"(x=0列,y=2行)
OLED_PrintString(0, 2, "Hello World!");
}
}
- 显示原理:OLED 屏按 “页” 和 “列” 划分,一个字符占 16x8 像素(2 页,8 列),整个屏幕可显示 4 行(0~3 页)、每行 16 个字符(0~15 列),坐标示意图:

- 效果:

2. 拼接字符串:利用返回值控制位置
OLED_PrintString返回字符串占用的列数,可用于拼接多个字符串,示例:
void OLED_Test(void)
{
OLED_Init();
OLED_Clear();
char *str1 = "Hello"; // 字符串1
char *str2 = "_Embed"; // 字符串2
int len; // 存储字符串占用的列数
while (1)
{
OLED_PutChar(0, 0, 'A');
OLED_PutChar(1, 0, 'Y');
OLED_PrintString(0, 2, "Hello World!");
// 先显示str1,获取其长度
len = OLED_PrintString(0, 4, str1);
// 从str1结束的位置开始显示str2
OLED_PrintString(len, 4, str2);
}
}
- 效果:“Hello” 和 “_Embed” 在同一行连续显示:

3. 动态显示:简易秒表
通过计数变量和延时函数,实现动态计数值的显示,示例:
void OLED_Test(void)
{
OLED_Init();
OLED_Clear();
char *str1 = "Hello";
char *str2 = "_Embed";
int len; // 总列数
int cnt = 0; // 计数值
while (1)
{
// 显示固定内容
OLED_PutChar(0, 0, 'A');
OLED_PutChar(1, 0, 'Y');
OLED_PrintString(0, 2, "Hello World!");
// 计算字符串总长度
len = OLED_PrintString(0, 4, str1);
len += OLED_PrintString(len, 4, str2);
// 在字符串后显示计数值(空出1列)
OLED_PrintSignedVal(len + 1, 4, cnt);
cnt++; // 计数递增
HAL_Delay(1000); // 延时1秒,避免计数过快
}
}
- 效果:计数值每秒递增,动态显示在字符串后方:

五、常见问题与解决
-
OLED 不显示:
- 检查电源(VCC 需接 3.3V,避免 5V 烧坏屏幕);
- 确认 IIC 引脚连接正确(SCL-PB6,SDA-PB7);
- 手动添加了上拉电阻(CubeMX 默认无上下拉)。
-
字符显示乱码:
- 字模文件与 OLED 分辨率不匹配(需使用 16x8 字模);
- 驱动代码中的 IIC 地址与 OLED 屏匹配(常见地址为 0x78 ,可在驱动中修改)。
结尾
本文通过实战掌握了 OLED 屏的基本使用:从硬件连接、IIC 配置到驱动集成,实现了静态字符显示、字符串拼接和动态计数功能。OLED 作为信息输出的重要载体,后续可用于显示传感器数据(如光敏电阻值)、系统状态等,让开发更直观。
下一篇笔记,我们将学习 “定时器消抖”—— 相比简单的延时消抖,定时器能更高效地处理按键抖动,进一步优化输入信号的可靠性。Hello_Embed 继续带你探索 STM32 的实用功能,敬请期待~
更多推荐



所有评论(0)