基于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在PGA128、数据率20SPS时有效分辨率能到21位以上噪声自由度高这才是工业级温度测量该有的前端。这套方案适合谁做工业数据采集模块的硬件工程师、搞HVAC控制器开发的嵌入式软件工程师、以及需要把温度信号接入PLC或SCADA系统的系统集成商。如果你正在选型温度采集前端或者手头有STM32板子想扩展高精度模拟输入这篇内容可以直接抄作业。2. 核心器件选型与信号链细节解析2.1 为什么选ADS122U04而不是ADS1220或ADS1248ADS122U04和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-28ADS122U04内置的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回到AIN2AIN1接RTD高端这样配置后引线1和引线3的电阻压降被ADC的差分输入抵消前提是IDAC1IDAC2且引线电阻相等。实测中引线电阻差异在0.1Ω以内时残余误差小于0.25°C。注意IDAC电流不要设太大。1mA激励在PT100上产生100mV压降自热约0.1mW温升可忽略。设成1.5mA虽然信号更大但自热翻倍长期稳定性变差。我一般用500μA配合PGA32信号幅度刚好在ADC量程的60%左右。2.3 STM32F410RB的SPI配置要点STM32F410RB的SPI1挂载在APB2总线上最高时钟100MHz。ADS122U04的SPI模式0CPOL0CPHA0或模式1CPOL0CPHA1都支持我习惯用模式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时钟100MHz32分频后SCLK3.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); // 配置寄存器0MUXAIN0/AIN1, GAIN32, PGA使能 ADS122U04_WriteReg(0x00, 0x08); // 位定义MUX[3:0]0000(AIN0/AIN1), GAIN[2:0]011(32), PGABYPASS0 // 配置寄存器1数据率20SPS, 连续转换模式, 内部基准 ADS122U04_WriteReg(0x01, 0x04); // DR[2:0]100(20SPS), MODE[1:0]00(连续), VREF[1:0]00(内部) // 配置寄存器2IDAC500uA, IDAC1AIN0, IDAC2AIN3 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°CR(t) R0 * (1 At Bt²)-200°C到0°CR(t) R0 * (1 At Bt² C*(t-100)*t³)其中A3.9083e-3B-5.775e-7C-4.183e-12R0100Ω。反过来从电阻算温度正向用公式反向用二分法或查表。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在PGA32时输入共模范围有限制。共模电压必须在(AVDD-0.9V)和(AVSS0.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的共模抑制比在PGA32、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触发EXTIEXTI中断里启动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μF1μs5个时间常数5μs。20SPS下50ms才出一个数据完全来得及。5.2 与Modbus RTU的对接工业现场最常用的通信协议是Modbus RTU。STM32F410RB的UART接RS-485收发器跑9600或19200波特率。温度值放在保持寄存器里主机用03功能码读取。寄存器映射寄存器地址内容数据类型说明0x0000通道1温度int16值温度×10单位0.1°C0x0001通道2温度int16值温度×100x0002状态字uint16bit0通道1有效bit1通道2有效0x0003校准偏移int16值偏移×10Modbus RTU的CRC16计算用查表法STM32F410RB的Flash放256个uint16的表占512字节完全没问题。5.3 低功耗设计考虑HVAC控制器有时用电池供电需要低功耗。ADS122U04在单次转换模式下转换完自动进入掉电模式电流从几百μA降到几μA。STM32F410RB在Stop模式下电流约10μARTC唤醒。工作流程RTC每10秒唤醒MCUMCU启动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中断里只置标志位主循环里读数据这样不会丢中断。