STM32中的SMBUS总线用在哪些场合-IIC,I2C

一直都在说IIC里面的SMBUS,单好像一直都没有使用过,所以想查查资料,看看SMBUS到底是啥?干啥用的?

一、SMBUS 典型应用场合

SMBUS(系统管理总线)是 I2C 的子集,更强调 "系统管理" 和 "可靠性",核心应用在需要低速、短距离、低成本的硬件监控 / 管理场景,常见场景如下:

  1. 硬件健康监控

    服务器、工控机、主板中监控核心电压、CPU / 芯片温度、风扇转速(符合 IPMI/PC99 规范),比如通过 SMBUS 读取电源管理芯片 (PMIC) 的电压数据。

  2. 电池管理系统(BMS)

    笔记本、手机、无人机的锂电池管理,通过 SMBUS 读取电池的剩余电量 (SoC)、循环次数、温度、充放电状态。

  3. 低速外设通信

    智能家居 / 工业场景中的温湿度传感器、电流传感器、EEPROM、LED 驱动芯片(要求通信简单且功耗低)。

  4. 系统配置管理

    主板 / 外设的配置信息读取(如内存 SPD 芯片、扩展卡的硬件参数),无需高速通信,优先保证稳定性。

二、HAL 库版 STM32 SMBUS 驱动(以 STM32F103 为例)

SMBUS 基于 I2C 外设实现,HAL 库下只需将 I2C 配置为 SMBUS 兼容时序(100KHz、开漏输出、7 位地址)即可。以下是完整驱动,兼容 STM32F1/F4/F7/H7 系列(仅 CubeMX 配置略有差异)。

前置准备(CubeMX 基础配置)

先通过 STM32CubeMX 完成基础配置:

  1. 选择对应 STM32 型号,配置系统时钟(如 72MHz)。

  2. 找到 I2C 外设(如 I2C1),模式选择SMBus Host(或 I2C,SMBUS 兼容)。

  3. 配置 SCL/SDA 引脚(如 PB6/PB7):模式为GPIO_Output_OD(开漏输出)、上拉使能。

  4. 配置 I2C 参数:时钟频率 100KHz、地址位 7 位、应答使能、占空比 2:1。

  5. 生成代码(选择 HAL 库,MDK-ARM 工程)。

  6. 头文件(smbus_hal.h)

cpp 复制代码
#ifndef __SMBUS_HAL_H
#define __SMBUS_HAL_H
#include "main.h"  // 包含CubeMX生成的核心头文件
#include "i2c.h"   // I2C HAL库头文件
// 硬件宏定义(与CubeMX配置一致)
#define SMBUS_HANDLE              hi2c1  // CubeMX生成的I2C句柄(如hi2c1/hi2c2)
#define SMBUS_SLAVE_ADDR          0xA0   // 从设备地址(7位地址左移1位,按需修改)
// 函数声明
uint8_t SMBUS_WriteByte(uint8_t slave_addr, uint8_t reg_addr, uint8_t data);  // 单字节写
uint8_t SMBUS_ReadByte(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data);   // 单字节读
uint8_t SMBUS_WriteBytes(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t len); // 多字节写
uint8_t SMBUS_ReadBytes(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t len);  // 多字节读
#endif /* __SMBUS_HAL_H */
  1. 源文件(smbus_hal.c)
cpp 复制代码
#include "smbus_hal.h"
/**
 * @brief  SMBUS单字节写操作(HAL库版)
 * @param  slave_addr: 从设备地址(7位左移1位)
 * @param  reg_addr: 寄存器地址
 * @param  data: 待写入数据
 * @retval 0:成功,其他:HAL库错误码(如1=超时、2=参数错误)
 */
uint8_t SMBUS_WriteByte(uint8_t slave_addr, uint8_t reg_addr, uint8_t data)
{
    HAL_StatusTypeDef status;
    // 检查参数有效性
    if (slave_addr == 0 || reg_addr > 0xFF) return 2;
    // HAL库I2C写:地址+寄存器+数据(SMBUS核心流程)
    status = HAL_I2C_Mem_Write(&SMBUS_HANDLE, slave_addr, reg_addr, 
                               I2C_MEMADD_SIZE_8BIT, &data, 1, 100); // 100ms超时
    return (status == HAL_OK) ? 0 : 1; // 0成功,1超时/失败
}
/**
 * @brief  SMBUS单字节读操作(HAL库版)
 * @param  slave_addr: 从设备地址
 * @param  reg_addr: 寄存器地址
 * @param  data: 存储读取数据的指针
 * @retval 0:成功,其他:错误码
 */
uint8_t SMBUS_ReadByte(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data)
{
    HAL_StatusTypeDef status;
    // 检查参数有效性
    if (data == NULL || slave_addr == 0 || reg_addr > 0xFF) return 2;
    // HAL库I2C读:地址+寄存器+读取数据
    status = HAL_I2C_Mem_Read(&SMBUS_HANDLE, slave_addr, reg_addr, 
                              I2C_MEMADD_SIZE_8BIT, data, 1, 100); // 100ms超时
    return (status == HAL_OK) ? 0 : 1;
}
/**
 * @brief  SMBUS多字节写操作
 * @param  slave_addr: 从设备地址
 * @param  reg_addr: 起始寄存器地址
 * @param  data: 数据缓冲区
 * @param  len: 数据长度
 * @retval 0:成功,其他:错误码
 */
