在工业测量和嵌入式系统中,多通道高精度电压采集是常见需求。TI的ADS1118作为一款16位ΔΣ型ADC,凭借其高集成度和优异性能,成为许多工程师的首选。然而在实际项目中,特别是使用STM32系列MCU通过模拟SPI驱动ADS1118进行多通道轮询时,数据错位问题频繁出现,导致测量结果与预期通道不匹配。本文将深入剖析问题根源,并提供一套完整的解决方案。
ADS1118采用典型的SPI Mode 1通信协议(CPOL=0,CPHA=1),但其数据返回机制存在特殊设计:
c复制// 典型错误示例 - 直接轮询读取四通道
for(int ch=0; ch<4; ch++){
set_channel(ch); // 设置新通道
val = read_adc(); // 读取的是上一个通道的数据
}
当以128SPS速率工作时,转换周期约8ms。若在转换完成前切换通道,会导致:
注意:这种错位具有累积效应,连续快速轮询时误差会不断叠加
ADS1118的DOUT/DRDY引脚具有双重功能:
推荐电路连接方案:
| STM32引脚 | ADS1118引脚 | 连接方式 |
|---|---|---|
| PA4 | CS | 直接连接 |
| PA5 | SCLK | 直接连接 |
| PA6 | DOUT/DRDY | 10kΩ上拉至3.3V |
| PA7 | DIN | 直接连接 |
| - | GND | 星型接地 |
c复制// DRDY状态检测函数
bool is_conversion_done(void){
CS_H();
delay_us(1); // 确保CS高电平稳定
return (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_6) == GPIO_PIN_RESET);
}
多通道采集时需特别注意:
c复制int16_t read_channel_safe(uint8_t channel){
uint16_t config = get_channel_config(channel);
// 第一次读取:启动转换并丢弃结果
Write_ADS1118(config | 0x8000, 1); // 启动单次转换
delay_ms(10); // 确保转换完成
// 第二次读取:获取正确数据
return Write_ADS1118(config, 0);
}
c复制typedef enum {
ADC_IDLE,
ADC_START_CONV,
ADC_WAIT_READY,
ADC_READ_DATA
} adc_state_t;
adc_state_t adc_state = ADC_IDLE;
uint8_t current_ch = 0;
int16_t adc_values[4];
void adc_state_machine(void){
static uint32_t timeout;
switch(adc_state){
case ADC_IDLE:
if(++current_ch >= 4) current_ch = 0;
Write_ADS1118(get_channel_config(current_ch) | 0x8000, 1);
adc_state = ADC_START_CONV;
timeout = HAL_GetTick();
break;
case ADC_START_CONV:
if(is_conversion_done() || (HAL_GetTick()-timeout)>12){
adc_state = ADC_READ_DATA;
}
break;
case ADC_READ_DATA:
adc_values[current_ch] = Write_ADS1118(get_channel_config(current_ch), 0);
adc_state = ADC_IDLE;
break;
}
}
问题现象:通道数据周期性错位
异常波形特征:
根据通道数自动优化采样率:
c复制void update_sample_rate(uint8_t channel_count){
uint16_t dr_setting;
if(channel_count <= 2) dr_setting = ADS1118_CONFIG_DR_860SPS;
else if(channel_count <= 4) dr_setting = ADS1118_CONFIG_DR_128SPS;
else dr_setting = ADS1118_CONFIG_DR_8SPS;
current_config = (current_config & ~ADS1118_CONFIG_DR_MASK) | dr_setting;
}
ADS1118内置温度传感器可用来补偿ADC误差:
c复制float read_temperature(void){
uint16_t config = ADS1118_DEFAULT_CONFIG;
config |= ADS1118_CONFIG_TS_MODE_TEMP | 0x8000;
Write_ADS1118(config, 1);
delay_ms(105); // 温度传感器需要100ms稳定时间
int16_t raw = Write_ADS1118(config, 0);
return (raw >> 4) * 0.03125 - 50;
}
在工业现场部署时发现,当多个ADS1118共用SPI总线时,CS信号线长度差异会导致时序偏移。建议:
对于需要更高实时性的应用,可以采用"乒乓缓存"策略: