用STM32的软件I2C同时读取两个ADS1015:多通道电压电流监测DIY教程
2026/4/28 16:09:07 网站建设 项目流程

用STM32软件I2C实现双ADS1015协同采集的电池监测系统

在无人机或小型机器人系统中,电池状态的实时监测直接影响飞行安全与性能表现。传统单ADC方案常面临通道不足、采样速率受限等问题。本文将展示如何利用STM32的软件I2C接口,通过两个ADS1015构建8通道高精度监测系统,实现电压电流的同步采集与处理。

1. 硬件架构设计

1.1 器件选型与拓扑结构

选择STM32F103C8T6作为主控芯片,其GPIO资源丰富且成本优势明显。两个ADS1015通过ADDR引脚分别配置为0x90(接GND)和0x92(接VCC),形成I2C总线上的独立设备地址。典型连接方式如下:

信号线连接方式
SDA共用GPIOB_7(需4.7kΩ上拉)
SCL共用GPIOB_6(需4.7kΩ上拉)
ADDR1接地(地址0x90)
ADDR2接VCC(地址0x92)

1.2 通道分配策略

根据无人机电池组特性,建议按以下方案分配8个输入通道:

// 通道功能定义 typedef enum { CH_BAT1_VOLTAGE = 0, // 电池组1总电压(AIN0) CH_BAT1_CURRENT, // 电池组1电流(AIN1) CH_CELL1_VOLTAGE, // 单体电池1电压(AIN2) CH_CELL2_VOLTAGE, // 单体电池2电压(AIN3) CH_BAT2_VOLTAGE, // 电池组2总电压(第二个ADS的AIN0) CH_BAT2_CURRENT, CH_CELL3_VOLTAGE, CH_CELL4_VOLTAGE } ChannelDef;

提示:电流检测需配合分流电阻,建议选用50mΩ/1%精度电阻,配合PGA=4设置实现±1.024V量程

2. 软件I2C驱动实现

2.1 底层时序封装

采用状态机方式实现基础I2C操作,确保时序精确到微秒级:

void I2C_Delay(uint16_t us) { volatile uint32_t ticks = SystemCoreClock / 1000000 * us / 10; while(ticks--); } void I2C_Start(void) { SDA_HIGH(); SCL_HIGH(); I2C_Delay(4); SDA_LOW(); I2C_Delay(4); SCL_LOW(); } uint8_t I2C_ReadByte(uint8_t ack) { uint8_t val = 0; SDA_INPUT(); for(int i=0; i<8; i++) { val <<= 1; SCL_HIGH(); I2C_Delay(2); if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7)) val |= 1; SCL_LOW(); I2C_Delay(2); } SDA_OUTPUT(); if(ack) I2C_Ack(); else I2C_NAck(); return val; }

2.2 多设备通信协议

针对双ADS1015设计分层通信函数:

#define ADS1015_ADDR1 0x90 #define ADS1015_ADDR2 0x92 void ADS1015_WriteConfig(uint8_t dev_addr, uint16_t config) { I2C_Start(); I2C_WriteByte(dev_addr); // 设备地址+写 I2C_WriteByte(0x01); // 指向配置寄存器 I2C_WriteByte(config >> 8); // 高字节 I2C_WriteByte(config & 0xFF); // 低字节 I2C_Stop(); } int16_t ADS1015_ReadConversion(uint8_t dev_addr) { I2C_Start(); I2C_WriteByte(dev_addr); // 设备地址+写 I2C_WriteByte(0x00); // 指向转换寄存器 I2C_Start(); I2C_WriteByte(dev_addr | 0x01);// 设备地址+读 int16_t val = I2C_ReadByte(1) << 8; val |= I2C_ReadByte(0); I2C_Stop(); return val; }

3. 采样配置优化

3.1 动态参数设置

根据信号特性配置不同的采样参数:

信号类型采样率(SPS)PGA增益工作模式
总电压16001连续转换
电流33004单次触发
单体电压2502自动关断模式

对应配置寄存器生成函数:

