ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于ADS122U04与STM32F410RB的工业级高精度温度测量方案

基于ADS122U04与STM32F410RB的工业级高精度温度测量方案

1. 工业与HVAC温度测量方案的整体设计思路

工业现场和HVAC系统里的温度测量,跟我们在实验室用个万用表测室温完全是两码事。工业场景往往要求-200°C到850°C的宽量程覆盖,HVAC水系统则常年泡在2°C到95°C的循环水里,还要面对长线缆引入的噪声、电机启停带来的共模干扰、以及传感器老化漂移带来的精度衰减。我做过几个楼宇自控和工业炉温采集的项目,踩过的坑基本都集中在信号链前端——传感器选型、激励方式、ADC配置这三块。这次拿ADS122U04IPWR配STM32F410RB来做温度采集,就是冲着这套组合在低速率高精度场景下的性价比去的。

ADS122U04IPWR是TI的一款24位ΔΣ型ADC,内置PGA、双匹配电流源、振荡器和温度传感器,QFN封装只有3.5mm×3.5mm,四路单端或两路差分输入,SPI兼容接口。STM32F410RB则是ST的Cortex-M4F内核MCU,带硬件浮点和128KB Flash,跑个温度线性化和Modbus从站绰绰有余。两者搭配的核心逻辑是:ADS122U04负责把RTD或热电偶的微弱信号数字化,STM32F410RB负责配置ADC、读取数据、做线性化运算、再通过UART或RS-485把温度值送出去。

为什么不用MCU自带的12位ADC直接测?因为PT100在0°C时只有100Ω,1°C对应约0.385Ω的变化,配合1mA激励电流也就0.385mV/°C。12位ADC在3.3V参考下LSB约0.8mV,根本分辨不出0.1°C的变化。ADS122U04在PGA=128、数据率20SPS时,有效分辨率能到21位以上,噪声自由度高,这才是工业级温度测量该有的前端。

这套方案适合谁?做工业数据采集模块的硬件工程师、搞HVAC控制器开发的嵌入式软件工程师、以及需要把温度信号接入PLC或SCADA系统的系统集成商。如果你正在选型温度采集前端,或者手头有STM32板子想扩展高精度模拟输入,这篇内容可以直接抄作业。

2. 核心器件选型与信号链细节解析

2.1 为什么选ADS122U04而不是ADS1220或ADS1248

ADS122U04和ADS1220是Pin-to-Pin兼容的,主要区别在于ADS122U04多了个UART接口选项,但我们用SPI模式时两者几乎一样。选ADS122U04IPWR的TSSOP-16封装(注意IPWR后缀是TSSOP,不是QFN)主要是为了手工焊接方便,QFN的ADS122U04IRTER虽然小但返修麻烦。ADS1248是8通道的,价格贵一截,做两路温度采集用不上。

关键参数对比:

特性ADS122U04ADS1220ADS1248
分辨率24位24位24位
输入通道4单端/2差分4单端/2差分8单端/4差分
PGA增益1~1281~1281~128
数据率5~2000SPS5~2000SPS5~2000SPS
激励电流源2路10μA~1.5mA2路10μA~1.5mA2路50μA~1.5mA
接口SPI/UARTSPISPI
封装TSSOP-16/QFNTSSOP-16/QFNTSSOP-28

ADS122U04内置的2.048V基准温漂典型值5ppm/°C,最大20ppm/°C。如果环境温度变化±20°C,基准漂移带来的误差约0.04%,对PT100在100°C时约0.04°C,可以接受。如果要更高精度,外接REF5025或ADR4525,但成本上去了。

2.2 RTD三线制接法与激励电流源配置

工业现场最常用的是三线制PT100,因为二线制引线电阻直接叠加在测量结果里,100米1mm²铜线来回电阻约3.4Ω,对应约8.8°C误差,完全不能用。四线制最准但线缆成本高,三线制在精度和成本间取得平衡。

ADS122U04的两个匹配电流源IDAC1和IDAC2可以分别从AIN0和AIN3流出,在RTD和引线电阻上产生压降。三线制接法:

  • IDAC1从AIN0流出,经引线1到RTD高端
  • IDAC2从AIN3流出,经引线3到RTD低端
  • RTD低端经引线2回到AIN2
  • AIN1接RTD高端

