1. 项目背景与核心需求
在工业测量、医疗设备和环境监测等领域,我们经常需要将模拟信号转换为数字信号进行处理。模拟信号是连续的物理量(如温度、压力、光强等),而数字信号则是离散的二进制数值。ADS122U04作为一款24位高精度Δ-Σ模数转换器(ADC),配合STM32F767ZG高性能微控制器,能够实现高精度的模拟信号采集和数字转换。
这个组合特别适合以下场景:
- 需要高精度测量的工业传感器(如称重传感器、压力传感器)
- 医疗设备中的生物电信号采集(如ECG、EEG)
- 环境监测系统(温湿度、大气压力等)
2. 硬件选型与配置
2.1 ADS122U04关键特性
ADS122U04是TI公司推出的24位低功耗ADC,具有以下突出特点:
- 24位无失码分辨率
- 数据速率可达2kSPS
- 内置可编程增益放大器(PGA),增益1~128
- 低噪声:150nV RMS(增益=128,20SPS)
- 工作电压:2.3V至5.5V
- 集成温度传感器和电压基准
实际应用中,24位分辨率意味着可以检测到μV级别的电压变化。例如在称重系统中,可以检测到0.1克以下的重量变化。
2.2 STM32F767ZG接口配置
STM32F767ZG通过SPI接口与ADS122U04通信,典型硬件连接如下:
ADS122U04 STM32F767ZG ----------------------------- VDD → 3.3V GND → GND DRDY → PA0 (外部中断) CS → PA4 (SPI片选) SCLK → PA5 (SPI时钟) DIN → PA7 (SPI MOSI) DOUT → PA6 (SPI MISO)在CubeMX中的配置步骤:
- 启用SPI1,模式为全双工主模式
- 设置预分频器使SPI时钟≤10MHz(ADS122U04最大支持)
- 配置PA0为外部中断输入,下降沿触发
- 配置PA4为GPIO输出(手动控制片选)
注意:ADS122U04的DRDY信号是开漏输出,建议在STM32端加上拉电阻(4.7kΩ)
3. 软件实现与寄存器配置
3.1 ADS122U04初始化
ADS122U04通过SPI命令和寄存器进行配置。上电后需要配置以下关键寄存器:
// 寄存器配置示例 typedef struct { uint8_t CONFIG0; // 数据速率、模式等 uint8_t CONFIG1; // 增益、输入选择 uint8_t CONFIG2; // 基准电压、温度传感器 uint8_t CONFIG3; // 数据就绪、校准设置 } ADS122U04_Config; void ADS122U04_Init(void) { // 复位设备 HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_RESET); uint8_t reset_cmd = 0x06; // 复位命令 HAL_SPI_Transmit(&hspi1, &reset_cmd, 1, 100); HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_SET); HAL_Delay(10); // 配置寄存器 ADS122U04_Config config = { .CONFIG0 = 0x01, // 20SPS, 普通模式 .CONFIG1 = 0x04, // 增益=8, 差分输入AIN0/AIN1 .CONFIG2 = 0x10, // 使用内部2.048V基准 .CONFIG3 = 0x00 // 默认设置 }; uint8_t write_cmd[5] = {0x40, config.CONFIG0, config.CONFIG1, config.CONFIG2, config.CONFIG3}; HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, write_cmd, 5, 100); HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_SET); // 启动连续转换 uint8_t start_cmd = 0x08; HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, &start_cmd, 1, 100); HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_SET); }3.2 数据采集实现
利用STM32的外部中断和DMA实现高效数据采集:
// 外部中断回调函数 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == ADS_DRDY_Pin) { static uint8_t rx_data[3]; HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Receive(&hspi1, rx_data, 3, 100); HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_SET); int32_t adc_value = (rx_data[0] << 16) | (rx_data[1] << 8) | rx_data[2]; if(adc_value & 0x800000) { // 处理24位有符号数 adc_value |= 0xFF000000; } // 转换为实际电压值 (增益=8, 基准=2.048V) float voltage = (adc_value * 2.048f) / (8388608.0f * 8); process_measurement(voltage); } }4. 精度优化与噪声抑制
4.1 PCB布局建议
高精度ADC对PCB布局非常敏感:
- 将ADS122U04尽可能靠近传感器放置
- 使用独立的模拟地和数字地,单点连接
- 电源引脚添加10μF钽电容+0.1μF陶瓷电容去耦
- 模拟信号走线远离数字信号和高频信号
- 使用屏蔽电缆连接传感器
4.2 软件滤波技术
结合硬件特性,可采用以下滤波方法:
- 移动平均滤波:取多个采样值求平均
#define FILTER_SIZE 16 float moving_avg_filter(float new_sample) { static float buffer[FILTER_SIZE]; static uint8_t index = 0; static float sum = 0; sum -= buffer[index]; buffer[index] = new_sample; sum += new_sample; index = (index + 1) % FILTER_SIZE; return sum / FILTER_SIZE; }- IIR低通滤波:适合实时处理
float iir_filter(float new_sample) { static float prev_output = 0; float alpha = 0.1; // 滤波系数 float output = alpha * new_sample + (1 - alpha) * prev_output; prev_output = output; return output; }- 去除工频干扰:采用50/60Hz陷波滤波
5. 实际应用案例:热电偶温度测量
5.1 硬件连接
使用K型热电偶测量高温(0-1200°C):
热电偶+ → AIN0 (ADS122U04) 热电偶- → AIN1 REF+ → 2.048V基准 REF- → GND5.2 冷端补偿
热电偶需要冷端补偿(CJC):
float read_temperature(void) { // 读取热电偶电压 float thermocouple_voltage = read_ads122u04(); // 读取冷端温度(使用ADS122U04内置温度传感器) float cjc_temp = read_internal_temp(); // 使用多项式近似计算温度 float temp = thermocouple_voltage * 25.5f; // 近似系数 temp += 0.1f * thermocouple_voltage * thermocouple_voltage; temp += cjc_temp; // 冷端补偿 return temp; }5.3 校准与线性化
高精度测量需要分段校准:
typedef struct { float min_temp; float max_temp; float coeff[3]; // 多项式系数 } Calibration_Segment; float calibrated_temperature(float raw_temp) { static const Calibration_Segment segments[] = { {0, 100, {0.98, 0.012, 0.0001}}, {100, 300, {1.02, 0.011, 0.00008}}, {300, 600, {1.05, 0.010, 0.00005}}, {600, 1200, {1.08, 0.009, 0.00003}} }; for(int i=0; i<4; i++) { if(raw_temp >= segments[i].min_temp && raw_temp < segments[i].max_temp) { float temp = segments[i].coeff[0] * raw_temp; temp += segments[i].coeff[1] * raw_temp * raw_temp; temp += segments[i].coeff[2] * raw_temp * raw_temp * raw_temp; return temp; } } return raw_temp; }6. 常见问题与调试技巧
6.1 数据不稳定问题排查
检查电源噪声:
- 用示波器观察ADC电源引脚
- 确保纹波<10mVpp
- 必要时增加LC滤波
验证基准电压:
- 测量REF引脚电压
- 内部基准精度±0.1%,温漂5ppm/°C
检查SPI时序:
- 确保SCLK频率不超过10MHz
- CS信号在传输前后保持足够时间
6.2 精度优化技巧
系统校准方法:
- 零点校准:短接输入端,读取偏移量
- 满量程校准:输入已知参考电压
- 存储校准系数到STM32 Flash
温度补偿:
- 使用ADS122U04内置温度传感器
- 建立温度-误差查找表
接地技巧:
- 星型接地布局
- 避免地环路
- 敏感电路使用独立电源
6.3 低功耗设计
对于电池供电设备:
- 配置ADS122U04为单次转换模式
- 关闭不用的模拟前端电路
- 使用STM32低功耗模式(STOP模式)
- 动态调整数据速率
void enter_low_power_mode(void) { // 配置ADS122U04为单次模式 uint8_t cmd = 0x02; // 单次转换命令 HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, &cmd, 1, 100); HAL_GPIO_WritePin(ADS_CS_GPIO_Port, ADS_CS_Pin, GPIO_PIN_SET); // 配置STM32进入STOP模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); }