工业现场和楼宇暖通系统里的温度测量,看起来是个再普通不过的需求,但真正做过项目的人都知道,这里面的坑一点都不少。PT100、PT1000 这类 RTD 传感器输出信号极其微弱,100Ω 的铂电阻在 0℃ 时满量程变化也就几十毫欧每摄氏度,直接接到普通 MCU 的 ADC 上,分辨率根本不够看,噪声一上来数据就飘得没法用。我最近在做一个 HVAC 冷热量表项目,需要四路温度采集,精度要求 ±0.1℃,量程覆盖 -50℃ 到 200℃,最后选定了 ADS122U04IPWR 这颗 24 位 ΔΣ ADC 搭配 STM32L452RE 低功耗 MCU 的方案。这套组合在工业测温领域算是比较经典的搭配,但实际调试过程中遇到的细节问题远比数据手册上写的复杂。下面我把整个方案的设计思路、硬件细节、软件实现和踩过的坑完整梳理一遍,给正在做类似项目的朋友一个可复现的参考。
1. 为什么 RTD 测温不能直接上 MCU 的 ADC
1.1 RTD 的信号特性决定了前端架构
先搞清楚测量对象。PT100 在 0℃ 时阻值 100Ω,温度系数约 0.385Ω/℃。如果温度变化 0.1℃,阻值变化只有 0.0385Ω。要分辨这个变化,测量电路本身的分辨率必须远高于此。STM32L452RE 内置的 12 位 ADC,参考电压 3.3V 时最小分辨电压是 3.3V/4096 ≈ 0.8mV。假设用 1mA 恒流源激励 PT100,0.1℃ 对应的电压变化是 0.0385Ω × 1mA = 0.0385mV,连一个 LSB 的十分之一都不到。这就是为什么必须用高分辨率的外部 ADC。
ADS122U04IPWR 是 TI 的一款 24 位 ΔΣ 型 ADC,内置 PGA(可编程增益放大器)、双匹配恒流源、温度传感器和参考电压。它的有效分辨率在增益 128、20SPS 数据率下可以做到 21 位以上,等效输入噪声只有几十纳伏级别。这个性能用来测 RTD 绰绰有余。而且它自带两路匹配电流源,可以直接给 RTD 提供激励,省掉了外部恒流源电路,这对空间紧张的工业变送器来说非常友好。
1.2 四线制还是三线制:先想清楚精度和成本的平衡
RTD 接线方式直接决定了测量精度和硬件成本。两线制最简单,但导线电阻直接叠加到测量结果里,几十米长的电缆引入几欧姆误差很正常,对应温度误差就是好几度,工业场合基本不能用。三线制通过一根补偿线来抵消导线电阻,是工业上最常见的折中方案。四线制精度最高,激励电流和测量电压走不同的线对,完全消除导线电阻影响,但需要四根线,接线成本高。
我最终选了三线制方案。原因很实际:HVAC 现场布线通常是标准三芯屏蔽电缆,改成四芯意味着重新布线,施工成本翻倍。三线制在导线电阻匹配良好的情况下,精度可以做到 ±0.1℃ 以内,完全满足冷热量表的计量要求。ADS122U04 内部有两路匹配电流源,正好支持三线制的比例测量法,这是选它的一个重要原因。
1.3 比例测量法:消除激励电流漂移的关键
很多人做 RTD 测量时忽略了一个问题:恒流源的温漂。如果激励电流随温度变化,测量结果就会跟着漂。比例测量法(ratiometric measurement)是解决这个问题的标准做法。具体思路是:用同一路电流源串联激励 RTD 和一颗高精度参考电阻 Rref,然后测量 RTD 上的电压和 Rref 上的电压,两者相除,电流项就被消掉了。
公式推导很直观。设激励电流为 I,RTD 阻值为 Rrtd,参考电阻为 Rref,则:
- Vrtd = I × Rrtd
- Vref = I × Rref
- Rrtd = Rref × (Vrtd / Vref)
最终结果只跟电阻比值有关,跟电流的绝对值无关。ADS122U04 支持外部参考输入,我把 Rref 上的电压接到 REFP0/REFN0 作为参考电压,RTD 上的电压接到 AIN0/AIN1 作为输入,ADC 输出的码值天然就是比例关系,软件里连除法都省了。这个设计思路是整个方案精度的基石,后面所有细节都围绕它展开。
2. ADS122U04IPWR 外围电路设计要点
2.1 模拟输入端的滤波与保护
ADS122U04 的模拟输入端非常敏感,工业现场的电磁干扰、浪涌、静电都可能通过传感器电缆耦合进来。我在 AIN0/AIN1 输入端加了一级 RC 低通滤波,电阻用 1kΩ,电容用 100nF,截止频率约 1.6kHz。这个频率远高于温度信号带宽(温度变化本身很慢),但能有效抑制高频噪声。注意这两个电阻要选低温漂的薄膜电阻,普通厚膜电阻的温漂会引入额外误差。
输入端还需要保护。我在每个输入引脚对地加了一颗 BAV199 双二极管做钳位,把电压限制在安全范围内。虽然 ADS122U04 内部有 ESD 保护,但工业现场的持续过压和浪涌能量远超芯片内部保护能力,外部钳位是必须的。另外,如果传感器电缆可能走长距离,建议在输入端加共模扼流圈,抑制共模干扰。
2.2 参考电阻的选型与布局
参考电阻 Rref 的精度直接决定测量精度,这是整个电路里最不能省钱的元件。我选的是 Vishay 的 PTF 系列精密电阻,阻值 3.9kΩ,初始精度 ±0.05%,温漂 ±5ppm/℃。为什么选 3.9kΩ?因为激励电流设为 500μA 时,Rref 上的压降是 1.95V,加上 RTD 上的最大压降(200℃ 时约 175Ω × 500μA = 87.5mV),总压降约 2.04V,在 3.3V 供电范围内留有余量。如果 Rref 太大,激励电流就得减小,信噪比会下降;太小则压降不够,参考电压太低影响 ADC 性能。
布局上,Rref 要尽量靠近 ADC 的 REFP0/REFN0 引脚,走线短而粗,避免引入寄生电阻。Rref 的接地端要和 ADC 的模拟地单点连接,不能和数字地混在一起。我见过有人把 Rref 放在传感器端,结果参考电压走线太长,噪声耦合严重,数据跳得厉害。记住:参考电阻必须放在 ADC 旁边。
2.3 电流源的配置与走线
ADS122U04 有两路匹配电流源 IDAC1 和 IDAC2,可以分别配置输出引脚和电流大小。三线制接法是这样的:IDAC1 从 AIN0 流出,经过 RTD 到 AIN1,再经过补偿线回到地;IDAC2 从 AIN2 流出,经过另一根补偿线到 AIN1。这样两根补偿线的导线电阻上流过的电流方向相反,在 AIN1 节点处产生的压降相互抵消。
实际配置时,IDAC 电流设为 500μA。为什么不设更大?因为电流太大会导致 RTD 自热。PT100 的自热系数大约 0.2℃/mW,500μA 在 100Ω 上产生的功率是 25μW,自热误差可以忽略。如果设 1mA,自热误差约 0.1℃,在精密测量中就不能忽视了。这是很多人容易忽略的细节。
走线方面,IDAC 输出线要和模拟输入线分开走,避免电流在输入线上产生额外压降。PCB 上我用的是差分对走线,AIN0/AIN1 和 AIN2/AIN3 分别成对,间距均匀,下面铺模拟地平面。
2.4 电源与去耦
ADS122U04 的模拟电源 AVDD 和数字电源 DVDD 都是 3.3V,但必须分开供电。我用了一颗 ADP7142 低压差稳压器专门给模拟部分供电,数字部分直接用 STM32L452RE 板上的 3.3V。两颗电源之间用磁珠隔离,每个电源引脚配 100nF 和 10μF 去耦电容,100nF 要尽量靠近引脚。
这里有个经验:ADS122U04 的电源抑制比在低频段很好,但在几十 kHz 以上会下降。如果开关电源的纹波频率落在敏感频段,会直接影响测量。我实测过用普通 DC-DC 供电时,数据在 20SPS 下会有约 5μV 的周期性波动,换成 LDO 后消失。所以模拟部分一定要用 LDO,不要图省事直接共用开关电源。
3. STM32L452RE 与 ADS122U04 的通信实现
3.1 SPI 接口配置与注意事项
ADS122U04 支持 SPI 接口,STM32L452RE 的 SPI1 配置为主模式,时钟极性 CPOL=0,时钟相位 CPHA=1,这是 ADS122U04 要求的模式。时钟频率不能超过 4MHz,我实际用的是 2MHz,留足余量。SPI 的 NSS 引脚用软件控制,因为 ADS122U04 的片选时序有特殊要求:每次命令之间必须拉高 NSS 至少 4 个时钟周期,否则命令会被忽略。
这个细节坑了我半天。一开始我用硬件 NSS,连续发命令时数据总是错位,后来查数据手册才发现这个要求。改成软件控制 NSS 后,每次操作前手动拉低、操作后拉高并延时,问题解决。代码里我封装了一个ADS122U04_CS_Low()和ADS122U04_CS_High()函数,中间加__NOP()延时确保时序满足。
SPI 的 MISO 线上要加上拉电阻,因为 ADS122U04 在转换期间不驱动 MISO,如果不加上拉,STM32 可能读到随机值。我用的是 10kΩ 上拉,实测稳定。
3.2 寄存器配置流程
ADS122U04 有四个配置寄存器,上电后必须先发 RESET 命令(0x06),然后写配置。我的配置顺序是这样的:
- 发 RESET 命令,等待 100μs
- 写配置寄存器 0:设置 MUX 为 AIN0/AIN1 差分输入,增益 128,PGA 使能
- 写配置寄存器 1:设置数据率 20SPS,连续转换模式,内部参考关闭(用外部参考)
- 写配置寄存器 2:设置 IDAC 电流 500μA,IDAC1 路由到 AIN0,IDAC2 路由到 AIN2
- 写配置寄存器 3:设置 IDAC 使能,参考输入选择 REFP0/REFN0
配置完成后发 START/SYNC 命令(0x08)启动转换。这里要注意,写寄存器和启动转换之间要留足够延时,我留了 1ms,确保配置生效。
3.3 数据读取与 DRDY 中断处理
ADS122U04 的 DRDY 引脚在转换完成时拉低,我把它接到 STM32L452RE 的 PA0 引脚,配置为外部中断下降沿触发。中断服务函数里拉低 CS,读取 3 字节转换结果,然后拉高 CS。读取时要注意,ADS122U04 输出的是 24 位二进制补码,需要做符号扩展。
void EXTI0_IRQHandler(void) { if (EXTI->PR1 & EXTI_PR1_PIF0) { EXTI->PR1 = EXTI_PR1_PIF0; // 清除中断标志 ADS122U04_CS_Low(); uint8_t rx[3]; HAL_SPI_Receive(&hspi1, rx, 3, 10); ADS122U04_CS_High(); int32_t raw = ((int32_t)rx[0] << 16) | ((int32_t)rx[1] << 8) | rx[2]; if (raw & 0x800000) raw |= 0xFF000000; // 符号扩展 g_adc_raw = raw; g_adc_ready = 1; } }中断里只做数据搬运,不做浮点运算和温度换算,这些放到主循环里做。这是嵌入式开发的通用原则:中断越短越好。
3.4 低功耗设计:让 MCU 在等待转换时睡觉
STM32L452RE 的一大优势是低功耗,配合 ADS122U04 的连续转换模式,可以做到很低的平均功耗。我的做法是:主循环里检查g_adc_ready标志,没数据时进入 STOP 模式,DRDY 中断唤醒。STOP 模式下 MCU 电流只有几微安,ADS122U04 在 20SPS 连续转换模式下电流约 200μA,整机平均功耗可以控制在 300μA 以内。
唤醒后先做温度换算,然后通过 UART 或 LoRa 发送数据,发送完继续睡。这个架构特别适合电池供电的无线温度变送器。注意 STOP 模式下 SPI 外设会关闭,唤醒后需要重新初始化 SPI,或者改用 STOP 模式下仍可工作的配置。我实测下来,重新初始化 SPI 的耗时约 50μs,对整体功耗影响可以忽略。
4. 温度换算算法与精度验证
4.1 从 ADC 码值到电阻值
前面说了用比例测量法,ADC 输出的码值直接对应 RTD 和 Rref 的比值。具体换算关系是:
- ADC 满量程码值 = 2^23 - 1 = 8388607(单端)或 ±2^23(差分)
- 设 ADC 输出码值为 Code,则 Rrtd / Rref = Code / 2^23
- Rrtd = Rref × Code / 2^23
这里要注意增益的影响。如果 PGA 增益设为 128,输入电压范围是 ±Vref/128,ADC 码值和输入电压的关系会变。但在比例测量中,因为参考电压也是从 Rref 上取的,增益项会被消掉,最终公式不变。这是比例测量法的另一个好处。
4.2 Callendar-Van Dusen 方程的正确用法
从电阻值到温度,标准做法是用 Callendar-Van Dusen(CVD)方程。对于 0℃ 以上的温度:
- R(t) = R0 × (1 + A×t + B×t²)
对于 0℃ 以下:
- R(t) = R0 × (1 + A×t + B×t² + C×(t-100)×t³)
其中 R0 = 100Ω,A = 3.9083×10⁻³,B = -5.775×10⁻⁷,C = -4.183×10⁻¹²。这些是 IEC 60751 标准里的系数。
实际用的时候,从电阻反推温度需要解方程。0℃ 以上可以直接用求根公式:
- t = (-A + sqrt(A² - 4B(1 - R/R0))) / (2B)
0℃ 以下没有解析解,需要用迭代法。我一般用牛顿迭代,初值取 0℃,迭代 3 次就能收敛到 0.001℃ 以内。代码里我写了一个rtd_resistance_to_temperature()函数,根据电阻值判断用哪种方法。
4.3 实测精度与误差来源分析
我用 Fluke 9142 干体炉做参考,在 -40℃、0℃、50℃、100℃、150℃、200℃ 六个点做了对比测试。实测误差如下:
| 测试点 | 参考温度 | 测量值 | 误差 |
|---|---|---|---|
| 1 | -40.0℃ | -40.08℃ | -0.08℃ |
| 2 | 0.0℃ | 0.02℃ | +0.02℃ |
| 3 | 50.0℃ | 50.05℃ | +0.05℃ |
| 4 | 100.0℃ | 100.03℃ | +0.03℃ |
| 5 | 150.0℃ | 149.94℃ | -0.06℃ |
| 6 | 200.0℃ | 200.09℃ | +0.09℃ |
整体误差在 ±0.1℃ 以内,满足设计要求。误差来源主要有几个:Rref 的初始精度和温漂贡献约 ±0.03℃,RTD 本身的公差(我用的是 A 级 PT100,0℃ 时 ±0.15℃)是主要误差源,ADC 噪声贡献约 ±0.01℃,PGA 非线性约 ±0.005℃。如果要进一步提高精度,可以换成 AA 级 PT100,或者对每颗 RTD 做单独标定。
4.4 数字滤波:让数据更稳
虽然 ADS122U04 在 20SPS 下噪声已经很低,但工业现场还是会有偶发干扰。我在软件里加了一级滑动平均滤波,窗口大小 8,相当于把数据率降到 2.5SPS。温度变化本身很慢,2.5SPS 完全够用。滤波后数据波动从 ±0.03℃ 降到 ±0.01℃。
如果对实时性要求高,可以用中值滤波加滑动平均的组合:先取 5 个点排序取中值,再对中值序列做滑动平均。这样既能抑制脉冲干扰,又能平滑随机噪声。我实测这个组合在 HVAC 场合效果很好。
5. 调试过程中踩过的坑与解决方案
5.1 数据跳变:从电源噪声到地环路
项目初期遇到最头疼的问题是数据偶尔跳变,幅度能到 0.5℃。排查过程是这样的:先看 ADC 原始码值,发现跳变时码值变化几千个 LSB,远超正常噪声水平。用示波器看 AVDD,发现有约 20mV 的周期性纹波,频率约 100kHz,正好是板上 DC-DC 的开关频率。虽然 ADS122U04 的 PSRR 在低频很好,但 100kHz 处已经衰减到 40dB 左右,20mV 纹波会耦合出约 200μV 的等效输入噪声。
解决方案是把模拟电源从 DC-DC 换成 LDO,并在 LDO 输入输出加 π 型滤波。换完后纹波降到 1mV 以下,数据跳变消失。这个坑告诉我,精密模拟电路千万别在电源上省钱。
5.2 三线制补偿失效:导线电阻不匹配
另一个问题是三线制补偿效果不理想,不同长度的电缆误差不一样。理论上三线制要求两根补偿线的电阻完全相等,但实际电缆的线电阻有公差,而且接头处接触电阻也不一样。我用的电缆是 0.5mm² 三芯屏蔽线,每米线电阻约 35mΩ,20 米电缆的线电阻约 0.7Ω,两根线之间差 0.05Ω 的话,对应温度误差约 0.13℃。
解决办法有两个:一是选用线电阻公差小的电缆,二是软件里做补偿。我在出厂标定时,短接传感器端,测量两根补偿线的电阻差,把这个差值存到 MCU 的 Flash 里,测量时从结果里减去。这个方法能把补偿误差降到 0.02℃ 以内。
5.3 SPI 通信偶发失败:时序余量不足
SPI 通信偶尔会失败,表现为读到的数据全 0 或全 1。用逻辑分析仪抓波形发现,SCK 时钟在 2MHz 时上升沿有约 50ns 的过冲,导致 ADS122U04 在时钟边沿采样时误判。ADS122U04 的 SPI 时序要求 SCK 上升时间小于 100ns,我的走线较长(约 8cm),加上没有端接电阻,反射导致过冲。
解决方法是把 SCK 频率降到 1MHz,并在 SCK 线上串一颗 33Ω 电阻做阻抗匹配。改完后通信稳定,连续跑 24 小时无一次失败。如果 PCB 空间允许,SCK 走线尽量短,并且包地处理。
5.4 低温下精度变差:元件温漂的锅
在 -40℃ 低温测试时,精度明显变差,误差到了 0.3℃。排查发现是 Rref 的温漂和 RTD 激励电流的温漂叠加。我用的 Rref 温漂是 ±5ppm/℃,在 -40℃ 时相对 25℃ 变化了 65℃,阻值变化约 0.03%,对应温度误差约 0.08℃。但实测误差更大,说明还有其他因素。
后来发现是 ADS122U04 内部 IDAC 的温漂。数据手册标称 IDAC 温漂 ±50ppm/℃,在 -40℃ 时变化 65℃,电流变化 0.3%。虽然比例测量能消掉电流的绝对值变化,但 IDAC1 和 IDAC2 之间的匹配度会随温度变化,导致三线制补偿失效。解决办法是选用温漂更小的 Rref(±2ppm/℃),并在软件里加温度补偿系数。这个系数需要在高低温箱里标定,比较费事,但能把低温误差压到 0.1℃ 以内。
6. 这套方案还能怎么扩展
6.1 多通道测温:用 MUX 切换
ADS122U04 有四路差分输入,可以接两路三线制 RTD。如果要测更多通道,可以外接模拟开关,比如 TMUX1108 八通道 MUX,用 STM32 的 GPIO 控制通道切换。切换后要留足够的建立时间,RC 滤波的建立时间约 5 倍时间常数,1kΩ 和 100nF 的时间常数是 100μs,所以每次切换后等 500μs 再启动转换。这样八通道轮询一遍约 10ms,对温度测量来说完全够用。
6.2 冷端补偿与热电偶混测
如果项目里既有 RTD 又有热电偶,ADS122U04 也能胜任。热电偶输出是毫伏级电压,需要冷端补偿。ADS122U04 内置温度传感器,精度 ±0.5℃,可以用来做冷端补偿。不过内置传感器测的是芯片温度,不是接线端子温度,如果接线端子离芯片远,会有温差。更稳妥的做法是在接线端子附近放一颗 DS18B20 或 TMP117 做冷端测量,通过 I2C 读给 STM32。
6.3 无线传输与云端对接
STM32L452RE 有丰富的通信外设,可以接 LoRa 模块做无线传输,也可以接 RS485 收发器做有线组网。我目前用的是 RS485 加 Modbus RTU 协议,波特率 9600,每 500ms 上报一次温度数据。如果要做无线方案,推荐用 SX1262 或 LLCC68 模块,配合 STM32 的 LPUART 低功耗串口,整体休眠电流可以做到 2μA 以下,电池寿命轻松超过 5 年。
6.4 自诊断与故障检测
工业设备需要自诊断功能。ADS122U04 可以检测传感器断线、短路和超量程。具体做法是:定期切换 IDAC 电流方向,测量正反向的电压差,如果差值为零说明传感器短路,如果为满量程说明断线。另外,ADC 内部有 burnout current source,可以注入微小电流检测传感器是否连接。这些诊断功能在冷热量表里是强制要求,做方案时一定要预留。
整套方案从选型到量产,前后花了大约三个月时间,中间踩的坑基本都记录在上面了。ADS122U04 加 STM32L452RE 这个组合,性能、功耗和成本平衡得不错,适合工业温度变送器、冷热量表、HVAC 控制器这类应用。如果你也在做类似项目,建议先把比例测量和三线制补偿这两个基础打牢,剩下的就是细节打磨。硬件上电源和参考电阻千万别省,软件上中断要短、滤波要稳,做到这两点,精度基本就有保障了。