[STM32F1] 移植U8G2到STM32,使用I2C接口的SSD1306屏幕

[复制链接]
 楼主| gejigeji521 发表于 2025-6-16 21:09 | 显示全部楼层 |阅读模式
硬件准备
连接方式:

SCL → PB6 (I2C1_SCL)

SDA → PB7 (I2C1_SDA)

VCC → 3.3V

GND → GND

可能需要:

上拉电阻(4.7kΩ)在SCL和SDA线上(如果模块上没有)

软件配置步骤
1. 添加u8g2库到Keil项目
从u8g2仓库复制以下文件到项目目录:

u8g2/csrc/ 下的所有.c文件

u8g2/csrc/u8g2.h

在Keil中添加这些文件到项目

添加头文件路径到项目设置

2. 配置I2C外设(使用STM32CubeMX或手动)
  1. // I2C初始化示例(HAL库)
  2. void MX_I2C1_Init(void)
  3. {
  4.   hi2c1.Instance = I2C1;
  5.   hi2c1.Init.ClockSpeed = 400000; // 400kHz
  6.   hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  7.   hi2c1.Init.OwnAddress1 = 0;
  8.   hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  9.   hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  10.   hi2c1.Init.OwnAddress2 = 0;
  11.   hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  12.   hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  13.   if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  14.   {
  15.     Error_Handler();
  16.   }
  17. }
3. 实现u8g2硬件抽象层
创建u8g2_hal.c文件:
  1. #include "u8g2.h"
  2. #include "stm32f1xx_hal.h"
  3. #include "i2c.h"

  4. extern I2C_HandleTypeDef hi2c1; // 假设使用I2C1

  5. #define I2C_ADDRESS 0x78 // 通常为0x78或0x7A,取决于模块

  6. uint8_t u8x8_byte_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  7. {
  8.   static uint8_t buffer[32]; // 传输缓冲区
  9.   static uint8_t buf_idx;
  10.   uint8_t *data;
  11.   
  12.   switch(msg)
  13.   {
  14.     case U8X8_MSG_BYTE_INIT:
  15.       // 初始化代码
  16.       break;
  17.       
  18.     case U8X8_MSG_BYTE_SEND:
  19.       data = (uint8_t *)arg_ptr;
  20.       while(arg_int > 0)
  21.       {
  22.         buffer[buf_idx++] = *data;
  23.         data++;
  24.         arg_int--;
  25.       }
  26.       break;
  27.       
  28.     case U8X8_MSG_BYTE_START_TRANSFER:
  29.       buf_idx = 0;
  30.       break;
  31.       
  32.     case U8X8_MSG_BYTE_END_TRANSFER:
  33.       if(HAL_I2C_Master_Transmit(&hi2c1, I2C_ADDRESS, buffer, buf_idx, HAL_MAX_DELAY) != HAL_OK)
  34.       {
  35.         return 0;
  36.       }
  37.       break;
  38.       
  39.     default:
  40.       return 0;
  41.   }
  42.   return 1;
  43. }

  44. uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  45. {
  46.   switch(msg)
  47.   {
  48.     case U8X8_MSG_GPIO_AND_DELAY_INIT:
  49.       // 可以初始化GPIO(如果需要)
  50.       break;
  51.       
  52.     case U8X8_MSG_DELAY_MILLI:
  53.       HAL_Delay(arg_int);
  54.       break;
  55.       
  56.     case U8X8_MSG_GPIO_I2C_CLOCK:
  57.     case U8X8_MSG_GPIO_I2C_DATA:
  58.       // 通常不需要处理,硬件I2C自动管理
  59.       break;
  60.       
  61.     default:
  62.       return 0;
  63.   }
  64.   return 1;
  65. }
4. 初始化u8g2并测试显示
  1. #include "u8g2.h"
  2. #include "u8g2_hal.h"

  3. u8g2_t u8g2;

  4. void u8g2_Init(void)
  5. {
  6.   // 使用I2C的SSD1306 128x64非分页模式
  7.   u8g2_Setup_ssd1306_i2c_128x64_noname_f(&u8g2, U8G2_R0,
  8.                                         u8x8_byte_hw_i2c,
  9.                                         u8x8_gpio_and_delay);
  10.   
  11.   u8g2_InitDisplay(&u8g2);
  12.   u8g2_SetPowerSave(&u8g2, 0); // 唤醒显示器
  13.   u8g2_ClearBuffer(&u8g2);
  14. }

  15. void DrawTestScreen(void)
  16. {
  17.   u8g2_ClearBuffer(&u8g2);
  18.   
  19.   u8g2_SetFont(&u8g2, u8g2_font_6x10_tr);
  20.   u8g2_DrawStr(&u8g2, 0, 10, "STM32F103 + SSD1306");
  21.   
  22.   u8g2_SetFont(&u8g2, u8g2_font_unifont_t_symbols);
  23.   u8g2_DrawGlyph(&u8g2, 20, 35, 0x2603); // 雪人图标
  24.   
  25.   u8g2_SetFont(&u8g2, u8g2_font_7x14B_tr);
  26.   u8g2_DrawStr(&u8g2, 40, 60, "u8g2");
  27.   
  28.   u8g2_SendBuffer(&u8g2);
  29. }

  30. int main(void)
  31. {
  32.   HAL_Init();
  33.   SystemClock_Config();
  34.   MX_I2C1_Init();
  35.   
  36.   u8g2_Init();
  37.   DrawTestScreen();
  38.   
  39.   while(1)
  40.   {
  41.     // 主循环
  42.   }
  43. }
常见问题解决
显示器无反应:

检查I2C地址是否正确(尝试0x78或0x7A)

确认I2C线路上有上拉电阻

用逻辑分析仪检查I2C信号

显示内容错乱:

降低I2C时钟速度(如100kHz)

检查电源稳定性

内存不足:

改用页缓冲模式(将_f改为_1或_2):
  1. u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, ...);
然后使用u8g2_FirstPage()和u8g2_NextPage()函数


 楼主| gejigeji521 发表于 2025-6-16 21:09 | 显示全部楼层
优化建议
减少内存使用:

使用页缓冲模式(_1或_2后缀)

移除不需要的字体和驱动

提高性能:

使用DMA传输(需要修改I2C发送函数)

只更新显示变化的部分

添加旋转支持:

修改U8G2_R0参数为U8G2_R1, U8G2_R2或U8G2_R3实现不同方向的旋转
您需要登录后才可以回帖 登录 | 注册

本版积分规则

195

主题

2460

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部

195

主题

2460

帖子

8

粉丝
快速回复 在线客服 返回列表 返回顶部