这样配置后,引线1和引线3的电阻压降被ADC的差分输入抵消,前提是IDAC1=IDAC2且引线电阻相等。实测中引线电阻差异在0.1Ω以内时,残余误差小于0.25°C。

注意:IDAC电流不要设太大。1mA激励在PT100上产生100mV压降,自热约0.1mW,温升可忽略。设成1.5mA虽然信号更大,但自热翻倍,长期稳定性变差。我一般用500μA,配合PGA=32,信号幅度刚好在ADC量程的60%左右。

2.3 STM32F410RB的SPI配置要点

STM32F410RB的SPI1挂载在APB2总线上,最高时钟100MHz。ADS122U04的SPI模式0(CPOL=0,CPHA=0)或模式1(CPOL=0,CPHA=1)都支持,我习惯用模式1,因为数据在第二个边沿采样,时序余量大。SCLK频率不要超过4MHz,虽然手册标称支持到10MHz,但长线缆上高速率容易出错,2MHz足够。

关键配置:

SPI_HandleTypeDef hspi1; hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_2EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

APB2时钟100MHz,32分频后SCLK=3.125MHz,实测稳定。CS引脚用GPIO手动控制,因为ADS122U04的CS下降沿启动通信,用硬件NSS反而容易出时序问题。

3. 硬件电路设计与实操配置

3.1 模拟前端电路布局

原理图这块,ADS122U04的外围元件不多但每个都关键。AVDD和DVDD都接3.3V,但模拟电源必须经过LC滤波。我用的是10μH电感串联,后面跟10μF钽电容加0.1μF陶瓷电容。数字电源单独走线,在芯片下方用0Ω电阻连接模拟地和数字地。

基准电压选择内部2.048V时,REF引脚接0.1μF加1μF电容到地。如果外接基准,REF5025的输出接REF引脚,同样加去耦电容。

输入滤波:每个模拟输入串10Ω电阻,对地接0.1μF电容,截止频率约160kHz,能滤掉大部分高频噪声又不影响20SPS的数据率。共模滤波用两个0.01μF电容分别对地,差模用0.1μF跨接。

实操心得:PCB布局时,ADS122U04的模拟输入走线要远离SPI时钟线和电源开关节点。我第一版把SCLK走线从AIN0旁边穿过,结果读数跳动超过50个码。后来把SPI线绕到板子另一层,跳动降到5个码以内。

3.2 寄存器配置流程

ADS122U04有四个配置寄存器,上电后需要按顺序写入。我整理了一个初始化序列:

// 复位ADC ADS122U04_WriteReg(0x06, 0x06); // 发送RESET命令 HAL_Delay(1); // 配置寄存器0:MUX=AIN0/AIN1, GAIN=32, PGA使能 ADS122U04_WriteReg(0x00, 0x08); // 位定义:MUX[3:0]=0000(AIN0/AIN1), GAIN[2:0]=011(32), PGABYPASS=0 // 配置寄存器1:数据率20SPS, 连续转换模式, 内部基准 ADS122U04_WriteReg(0x01, 0x04); // DR[2:0]=100(20SPS), MODE[1:0]=00(连续), VREF[1:0]=00(内部) // 配置寄存器2:IDAC=500uA, IDAC1=AIN0, IDAC2=AIN3 ADS122U04_WriteReg(0x02, 0x15); // IDAC[2:0]=101(500uA), IDAC1[3:0]=0000(AIN0), IDAC2[3:0]=0011(AIN3) // 配置寄存器3:禁用温度传感器, 禁用 burnout 电流源 ADS122U04_WriteReg(0x03, 0x00);

写寄存器时注意,ADS122U04的SPI写操作是:先发命令字节(0x40 | 寄存器地址<<2),然后发数据字节。读操作是发0x20 | 地址<<2,然后读一个字节。

3.3 温度换算与线性化

PT100的电阻-温度关系用Callendar-Van Dusen方程:

  • 0°C到850°C:R(t) = R0 * (1 + At + Bt²)
  • -200°C到0°C:R(t) = R0 * (1 + At + Bt² + C*(t-100)*t³)

