当前位置: 首页 > news >正文

STM32F103C8T6上跑u8g2图形库?手把手教你用HAL库+模拟IIC点亮OLED屏

STM32F103C8T6上跑u8g2图形库?手把手教你用HAL库+模拟IIC点亮OLED屏

在嵌入式开发领域,STM32F103C8T6这款被称为"蓝桥杯神器"的MCU因其性价比和易用性广受欢迎。而u8g2作为一款功能强大的嵌入式图形库,能够为各种OLED显示屏提供丰富的图形界面支持。本文将带你从零开始,在STM32F103C8T6上使用HAL库和模拟IIC接口驱动0.96寸OLED显示屏(SSD1306控制器),特别针对这款MCU的RAM资源有限的特点进行优化。

1. 开发环境准备与硬件连接

1.1 所需硬件清单

在开始之前,确保你已准备好以下硬件组件:

  • STM32F103C8T6最小系统板(核心资源:72MHz主频,64KB Flash,20KB RAM)
  • 0.96寸OLED显示屏(SSD1306驱动芯片,128×64分辨率)
  • 杜邦线若干(建议使用优质线材减少干扰)
  • USB转TTL模块(用于程序下载和调试)

1.2 硬件连接方式

OLED与STM32的连接非常简单,只需要4根线:

OLED引脚STM32引脚功能说明
VCC3.3V电源正极
GNDGND电源地
SCLPB6时钟线
SDAPB7数据线

提示:虽然理论上可以任意选择GPIO引脚,但建议优先使用PB6/PB7,因为这两个引脚在硬件I2C模式下也有对应功能,方便后续扩展。

1.3 开发环境配置

推荐使用以下开发工具组合:

  1. STM32CubeMX:用于初始化代码生成(版本建议≥6.0)
  2. Keil MDK-ARM:作为主要开发IDE(建议使用V5.25以上版本)
  3. ST-Link Utility:用于程序烧录和调试

在CubeMX中创建新工程时,关键配置步骤如下:

/* System Core配置 */ RCC-> High Speed Clock (HSE): Crystal/Ceramic Resonator SYS-> Debug: Serial Wire GPIO-> PB6: GPIO_Output (重命名为OLED_SCL) GPIO-> PB7: GPIO_Output (重命名为OLED_SDA)

2. u8g2库的移植与优化

2.1 获取u8g2源码

u8g2的最新源码可以从GitHub获取:

git clone https://github.com/olikraus/u8g2.git

或者直接下载zip压缩包。我们主要需要的是csrc目录下的核心源文件。

2.2 精简u8g2库以节省内存

STM32F103C8T6仅有20KB RAM,而完整版u8g2会占用较多内存。我们需要进行以下优化:

  1. 删除不必要的显示驱动: 在u8g2_d_setup.c中,只保留与SSD1306相关的代码,其他全部注释掉。

  2. 选择合适的内存模式: u8g2提供多种内存模式,针对小内存MCU推荐使用page buffer模式:

    // 使用页缓冲模式(相比全缓冲节省约1KB内存) u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_gpio_and_delay_stm32);
  3. 修改u8g2_d_memory.c: 注释掉所有未使用的全局变量定义,仅保留SSD1306相关部分。

2.3 关键回调函数实现

u8g2需要通过回调函数与硬件交互,以下是针对STM32HAL库的实现:

uint8_t u8x8_gpio_and_delay_stm32(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; case U8X8_MSG_GPIO_I2C_CLOCK: HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET); break; case U8X8_MSG_GPIO_I2C_DATA: HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, arg_int ? GPIO_PIN_SET : GPIO_PIN_RESET); break; default: return 0; } return 1; }

3. 模拟I2C驱动实现

3.1 I2C时序控制

模拟I2C需要精确控制时序,以下是关键时序参数:

时序参数典型值说明
起始条件保持时间4.7μsSDA下降沿到SCL下降沿
数据保持时间4.0μsSCL高电平期间数据稳定
停止条件建立时间4.0μsSCL上升沿到SDA上升沿

对应的延时函数实现:

void I2C_Delay(void) { volatile uint8_t i = 5; while(i--); } void I2C_Start(void) { SDA_HIGH(); SCL_HIGH(); I2C_Delay(); SDA_LOW(); I2C_Delay(); SCL_LOW(); } void I2C_Stop(void) { SDA_LOW(); SCL_HIGH(); I2C_Delay(); SDA_HIGH(); }

3.2 完整数据传输函数

以下是带ACK检查的字节发送函数:

