一、项目背景与准备:搞懂核心器件

在开始之前,我们先明确项目的核心目标:通过 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 初始化代码或硬件接线。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