其中A=3.9083e-3,B=-5.775e-7,C=-4.183e-12,R0=100Ω。

反过来从电阻算温度,正向用公式,反向用二分法或查表。STM32F410RB有硬件浮点,直接跑二分法迭代10次就能到0.01°C精度,耗时不到100μs。

float PT100_ResistanceToTemp(float resistance) { float t_low = -200.0f, t_high = 850.0f, t_mid; for (int i = 0; i < 20; i++) { t_mid = (t_low + t_high) / 2.0f; float r_calc = PT100_TempToResistance(t_mid); if (r_calc > resistance) t_high = t_mid; else t_low = t_mid; } return t_mid; }

ADC码值到电阻的换算:ADS122U04输出24位有符号数,满量程对应±VREF/GAIN。RTD电阻 = (码值 / 2^23) * (VREF / GAIN) / IDAC。注意这里码值是二进制补码,要先转成有符号整数。

注意:ADS122U04在PGA=32时,输入共模范围有限制。共模电压必须在(AVDD-0.9V)和(AVSS+0.9V)之间。三线制接法下,RTD高端电压约100mV+引线压降,低端约0V+引线压降,共模约50mV,完全在范围内。但如果用四线制且激励电流从高端流入,共模会抬高,需要重新计算。

4. 常见问题排查与实战避坑指南

4.1 读数跳动大怎么办

这是最常遇到的问题。我按排查顺序列个表:

现象可能原因排查方法解决措施
跳动>100码电源噪声示波器看AVDD纹波加LC滤波,模拟电源独立LDO
跳动>50码SPI时序问题逻辑分析仪抓SCLK和DIN降低SCLK频率,检查CS时序
跳动>20码输入滤波不足短接输入看噪声加RC滤波,截止频率<200kHz
跳动>10码基准噪声换外部基准对比用REF5025,加去耦
跳动>5码PCB布局检查地平面完整性模拟地数字地单点连接

我遇到过最诡异的一次,读数每隔几秒跳一次大数,最后发现是附近继电器动作时通过空间耦合进来的。解决办法是在RTD引线上套磁环,同时软件做中值滤波,连续采5个点去掉最大最小取平均。

4.2 温度值偏差大怎么校准

偏差分两种:零点偏差和增益偏差。零点偏差用冰水混合物校准,增益偏差用沸水或标准温度源校准。

单点校准只能修零点,两点校准才能同时修零点和增益。我一般用0°C和100°C两点:

// 校准系数 float cal_offset = 0.0f; // 零点偏移 float cal_gain = 1.0f; // 增益系数 // 在0°C时读取raw_temp_0,在100°C时读取raw_temp_100 cal_gain = 100.0f / (raw_temp_100 - raw_temp_0); cal_offset = -raw_temp_0 * cal_gain; // 应用校准 float calibrated_temp = raw_temp * cal_gain + cal_offset;

校准系数存在STM32F410RB的Flash里,上电读取。注意Flash写入前要解锁,写入后要锁回。

4.3 长线缆引入的共模干扰

工业现场RTD线缆可能长达几十米,电机变频器产生的共模电压能到几十伏。ADS122U04的共模抑制比在PGA=32、50/60Hz时约100dB,但前提是共模电压在允许范围内。

我的做法是在ADC输入端加共模扼流圈,同时用屏蔽双绞线,屏蔽层单端接地。如果共模电压可能超过电源轨,需要加TVS管钳位。实测在变频器旁边,不加共模扼流圈时读数跳动约2°C,加了之后降到0.1°C以内。

实操心得:ADS122U04的内部振荡器在连续转换模式下会自动运行,不需要外部时钟。但如果用外部晶振,注意晶振频率要在2MHz到4MHz之间,且要加负载电容。我试过用8MHz晶振,结果ADC完全不工作,后来查手册才发现超频了。

4.4 STM32F410RB的DMA与中断配置

连续转换模式下,ADS122U04的DRDY引脚会在新数据准备好时拉低。用STM32F410RB的外部中断检测DRDY下降沿,在中断里读SPI数据。但SPI读取需要24个时钟周期,在中断里做会阻塞其他中断。

