STM32F103与ADS1115实战:如何用I2C非标协议读取4通道ADC数据(附完整代码)

张开发
2026/6/27 17:18:15 15 分钟阅读
STM32F103与ADS1115实战:如何用I2C非标协议读取4通道ADC数据(附完整代码)
STM32F103与ADS1115实战如何用I2C非标协议读取4通道ADC数据附完整代码在工业传感器数据采集和精密测量领域16位ADC芯片ADS1115凭借其高精度和灵活的配置选项成为许多嵌入式工程师的首选。本文将深入解析STM32F103与ADS1115通过I2C非标准协议通信的技术细节提供可直接复用的驱动代码并分享实际工程中的优化技巧。1. ADS1115核心特性与硬件设计要点ADS1115是TI推出的一款16位精度、4通道输入的模数转换器相比常见的12位ADC其分辨率提升了16倍特别适合需要高精度测量的场景。这颗芯片有几个关键特性值得关注可编程增益放大器(PGA)支持2/3x到16x共6档增益对应不同的满量程输入范围灵活的数据速率从8SPS到860SPS共8档可选在速度和噪声之间取得平衡内置比较器可设置上下阈值通过ALERT引脚输出超限信号低功耗设计单次转换模式下的典型电流仅150μA硬件设计时需特别注意模拟电源建议增加LC滤波AVDD引脚接0.1μF去耦电容输入信号超过VDD0.3V时需增加保护电路ALERT/RDY引脚可配置为开漏输出需根据实际需求选择上拉电阻I2C总线建议使用2.2kΩ上拉电阻长距离传输时可适当减小阻值典型应用电路如下// ADS1115基本连接示意图 VDD ---- 3.3V GND ---- GND SCL ---- STM32_PB6(SCL) SDA ---- STM32_PB7(SDA) ADDR --- GND(地址0x48) ALERT --- STM32_PC8(EXTI) AIN0~AIN3 -- 传感器信号输入2. I2C非标准协议深度解析ADS1115虽然使用I2C接口但其读时序与标准I2C设备有显著差异这是许多开发者容易踩坑的地方。关键差异点在于标准I2C读时序发送设备地址写位(0)发送寄存器地址重新发送设备地址读位(1)读取数据ADS1115读时序先通过写操作设置Pointer寄存器(指定要读的寄存器)直接发送设备地址读位(1)读取数据这种设计减少了每次读取时的通信开销但也带来了配置上的复杂性。具体实现时我们需要先写Pointer寄存器指向目标寄存器之后的读操作就可以省略寄存器地址的发送。// ADS1115读寄存器流程示例 void ADS1115_ReadConfigRegister(uint8_t addr) { // 1. 设置Pointer寄存器指向配置寄存器 I2C_Start(); I2C_WriteByte(addr | 0x00); // 写地址 I2C_WriteByte(0x01); // 指向配置寄存器 I2C_Stop(); // 2. 直接读取配置寄存器 I2C_Start(); I2C_WriteByte(addr | 0x01); // 读地址 uint8_t msb I2C_ReadByte(1); uint8_t lsb I2C_ReadByte(0); I2C_Stop(); return (msb 8) | lsb; }3. 寄存器配置与驱动实现ADS1115的配置主要通过4个16位寄存器实现我们可以使用联合体和位域来简化配置过程typedef union { uint16_t value; struct { uint16_t OS:1; // 操作状态 uint16_t MUX:3; // 输入通道选择 uint16_t PGA:3; // 增益设置 uint16_t MODE:1; // 工作模式 uint16_t DR:3; // 数据速率 uint16_t COMP_MODE:1; // 比较器模式 uint16_t COMP_POL:1; // 比较器极性 uint16_t COMP_LAT:1; // 比较器锁存 uint16_t COMP_QUE:2; // 比较器队列 } bits; } ADS1115_ConfigReg;典型配置流程如下初始化I2C接口设置STM32的I2C引脚和时钟配置比较器阈值设置Lo_thresh和Hi_thresh寄存器设置工作模式通过Config寄存器选择通道、增益、数据速率等启动转换单次模式需设置OS位连续模式自动开始void ADS1115_Init(uint8_t addr) { // 1. 配置比较器阈值(-1V ~ 1V) ADS1115_SetThreshold(addr, -32768/6, 32767/6); // 2. 配置工作参数 ADS1115_ConfigReg config { .bits { .OS 1, // 启动转换 .MUX AIN0_GND, // 单端测量AIN0 .PGA GAIN_4_096V, // ±4.096V范围 .MODE 0, // 连续转换模式 .DR DR_128SPS, // 128SPS .COMP_MODE 1, // 窗口比较器 .COMP_POL 0, // 低电平有效 .COMP_LAT 0, // 非锁存 .COMP_QUE 0 // 一次转换后触发 } }; // 3. 写入配置寄存器 ADS1115_WriteRegister(addr, CONFIG_REG, config.value); // 4. 设置Pointer指向转换寄存器 ADS1115_SetPointer(addr, CONVERSION_REG); }4. 多通道采集与中断处理实战ADS1115支持4个单端输入或2个差分输入通过轮询方式切换通道会引入额外延迟。更高效的做法是利用ALERT引脚中断配置GPIO中断将ALERT引脚连接到STM32的外部中断引脚设置比较器阈值根据各通道预期范围设置不同阈值中断服务例程读取数据后切换通道并更新阈值// 中断服务例程示例 void EXTI9_5_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line8) ! RESET) { // 1. 读取当前通道数据 int16_t adc_val ADS1115_ReadConversion(ADS1115_ADDR); // 2. 处理数据 ProcessADCData(current_channel, adc_val); // 3. 切换通道 current_channel (current_channel 1) % 4; ADS1115_SetChannel(current_channel); // 4. 更新比较器阈值 ADS1115_SetThreshold(ADS1115_ADDR, channel_thresholds[current_channel].low, channel_thresholds[current_channel].high); EXTI_ClearITPendingBit(EXTI_Line8); } }对于需要精确时序的应用可以采用单次转换模式通过ALERT引脚指示转换完成float ReadVoltagePrecise(uint8_t channel) { // 1. 配置为单次转换模式 ADS1115_SetMode(ADS1115_ADDR, SINGLE_SHOT); // 2. 设置目标通道 ADS1115_SetChannel(ADS1115_ADDR, channel); // 3. 启动转换 ADS1115_StartConversion(ADS1115_ADDR); // 4. 等待ALERT引脚变低 while(GPIO_ReadInputDataBit(ALERT_PORT, ALERT_PIN)); // 5. 读取转换结果 int16_t raw ADS1115_ReadConversion(ADS1115_ADDR); return raw * 0.125f / 32768.0f; // 假设PGA1(±4.096V) }5. 工程优化与常见问题排查在实际项目中我们总结了几个提高ADS1115性能的关键技巧降低噪声干扰使用屏蔽电缆连接模拟信号在AIN引脚增加RC滤波(如1kΩ0.1μF)避免高频数字信号线与模拟信号平行走线选择适当的数据速率(高速率噪声更大)提高测量精度定期读取内部温度传感器值进行补偿对关键通道进行多次采样取平均在软件中实现数字滤波(如移动平均)避免输入信号接近满量程(留10%余量)常见问题排查读取值始终为0xFFFF检查I2C地址是否正确确认芯片焊接良好数据波动大检查电源稳定性增加输入滤波ALERT引脚不触发确认比较器模式和阈值设置正确转换值不准确校准PGA增益误差检查参考电压// 软件校准示例 float calibrated_read(uint8_t channel) { const float gain_error 0.9987f; // 实测增益误差 const float offset 0.0012f; // 零点偏移 float raw ReadVoltage(channel); return raw * gain_error offset; }对于需要多片ADS1115的系统可以通过ADDR引脚设置不同地址(0x48-0x4B)最多可级联4片芯片实现16通道采集。此时需注意I2C总线的负载能力必要时使用I2C缓冲器。

更多文章