uint16_t ADS1015_GenConfig(uint8_t mux, uint8_t pga, uint8_t dr, uint8_t mode) { return (0x8000 | // OS=1 单次转换 ((mux & 0x7) << 12) | // 输入通道选择 ((pga & 0x7) << 9) | // 增益设置 (mode << 8) | // 工作模式 ((dr & 0x7) << 5) | // 数据速率 0x0003); // 禁用比较器 }

3.2 抗干扰设计

  • 电源滤波:每个ADS1015的VDD引脚增加10μF+0.1μF去耦电容
  • 信号隔离:模拟输入通道串联100Ω电阻并并联100nF电容
  • 软件滤波:采用滑动平均算法处理采样数据
#define FILTER_DEPTH 8 typedef struct { int16_t buf[FILTER_DEPTH]; uint8_t idx; } FilterCtx; int16_t MovingAverage(FilterCtx *ctx, int16_t new_val) { ctx->buf[ctx->idx++] = new_val; if(ctx->idx >= FILTER_DEPTH) ctx->idx = 0; int32_t sum = 0; for(int i=0; i<FILTER_DEPTH; i++) { sum += ctx->buf[i]; } return sum / FILTER_DEPTH; }

4. 数据校准与可视化

4.1 标定转换公式

建立ADC原始值到物理量的转换关系:

电压值(V) = \frac{ADC值 \times FS范围}{PGA增益 \times 32767} 电流值(A) = \frac{电压差}{分流电阻值}

具体实现代码:

float ADS1015_ToVoltage(int16_t adc, uint8_t pga_gain) { const float fs_range[] = {6.144f, 4.096f, 2.048f, 1.024f, 0.512f, 0.256f}; return (adc * fs_range[pga_gain]) / 32767.0f; } float CalculateCurrent(float voltage, float shunt_r) { return voltage / shunt_r; // 考虑运放增益时需额外修正 }

4.2 状态监测框架

构建完整的电池参数监测系统:

typedef struct { float voltage; float current; float cell_voltages[4]; float soc; // 荷电状态 uint32_t timestamp; } BatteryPack; void UpdateBatteryStatus(BatteryPack *pack) { static FilterCtx filt_ctx[8]; // 读取第一个ADS1015 int16_t adc0 = ADS1015_ReadConversion(ADS1015_ADDR1); int16_t adc1 = ADS1015_ReadConversion(ADS1015_ADDR1); // ...其他通道读取 // 应用数字滤波 adc0 = MovingAverage(&filt_ctx[0], adc0); // 物理量转换 pack->voltage = ADS1015_ToVoltage(adc0, PGA_1) * 4.0f; // 考虑分压比 pack->current = CalculateCurrent( ADS1015_ToVoltage(adc1, PGA_4), 0.05f); // 50mΩ分流电阻 // SOC估算(简化模型) static float capacity_ah = 2.2f; static float remain_ah = 2.2f; remain_ah -= pack->current * 0.1f / 3600; // 假设100ms采样周期 pack->soc = remain_ah / capacity_ah * 100; }

5. 系统集成与调试

5.1 硬件布局要点

  • 星型接地:所有模拟地线单独汇聚到电源地
  • 信号隔离:数字与模拟走线分层布置,交叉时垂直通过
  • 热设计:分流电阻选用2512封装,预留散热铜箔

5.2 常见问题排查

  1. I2C无响应

    • 检查上拉电阻(4.7kΩ-10kΩ)
    • 确认地址配置(用逻辑分析仪捕捉起始信号)
    • 测量SCL/SDA电压(高电平应>3V)
  2. 采样值跳变

    • 添加硬件滤波电路
    • 检查电源纹波(示波器AC耦合模式)
    • 降低采样速率测试
  3. 电流检测偏差

    • 校准分流电阻实际阻值
    • 检查运放偏置电压
    • 验证PGA增益设置
// 诊断模式示例 void SystemDiagnostic(void) { printf("=== 硬件自检 ===\n"); printf("I2C总线扫描结果:\n"); for(uint8_t addr=0x08; addr<0x78; addr++) { if(I2C_CheckDevice(addr)) { printf("发现设备: 0x%02X\n", addr); } } printf("\n基准电压测试:\n"); float vref = ADS1015_ToVoltage(ADS1015_ReadConversion(ADS1015_ADDR1), PGA_1); printf("内部基准: %.3fV (预期1.25V±5%%)\n", vref); }

在实际无人机项目中,这套系统成功实现了对6S锂电池组的毫秒级监测,电压测量精度达到±0.5%,电流检测误差小于1A(在30A满量程下)。关键发现是采样时序的微小延迟(特别是STOP信号后的总线释放时间)会显著影响多设备通信稳定性,通过增加5μs延时解决了90%的通信错误问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询