uint8_t I2C_WriteByte(uint8_t byte) { uint8_t i, ack; for(i=0; i<8; i++) { if(byte & 0x80) SDA_HIGH(); else SDA_LOW(); SCL_HIGH(); I2C_Delay(); SCL_LOW(); byte <<= 1; } // 读取ACK SDA_HIGH(); SCL_HIGH(); ack = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7); SCL_LOW(); return ack; // 0表示ACK, 1表示NACK }

4. 实际应用与性能优化

4.1 显示性能测试

在72MHz主频下,不同刷新模式的性能对比:

刷新模式全屏刷新时间内存占用适用场景
全缓冲模式15ms1KB复杂动画
页缓冲模式25ms128B文本显示
直接写入模式120ms0B极低内存环境

4.2 常用显示功能实现

显示文本

u8g2_SetFont(&u8g2, u8g2_font_6x10_tf); u8g2_DrawStr(&u8g2, 0, 10, "Hello STM32!");

绘制图形

// 画线 u8g2_DrawLine(&u8g2, 0, 0, 127, 63); // 画矩形 u8g2_DrawFrame(&u8g2, 10, 10, 50, 20); // 画圆 u8g2_DrawCircle(&u8g2, 64, 32, 20, U8G2_DRAW_ALL);

显示位图

static const uint8_t logo_bits[] = { 0x00, 0x00, 0x1F, 0x80, 0x20, 0x40, 0x40, 0x20, // 更多位图数据... }; u8g2_DrawXBM(&u8g2, 30, 20, 32, 32, logo_bits);

4.3 内存优化技巧

  1. 使用PROGMEM存储字体: 将不常用的字体存储在Flash而非RAM中:

    static const uint8_t font_data[] U8G2_FONT_SECTION("font_data") = {...};
  2. 动态加载字体: 只在需要时加载特定字体,使用后立即释放:

    u8g2_SetFont(&u8g2, u8g2_font_6x10_tf); // 显示操作... u8g2_SetFont(&u8g2, NULL); // 释放字体
  3. 使用u8x8模式: 如果只需要显示文本,可以使用更轻量的u8x8模式:

    u8x8_Setup(&u8x8, u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_i2c, u8x8_byte_sw_i2c, u8x8_gpio_and_delay_stm32);

在实际项目中,我发现合理组合这些优化技巧,可以在STM32F103C8T6上实现相当流畅的图形界面效果。特别是在使用页缓冲模式时,配合精心设计的局部刷新策略,完全可以满足大多数嵌入式GUI的需求。

http://www.jsqmd.com/news/590253/

相关文章:

  • OpenClaw硬件兼容清单:Qwen3-32B镜像适配显卡全测试
  • Qwen3-14B集成IDEA开发环境:Java大模型应用快速构建指南
  • 零基础玩转OFA视觉蕴含模型:手把手教你搭建智能图文审核系统
  • HG-ha/MTools效果展示:AI实时字幕+发言者分离+重点语句自动标亮
  • 手把手教你用uniapp插件搞定高德地图后台定位(支持息屏保活和坐标转换)
  • Pixel Mind Decoder 构建自动化工作流:与Zapier/Make等工具集成
  • Pixel Couplet Gen 集成SpringBoot实战:打造智能春联生成API服务
  • Nunchaku-flux-1-dev在Dify平台上的无缝集成应用
  • Unity2021升级踩坑记:手把手教你解决Android/res文件夹打包报错(附完整Android Library创建流程)
  • Comsol与Matlab协同优化:基于遗传算法的低频宽带吸声结构设计
  • Realistic Vision V5.1实战:电商模特图、小说配图、头像壁纸一键生成
  • CogVideoX-2b部署经验:多卡环境下负载均衡配置方法
  • Intv_AI_MK11远程开发实践:通过MobaXterm连接GPU服务器进行模型调试
  • Qwen3-VL-8B支持多场景扩展:轻松接入RAG、插件系统与企业身份认证
  • LiteLLM Proxy:简化大模型API接口的统一接入与管理
  • KEIL编译报错全解析:从常见问题到高效解决策略
  • Qwen3-14B私有化部署实战:一键启动WebUI和API,小白也能快速上手
  • 从HiFi到ONT:手把手教你构建T2T基因组的完整测序策略
  • PyTorch 2.8 镜像部署MySQL:管理AI实验元数据与数据集
  • vLLM-v0.11.0资源配额设置:防止一人占用,全员瘫痪
  • 小白也能玩转Qwen3-TTS:用自然语言描述生成专属语音的保姆级指南
  • Pixel Fashion Atelier保姆级教程:从Docker Pull到Forge!按钮点击的完整链路
  • InstructPix2Pix实现LaTeX文档图像自动处理
  • 别再只盯着GNN了!用Transformer和图注意力网络搞定DTI预测,保姆级代码解读
  • Android13 BLE扫描不到设备?三星S22 Ultra用户必看的解决方案
  • GME多模态向量-Qwen2-VL-2B:5分钟快速上手,解锁跨模态搜索新姿势
  • 千问3.5-9B YOLOv5目标检测项目集成:智能标注与结果分析
  • Nanobot性能基准测试:OpenClaw在不同硬件上的表现对比
  • PROJECT MOGFACE代码解释器效果:复杂Python源码逐行分析与注释
  • Pi0机器人控制中心性能评测:不同GPU型号下动作预测吞吐量与延迟对比