一、实验目的
掌握STM32F103通过I2C接口驱动OLED显示屏的方法
学习U8g2图形库的移植和使用
实现多种显示效果:学号姓名显示、滑动动画、图形绘制
了解I2C通信协议及调试方法
U8g2库开源网址:https://github.com/olikraus/u8g2
二、实验环境
2.1 硬件环境
主控芯片:STM32F103C8T6
OLED显示屏:0.96寸SSD1306,I2C接口
接口连接:
SCL → PB10
SDA → PB11
VCC → 3.3V
GND → GND
2.2 软件环境
开发环境:STM32CubeMX + Keil MDK
图形库:U8g2
调试工具:逻辑分析仪
三、实验原理
3.1 OLED显示原理
OLED(Organic Light-Emitting Diode)是有机发光二极管,具有自发光特性,不需要背光。SSD1306控制器支持128×64分辨率,通过I2C协议进行通信。
3.2 I2C通信协议
I2C(Inter-Integrated Circuit)是一种同步、多主从的串行总线,包含:
SCL:时钟线
SDA:数据线
7位设备地址:0x78(OLED地址)
3.3 U8g2图形库
U8g2是嵌入式设备的单色图形库,支持多种显示器控制器,提供丰富的绘图API。
四、实验步骤
4.1 CubeMX配置
时钟配置
HSE:8MHz
PLL倍频:9倍
系统时钟:72MHz
I2C配置
使用I2C2
标准模式(100kHz)
SCL:PB10
SDA:PB11
生成代码
生成HAL库基础框架
4.2 U8g2库移植
4.2.1准备U8g2库文件
移植U8g2图像库需要准备好,U8g2的源码是在GitHub上开源的。
U8g2下载地址: https://github.com/olikraus/u8g2
进入源码地址后下载整个U8g2图形库的压缩包。
————————————————
原文链接:https://blog.csdn.net/black_sneak/article/details/126312657
4.2.2将精简后的U8g2库添加至Keil
// stm32_u8g2.c
uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
static uint8_t buffer[32];
static uint8_t buf_idx;
uint8_t *data;
switch(msg)
{
case U8X8_MSG_BYTE_SEND:
data = (uint8_t *)arg_ptr;
while(arg_int > 0)
{
buffer[buf_idx++] = *data;
data++;
arg_int--;
}
break;
case U8X8_MSG_BYTE_START_TRANSFER:
buf_idx = 0;
break;
case U8X8_MSG_BYTE_END_TRANSFER:
HAL_I2C_Master_Transmit(&hi2c2, 0x78, buffer, buf_idx, 1000);
break;
default:
return 0;
}
return 1;
}
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
switch(msg)
{
case U8X8_MSG_DELAY_MILLI:
HAL_Delay(arg_int);
break;
default:
return 0;
}
return 1;
}
void u8g2Init(u8g2_t *u8g2)
{
u8g2_Setup_ssd1306_i2c_128x64_noname_f(u8g2, U8G2_R0, u8x8_byte_hw_i2c, u8x8_gpio_and_delay);
u8g2_InitDisplay(u8g2);
u8g2_SetPowerSave(u8g2, 0);
}
4.3 显示功能实现
主程序框架:
// main.c
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C2_Init();
u8g2_t u8g2;
u8g2Init(&u8g2);
while(1)
{
u8g2_FirstPage(&u8g2);
do {
u8g2DrawTest(&u8g2); // 主要显示函数
} while(u8g2_NextPage(&u8g2));
}
}
五、功能实现与代码分析
5.1 三模式切换显示
void testMyDisplay(u8g2_t *u8g2)
{
static uint8_t mode = 0;
static uint32_t last_change = 0;
// 3秒自动切换模式
if(HAL_GetTick() - last_change > 3000) {
mode = (mode + 1) % 3;
last_change = HAL_GetTick();
}
u8g2_ClearBuffer(u8g2);
switch(mode) {
case 0:
// 模式0:大字体显示学号
u8g2_SetFont(u8g2, u8g2_font_ncenB18_tr);
u8g2_DrawStr(u8g2, 5, 35, "632307030613");
break;
case 1:
// 模式1:显示中文名字
u8g2_SetFont(u8g2, u8g2_font_ncenB14_tr);
u8g2_DrawStr(u8g2, 30, 35, "扎西坚才");
break;
case 2:
// 模式2:同时显示学号和名字
u8g2_SetFont(u8g2, u8g2_font_ncenB12_tr);
u8g2_DrawStr(u8g2, 15, 25, "632307030613");
u8g2_SetFont(u8g2, u8g2_font_ncenB10_tr);
u8g2_DrawStr(u8g2, 40, 45, "扎西坚才");
break;
}
}
5.2 滑动动画效果
void slideAnimation(u8g2_t *u8g2)
{
// 文字从右侧滑入
for(int x = 128; x >= 0; x -= 2) {
u8g2_ClearBuffer(u8g2);
u8g2_SetFont(u8g2, u8g2_font_ncenB12_tr);
u8g2_DrawStr(u8g2, x, 32, "滑动显示效果");
u8g2_SendBuffer(u8g2);
HAL_Delay(30);
}
// 文字向上滑动消失
for(int y = 32; y >= -20; y -= 2) {
u8g2_ClearBuffer(u8g2);
u8g2_SetFont(u8g2, u8g2_font_ncenB12_tr);
u8g2_DrawStr(u8g2, 0, y, "向上滑动");
u8g2_SendBuffer(u8g2);
HAL_Delay(30);
}
}
5.3 图形绘制与动态效果
void drawGraphics(u8g2_t *u8g2)
{
// 绘制基本图形
u8g2_ClearBuffer(u8g2);
// 绘制矩形框
u8g2_DrawFrame(u8g2, 10, 10, 50, 30);
// 绘制填充圆
u8g2_DrawDisc(u8g2, 90, 25, 15, U8G2_DRAW_ALL);
// 绘制三角形
u8g2_DrawTriangle(u8g2, 30, 50, 50, 30, 70, 50);
// 绘制线条
u8g2_DrawLine(u8g2, 5, 5, 120, 60);
u8g2_SendBuffer(u8g2);
HAL_Delay(2000);
}
void dynamicSmile(u8g2_t *u8g2)
{
// 动态笑脸动画
for(int i = 0; i < 5; i++) {
u8g2_ClearBuffer(u8g2);
// 绘制脸型
u8g2_DrawCircle(u8g2, 64, 32, 25, U8G2_DRAW_ALL);
// 眼睛
u8g2_DrawDisc(u8g2, 50, 25, 4, U8G2_DRAW_ALL);
u8g2_DrawDisc(u8g2, 78, 25, 4, U8G2_DRAW_ALL);
// 动态嘴巴
if(i % 2 == 0) {
// 直线嘴巴
u8g2_DrawLine(u8g2, 50, 40, 78, 40);
} else {
// 微笑嘴巴
u8g2_DrawCircle(u8g2, 64, 40, 12, U8G2_DRAW_UPPER_LEFT | U8G2_DRAW_UPPER_RIGHT);
}
u8g2_SendBuffer(u8g2);
HAL_Delay(500);
}
}
5.4 进度条显示
void progressBar(u8g2_t *u8g2)
{
for(int i = 0; i <= 100; i += 5) {
u8g2_ClearBuffer(u8g2);
// 显示标题
u8g2_SetFont(u8g2, u8g2_font_ncenB10_tr);
u8g2_DrawStr(u8g2, 10, 15, "Loading...");
// 绘制进度条边框
u8g2_DrawRFrame(u8g2, 10, 25, 100, 15, 3);
// 绘制进度条填充
u8g2_DrawRBox(u8g2, 10, 25, i, 15, 3);
// 显示百分比
char percent[10];
sprintf(percent, "%d%%", i);
u8g2_DrawStr(u8g2, 115, 38, percent);
u8g2_SendBuffer(u8g2);
HAL_Delay(100);
}
}
六、I2C通信分析
6.1 波形特征分析
使用逻辑分析仪捕获的I2C波形显示:
起始条件:SCL为高电平时,SDA出现下降沿
设备地址:0x78(写模式)
数据传送:每个字节后跟随ACK位
停止条件:SCL为高电平时,SDA出现上升沿
6.2 通信数据格式
开始 → 设备地址(0x78) → 控制字节(0x00) → 显示数据 → 停止
6.3 调试方法
逻辑分析仪:直接捕获硬件I2C波形
软件模拟:使用GPIO模拟I2C便于调试
串口打印:输出调试信息验证通信状态
七、实验结果
7.1 显示效果
嵌入式2
7.2 性能指标
显示刷新率:约30fps
模式切换间隔:3秒
动画流畅度:良好
内存占用:优化合理
八、实验总结
8.1 技术要点
U8g2库移植:成功将U8g2库移植到STM32F103平台
I2C驱动:实现了稳定的硬件I2C通信
显示优化:通过页面刷新机制提高显示效率
动画实现:掌握了嵌入式系统中的动画编程技巧
8.2 遇到的问题及解决方案
问题:初始显示乱码
解决:检查I2C地址配置,确认使用0x78
问题:显示刷新闪烁
解决:使用u8g2的页面刷新机制,减少闪烁
问题:中文字符显示异常
解决:使用合适的字体或点阵显示中文
8.3 创新点
实现了多种显示模式的自动切换
结合了静态显示和动态动画效果
优化了显示性能,提高了用户体验
九、附录
9.1 源代码结构
Project/
├── Core/
│ ├── main.c
│ ├── stm32_u8g2.c
│ └── test.c
├── Drivers/
└── U8g2/
└── u8g2库文件
9.2 参考资料
STM32F103 Reference Manual
U8g2 Library Documentation
SSD1306 Datasheet
I2C Protocol Specification
感谢友情链接https://blog.csdn.net/black_sneak/article/details/126312657
————————————————
版权声明:本文为CSDN博主「བཀྲིས་」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/2301_79825245/article/details/154251730
|