STM32F103驱动OLED屏全流程解析
本文详细介绍了基于STM32F103驱动0.96寸OLED屏幕的实现过程。主要内容包括:硬件准备(STM32最小系统板、OLED屏及工具)、I2C协议原理和U82G库特点;硬件接线注意事项(3.3V供电不可接5V);CubeMX配置步骤(I2C、SYS和时钟设置);Keil工程中添加U82G源码;编写HAL库对接代码和显示功能实现(Demo、个人信息、滑动效果和动态图案);最后给出调试方法和常见问
一、项目背景与准备:搞懂核心器件
在开始之前,我们先明确项目的核心目标:通过 STM32F103 的 I2C 外设,基于 U82G 库驱动 0.96 寸 OLED 屏,实现 Demo 演示、个人信息显示、滑动效果和动态图案。
1. 核心器件清单
- 主控芯片:STM32F103C8T6 最小系统板(性价比高,适合入门)
- 显示模块:0.96 寸 I2C 接口 OLED 屏(分辨率 128*64,默认 I2C 地址 0x78,注意区分 4 针 / 7 针,这里用 4 针款)
- 辅助工具:ST-Link 下载器(用于程序下载和调试)、杜邦线(建议用带颜色的,方便区分引脚)、电脑(安装 CubeMX、Keil5)
2. 关键原理提前懂
- I2C 协议:双总线(SCL 时钟线、SDA 数据线),主从通信模式,OLED 屏作为从设备,STM32 作为主设备发送指令和数据。
- U82G 库:轻量级开源 GUI 库,支持多种 OLED/LCD 屏,封装了丰富的显示接口(文字、图形、动画),无需手动写复杂的时序代码。
- OLED 显示原理:通过控制像素点的亮灭显示内容,汉字需通过点阵编码实现,U82G 已内置常用字体,可直接调用。
二、硬件接线:关键!接错会烧屏
这一步是基础中的基础,0.96 寸 OLED 屏的供电是 3.3V,绝对不能接 5V,否则会直接烧毁屏幕!我第一次调试时就因为误接 5V,屏幕直接报废,大家一定要注意。
接线对照表(STM32F103C8T6 ↔ OLED 屏)
|
STM32F103 引脚 |
OLED 屏引脚 |
功能说明 |
注意事项 |
|
VCC(3.3V) |
VCC |
供电 |
必须 3.3V,不可接 5V |
|
GND |
GND |
共地 |
确保与 STM32 共地,避免干扰 |
|
PB6 |
SCL |
I2C 时钟线 |
可选择 I2C1 的 PB6,也可换 I2C2 引脚 |
|
PB7 |
SDA |
I2C 数据线 |
需与 SCL 对应同一 I2C 外设 |
接线时建议用杜邦线按颜色区分:红色接 VCC、黑色接 GND、蓝色接 SCL、白色接 SDA,后续排查问题时更清晰。接好后别急着通电,再核对一遍引脚,确认无误后再连接 ST-Link。
三、CubeMX 配置:生成 HAL 库框架
CubeMX 是 STM32 的可视化配置工具,能快速生成 HAL 库代码,省去手动写外设初始化的麻烦。这里我们重点配置 I2C、SYS 和时钟,步骤如下:
1. 新建工程与选择芯片
- 打开 CubeMX,点击「New Project」,在搜索框输入「STM32F103C8T6」,选中芯片后点击「Start Project」。
2. 配置 SYS(调试模式)
- 进入「Pinout & Configuration」→「SYS」,在「Debug」选项中选择「Serial Wire」。这一步很重要,若不配置,后续 ST-Link 无法下载和调试程序。
3. 配置 I2C 外设(核心步骤)
- 展开「Connectivity」→「I2C1」,将模式设为「I2C Master Mode」(主模式)。
- 点击「Parameter Settings」,「I2C Clock Speed」设为「100kHz」(OLED 屏默认支持的标准 I2C 速率,若设为 400kHz 可能导致通信失败)。
- 右侧引脚图会自动关联 PB6(SCL)和 PB7(SDA),若未关联,手动在引脚下拉菜单中选择对应引脚,并确保引脚模式为「Alternate function open-drain」(开漏输出,I2C 协议要求)。
4. 配置时钟(确保外设正常工作)
- 进入「Clock Configuration」,HSE(外部晶振)选择「Crystal/Ceramic Resonator」(STM32F103C8T6 最小系统板通常带 8MHz 外部晶振)。
- 手动配置时钟树:将 HCLK(系统时钟)设为 72MHz(STM32F103 的最大主频,能保证外设稳定运行),I2C 外设时钟会自动匹配为 100kHz,点击「OK」保存。
5. 生成代码
- 进入「Project Manager」→「Project」,设置工程名称(如「OLED_U82G_Project」)、保存路径(避免中文路径,否则 Keil 可能报错),Toolchain/IDE 选择「MDK-ARM」。
- 进入「Code Generator」,勾选「Generate peripheral initialization as a pair of .c/.h files per peripheral」(将外设初始化代码分开到独立的.c/.h 文件,代码结构更清晰)。
- 点击「GENERATE CODE」,生成完成后关闭 CubeMX,此时会得到一个完整的 HAL 库工程框架。
四、Keil 工程配置:添加 U82G 源码
接下来需要将 U82G 库的核心文件添加到 Keil 工程中,并配置头文件路径,确保编译器能找到相关文件。
1. 下载 U82G 源码
- 从 U82G 官网(https://github.com/olikraus/u8g2)下载源码,解压后进入「csrc」文件夹,我们只需要 4 个核心文件:u8g2.h、u8g2.c、u8x8.h、u8x8.c(其他文件是针对不同平台的适配代码,STM32 用不到,可删除以减小工程体积)。
2. 添加文件到 Keil 工程
- 打开 Keil 工程(工程文件夹下的「OLED_U82G_Project.uvprojx」文件)。
- 右键工程名称→「Manage Project Items」,在「Groups」栏点击「Add」,新建一个分组「U82G_LIB」(用于存放 U82G 库文件),点击「OK」。
- 右键「U82G_LIB」分组→「Add Existing Files to Group 'U82G_LIB'」,选中刚才下载的 4 个核心文件,点击「Add」→「Close」。
3. 配置头文件路径
- 点击 Keil 工具栏的「魔术棒」(Options for Target)→「C/C++」→「Include Paths」右侧的「...」按钮。
- 在弹出的窗口中点击「New」,添加 U82G 源码所在的文件夹路径(例如「E:\STM32_Projects\OLED_U82G_Project\U82G_Src」),点击「OK」保存。这一步若遗漏,编译器会报「头文件找不到」的错误。
五、代码修改:对接 HAL 库与实现显示功能
这是整个移植过程的核心,需要编写 U82G 与 HAL 库 I2C 的对接函数,再在主函数中实现具体的显示功能(Demo、个人信息、滑动、动态图案)。
1. 新建 U82G HAL 对接文件(u8g2_hal.c)
- 在 Keil 工程的「Src」文件夹下,右键→「Add New Item to Group 'Src'」,选择「C File (.c)」,命名为「u8g2_hal.c」,点击「Add」。
- 复制以下代码到文件中,关键是替换 I2C 句柄(hi2c1),如果你的 I2C 外设是 I2C2,就改为 hi2c2:
#include "u8g2.h"
#include "stm32f1xx_hal.h"
// 声明STM32的I2C句柄(需与CubeMX生成的一致,这里用I2C1)
extern I2C_HandleTypeDef hi2c1;
/**
* @brief U82G I2C发送函数(对接STM32 HAL库)
* @param u8g2:U82G设备结构体
* @param addr:I2C从设备地址(OLED屏默认0x78)
* @param data:要发送的数据(包含命令/数据标志)
* @param len:数据长度
* @retval 0:成功,其他:失败
*/
uint8_t u8g2_hal_i2c_send(u8g2_t *u8g2, uint8_t addr, uint8_t *data, uint16_t len)
{
// HAL_I2C_Master_Transmit:HAL库I2C发送函数,超时时间100ms
return HAL_I2C_Master_Transmit(&hi2c1, addr, data, len, 100);
}
/**
* @brief U82G I2C接收函数(OLED显示暂用不到,空实现)
* @param 参数同发送函数
* @retval 0:成功
*/
uint8_t u8g2_hal_i2c_recv(u8g2_t *u8g2, uint8_t addr, uint8_t *data, uint16_t len)
{
return HAL_I2C_Master_Receive(&hi2c1, addr, data, len, 100);
}
/**
* @brief U82G延迟函数(对接HAL库延迟)
* @param ms:延迟时间(毫秒)
*/
void u8g2_hal_delay(uint32_t ms)
{
HAL_Delay(ms);
}
/**
* @brief U82G初始化回调函数(绑定I2C和延迟函数)
* @param u8g2:U82G设备结构体
*/
void u8g2_hal_init(u8g2_t *u8g2)
{
u8g2->cb_i2c_send = u8g2_hal_i2c_send;
u8g2->cb_i2c_recv = u8g2_hal_i2c_recv;
u8g2->cb_delay_ms = u8g2_hal_delay;
}
2. 修改 main.c:实现显示功能
- 在main.c的顶部添加 U82G 头文件和全局变量:
#include "u8g2.h"
// 定义U82G设备结构体(全局变量,方便在各函数中调用)
u8g2_t u8g2;
- 在main()函数中,MX_I2C1_Init ();` 之后,添加 U82G 初始化代码(初始化 OLED 屏):
/* U82G初始化:配置OLED型号、I2C地址、显示方向 */
// u8g2_Setup_ssd1306_i2c_128x64_noname_f:0.96寸OLED屏(SSD1306驱动)配置函数
// U8G2_R0:显示方向(0度,即正常显示)
u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0);
u8g2_hal_init(&u8g2); // 绑定HAL库函数
u8g2_InitDisplay(&u8g2); // 初始化OLED显示
u8g2_SetPowerSave(&u8g2, 0); // 唤醒屏幕(0=唤醒,1=休眠)
- 在while(1)循环中,添加 4 个显示功能的代码(循环执行,每个功能停留 2 秒):
while (1)
{
/* 1. 显示U82G Demo(文字+图形) */
u8g2_ClearBuffer(&u8g2); // 清屏(清空缓冲区,避免残影)
u8g2_SetFont(&u8g2, u8g2_font_ncenB08_tr); // 设置字体(8号字,无加粗)
u8g2_DrawStr(&u8g2, 0, 10, "U82G Demo"); // 显示字符串(x=0, y=10)
u8g2_DrawCircle(&u8g2, 64, 32, 20, U8G2_DRAW_ALL); // 画圆(中心x=64,y=32,半径20)
u8g2_DrawLine(&u8g2, 0, 50, 127, 50); // 画横线(从x=0,y=50到x=127,y=50)
u8g2_SendBuffer(&u8g2); // 刷新缓冲区数据到OLED屏
HAL_Delay(2000); // 停留2秒
/* 2. 显示个人信息(学号+名字/昵称) */
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_ncenB12_tr); // 12号加粗字体,显示更清晰
u8g2_DrawStr(&u8g2, 10, 20, "ID: 20240001"); // 替换为你的学号
u8g2_DrawStr(&u8g2, 10, 40, "Name: TechBlog"); // 替换为你的名字/昵称
u8g2_SendBuffer(&u8g2);
HAL_Delay(2000);
/* 3. 左右滑动显示(通过偏移x坐标实现) */
static int16_t x_offset = 0; // x轴偏移量(全局静态变量,每次循环保持值)
for (x_offset = 0; x_offset > -60; x_offset -= 2) // 向左滑动(x从0到-60)
{
u8g2_ClearBuffer(&u8g2);
u8g2_SetFont(&u8g2, u8g2_font_ncenB10_tr);
u8g2_DrawStr(&u8g2, x_offset, 32, "Sliding Text!"); // 文字随x_offset偏移
u8g2_SendBuffer(&u8g2);
HAL_Delay(50); // 控制滑动速度(值越小越快)
}
HAL_Delay(1000); // 滑动结束后停留1秒
/* 4. 动态图案(闪烁的正方形) */
static uint8_t blink_flag = 0; // 闪烁标志(0=实心,1=空心)
for (uint8_t i = 0; i < 5; i++) // 闪烁5次
{
u8g2_ClearBuffer(&u8g2);
if (blink_flag == 0)
{
u8g2_DrawBox(&u8g2, 50, 20, 30, 30); // 画实心正方形(x=50,y=20,宽30,高30)
blink_flag = 1;
}
else
{
u8g2_DrawFrame(&u8g2, 50, 20, 30, 30); // 画空心正方形
blink_flag = 0;
}
u8g2_SendBuffer(&u8g2);
HAL_Delay(500); // 闪烁间隔500ms
}
}
六、下载与调试:解决常见问题
代码编写完成后,就可以下载到 STM32 中调试了。这里分享几个常见问题的解决方法,帮你快速定位问题。
1. 配置 ST-Link 下载参数
- 点击 Keil 工具栏的「Debug」按钮,进入调试模式。
- 打开「Logic Analyzer」(逻辑分析仪,用于查看 I2C 波形),点击「Setup」→「Add」,添加 SDA 和
SCL 引脚的监测:在「Signal」栏输入 “SDA”,「Pin」选择 “PB7”(对应我们接线的 SDA 引脚);再添加一个 “STC” 信号,「Pin」选择 “PB6”,点击「OK」保存配置。
- 回到调试界面,点击「Run」按钮运行程序,同时点击逻辑分析仪的「Start」按钮开始采集波形。正常情况下,会看到周期性的 I2C 波形:起始信号(SDA 从高变低时,SCL 保持高电平)→ 8 位数据位(SCL 高电平时 SDA 电平稳定,代表 1 或 0)→ 应答信号(SDA 被拉低,持续一个 SCL 周期)→ 停止信号(SDA 从低变高时,SCL 保持高电平)。若看不到波形,需检查 I2C 初始化代码或硬件接线。
更多推荐



所有评论(0)