做暖通和工业温度测量方案时,ADS122U04IPWR 这颗芯片我前后在多个项目里用过。STM32F373VC 自带16位Σ-Δ型ADC,很多人第一反应是"F373 自带的都不差,何必再外挂一颗24位的ADS122U04?"这个问题恰恰是整个方案里最值得展开的地方。下面记录的内容,按从硬件电路到通信协议、再从数据换算到实测排障的顺序来写,涉及PT100/PT1000、热电偶、模拟前端布线、UART帧解析、50/60Hz工频抑制这些HVAC温度测量里绕不开的硬骨头。如果你正在做楼宇自控、冷水机、风柜或者电控柜温度采集,这篇可以直接参考落地。
1. 方案拆解:为什么F373已有高精度ADC,还要外挂ADS122U04
1.1 F373片内16位Σ-Δ ADC的现实表现
STM32F373VC 是市面上少有的自带16位Σ-Δ型ADC的MCU,它内部除了常规12位SAR ADC之外,还集成了好几个独立的16位Σ-Δ转换器,选型时确实很有吸引力。但真把它用在工业 HVAC 场景里,会有几个绕不开的约束。首先,片内Σ-Δ ADC的输入通道有限,F373虽然有多路,但做多通道温度巡检时,配合输入多路开关会引起电荷注入、通道串扰和建立时间不足的问题,连续切换采样时很难把所有通道都稳定读出。
其次是参考电压来源。片内ADC可以用VDDA作参考,但VDDA通常经过LDO或DC-DC,噪声往往不算理想。工业测温现场又有变频器、接触器、水泵电机等干扰源,如果参考不够干净,LSB再小也是白搭。在实际做西门子风柜控制器和冷水机群的温度采集时,我遇到过用F373内置ADC采集PT100,读数在目标温度附近来回跳 ±1.2℃ 的情况,做普通显示可以,但做PID闭环就明显不够。
这就引出了外挂ADC的核心价值:把模拟前端、参考电压、PGA增益、激励电流源都交给一颗专门的芯片去管理,MCU只负责通信和算法。模拟部分和数字部分分离,噪声回路短,抗干扰能力直接上了一个台阶。
1.2 ADS122U04到底是谁,怎么和F373分工
ADS122U04 是TI推出的24位低功耗ADC,U后缀代表带UART接口,04表示有4路模拟输入通道,PWR 后缀对应TSSOP-16封装。把"UART接口"和"24位ADC"放在同一颗芯片里,在工业温度采集场景里是个很聪明的设计。传统SPI接口ADC需要MCU额外占用GPIO去模拟时序,或者至少得拉SCLK、MOSI、MISO、CS四条线,而ADS122U04只需要RX、TX两条线,加上一个可选的DRDY状态引脚。走线简单、隔离容易,甚至在MCU资源紧张时可以挂在已有的串口上,用DMA接收去做协议解析,不增加CPU负担。
ADS122U04内部集成了很多对温度测量非常关键的外设:可编程增益放大器PGA、两个可配置的IDAC恒流源、内部精密参考电压(2.048V),还带内部温度传感器专门给热电偶做冷端补偿。这些功能如果全用分立元件搭建,PCB面积和调试成本会迅速膨胀。更关键的是,PGA和IDAC都是经过出厂校准的,一致性比离散方案好很多,批量生产时不用每台设备去调激励电流。
它和STM32F373VC的分工很清晰:ADS122U04负责模拟信号调理与模数转换,STM32F373VC负责指令下发、数据解析、数字滤波、温度标定、通信组网和PID控制。MCU做不了精确的微伏级测量,ADC做不了复杂的控制逻辑,两者搭配是典型的"让专业的人干专业的事"。
2. 硬件电路设计:照着画就能稳定跑的方案
2.1 电源、参考电压与PT100比例测量电路
ADS122U04的电源域分AVDD/AVSS和DVDD/DGND,模拟和数字供电需要分别接0.1μF陶瓷电容做高频去耦,同时在靠近AVDD引脚处并联一颗10μF钽电容或者X7R大电容,应对低频扰动。DVDD和AVDD如果都从同一路3.3V供电,中间至少要加一个磁珠或者一颗10Ω电阻做隔离,避免数字串口开关噪声窜进模拟参考路径。实测中这个磁珠位置处理不当,会导致ADC噪声从大约1μVpp恶化到5μVpp。
参考电压是整个测量链路里最容易出问题的环节。ADS122U04提供内部2.048V参考,但内部参考的温漂和噪声虽然够用,追求更高稳定性时我还是建议外接精密基准,比如用REF5025或者ADR4525输出2.5V接到REFP0/REFN0。千万别以为给REFP0接个LDO输出就可以了,LDO的电压调整率和噪声根本不满足24位ADC对参考的预期,轻则噪声变大,重则低端码值出现明显非线性。
测量PT100时采用比例测量法,这是整个设计中最值得花时间理解的部分。思路是让同一个IDAC恒流源同时流过PT100和精密基准电阻Rref,ADC的参考电压直接取自Rref两端,测量电压取自PT100两端,最后ADC输出代码只取决于两个电阻的比值,和激励电流的绝对值无关。这样即使IDAC随温度从500μA漂到498μA,只要两端同步变化,最终计算出的电阻值仍然准确。
电路连接上,PT100用四线制接法最稳:IDAC1从PT100一端注入电流,PT100另一端经过引线回到AIN0;同时再用两根独立的电压采样线分别接PT100两端到AIN1和AIN0之间做差分输入。选Rref时,如果IDAC设为500μA,选择Rref=1.8kΩ,参考电压就是0.9V。PT100在0℃时约100Ω,对应电压50mV,ADC输出码为 100/1800×2^23 ≈ 466033。这个码值范围让24位ADC的性能得到比较充分的利用。
三线制RTD也能用,但要遵循"电流路径和电压路径分离"的原则。三根线里,两根同色线接在RTD同一端,分别走电流回路和电压采样,另一根单独接IDAC电流入口。原理上两线制无法消除引线电阻,三线制可以消去一侧引线电阻,四线制才是完整消除两边引线电阻的终极方案。工程上如果为了省线必须用三线制,记得让两根同色线的长度尽量一致,线阻对称性越好,补偿效果越好。
2.2 UART接口与输入保护电路
ADS122U04的UART接口就是标准的异步串行,TXD接STM32的RX引脚,RXD接STM32的TX引脚,需要注意它不是RS232也不是RS485电平,而是3.3V TTL电平,传输距离超过1米就必须加电平转换或者隔离。在工业HVAC场景中,传感器板常常和主控板分开放置,这时我习惯在UART中间加ISO7241这类数字隔离器,隔离地环路噪声,顺带增强抗浪涌能力。如果不隔离,雷击或接触器拉弧时,感应电压容易从串口地线窜进来。
模拟输入端AIN0~AIN3需要加RC低通滤波。典型值是100Ω电阻加1nF电容,截至频率约1.6MHz,主要作用是拦住高频辐射干扰,同时给ADC内部采样保持电容提供瞬态电荷。R值可以取更大,比如1kΩ,但要注意R过大和输入偏置电流会产生压降,特别是切换PGA增益时偏置电流的变化会导致直流误差。C值不建议加大到远高于1nF,过大的输入电容会让PGA稳定时间变长,快速切换通道时第一拍数据容易偏。
对工业现场的长线来说,输入端还需要放TVS管或BAT54S这类钳位二极管,把浪涌电压钳制在电源轨和地之间。我遇到过传感器线缆被电机扫断的情况,若无保护,24V电源瞬时串进AIN引脚会直接把ADC内部ESD结构击穿。加了BAT54S之后,至少能扛住短时意外上电。注意钳位二极管的漏电流会影响高阻源的测量精度,热电偶这类高内阻源尤其明显,所以BAT54S是比普通二极管更好的选择。
2.3 PCB布局的几个实战细节
ADS122U04的TSSOP-16封装不算大,布局时重点是分清模拟区与数字区。我的习惯是先确定AGND和DGND的星形连接点,在ADC芯片下方的焊盘处单点汇合,避免数字地电流穿过模拟地平面。STM32F373VC的IO翻转噪声比较大,尽量把它放在PCB的另一侧,中间用地平面隔离,串口线从ADC出来之后两线并行走,短而直,不要跨越模拟输入线。
参考电阻Rref的位置要离REFP0/REFN0尽可能近,因为参考引脚输入阻抗随时间变化,任何串联寄生电阻都会引入参考电压误差。IDAC1到PT100的走线也尽量短,如果走线穿过继电器区,最好加屏蔽地。实测中发现,把Rref放在ADC背面时,参考电压纹波被放大了将近一倍,重新布局后噪声恢复正常。
电源顺序也有讲究。如果系统有多个电源轨,先让STM32F373VC完成启动,再给ADS122U04上电。ADC上电之后主机不要立刻发命令,等待约1ms让内部振荡器和参考电压稳定,否则第一帧命令容易丢失,返回数据是随机值。这个启动时序上的坑在批量测试时能遇到好几次,建议在MCU初始化里加一个明确延时。
3. UART通信与寄存器配置:协议没有想象中那么复杂
3.1 帧格式和时序:从SOF到XOR校验
ADS122U04的UART协议基于命令-响应模式。主机发送命令帧,ADC处理后返回响应帧或者开始转换。帧结构包含起始字节SOF(固定为0xAA)、命令字节、数据字节和校验字节。广播下发过程中,0xAA既是帧头又承担同步作用,ADC会利用这个字节的边沿关系来自动校准波特率,所以上电后建议先发送一两个0xAA让协议栈对齐,再进行真正的寄存器配置。
校验字节用的是XOR校验。对命令帧来说,XOR = 命令字节和数据字节逐字节异或。举个例子,向配置寄存器0x00写入0x08,命令就是 0xAA 0x40 0x00 0x08 0x48,其中0x40是WREG命令加寄存器地址0x00,0x48是0x40、0x00、0x08三个字节的异或结果。发送过程别漏掉末尾的XOR,否则ADC会直接丢弃整个命令帧。接收端解析时,注意引脚配置为开漏输出的DRDY状态,有些模式下它会拉低以指示数据就绪,与SPI接口不同,UART模式下不存在时钟约束,时序处理上更宽松,但帧同步反而成了主要难点。
实际使用中我倾向于用一个简单的环形缓冲区接收UART数据,DMA每收到一个字节就丢进缓冲区,主循环里按状态机寻找0xAA帧头,之后边收数据边累计XOR,凑满整帧长度后校验通过才认为这是一条合法响应。这种做法不挑串口中断优先级,即使UART中断偶尔被打断也不会错乱帧边界。
3.2 关键寄存器配置:靠一组字节搞定所有通道
ADS122U04的配置寄存器一共有4个。寄存器0x00重点是输入多路开关MUX选择、PGA增益和旁路设置。MUX字段决定当前测量哪一路输入,比如差动AIN0-AIN1、单端AIN0和AVSS,或者内部温度传感器。PGA增益支持1、2、4、8、16、32、64、128倍,PT100测温通常用1倍就够了,热电偶因为信号只有十几毫伏,建议至少开到32倍以上。
寄存器0x01是数据速率和滤波器模式配置。DR字段决定数据速率,SINC3滤波器适合低频高精度,SINC1滤波器响应更快但噪声大些。在50Hz电网地区的工业现场,选择数据速率时可以考虑让滤波器陷波点对准50Hz,或者在软件里再做一次平均。寄存器0x02控制参考电压和IDAC电流源,这部分和2.1节的比例测量方案搭配,IDAC输出引脚选择、电流量级都要在这里配合硬件电路完成。
具体来说,我常用的初始化配置序列是:先把寄存器0x00设为PGA=1倍、差动AIN0-AIN1,寄存器0x02设置为IDAC=500μA、IDAC输出到IDAC1引脚、参考电压使用外部REFP0/REFN0。这一步定了之后,后续切换通道只需要重新写寄存器0x00的MUX字段即可。切换通道后ADS122U04内部PGA需要约十几个转换周期建立,务必丢弃切换后的前几个读数,否则会看到数据从旧通道慢慢"爬"到新通道的现象。
3.3 STM32F373侧的驱动与数据读取代码
STM32侧我直接用HAL库加DMA方式收发。代码逻辑上,用一个发送函数把命令帧发给ADC,另一个接收函数等响应帧。由于响应帧是异步进来的,接收我用了空闲中断或者字节数匹配中断,实测下来空闲中断最简单,因为每帧数据之间有足够长的间隔,恰好可以利用"总线空闲"来切断一帧。
写寄存器命令可以这样实现:
static void ads122u04_write_reg(uint8_t reg_addr, uint8_t reg_val) { uint8_t cmd[5]; cmd[0] = 0xAA; cmd[1] = 0x40 | (reg_addr & 0x03); cmd[2] = 0x00; cmd[3] = reg_val; cmd[4] = cmd[1] ^ cmd[2] ^ cmd[3]; HAL_UART_Transmit(&huart1, cmd, 5, 100); HAL_Delay(1); }读取ADC数据时,先发RDATA命令,然后从UART接收响应帧。响应帧里的数据字段就是24位二进制补码,即真实的转换结果。将三个字节拼接成int32_t之后,再按照比例关系换算成电压或电阻值。
uint8_t read_cmd[5] = {0xAA, 0x12, 0x00, 0x00, 0x12}; HAL_UART_Transmit(&huart1, read_cmd, 5, 100); uint8_t resp[16]; HAL_UART_Receive(&huart1, resp, sizeof(resp), 100); int32_t raw = (resp[2] << 16) | (resp[3] << 8) | resp[4]; if (raw & 0x800000) raw |= 0xFF000000; float ratio = (float)raw / 8388608.0f;驱动写完以后,用逻辑分析仪抓一次UART波形能排查掉大半个通信问题。重点关注帧间隔是否稳定、ADC响应是否完整、XOR校验是否一致。把这三条确认清楚,UART层就算打通了。
4. 温度换算:从裸ADC值到真实温度的关键一步
4.1 PT100的线性化与查表方法
拿到原始ADC码值后,第一步是换算电阻。比例法下的公式很简单:
R_rtd = (ADC_code / 8388608.0f) × Rref
这里ADC_code是24位补码转出的正数,Rref是精密基准电阻的标称值。重点来了,Rref这颗电阻的精度和温漂直接影响最终测温精度,必须选低温漂的精密电阻,比如±0.1%精度、温漂≤5ppm/℃的金属箔电阻。实测中如果Rref用了普通厚膜电阻,温度扫描时换算出的R_rtd会跟着环境温度摆动,这个误差非常隐蔽。
从电阻到温度,PT100的阻温特性可以用Callendar-Van Dusen方程描述。0℃以上简化为:
R(t) = R0 × (1 + A×t + B×t²)
其中R0=100Ω,A=3.9083×10⁻³,B=-5.775×10⁻⁷。反求温度t是个一元二次方程,直接用求根公式或者牛顿迭代都能快速解决。我用牛顿迭代的代码简单可靠,最多迭代5次就能收敛到0.001℃以内。
float resistance_to_pt100_temp(float resistance) { float t = (resistance / 100.0f - 1.0f) / 0.00385f; for (int i = 0; i < 5; i++) { float r = 100.0f * (1.0f + 3.9083e-3f * t - 5.775e-7f * t * t); float drdt = 100.0f * (3.9083e-3f - 2.0f * 5.775e-7f * t); t -= (r - resistance) / drdt; } return t; }批量项目如果怕浮点运算慢,直接用查表法更省事。把温区按每0.1℃一个点做成常量表,用二分查找加线性插值,速度飞快。查表法还自带纠错效果,因为表来自标准ITS-90的数据,比简化方程要精确。我个人在HVAC项目里普遍用查表法,反正Flash装得下。
4.2 热电偶冷端补偿与内部温度传感器
热电偶测温的原理是热电效应,测量端和冷端温差产生热电势。但ADC本身只能测到毫伏级电压,冷端温度必须额外补偿。ADS122U04内置了片上温度传感器,精度典型值±0.5℃左右,用于冷端补偿完全够用。配置寄存器把MUX切到内部温度传感器模式,读取到的ADC码再换算成温度,这个数就是热电偶冷端的实际温度。
K型热电偶在0~1000℃范围内的热电势可以查NIST多项式,直接算也行。基本的补偿公式是:
T_hot = T_cold + E_measured / S(T_cold)
其中S是热电偶在冷端温度附近的塞贝克系数,K型约41μV/℃。这种线性化精度够HVAC使用,控制风管温度在±0.5℃内没问题。真要更高精度,用查表法对热电偶全温区做逐段补偿。
费用上要注意,热电偶信号本身就非常微弱,PGA增益需要开高,同时输入端更怕工频干扰。我在焓差实验室用K型热电偶实测过,PGA设置64倍、数据速率20SPS加50Hz滤波时,数据显示平稳,而增益选择过低时读数明显被噪声淹没。热电偶输入线建议全程屏蔽双绞,屏蔽层单端接地。
4.3 转换结果的软件滤波与抗工频处理
硬件滤波和软件滤波要配合。ADS122U04内部SINC3滤波器本身对工频有陷波,但它只对特定频率的小倍数有效。现场变频器是主要干扰源,变频器输出的PWM谐波频谱很宽,单靠ADC内滤波不彻底,软件上还要加移动平均或一阶低通。
我在HVAC应用里最常用的软件滤波是滑动窗口中值加平均:先取5个原始采样值去掉最大最小,再对剩下3个做平均。这样能同时抑制脉冲噪声和随机噪声,响应速度也不至于太慢。温度控制回路要求输出周期在几百毫秒级别,这个滤波方案完全够用。
风速、水流变化带来的温度波动其实是真实物理量,软件滤波不能把它滤掉,否则控制回路会失去对扰动的感知。所以滤波强度的选择要结合被控对象的时间常数,风管温度传感器时间常数通常是几十秒,滤波可以激进一点;水管温度传感器时间常数小,滤波就要保守。
5. 实测数据与经典问题排查
5.1 干扰导致测量跳动的现场复查
我接手过一个现场,冷水机群回水温度采集,用ADS122U04读数在±0.8℃范围乱跳。起初怀疑ADC坏了,后来用示波器量AIN0/AIN1波形,看到上面叠加了一大堆几百kHz的毛刺。追查发现传感器线缆和接触器控制线在同一个线槽里走了十几米,接触器一通断,毛刺就来了。
处理办法分两步:先在线缆端加共模扼流圈和RC滤波,再把传感器线缆移出动力线线槽。改动之后,噪声毛刺幅度从200mV降到5mV以内,ADC读数稳定在±0.05℃。这件事让我确立了规矩,模拟传感器的走线永远不和动力线平行敷设,必要时用金属软管屏蔽并两端接地。
5.2 温漂和器件选型不当的双重教训
有一批设备在客户现场运行半个月后,温度读数整体偏移了1.2℃。产线排查后发现参考电阻Rref用的是普通的0603厚膜电阻,环境温度从20℃升到45℃,阻值漂移了将近千分之三。换成低温漂精密电阻后问题彻底消失。
另外一次偏移问题来自热电偶本身而非ADC,客户用了非标长度的热电偶延长线,补偿导线材质不匹配,在冷端引入了额外的寄生电动势。这种问题仅靠ADC侧修不回来,必须在传感器的选型、线材和接线端子上做规范。所有工业测量系统的精度瓶颈经常不在ADC而在外设链路,这点反复强调都不为过。
5.3 通信偶发异常的排查记录
串口通信偶发丢帧是另一类高频问题。现象是设备运行一天会有一两次读到全0xFF或者校验错误。排查时首先查波特率误差,STM32F373VC的USART1使用HSE 8MHz晶振,默认配置下波特率误差很小。但如果代码里改了系统时钟来源,或者用了内部HSI振荡器,UART波特率误差会显着增大,ADC的自动波特率检测就可能失败。
解决方式是固定使用外部晶振并校验串口波特率误差,同时把UART接收超时和错误重试机制加上。我在驱动层做了一旦5帧连续错误就重新发送0xAA进行波特率同步的逻辑,这样即使个别帧丢失也能自动恢复。别小看这层保障,连续运行几个月的设备,UART抖动、晶振老化都是客观存在,没有重同步机制会越跑越乱。
5.4 常见问题速查表
| 故障现象 | 可能原因 | 排查建议 |
|---|---|---|
| 读到的ADC码恒为0xFF或0x00 | UART帧不同步、波特率误差大 | 发送0xAA同步,检查时钟配置,抓波形看帧时序 |
| 数据跳动超过±0.5℃ | 共模干扰、参考电压噪声、滤波不足 | 检查传感器线缆屏蔽、RC参数、PGA增益和软件滤波 |
| 读数随环境温度缓慢漂移 | 参考电阻温漂、IDAC激励电流异常 | 换低温漂Rref,确认比例测量接线正确 |
| 切换通道后第一次读数明显偏大 | 输入模拟开关残留电荷 | 丢弃通道切换后前2~3个转换结果 |
| DRDY引脚无变化 | ADC未收到START命令、模式配置错误 | 检查Write Register是否成功,读回寄存器验证 |
6. 方案延伸:多通道扩展与系统集成建议
6.1 用四路输入做多点温度巡检
ADS122U04只有4路模拟输入,好在它支持差动、单端和带GPIO功能的混合使用。比如一路差动测PT100,另一路差动测热电偶,再用内部温度传感器做冷端,这样单颗ADC能覆盖三种类型的温度点。做HVAC控制器时,我把回风温度、送风温度、盘管出水温度各用一颗ADC,每颗只负责单一类型传感器,好处是配置固定,不需要频繁切换MUX和PGA,稳定性更好。
如果温度点更多,比如冷库24点巡检,可以用多颗ADS122U04并联在同一个UART总线上,通过硬件地址或软件握手来区分。UART总线不像SPI有CS片选,多设备共享时需要用额外的GPIO做片选,或者用RS485总线方式寻址。项目量产后要注意,多颗ADC并发工作时,每颗的DRDY状态要分别接MCU中断引脚,避免用轮询方式不及时。
6.2 和控制器主机的整体通信设计
STM32F373VC采集到温度之后,还需要和上位机或组网主机通信。F373本身有CAN、I2C、USART,做楼宇自控时走RS485 Modbus RTU协议很常见,也可以接Wi-Fi模块做数据上云。设计上注意把模拟采集的软件模块和Modbus协议栈剥离,采用环形缓冲区解耦,这样任意一端的升级或改动不会影响另一端的稳定运行。
模块化之后,我在代码里保持了清晰的接口,比如有一个函数专门返回通道温度,另一个函数专门负责ADC配置,中间的数据换算和滤波完全隔离。这种设计在后续换用其他传感器类型时改动最小,多路温度采集的初始化、周期读取、异常上报、数据历史曲线都能相对独立地调试。
6.3 低功耗与待机模式的经验
ADS122U04本身支持关断模式和低功耗采样模式,这对电池供电的温湿度记录仪非常关键。如果设备只需要每分钟记录一次温度,可以让ADC在两次采样之间进入休眠,由MCU的定时器唤醒后启动一次转换,读取结果后再次睡去。实测整机平均电流能从连续模式的30mA降到1.5mA左右,一节锂电池可以撑过整个供暖季。
低功耗设计里有个小窍门,不要频繁给ADC上下电,上下电过程的瞬态反而更耗电。更合理做法是保持ADC供电,让它长期处于idle状态,只在采样瞬间启动转换。启动转换到数据准备好大约需要几十毫秒,对采集周期来说完全可接受。
最后说说我测过的整体效果
我手头这套配置,ADS122U04接三线PT100,Rref用1.8kΩ精密电阻,STM32F373VC跑72MHz,数据速率设为20SPS,PGA=1,连续运行72小时后,恒温槽25℃下的测量标准差大约在0.008℃左右,转换到温度示值跳动不超过±0.03℃。这个精度在HVAC里已经非常冗余,实际上我们通常会在软件里把显示分辨率限制到0.1℃,避免操作工对着小数点后面三位数字犯迷糊。
回头来看整个方案,最容易翻车的不是ADC芯片本身,而是外部的参考电阻、传感器线缆、接地和滤波。先把比例测量这条路走对,把参考和输入噪声压住,24位ADC才能显示出它该有的价值。