1. 项目概述
NUCLEO-WBA65RI开发板搭载了ST最新推出的STM32WBA系列无线MCU,这款芯片在保持STM32传统优势的同时,集成了蓝牙5.3无线功能。本次测评将重点展示如何利用该开发板的I2C接口驱动OLED屏幕显示文本信息。
OLED屏幕因其自发光、高对比度、低功耗等特性,在嵌入式设备的人机交互界面中应用广泛。通过I2C总线连接OLED模块,仅需4根线(VCC、GND、SCL、SDA)即可实现通信,非常适合资源有限的嵌入式系统。
2. 硬件准备与连接
2.1 所需材料清单
- NUCLEO-WBA65RI开发板(主控为STM32WBA52CG)
- 0.96寸I2C接口OLED显示屏(SSD1306驱动芯片)
- 杜邦线若干
- USB Type-C数据线(供电与调试)
2.2 硬件连接详解
开发板的I2C接口位于CN10连接器:
- OLED VCC → 开发板3.3V
- OLED GND → 开发板GND
- OLED SCL → 开发板PB6(I2C1_SCL)
- OLED SDA → 开发板PB7(I2C1_SDA)
注意:部分OLED模块工作电压为5V,需确认模块规格。NUCLEO-WBA65RI的I2C接口为3.3V电平,直接连接5V模块可能损坏IO口。
3. 软件开发环境搭建
3.1 工具链准备
- 安装STM32CubeIDE(当前最新版本1.13.2)
- 通过STM32CubeMX更新STM32WBA系列支持包
- 准备OLED驱动库(推荐使用开源SSD1306驱动)
3.2 工程创建步骤
- 新建STM32CubeIDE工程,选择STM32WBA52CG作为目标器件
- 配置时钟树:使用HSI16作为时钟源,主频64MHz
- 启用I2C1外设:
- 模式:I2C
- 速度:标准模式(100kHz)
- 引脚分配:PB6(SCL), PB7(SDA)
4. OLED驱动实现
4.1 I2C初始化代码
c复制void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x10707DBC; // 100kHz时序配置
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
4.2 SSD1306驱动移植
- 实现基础通信函数:
c复制void SSD1306_WriteCommand(uint8_t cmd)
{
HAL_I2C_Mem_Write(&hi2c1, SSD1306_I2C_ADDR, 0x00, 1, &cmd, 1, HAL_MAX_DELAY);
}
void SSD1306_WriteData(uint8_t* data, uint16_t size)
{
HAL_I2C_Mem_Write(&hi2c1, SSD1306_I2C_ADDR, 0x40, 1, data, size, HAL_MAX_DELAY);
}
- 初始化序列配置:
c复制void SSD1306_Init(void)
{
// 关闭显示
SSD1306_WriteCommand(0xAE);
// 设置显示时钟分频比/振荡器频率
SSD1306_WriteCommand(0xD5);
SSD1306_WriteCommand(0x80);
// 设置多路复用比例
SSD1306_WriteCommand(0xA8);
SSD1306_WriteCommand(0x3F);
// ...其他初始化命令
// 最后开启显示
SSD1306_WriteCommand(0xAF);
}
5. 字符串显示实现
5.1 字库设计与实现
- 使用8x16点阵ASCII字库:
c复制const uint8_t Font8x16[95][16] = {
// 空格
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
// !
{0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
// 其他字符...
};
- 字符显示函数:
c复制void SSD1306_DrawChar(uint8_t x, uint8_t y, char ch)
{
if(ch < 32 || ch > 126) return;
uint8_t* font = (uint8_t*)&Font8x16[ch-32];
uint8_t buffer[16];
for(uint8_t i=0; i<16; i++) {
buffer[i] = font[i];
}
SSD1306_SetCursor(x, y);
SSD1306_WriteData(buffer, 16);
}
5.2 字符串显示功能
c复制void SSD1306_DrawString(uint8_t x, uint8_t y, char* str)
{
while(*str) {
if(x > 120) { // 换行处理
x = 0;
y += 2;
}
SSD1306_DrawChar(x, y, *str++);
x += 8;
}
}
6. 主程序逻辑
6.1 系统初始化流程
c复制int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
SSD1306_Init();
SSD1306_Clear();
SSD1306_DrawString(0, 0, "NUCLEO-WBA65RI");
SSD1306_DrawString(0, 2, "I2C OLED Test");
SSD1306_DrawString(0, 4, "STMicroelectronics");
while (1) {
HAL_Delay(1000);
}
}
6.2 显示效果优化技巧
- 反色显示实现:
c复制void SSD1306_InvertDisplay(uint8_t invert)
{
SSD1306_WriteCommand(invert ? 0xA7 : 0xA6);
}
- 滚动显示配置:
c复制void SSD1306_StartScroll(uint8_t dir)
{
SSD1306_WriteCommand(dir ? 0x26 : 0x27);
SSD1306_WriteCommand(0x00);
SSD1306_WriteCommand(0x07); // 起始页
SSD1306_WriteCommand(0x00); // 间隔时间
SSD1306_WriteCommand(0x07); // 结束页
SSD1306_WriteCommand(0x00);
SSD1306_WriteCommand(0xFF);
SSD1306_WriteCommand(0x2F); // 启动滚动
}
7. 常见问题排查
7.1 I2C通信失败排查
-
使用逻辑分析仪检查SCL/SDA信号
- 确认起始条件、地址字节、ACK信号正常
- 检查时钟频率是否符合配置
-
软件排查步骤:
- 确认I2C外设时钟已使能
- 检查上拉电阻(通常4.7kΩ)
- 验证设备地址(通常0x78或0x7A)
7.2 显示异常处理
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 屏幕全亮 | 未正确初始化 | 检查初始化序列 |
| 显示乱码 | 字库不匹配 | 确认字库编码格式 |
| 内容偏移 | 显存指针错误 | 重置显示起始行 |
| 闪烁严重 | 刷新率过低 | 优化刷新逻辑 |
7.3 低功耗优化建议
- 动态刷新:仅在内容变化时更新显示
- 睡眠模式:利用SSD1306的省电命令
c复制void SSD1306_EnterSleepMode(void) { SSD1306_WriteCommand(0xAE); // 关闭显示 SSD1306_WriteCommand(0xAD); // 进入睡眠 }
8. 项目扩展思路
8.1 多语言支持
- 添加中文字库(16x16点阵)
- 实现UTF-8解码器
- 设计字库存储方案(内部Flash/外部SPI Flash)
8.2 图形界面增强
- 移植u8g2图形库
- 实现基本绘图原语(线、圆、矩形)
- 添加菜单导航系统
8.3 无线数据传输显示
- 利用STM32WBA的蓝牙功能
- 设计通信协议接收显示内容
- 实现OTA更新显示内容
实操心得:在调试I2C通信时,发现STM32WBA的I2C时序配置与F系列略有不同。建议在CubeMX生成代码后,先用逻辑分析仪验证时序参数是否符合OLED模块要求。特别是在切换时钟源后,需要重新计算I2C时序配置值。