硬件准备
连接方式:
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或手动)
- // I2C初始化示例(HAL库)
- void MX_I2C1_Init(void)
- {
- hi2c1.Instance = I2C1;
- hi2c1.Init.ClockSpeed = 400000; // 400kHz
- hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
- hi2c1.Init.OwnAddress1 = 0;
- hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
- hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
- hi2c1.Init.OwnAddress2 = 0;
- hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
- hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
- if (HAL_I2C_Init(&hi2c1) != HAL_OK)
- {
- Error_Handler();
- }
- }
3. 实现u8g2硬件抽象层
创建u8g2_hal.c文件:
- #include "u8g2.h"
- #include "stm32f1xx_hal.h"
- #include "i2c.h"
- extern I2C_HandleTypeDef hi2c1; // 假设使用I2C1
- #define I2C_ADDRESS 0x78 // 通常为0x78或0x7A,取决于模块
- 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_INIT:
- // 初始化代码
- break;
-
- 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:
- if(HAL_I2C_Master_Transmit(&hi2c1, I2C_ADDRESS, buffer, buf_idx, HAL_MAX_DELAY) != HAL_OK)
- {
- return 0;
- }
- 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_GPIO_AND_DELAY_INIT:
- // 可以初始化GPIO(如果需要)
- break;
-
- case U8X8_MSG_DELAY_MILLI:
- HAL_Delay(arg_int);
- break;
-
- case U8X8_MSG_GPIO_I2C_CLOCK:
- case U8X8_MSG_GPIO_I2C_DATA:
- // 通常不需要处理,硬件I2C自动管理
- break;
-
- default:
- return 0;
- }
- return 1;
- }
4. 初始化u8g2并测试显示
- #include "u8g2.h"
- #include "u8g2_hal.h"
- u8g2_t u8g2;
- void u8g2_Init(void)
- {
- // 使用I2C的SSD1306 128x64非分页模式
- 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); // 唤醒显示器
- u8g2_ClearBuffer(&u8g2);
- }
- void DrawTestScreen(void)
- {
- u8g2_ClearBuffer(&u8g2);
-
- u8g2_SetFont(&u8g2, u8g2_font_6x10_tr);
- u8g2_DrawStr(&u8g2, 0, 10, "STM32F103 + SSD1306");
-
- u8g2_SetFont(&u8g2, u8g2_font_unifont_t_symbols);
- u8g2_DrawGlyph(&u8g2, 20, 35, 0x2603); // 雪人图标
-
- u8g2_SetFont(&u8g2, u8g2_font_7x14B_tr);
- u8g2_DrawStr(&u8g2, 40, 60, "u8g2");
-
- u8g2_SendBuffer(&u8g2);
- }
- int main(void)
- {
- HAL_Init();
- SystemClock_Config();
- MX_I2C1_Init();
-
- u8g2_Init();
- DrawTestScreen();
-
- while(1)
- {
- // 主循环
- }
- }
常见问题解决
显示器无反应:
检查I2C地址是否正确(尝试0x78或0x7A)
确认I2C线路上有上拉电阻
用逻辑分析仪检查I2C信号
显示内容错乱:
降低I2C时钟速度(如100kHz)
检查电源稳定性
内存不足:
改用页缓冲模式(将_f改为_1或_2):
- u8g2_Setup_ssd1306_i2c_128x64_noname_1(&u8g2, U8G2_R0, ...);
然后使用u8g2_FirstPage()和u8g2_NextPage()函数
|