1. STM32 I2C通信外设概述
I2C(Inter-Integrated Circuit)是飞利浦公司开发的一种串行通信总线协议,在嵌入式系统中广泛应用。STM32系列微控制器内置硬件I2C外设,支持标准模式(100kHz)、快速模式(400kHz)和高速模式(3.4MHz)三种传输速率。
在实际项目中,I2C常用于连接各类传感器(如温湿度传感器、加速度计)、EEPROM存储器、LCD显示屏等外设。与SPI相比,I2C只需要两根信号线(SCL时钟线和SDA数据线),支持多主多从架构,硬件实现简单且节省IO资源。
注意:STM32不同系列(F1/F4/H7等)的I2C外设在寄存器配置上存在差异,开发时需参考对应型号的参考手册。
2. I2C硬件电路设计要点
2.1 基本电路连接
典型的I2C硬件连接如下图所示(省略图示描述):
- SCL:串行时钟线,需接上拉电阻(通常4.7kΩ)
- SDA:串行数据线,需接上拉电阻(与SCL相同阻值)
- 从设备地址:每个I2C设备有唯一7位或10位地址
上拉电阻取值计算:
code复制Rp(min) = (VDD - VOLmax) / IOL
Rp(max) = tr / (0.8473 × Cb)
其中:
- VDD:电源电压(通常3.3V)
- VOLmax:输出低电平最大值(通常0.4V)
- IOL:输出低电平电流(查阅器件手册)
- tr:上升时间(标准模式≤1000ns)
- Cb:总线电容(包括走线和器件引脚电容)
2.2 PCB布局注意事项
- 上拉电阻尽量靠近主设备放置
- SCL/SDA走线等长,避免过长(一般不超过30cm)
- 高速模式需考虑阻抗匹配
- 避免与高频信号线平行走线
3. STM32CubeMX配置
3.1 基本参数设置
- 在Connectivity选项卡中选择I2C外设
- 配置模式:
- I2C:标准主机模式
- Clock Speed:根据从设备选择(如400kHz)
- 参数计算:
- 时钟源通常选择APB1时钟(如36MHz)
- CCR寄存器值 = APB1时钟 / (2 × I2C时钟频率)
- TRISE寄存器值 = (上升时间 × APB1时钟) / 1000 + 1
3.2 生成代码解析
生成的初始化代码包含以下关键部分:
c复制hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
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;
4. I2C通信协议实现
4.1 基本通信流程
- 起始条件(START):SCL高电平时SDA从高到低跳变
- 地址传输:7位地址+1位读写方向(0-写,1-读)
- 应答信号(ACK):每字节后接收方拉低SDA
- 数据传输:每个字节8位,MSB先传
- 停止条件(STOP):SCL高电平时SDA从低到高跳变
4.2 HAL库常用函数
c复制// 阻塞式传输
HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
// 中断方式
HAL_I2C_Master_Transmit_IT();
HAL_I2C_Master_Receive_IT();
// DMA方式
HAL_I2C_Master_Transmit_DMA();
HAL_I2C_Master_Receive_DMA();
4.3 典型读写操作示例
读取BMP280气压传感器(地址0x76)的ID寄存器(0xD0):
c复制uint8_t reg_addr = 0xD0;
uint8_t id_value;
// 写寄存器地址
HAL_I2C_Master_Transmit(&hi2c1, 0x76<<1, ®_addr, 1, 100);
// 读寄存器值
HAL_I2C_Master_Receive(&hi2c1, 0x76<<1, &id_value, 1, 100);
5. 常见问题与调试技巧
5.1 典型故障现象及排查
-
通信无响应:
- 检查硬件连接(上拉电阻、电源)
- 用逻辑分析仪抓取波形
- 确认从设备地址是否正确(注意左移1位)
-
数据错误:
- 检查时钟速率是否超过从设备支持范围
- 验证时序是否符合标准(建立/保持时间)
- 检查总线电容是否过大
-
死锁问题:
- 添加超时处理机制
- 必要时硬件复位I2C外设
5.2 逻辑分析仪使用技巧
- 设置触发条件:START信号(SDA下降沿时SCL高电平)
- 解码设置:选择I2C协议,设置地址格式(7位/10位)
- 测量参数:
- 时钟频率
- 信号上升/下降时间
- 数据建立/保持时间
5.3 软件模拟I2C备选方案
当硬件I2C出现兼容性问题时,可使用GPIO模拟:
c复制void I2C_Start(void) {
SDA_HIGH();
SCL_HIGH();
Delay_us(5);
SDA_LOW();
Delay_us(5);
SCL_LOW();
}
void I2C_WriteByte(uint8_t byte) {
for(int i=0; i<8; i++) {
(byte & 0x80) ? SDA_HIGH() : SDA_LOW();
byte <<= 1;
SCL_HIGH();
Delay_us(5);
SCL_LOW();
Delay_us(5);
}
// ACK检查...
}
6. 性能优化与高级应用
6.1 DMA传输配置
- 在CubeMX中启用I2C DMA
- 配置DMA流:
- 方向:存储器到外设/外设到存储器
- 增量模式:存储器地址递增
- 数据宽度:字节
- 示例代码:
c复制HAL_I2C_Master_Transmit_DMA(&hi2c1, DEV_ADDR, pData, size);
6.2 多主机仲裁
- 硬件自动检测总线冲突
- 当SDA采样值与输出值不一致时产生错误
- 处理流程:
- 检测BUSY标志
- 等待总线空闲
- 重新发起传输
6.3 低功耗设计
- 时钟延展(Clock Stretching)支持
- 睡眠模式下唤醒功能
- 动态调整通信速率:
c复制hi2c1.Init.ClockSpeed = new_speed;
HAL_I2C_Init(&hi2c1);
7. 实际项目经验分享
在最近的环境监测项目中,我们使用STM32F407的I2C接口同时连接了以下设备:
- SHT31温湿度传感器(地址0x44)
- MPL3115A2气压计(地址0x60)
- AT24C512 EEPROM(地址0x50)
遇到的典型问题及解决方案:
- 地址冲突:通过调整EEPROM的A0-A2引脚改变地址
- 长距离传输(20cm):降低速率到100kHz,减小上拉电阻至2.2kΩ
- 中断冲突:为每个设备设置独立的通信超时(300ms)
- 电源干扰:在VDD和GND之间添加0.1μF去耦电容
调试心得:使用Saleae逻辑分析仪捕获完整通信过程后,发现SHT31的ACK信号响应较慢,通过将I2C时钟延展超时从10ms调整为25ms后问题解决。