更好的做法是用DMA。配置SPI1的RX DMA通道,DRDY触发EXTI,EXTI中断里启动DMA传输,DMA完成中断里处理数据。这样CPU占用率极低。

void EXTI0_IRQHandler(void) { if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) != RESET) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0); HAL_SPI_Receive_DMA(&hspi1, adc_rx_buf, 3); } } void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { int32_t raw = (adc_rx_buf[0] << 16) | (adc_rx_buf[1] << 8) | adc_rx_buf[2]; if (raw & 0x800000) raw |= 0xFF000000; // 符号扩展 temp_queue_push(raw); }

注意ADS122U04的DRDY在连续转换模式下,数据率20SPS时每50ms拉低一次。如果MCU在50ms内处理不完,会丢数据。STM32F410RB跑100MHz,处理这点数据绰绰有余。

5. 系统集成与扩展应用

5.1 多路温度采集的通道切换

ADS122U04只有两路差分输入,做多路温度采集需要外接多路复用器。我用过CD4051和ADG708,前者便宜但导通电阻大(约100Ω),后者贵但导通电阻只有几欧姆。导通电阻会与RTD串联,引入误差。如果必须用CD4051,要在软件里补偿导通电阻,或者用四线制接法让导通电阻不影响测量。

通道切换后要等稳定再读数据。CD4051的切换时间约100ns,但RTD和滤波电容的建立时间要算:RC时间常数=10Ω×0.1μF=1μs,5个时间常数5μs。20SPS下50ms才出一个数据,完全来得及。

5.2 与Modbus RTU的对接

工业现场最常用的通信协议是Modbus RTU。STM32F410RB的UART接RS-485收发器,跑9600或19200波特率。温度值放在保持寄存器里,主机用03功能码读取。

寄存器映射:

寄存器地址内容数据类型说明
0x0000通道1温度int16值=温度×10,单位0.1°C
0x0001通道2温度int16值=温度×10
0x0002状态字uint16bit0=通道1有效,bit1=通道2有效
0x0003校准偏移int16值=偏移×10

Modbus RTU的CRC16计算用查表法,STM32F410RB的Flash放256个uint16的表占512字节,完全没问题。

5.3 低功耗设计考虑

HVAC控制器有时用电池供电,需要低功耗。ADS122U04在单次转换模式下,转换完自动进入掉电模式,电流从几百μA降到几μA。STM32F410RB在Stop模式下电流约10μA,RTC唤醒。

工作流程:RTC每10秒唤醒MCU,MCU启动ADS122U04单次转换,等DRDY,读数据,算温度,存Flash,然后MCU和ADC都进低功耗模式。平均电流可以做到50μA以下,一节18650电池能用好几年。

注意:ADS122U04从掉电模式唤醒后,内部基准需要稳定时间。手册标称最大1ms,我实测约0.5ms。单次转换模式下,启动转换后要等至少1ms再读数据,否则基准没稳,读数偏差大。

5.4 电磁兼容性测试要点

工业产品要做EMC测试,辐射发射和传导发射是必测项。ADS122U04的SPI时钟是主要辐射源,SCLK频率3.125MHz,谐波能到几十MHz。我在SCLK线上串了33Ω电阻,辐射降了6dB。电源线加共模扼流圈,传导发射也能过。

静电放电测试时,RTD输入端要加TVS管。我用的是SM712,双向钳位电压12V,结电容10pF,对20SPS的数据率没影响。接触放电8kV测试时,不加TVS管ADC会复位,加了之后读数只是短暂跳动,自动恢复。

这套ADS122U04加STM32F410RB的温度测量方案,我从第一版打样到最终过EMC测试,前后改了四版PCB。最大的教训是模拟电源和数字电源一定要分开,哪怕多用一个LDO也值得。另外ADS122U04的寄存器配置顺序不能乱,必须先复位再配置,否则内部状态机可能卡死。软件上,温度换算的二分法迭代次数不要少于15次,否则在-200°C附近精度不够。最后分享一个小技巧:ADS122U04的DRDY引脚在连续转换模式下,如果MCU来不及读,数据会覆盖。可以在DRDY中断里只置标志位,主循环里读数据,这样不会丢中断。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进