STM32 实现I2C SMBus
基于STM32实现I2C SMBus协议
一、SMBus协议特性
-
协议基础
- 基于I2C总线,增加SMBus特定时序与校验机制
- 支持主机/从机模式,标准地址7位或10位格式
- 新增PEC(分组错误校验)与警报响应机制
-
核心差异
特性 I2C标准协议 SMBus协议 时钟频率 100/400kHz 10-100kHz(典型值) 地址格式 7/10位 7位为主流 错误检测 无 PEC校验(CRC-8) 从机响应 仅ACK/NACK 支持SMBus警报响应
二、硬件配置方案
1. 引脚连接规范
STM32 SMBus设备
SCL → SCL (需上拉至3.3V)
SDA → SDA (需上拉至3.3V)
GND → GND
VCC → 3.3V
硬件设计要点:
- 必须使用开漏输出模式(OD模式)
- 推荐4.7kΩ上拉电阻(单总线可降低至2.2kΩ)
- 电源滤波需添加0.1μF陶瓷电容
2. CubeMX配置流程
-
时钟配置
- 启用I2C外设时钟(如I2C1)
- 设置APB总线时钟频率(通常100MHz)
-
I2C模式设置
// HAL库配置示例 hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; // 100kHz hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0x00; // 主机模式设为0x00 hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(&hi2c1);
三、协议实现代码
1. 基础通信函数
// SMBus起始条件
void SMBus_Start(void) {
HAL_I2C_EnableListen_IT(&hi2c1); // 启用监听模式
hi2c1.Instance->CR2 |= I2C_CR2_START; // 生成起始信号
}
// SMBus停止条件
void SMBus_Stop(void) {
hi2c1.Instance->CR2 |= I2C_CR2_STOP; // 生成停止信号
HAL_I2C_DisableListen_IT(&hi2c1); // 关闭监听模式
}
// 发送从机地址(带读写位)
HAL_StatusTypeDef SMBus_SendAddr(uint8_t addr, uint8_t rw) {
return HAL_I2C_Master_Transmit_IT(&hi2c1, addr<<1|rw, NULL, 0);
}
2. PEC校验实现
// CRC-8计算(SMBus标准多项式:0x07)
uint8_t SMBus_CalculatePEC(uint8_t *data, uint16_t len) {
uint8_t crc = 0xFF;
for(uint16_t i=0; i<len; i++) {
crc ^= data[i];
for(uint8_t j=0; j<8; j++) {
if(crc & 0x80) crc = (crc<<1) ^ 0x07;
else crc <<= 1;
}
}
return crc;
}
// 带PEC的写操作示例
HAL_StatusTypeDef SMBus_WriteWithPEC(uint8_t devAddr, uint8_t *buf, uint16_t len) {
uint8_t data[len+1];
memcpy(data, buf, len);
data[len] = SMBus_CalculatePEC(buf, len);
return HAL_I2C_Master_Transmit(&hi2c1, devAddr<<1, data, len+1, 100);
}
四、典型应用场景
1. 电池管理系统(BMS)
// 读取BQ40Z50电量寄存器(地址0x16)
#define BQ40Z50_ADDR 0x16
#define SOC_REG 0x0D
uint8_t soc_buf[2] = {SOC_REG, 0x00};
HAL_StatusTypeDef status = SMBus_WriteWithPEC(BQ40Z50_ADDR, soc_buf, 1);
if(status == HAL_OK) {
HAL_I2C_Master_Receive(&hi2c1, BQ40Z50_ADDR<<1, soc_buf, 2, 100);
uint16_t soc = (soc_buf[0]<<8) | soc_buf[1];
}
2. 温度传感器读取
// DS1624温度传感器操作
#define DS1624_ADDR 0x48
#define TEMP_REG 0x00
void Read_Temperature(float *temp) {
uint8_t cmd[2] = {TEMP_REG, 0x00};
SMBus_WriteWithPEC(DS1624_ADDR, cmd, 1);
HAL_Delay(750); // 转换时间
HAL_I2C_Master_Receive(&hi2c1, DS1624_ADDR<<1, cmd, 2, 100);
*temp = (cmd[1]<<8 | cmd[0]) * 0.0625f;
}
五、错误处理机制
-
错误类型检测
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c) { if(HAL_I2C_GetError(hi2c) & HAL_I2C_ERROR_AF) { // 处理NACK错误 } if(HAL_I2C_GetError(hi2c) & HAL_I2C_ERROR_TIMEOUT) { // 处理超时错误 } } -
重试策略
#define MAX_RETRY 3 HAL_StatusTypeDef Retried_Write(uint8_t devAddr, uint8_t *buf, uint16_t len) { HAL_StatusTypeDef status; for(uint8_t i=0; i<MAX_RETRY; i++) { status = SMBus_WriteWithPEC(devAddr, buf, len); if(status == HAL_OK) return HAL_OK; HAL_Delay(10); // 重试间隔 } return status; }
六、性能优化策略
-
DMA传输配置
// DMA初始化(STM32CubeMX生成) hdma_i2c1_tx.Instance = DMA1_Channel6; hdma_i2c1_tx.Init.Request = DMA_REQUEST_I2C1_TX; hdma_i2c1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_i2c1_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_i2c1_tx.Init.MemInc = DMA_MINC_ENABLE; HAL_DMA_Init(&hdma_i2c1_tx); hi2c1.hdmatx = &hdma_i2c1_tx; -
时钟同步优化
// 动态调整时钟频率 void SMBus_AdjustClock(uint32_t freq) { hi2c1.Init.ClockSpeed = freq; HAL_I2C_DeInit(&hi2c1); HAL_I2C_Init(&hi2c1); }
七、调试与验证
-
逻辑分析仪捕获
-
关键信号时序验证:
Start → Addr+R/W → ACK → Data → PEC → Stop -
典型波形参数:
参数 标准值 上升时间 <1μs 下降时间 <0.5μs 高电平保持 4.7μs-40μs
-
-
协议分析工具
-
使用
I2C Analyzer
(如Saleae Logic)解码:
// 示例数据帧 [Start] [0xA0] [0x0D] [0x00] [0x12] [0x34] [Stop] → 写入寄存器0x0D的0x1234值
-
八、开发资源推荐
-
官方资料
- 《STM32参考手册》第27章:I2C外设
- X-CUBE-SMBUS软件包(V2.3.0)
-
代码:STM32 实现I2C SMBus www.youwenfan.com/contentcna/51713.html
通过上述方案,开发者可快速实现符合SMBus协议的I2C通信系统。实际应用中需注意:
- 严格遵循总线时序规范
- 合理配置PEC校验机制
- 针对噪声环境优化滤波设计
- 使用DMA提升大数据量传输效率

浙公网安备 33010602011771号