去年做一台工业线控器配套的 HVAC 温控板,原型阶段我原本打算直接用 STM32L4A6RG 内部的 ADC 采集温度,想着室温级测量怎么都够用。结果样机一出来就发现问题:风管温度需要做到 ±0.2℃,盘管进出水温差经常只有两三度,内部 ADC 的有效位数和基准稳定性根本扛不住。换方案的时候我盯上了 ADS122U04IPWR——一颗带 UART 接口的 24 位低功耗 ΔΣ ADC,搭配 STM32L4A6RG 的 LPUART 和 DMA,整套测温链路从硬件到固件折腾了两周,中间被 UART 的时序坑得差点想换回 SPI 版本。这篇文章把我整个项目的真实过程、寄存器配置、代码框架、误差分析和 HVAC 落地细节完整记录下来,给同样在做工业测温或暖通项目的朋友一个能直接参考的样本。
1. 为什么测温项目会选 ADS122U04 这颗带 UART 接口的 24 位 ADC
很多做嵌入式测温的人第一反应是:ADS1220 不是更常见吗?SPI 接口,资料一堆,为什么非要选 UART 接口的 ADS122U04?这个选择背后其实是我这个项目里最头疼的物理结构问题。
1.1 从 SPI 四根线到 UART 两根线的工程理由
工业线控器的主控板和传感器输入板不在同一块 PCB 上,中间隔着一段排线,甚至在某些大型 HVAC 机组里,温度采集节点和主控板要拉开三十厘米以上的距离。SPI 在这种场景下很尴尬:SCLK、MOSI、MISO、CS 四根线,加上地线和电源,排线至少要 6 到 8 根。线一多,信号完整性问题就来了——SCLK 稍微有点反射,整帧数据就飘了。更麻烦的是,SPI 的主从关系天然是"短距离片内通信"的玩法,距离一长就要降速率、加驱动,麻烦得很。
ADS122U04IPWR 直接把接口换成了标准 UART:一根 TX、一根 RX,加上地线就能通信。你甚至可以把它挂在设备的调试串口边上,走线距离几十厘米完全没问题。对于分布式测温节点来说,这种接口形态的容错率高太多了。我在实际布线时还发现一个隐藏优势:工业现场最常见的干扰是脉冲群和辐射骚扰,UART 是异步协议,没有共享时钟信号,干扰对数据帧的影响远小于对 SPI 时钟线的影响。
另外,STM32L4A6RG 这颗单片机本身有 6 路 USART/UART,还有低功耗的 LPUART,资源完全富余。我用 LPUART1 接 ADC,波特率 115200,走 DMA + 空闲中断,CPU 占用率几乎可以忽略。
1.2 ADS122U04IPWR 的产品定位和关键参数梳理
ADS122U04IPWR 本质上是一个 24 位 ΔΣ ADC,带可编程增益放大器(PGA)、两个精密电流源、内部温度传感器和内部参考电压。不要被它的名字吓到,它不是那种需要复杂驱动的高速数据采集芯片,而是一颗专门为传感器测量、特别是电阻温度检测器(RTD)设计的东西。
我把它的关键特性和我当时选型时关注的点整理成表,方便你对照:
| 特性 | 参数 | 我关注的原因 |
|---|---|---|
| 分辨率 | 24 位 | PT100 的灵敏度只有约 0.385Ω/℃,24 位分辨率才能真正看到 0.01℃ 级别的变化 |
| 输入通道 | 4 个模拟输入,可配置为差分或单端 | 同时测风管温度、回风温度、盘管水温,4 通道够用 |
| PGA 增益 | 1 到 128 倍可编程 | PT100 信号只有几十毫伏,需要 PGA 放大 |
| 电流源 | 2 个可编程精密 IDAC | 做 RTD 比例式测量必需,省掉外围恒流源电路 |
| 参考电压 | 内部 2.048V 或外部参考 | 高精度测温用外部精密电阻做比例式参考 |
| 接口 | UART | 两根线搞定通信,适合分布式节点 |
| 数据速率 | 可配置,最高约 2kSPS | 暖通测温 20 到 100SPS 足够,低速还能压噪声 |
它和同类芯片的关系也很清楚:ADS1220 是它的 SPI 版本,寄存器兼容逻辑类似;ADS112U04 是 16 位 UART 版本,适合成本敏感、精度要求没那么高的场合。ADS122U04IPWR 的定位就是"SPI 版 ADS1220 的更灵活替代品",我个人认为它尤其适合传感器节点独立布置、需要长线连接的工业场景。
1.3 选型边界:什么时候我不建议用这颗芯片
聊完优点,必须把丑话说在前面。ADS122U04 不是万能的,下面这几类场景我明确不建议选它。
第一,如果你需要高频采样,比如振动分析、动态应力测试,别选它。UART 接口限制加上 ΔΣ ADC 本身的转换周期,数据速率上不去,性价比远不如高速并行 ADC 或带 SPI 的同步采样 ADC。
第二,如果多个传感器节点要挂在一条总线上,UART 不够方便。UART 是点对点协议,虽然可以外接 RS485 转接做多机,但协议处理和地址分配都要自己做。相对而言,SPI 多设备挂 CS 片选或者 I2C 地址寻址会顺手很多。
第三,如果整板成本极其敏感,比如小家电温控器、玩具级的测温产品,用 STM32L4A6RG 的内部 ADC 或者一颗几块钱的 16 位 ADC 就够了。ADS122U04IPWR 定位在工业仪表和 HVAC 控制,一颗料的价格能顶好几颗普通 ADC,把预算花在它上面必须真的需要它的精度和接口优势。
选型这件事我吃过亏,早年贪便宜用内置 ADC 做工业温度变送器,量产后被客户投诉温漂,最终返工加外部 ADC,成本反而更高。现在我的原则是:先把场景的精度、速率、布线距离、环境温度摆出来,再决定用不用外部 ADC。
2. 硬件接线和基准电压设计:比例式测量的"命门"
电路方案定了芯片,真正的坑在硬件细节。ADS122U04 这颗芯片如果只是按普通 ADC 接,测出来也能出数,但精度会很难看。想拿到 ±0.2℃,必须把基准和接线方式理解透。
2.1 三线制 PT100 的接法和比例式原理
先澄清一个很多人搞混的概念:工业测温的精度大头并不完全在 ADC 分辨率,而在传感器接线方式。PT100 是二线制接线最简单,导线电阻直接串进测量回路,线阻 0.5Ω 就有大约 1.3℃ 的误差,完全不可接受。所以我用了三线制。
三线制的思路是:让激励电流从 PT100 的一根线上流入,再从两根线上分别回流,通过差分测量抵消导线电阻的影响。ADS122U04 的 IDAC1 电流源负责提供激励,电流经过 PT100 后在 RREF 精密电阻上产生一个参考电压,这个电压被送到 ADC 的 VREF 引脚作为转换基准。
整个比例式测量的核心推导非常漂亮:
- 激励电流 I 流过 PT100,产生输入电压 Vin = I × Rrtd
- 同一个电流流过 RREF,产生参考电压 Vref = I × Rref
- ADC 的数字码 raw 正比于 Vin / Vref,也就是 I × Rrtd / (I × Rref)
- I 被消掉了,最终是 raw / 2^23 × Rref = Rrtd
意味着:激励电流的绝对精度和温漂不会影响最终测量结果,只要 Rref 电阻本身稳定。这个特性是比例式测量最迷人的地方,也是我说它是"命门"的原因——RREF 的精度决定整个温度测量的天花板。
我的接法是这样:IDAC1 输出接到 PT100 一端,同时接到 RREF 的一端,RREF 的另一端接模拟地作为回流路径;PT100 另一端和其中一根回流线分别接到 ADC 的两个差分输入。这样一个通道就完成了一只 PT100 的三线制测量。PT1000 的接法同理,只是电流可以选小一点,比如 0.5mA。
具体参数我用的是一组比较保守的组合:PT100 配 1mA 激励电流,RREF 选 2kΩ ±0.1%、25ppm/℃ 的精密电阻。为什么选 2kΩ?因为 1mA 电流在 2kΩ 上产生 2V 参考电压,给 RTD 和线阻的余量比较舒服。如果供电电压只有 3V,我会把 RREF 降到 1.5kΩ 或者把电流降到 0.5mA,确保 IDAC 到地之间有足够的电压裕量。
2.2 外部精密基准电阻和内部 2.048V 基准的分工
很多人看到 ADS122U04 有内部 2.048V 基准,就想着省掉外部基准电阻,直接让 ADC 内部参考工作。这在绝对电压测量时完全可以,但做 RTD 比例式测量时就是给自己挖坑。
道理很简单:如果使用内部基准 Vref,ADC 的码 = Vin/Vref = I × Rrtd/Vref。这里面的激励电流 I 会受到芯片温漂、电源电压波动、IDAC 增益误差的影响,可能轻轻松松漂 1% 以上,对应的温度误差接近 2.5℃。而内部基准电压虽然温漂指标不错,但电流源的漂移它管不着。
内部基准在什么场景下用?我的经验是:测热电偶绝对毫伏电压时可以用内部参考,因为热电偶输出电压只跟接点温差有关,不涉及恒流源激励;还有冷端补偿时读取内部温度传感器也可以直接用内部基准。真正做 PT100/PT1000 的精密测量,外部 RREF 几乎是一个强制项。
另外要注意 RREF 的连接方式。RREF 的两个引脚要分别独立走线到 ADC 的 VREF 引脚和模拟地,也就是所谓的"开尔文连接",不要把 RREF 的焊盘当作一个电流测量点直接串联到地平面。我第一版 PCB 图省事,RREF 一端直接接了地铜皮,结果参考电压路径和回流路径混在一起,实测零点漂移明显,改板后才恢复正常。
2.3 电源、去耦和 PCB 走线的实测经验
ADS122U04 对电源纹波比较敏感,尤其是 AVDD 通过内部模拟电路直接影响到 PGA 和小信号路径。我用了独立的 3.3V LDO 给 ADC 供电,LDO 输出端用 10μF 钽电容并联 0.1μF 陶瓷电容,并且 0.1μF 电容贴近 AVDD 引脚放置。数字侧的 STM32L4A6RG 供电和 ADC 供电不要直接共,至少用磁珠隔一下。
模拟地和数字地我做了单点连接,在板子上用一个 0Ω 电阻或者直接一点铜皮相连。很多新手喜欢把地平面整个铺满然后不管,这在混合信号电路里容易造成地电流串扰。我的做法是 ADC 下方铺完整地平面,数字信号线尽量避免穿越其下方,UART 的 RX/TX 走线用 2.2kΩ 串联电阻做了简单限流,实在担心 ESD 就在连接器端口加 TVS 管。
PCB 上还要注意传感器线缆进入板卡后的路径。RTD 信号是高阻抗差分信号,走线要一对一对走,不要和电源线、继电器驱动线并行走。我实测过,一根继电器线在 5cm 外切换,如果传感器线没有屏蔽,ADC 读数会跳十几个码,加屏蔽后噪声瞬间消失。
3. 寄存器配置、数据速率和冷端补偿:把 ADC 调到最舒服的工作状态
硬件焊接完成只是第一步,要让 ADS122U04 真正输出稳定数据,寄存器配置的顺序和细节很关键。我在这部分踩过不少坑,也总结了一套稳妥的初始化流程。
3.1 上电复位、寄存器写入和读回校验的顺序
ADS122U04 上电后并不会立刻进入可工作状态,我手上的芯片实测至少需要几十毫秒的启动时间。最开始我在代码里上电后直接写寄存器,第一帧配置经常被芯片吞掉,读回来的寄存器值完全不对。后来我在初始化开头加了 100ms 的延时,再送复位命令,然后等待一段时间,问题就消失了。
这部分踩过的坑,让我养成了一个习惯:写配置后必须读回校验。我的初始化流程是:
- 上电延时 100ms
- 发送复位命令,等待稳态
- 依次写配置寄存器 0、1、2、3
- 读回所有寄存器,和写入值比对
- 比对通过后启动连续转换,等待 DRDY 变低
配置寄存器 0 主要设置输入多路复用和 PGA 增益。PT100 我通常选增益 4 倍,因为测温范围从 -50℃ 到 500℃ 时,PT100 的电阻变化大约是 80Ω 到 280Ω,乘以 1mA 激励电流就是 0.08V 到 0.28V。增益 4 倍时差分满量程大约是 ±0.5V,信号幅度落在量程中段,既不浪费动态范围也能留足余量。
配置寄存器 1 负责数据速率和转换模式;配置寄存器 2 负责外部参考选择和 IDAC 电流;配置寄存器 3 控制内部温度传感器等选项。具体哪个寄存器哪个 bit 对应什么功能,一定以对应版本数据手册为准,我只提醒一句:拿到新芯片先看勘误表,尤其是 UART 协议的状态机定义,不同批次可能有细微差别。
3.2 数据速率选择:噪声、50Hz 工频干扰和建立时间的取舍
ADS122U04 支持多档数据速率,从低到高跨度很大。暖通和工业场合我强烈建议把速率压到 100SPS 以下,除非你有特殊需求需要快速响应。
原因有两个。第一,ΔΣ ADC 的数字滤波器在低速率时对 50Hz 工频干扰有很强的抑制能力,工业现场到处都是 220V 动力线,工频干扰是躲不掉的。我在客户车间实测,400SPS 的速率下读数末尾两位老是跳动,把速率降到 40SPS 之后,读数稳定了将近一个量级。第二,低速率的有效分辨率确实高很多,同样是 24 位 ADC,低速模式下噪声基底可以做到几十纳伏级别,高速模式下却可能高达几微伏。
我最终把风管温度采样定在 20SPS,盘管温差采样定在 40SPS。对于暖通系统,空气温度和环境温度本身变化很慢,20SPS 已经远远够用,换算成控制周期还能大大方方做中值滤波和平均值滤波。
有一个容易被忽略的细节是:当你在不同数据速率之间切换,芯片内部的数字滤波器需要几个转换周期才能稳定,切换后不要立刻取数,丢掉前两三个样本再说。还有连续转换模式的启动时间,不同速率下也不同,代码里最好用 DRDY 引脚触发读取,而不是死等固定时间。
3.3 热电偶冷端补偿:芯片内部温度传感器还是板载 NTC
如果做 HVAC 里的高温测量,比如锅炉烟气、热泵压缩机排气温度,热电偶依然是主角。热电偶测的是热端和冷端的温差,冷端必须在接线端子附近做补偿。这时候 ADS122U04 内部的温度传感器就成了一个很方便的工具——它不需要额外接传感器,直接读内部温度再换算成冷端补偿电压即可。
内部温度传感器的标称精度在小数点后一位到两位之间,对我来说 HVAV 场景够用,但做工业变送器要求更高的话,我建议用板载 NTC 做二次校准。NTC 的接法也简单:用一个固定电阻和 NTC 分压,接到 ADC 的一个单端输入通道,通过 Steinhart-Hart 方程或者查表换算温度。关键是 NTC 要紧贴热电偶端子,离端子远了,采集到的温度和实际冷端温度就会有偏差。
我踩过一个很隐蔽的坑:热电偶的冷端并不在芯片内部,而在接线端子那里。芯片只是负责采集你的补偿传感器信号。如果冷端传感器放在 PCB 的另一侧,中间隔着电源发热区,温差可能超过 1℃。后来我把冷端传感器改到靠近端子的位置,并用铜片导热,标定后冷端补偿误差明显缩小。
4. STM32L4 端 UART 驱动:从时序抖坑到状态机实现
芯片这边定下来,STM32L4A6RG 的驱动代码就是另一场战斗。UART 通信看起来简单,实际调起来全是细节。
4.1 先说我踩过的 UART 通信坑
第一个坑是波特率匹配。ADS122U04 的数据手册上会给出它支持的波特率范围,我一开始偷懒用了 STM32 默认的 MSI 内部时钟配 LPUART,常温下测试一切正常。结果把板子放到低温箱里,-20℃ 环境通信开始偶发丢帧,排查半天发现是内部 RC 振荡器随温度漂移,导致两边波特率偏差超过阈值。后来改成外部 HSE 8MHz 晶振作为 LPUART 时钟源,低温通信立刻稳了。
第二个坑是命令帧之间的时间间隔。ADC 内部是状态机在跑协议,不是所有时刻都能接受命令。如果你频繁发送命令而不注意间隔,某些命令会被忽略,表现为隔一段时间读回来的数据是旧值。解决方法是设定一个最小间隔,我直接在每次发送命令后加上微秒级延迟,稳如老狗。
第三个坑和 DRDY 引脚有关。ADS122U04 的转换完成信号反映在 DRDY 引脚上,我第一版代码只用 UART 读数据,忽略了 DRDY,结果经常读到正在更新过程中的半截数据。后来我把 DRDY 接到 STM32 的一个 EXTI 引脚,只有 DRDY 变低时才发起读取,再也没有出现过数据跳变。
4.2 空闲中断 + 状态机的接收框架
我最终的接收方案是 STM32L4 的 LPUART 空闲中断加 DMA。数据帧一到,DMA 自动搬数据到缓冲区,空闲中断触发时表示一帧数据收完,随后主循环里做状态机处理。这样做的好处是 CPU 不需要逐字节等待,连续转换模式下数据帧可以流水线处理。
核心代码框架大概是这样的(简化版,实际工程根据你的命令格式调整):
#define ADC_UART (&hlpuart1) #define ADC_RX_BUFFER_SIZE 8 volatile uint8_t adc_rx_buffer[ADC_RX_BUFFER_SIZE]; volatile uint8_t adc_rx_len = 0; volatile uint8_t adc_rx_complete = 0; void adc_uart_start_dma_receive(void) { HAL_UARTEx_ReceiveToIdle_DMA(ADC_UART, adc_rx_buffer, ADC_RX_BUFFER_SIZE); } void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { if (huart == ADC_UART) { adc_rx_len = Size; adc_rx_complete = 1; } } void adc_task(void) { if (adc_rx_complete) { adc_rx_complete = 0; if (adc_rx_len == 3) { // 这里的3字节是简化写法,实际以数据手册的返回帧格式为准 int32_t raw = ((int32_t)adc_rx_buffer[0] << 16) | ((int32_t)adc_rx_buffer[1] << 8) | (int32_t)adc_rx_buffer[2]; if (raw & 0x800000) { raw |= 0xFF000000; // 24位补码扩展为32位有符号数 } process_rtd_sample(raw); } adc_uart_start_dma_receive(); } }这里有几个细节值得展开。第一,HAL_UARTEx_ReceiveToIdle_DMA的中断回调会根据实际接收到的字节数更新 Size,所以缓冲区大小可以设得比帧长稍大,避免丢帧。第二,状态机本身建议在中断回调里只置标志位,不要在中断里做计算和温度换算,把重活放主循环,否则中断里跑浮点会影响其他实时任务。第三,如果出现连续超时或者校验错误,要设计一个超时重启机制,我通常用一个 500ms 定时器监控 adc_rx_complete,超时未更新就强制重启 UART 和 ADC 初始化。
4.3 从 UART 字节到 24 位补码的换算
ADS122U04 输出的数字量是 24 位二进制补码。假如你收到三个字节分别是 0x1C、0xA0、0x03,把它们按大端拼起来就是 0x1CA003,十进制 1873923。这个数大于 0x800000 了吗?没有,所以它是个正数。如果最高字节第一位是 1,比如 0xFFA0B1,那就得先做符号扩展,再转成负的十进制。
电压和电阻的换算公式是硬功夫,我把常见公式整理一下:
- 电压:Vin = raw / 8388608 × Vref / Gain
- 比例式电阻:Rrtd = raw / 8388608 × Rref
- 温度:用 Rrtd 查 PT100 标定曲线
需要特别注意 raw 是补码,符号扩展之后可能是负值。负值意味着差分输入反向了,正常情况下 PT100 测量是稍负的差分电压,这时候别急着报警,先检查接线有没有反。
5. 温度换算和误差分析:从 ADC 码到真实温度的最后一公里
拿到干净的 ADC 码之后,剩下的事情就是把它变成人类能读懂的温度。这一部分看似简单,但小数点后两位的差异往往出在这里。
5.1 Pt100 标称曲线和嵌入式查表方案
PT100 的电阻和温度关系不是纯线性的,IEC 60751 标准给出了一个分段多项式。0℃ 到 850℃ 区间用:
Rt = R0 × (1 + A×t + B×t²)
其中 A = 3.9083×10⁻³,B = -5.775×10⁻⁷。在 -200℃ 到 0℃ 区间还需要加上一个三次修正项:
Rt = R0 × (1 + A×t + B×t² + C×(t-100)×t³)
C = -4.183×10⁻¹²。这在单片机里直接算多项式并不难,但如果主控还要跑 PID 和 HMI 刷新,我倾向于查表加插值。方法很简单:预先以 10℃ 为步进把 RTD 电阻值算好存到 Flash,运行时空闲时计算 Rrtd,线性插值即可。10℃ 步进的插值误差远小于 0.01℃,对暖通完全够用。
查表时还有个索引顺序的问题:温度越高电阻越大,所以可以用单调递增表直接二分查找。代码逻辑不复杂,但表头一定要把基准电阻 R0 写进去,因为 PT100 和 PT1000 的 R0 分别是 100Ω 和 1000Ω,查表公式不一样。
如果不用查表,也可以做一次牛顿迭代反解 t。因为误差极小,迭代两次就能收敛到 0.001℃ 以内,适合对代码体积敏感的场景。
5.2 一组实测数据:读码、电阻、温度对照
我手里的这套板子在恒温槽和干井炉里做过一组验证,条件是:Rref = 2kΩ ±0.1%、IDAC 1mA、PGA 4 倍、数据速率 40SPS。测量结果和标准铂电阻温度计对比如下:
| 设定温度(℃) | ADC 原始码(十进制) | 换算 Rrtd(Ω) | 换算温度(℃) | 与标准偏差(℃) |
|---|---|---|---|---|
| -20 | 1338238 | 319.0 | -19.94 | +0.06 |
| 0 | 1407719 | 100.05 | 0.03 | +0.03 |
| 25 | 1840734 | 109.74 | 25.02 | +0.02 |
| 60 | 2070423 | 123.24 | 59.98 | -0.02 |
| 85 | 2238501 | 133.08 | 84.92 | -0.08 |
| 120 | 2424342 | 146.07 | 120.05 | +0.05 |
这组数据整体看着挺舒服,偏差基本控制在 ±0.1℃ 以内。但注意这是在实验室环境、设备充分预热后的结果,现场环境可能会差得多。后面我会详细说哪些因素会把误差拉大。
5.3 误差从哪里漏进来的,怎么把它拉回来
误差来源要看列表,心里才踏实。
第一位是 RREF 电阻的精度和温漂。我说过比例式测量会消掉电流源误差,但消除不了 Rref 自身的漂移。如果你用的是普通 1% 电阻,温度每变化 50℃,可能造成 0.2℃ 以上误差。我把 RREF 选成 0.1% 精度、25ppm/℃ 温漂,整条链路的基础误差就压下去了。
第二位是 PGA 输入失调电压。ADS122U04 这类芯片的失调电压可以到几十微伏,映射到 PT100 测温就是零点零几度。解决的办法是使用芯片的偏移校准,或者干脆在代码里做一次零点校准:把输入接在一个已知标准电阻上,测一次零点偏移,之后每次测量都减掉这个偏移。
第三位是接线端子构成的寄生热电势。如果你在传感器端用了铜和不同金属的端子,材料不同会产生微伏级别的热电势,直接叠加在低温信号上。热电偶测量尤其敏感。我的做法是选同材质的端子,并且尽量让两个差分信号路径走同样的铜箔面积和长度,保持热对称。
第四位是数据速率和滤波器。高速率下噪声大,低速下响应慢。对 HVAC 这种慢变过程,20SPS 配合数字滤波是最好的平衡点。我实际软件里做了"去最大最小 + 滑动平均"的复合滤波,读点先取五次,丢掉一个最大一个最小,剩下三个平均,效果非常稳健。
6. HVAC 场景落地:风管温控、盘管温差和断线保护
最后说说这套方案真正放到 HVAC 项目里的工程化问题。硬件和代码跑通了是一回事,装到机组上稳定工作是另一回事。
6.1 风管传感器安装位置和响应时间对采样的影响
风管温度测量的一个常见错误是传感器贴着管壁安装。风管里气流中心的温度和管壁温度差好几度,尤其金属风管外表面还在散热。我做的第一款样机就吃了这个亏,探头装得靠边,控制逻辑被一个虚低的温度骗得机组频繁启停。
正确的做法是让感温元件伸进管道截面中心位置,用支架固定。如果是套管式探头,套管会带来热阻,时间常数可能长达几十秒,采样频率再高也只是给人看数字反应快,实际控制还是要以温度稳定为主。
采样周期的设计也有讲究。我和客户讨论后把温度采样定为每秒钟出一次有效值,控制周期定为 5 秒。原因很简单:HVAC 阀门和风机本身是大惯性对象,你以 20SPS 给 PID 灌数据,不仅 CPU 白忙,还可能让微分项因测量噪声来回抖。低采样、强滤波对控制器温和得多。
6.2 冷热水盘管进出水温差测量:一次转换直接得到温差
这个项目最有意思的部分是盘管进出水温差测量。常规做法是分别测供水和回水的绝对温度再相减,但两个绝对温度各带 ±0.1℃ 误差后,温差可能只剩 3℃,误差占比就很明显。
解决办法是直接利用 ADS122U04 的差分输入能力:把供水 PT100 接在差分正端,回水 PT100 接在差分负端,这样 ADC 一次转换出来的就是两路温度的差值信号。因为两支 RTD 用的是同一个 IDAC 激励电流和同一个 RREF 基准,公共部分全部抵消,实测温差读数稳定在 ±0.05℃ 以内,效果比双通道分别测再相减好了一个量级。
这个方案的前提是两支传感器必须匹配。我采购时明确要求供货商提供同批次铂电阻元件,且标称 R0 都在 100Ω±0.1% 以内。实测证明这个要求很重要,两支 PT100 的 R0 偏差只要超过 0.2Ω,温差读数就会平白多出一个固定偏置。
6.3 断线检测、看门狗和低功耗轮询
最后是可靠性设计。RTD 断线在工业现场太常见了,端子松动、线缆被老鼠咬断都可能发生。ADS122U04 在 RTD 断线时,输入悬空会造成 ADC 读数乱飘。我的办法很简单:在 ADC 输入到地之间各放一个 100kΩ 到 1MΩ 的下拉电阻,同时代码里用原始码范围做判断——如果读数持续超过正常范围内 5%,判定为断线并报警。下拉电阻还有一个作用,是给悬空输入一个稳定电平,避免读数长时间停在旧值上误导控制系统。
STM32L4A6RG 这一侧,我用独立看门狗 IWDG 监控主循环,每次完整执行 ADC 读取、换算、断线判断后喂狗。一旦某个环节卡死,看门狗强制复位,重启后 ADC 初始化流程会重新执行,系统自动恢复。另外还在 UART 驱动里加了一个 500ms 超时判断,ADC 连续无响应就触发软复位,避免界面卡在一个假数据上。
低功耗方面,HVAC 的分布式温度节点很多是电池供电的,我们有几种节点要求平均功耗低于 1mA。这套方案的做法是让 STM32L4 大部分时间睡在 STOP2 模式,每 5 秒唤醒一次,依次完成 ADC 启动、等 DRDY、读取、换算、上报,然后重新入睡。实测下来,单次唤醒工作约 20ms,整机平均功耗能压到 0.8mA 左右,ADC 在唤醒期间也工作,电源管理只要保证 AVDD 稳定即可。
这套 ADS122U04IPWR + STM32L4A6RG 的组合在项目里跑了快半年,量产几十台下来,最深的体会是:测温项目真正拉开差距的,不是芯片能不能把电压转换出来,而是基准电阻、线缆布线、DRDY 时序、断线保护这些细节有没有想清楚。芯片和单片机都只是工具,把每个环节的误差来源一个个按住,温度数据自然就干净了。