uint8_t SMBUS_WriteBytes(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t len)
{
    HAL_StatusTypeDef status;
    if (data == NULL || len == 0 || slave_addr == 0) return 2;
    status = HAL_I2C_Mem_Write(&SMBUS_HANDLE, slave_addr, reg_addr,
                               I2C_MEMADD_SIZE_8BIT, data, len, 100);
    return (status == HAL_OK) ? 0 : 1;
}
/**
 * @brief  SMBUS多字节读操作
 * @param  slave_addr: 从设备地址
 * @param  reg_addr: 起始寄存器地址
 * @param  data: 接收缓冲区
 * @param  len: 读取长度
 * @retval 0:成功,其他:错误码
 */
uint8_t SMBUS_ReadBytes(uint8_t slave_addr, uint8_t reg_addr, uint8_t *data, uint8_t len)
{
    HAL_StatusTypeDef status;
    if (data == NULL || len == 0 || slave_addr == 0) return 2;
    status = HAL_I2C_Mem_Read(&SMBUS_HANDLE, slave_addr, reg_addr,
                              I2C_MEMADD_SIZE_8BIT, data, len, 100);
    return (status == HAL_OK) ? 0 : 1;
}
  1. 测试示例(main.c 中调用)
cpp 复制代码
#include "smbus_hal.h"
int main(void)
{
  /* 1. CubeMX生成的初始化代码(无需修改) */
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_I2C1_Init(); // I2C/SMBUS初始化
  /* 2. SMBUS测试 */
  uint8_t write_data = 0x66;
  uint8_t read_data;
  uint8_t write_buf[3] = {0x01, 0x02, 0x03};
  uint8_t read_buf[3];
  uint8_t ret;
  // 单字节写
  ret = SMBUS_WriteByte(SMBUS_SLAVE_ADDR, 0x01, write_data);
  if (ret == 0) {
      // 写成功
  }
  // 单字节读
  ret = SMBUS_ReadByte(SMBUS_SLAVE_ADDR, 0x01, &read_data);
  if (ret == 0) {
      // 读成功,read_data即为读取的值
  }
  // 多字节写
  ret = SMBUS_WriteBytes(SMBUS_SLAVE_ADDR, 0x02, write_buf, 3);
  // 多字节读
  ret = SMBUS_ReadBytes(SMBUS_SLAVE_ADDR, 0x02, read_buf, 3);
  /* 3. 主循环 */
  while (1)
  {
    // 循环执行
    HAL_Delay(1000);
  }
}

三、关键说明(HAL 库版 vs 标准库版)

  1. 核心 API 差异

    HAL 库封装了底层 I2C 操作,直接使用HAL_I2C_Mem_Write/Read即可实现 SMBUS 读写,无需手动处理起始 / 停止信号、应答等(由 HAL 库自动完成)。

  2. 错误处理

    驱动中返回 0 表示成功,1 表示超时 / 通信失败,2 表示参数错误,便于调试。

  3. 兼容性

    若使用 STM32F4/F7/H7,仅需修改SMBUS_HANDLE(如 hi2c2),核心函数完全通用。

  4. 硬件要求

    SCL/SDA 引脚必须为开漏输出 + 上拉(CubeMX 中配置为 GPIO_Output_OD),否则 SMBUS 通信会异常。

总结

  1. SMBUS 主要用于硬件监控(电压 / 温度)、电池管理、低速外设通信等场景,核心是 "稳定" 而非 "高速"。

  2. HAL 库版 SMBUS 驱动基于HAL_I2C_Mem_Write/Read封装,无需手动处理总线时序,比标准库更简洁。

  3. 使用前需通过 CubeMX 配置 I2C 为 SMBUS 兼容模式(100KHz、7 位地址、开漏引脚),驱动函数直接调用即可。

如果需要适配特定从设备(如电池管理芯片、传感器),只需修改SMBUS_SLAVE_ADDR和寄存器地址,核心读写逻辑无需调整。

相关推荐
不做无法实现的梦~10 小时前
ros2实现路径规划---nav2部分
linux·stm32·嵌入式硬件·机器人·自动驾驶
熊猫_豆豆14 小时前
同步整流 Buck 降压变换器
单片机·嵌入式硬件·matlab
chenchen0000000019 小时前
49元能否买到四核性能?HZ-RK3506G2_MiniEVM开发板评测:MCU+三核CPU带来的超高性价比
单片机·嵌入式硬件
孤芳剑影19 小时前
反馈环路设计总结
嵌入式硬件·学习
dump linux20 小时前
设备树子系统与驱动开发入门
linux·驱动开发·嵌入式硬件
专注VB编程开发20年20 小时前
简易虚拟 PLC 服务器-流水线自动化,上位机程序维护升级,西门子PLC仿真
服务器·单片机·自动化·上位机·plc·流水线·工控
LeoZY_21 小时前
CH347/339W开源项目:集SPI、I2C、JTAG、SWD、UART、GPIO多功能为一体(3)
stm32·单片机·嵌入式硬件·mcu·开源
chenchen0000000021 小时前
国产显示芯势力新篇章:内置DDR+四核A35!MY-SSD2351-MINI开发板深度评测
驱动开发·嵌入式硬件
BackCatK Chen21 小时前
第13篇:TMC2240 StallGuard4失速检测|寄存器配置+状态读取(保姆级)
单片机·嵌入式硬件·tmc2240·stm32实战·stallguard4·失速检测·电机故障识别
Hello_Embed1 天前
libmodbus STM32 板载串口实验(双串口主从通信)
笔记·stm32·单片机·学习·modbus