基于ADS122U04与STM32L4的工业温度采集系统设计
做工业测控和HVAC系统的人,迟早会面对一个看起来基础、实际上很缠人的问题:温度到底测准没有。管道风道里的PT100信号拉到控制器时,经常已经裹上一堆噪声;热电偶输出只有几十微伏,远一点就被变频器、接触器和电机干扰得没法看。所以在最近一个项目里,我换了TI的ADS122U04IPWR加ST的STM32L4A6RG来做温度采集。ADS122U04IPWR是一颗24位Δ-Σ ADC,自带PGA、基准源和可编程激励电流源,最重要的是它直接用UART把转换结果送出来,等于把模拟前端的全套工作放到传感器附近完成,再用一根串口线把数字信号传到MCU。STM32L4A6RG是Cortex-M4F内核的低功耗MCU,1MB Flash加320KB RAM,串口、DMA、低功耗模式都很齐全。这套组合特别适合多通道风道温度监控、冷水机组进出口温度管理、热泵和压缩机保护这类工业和HVAC应用。文章不写空话,把我选型时怎么想、硬件怎么接、底层怎么调、温度怎么算、现场怎么校准,完整摊开讲一遍。
1. 选型逻辑:为什么是UART型24位ADC加STM32L4,而不是SPI接口方案
先说说ADS122U04的来路。它本质上是ADS1220的UART输出版本。ADS1220用的人很多,SPI接口,性能稳定,但SPI在工程现场有一个先天烦恼:它讲究时钟同步和时序,线一长就不可靠,而且每个从机都要一根片选线。ADS122U04把这个痛点点掉了,内部照样是24位Δ-Σ转换核心,照样带PGA、2.048V内部基准、两个IDAC电流源和内部温度传感器,但转换结果通过UART按帧发出。UART是异步通信,对时钟同步的要求低得多,对线长的宽容度也高得多,连三根线(TX、RX、GND)就能工作,距离拉到两三米完全没压力。
STM32L4A6RG这边,选它不是冲着"大厂稳妥"去的,而是四个实际的理由:Cortex-M4F带FPU,温度多项式计算、数字滤波这些活很轻松;1MB Flash和320KB RAM,放得下热电偶分度表、RTD查表数据,还能存一段现场日志;UART资源多,用DMA收ADC数据几乎不占CPU;低功耗模式完整,HVAC控制器常年通电,能在停止模式里跑定时唤醒,省电效果很直接。
1.1 传感器侧数字化:工业现场最值钱的一种取舍
让我下决心用"ADC和MCU分离"而不是"把传感器模拟信号直接拉回控制器"的,是现场布线的长度和干扰。PT100在0℃时是100Ω,温度每升1℃只增加0.385Ω;用1mA激励电流,温差1℃对应的电压变化只有0.385mV。这个量级的信号在工业现场走三五米,旁边的变频器一启动,信号基本就废了。把ADS122U04放在传感器箱子旁边,模拟信号只走最短距离,之后全走数字,这是最干净的做法。STM32那边读到的已经是24位干净数据,后面处理逻辑一下子简化了。
1.2 同类型接口方案对比:UART在这个场景下为什么更讨巧
| 接口 | 距离与抗干扰 | 接线复杂度 | 多设备扩展 | 在HVAC场景的实用性 |
|---|---|---|---|---|
| SPI | 20cm以内可靠,线长易丢数据 | 需CLK/CS/MOSI/MISO,4线起步 | 每个从机一根片选 | 适合板级近距离,不适合跨箱体 |
| I2C | 地址有限,速率低,抗干扰一般 | 2线,但要处理上拉 | 地址冲突要规划 | 短距离板级还可以 |
| UART(本方案) | 数米无压力,物理层还能升级RS485 | 2~3线 | 一主一从最简单 | 温度采集点分散时非常实用 |
| 单总线 | 线少,距离远但是时序敏感 | 1线 | 可挂多个但时序严苛 | 高精度型号少 |
在"传感器散落在设备各处"的HVAC场景,UART的现实优势非常明显。而且如果觉得两三米还不够,加个RS485收发器就能把距离推到百米级别,上层代码基本不用动。这一点在我做后续扩展项目时省了不少事。
2. 硬件连接与传感器前端:RTD、热电偶、热敏电阻三套接线
2.1 电源、地线和一个必须守的上电时序
ADS122U04的供电范围比较宽,3.3V下运行很正常。AVDD和DVDD都要就近放0.1µF陶瓷电容,再并一个1µF左右的电容,模拟地和数字地在芯片附近单点汇合,避免数字电流串进模拟回路。一个重要注意事项:MCU和ADC之间一定要保证同地,UART的RX/TX虽然是数字信号,但如果两端地电位差过大,轻则误码,重则烧接口。实际项目里我在两根UART线上各串联一个33Ω电阻,对热插拔和静电都友好。
上电时序同样容易被忽略。ADC需要先上电稳定,之后才能接收配置命令。如果MCU复位比ADC快,一上电就往ADC发配置,第一帧很可能会丢。稳妥做法是MCU启动后先延时几十毫秒,再发一条RESET命令,最后才做寄存器配置。
2.2 RTD四线制比值测量:接线与消误差原理
测PT100/PT1000,最推荐四线制比值测量。典型接法是:IDAC1从ADC芯片流出,先经过RTD,再经过一个精密参考电阻RREF,最后回到GND;ADC的两个差分输入脚跨接在RTD两端;ADC的基准电压输入跨接在RREF两端。这样同一个激励电流I既流过RTD也流过RREF,ADC测量到的电压比就是:
ADC输出码正比于 V_RTD / V_REF,而 V_RTD / V_REF = (I × R_RTD) / (I × R_REF) = R_RTD / R_REF。
电流I在等式里约掉了,这带来的好处很直接:IDAC的精度、温漂、长期漂移全都不影响测量结果。整个测量链路里,RREF的品质才是关键。这就是比值测量的精髓。
RREF选型有讲究。温度系数建议25ppm/℃以下,初始精度0.1%以内,我一般选精密金属膜电阻或金属箔电阻。对PT100,RREF常用100Ω或430Ω;太小,基准电压低会压缩有效范围;太大,RTD上的压降和自热功耗都会升高,同时共模电压也被抬高。项目里我用过430Ω配250µA激励电流,实测效果很好。两线制和三线制是成本和精度之间的折衷:两线制会把导线电阻直接算进阻值,PT100线阻10Ω能带来约26℃的误差,几乎不可接受;三线制可以用两个IDAC做补偿,接线和配置复杂一点,适合没有四线条件又想控制误差的场景。我在HVAC项目里只要空间允许就用四线。
RTD和热电偶的接线端子最好加TVS或钳位二极管,现场带电插拔不是没发生过,输入级有保护会安心很多。
2.3 热电偶的高增益接线与冷端补偿
热电偶信号非常微弱,K型热电偶大约40µV/℃,所以PGA要设高增益,一般取64或128。热电偶输出的是热端与冷端的温差电压,冷端就是接线端子那里的温度,必须做冷端补偿。ADS122U04内部自带温度传感器,可以测芯片附近温度,把接线端子靠近芯片安装,用内部温度传感器读数做冷端温度,再配合分度表就能算出真实温度。
接线小细节:热电偶线不能直接和铜线长时间拧在一起,最好用专用端子或等温块。冷端温度变化是热电偶测量里最主要的误差来源,要给接线端子加个遮风罩,别让它被气流直吹。曾经遇到一个项目,风道里的测温点读数跟着风机启停周期性波动,查到最后就是冷端被风直吹导致的。
2.4 NTC热敏电阻的另一套玩法
NTC阻值大,自热是主要矛盾。激励电流一般选100µA到250µA,大了发热明显,小了信噪比差。如果只是做管道温度趋势监测,NTC性价比确实高;要做高精度控制,RTD更稳。用NTC配合IDAC做比值测量时,同样可以把NTC串一个精密RREF,让ADC测电压比,再通过Steinhart-Hart公式反算温度。Steinhart-Hart公式里有三个系数,需要三个温度点标定,但一旦标定好,线性度比简单查表平滑得多。
3. 从原始码到温度:ADS122U04输出数据的三步换算链路
3.1 24位二进制补码的接收与符号扩展
ADS122U04每次转换结果通过UART发出3个字节,高位在前,数据是有符号数,因为差分输入下负电压也能表示。MCU收到3字节后,要转成32位有符号整数:
uint8_t data[3]; int32_t raw, value; if (HAL_UART_Receive(&huart1, data, 3, 100) == HAL_OK) { raw = (data[0] << 16) | (data[1] << 8) | data[2]; if (raw & 0x800000) raw |= 0xFF000000; // 24位符号扩展 value = raw; }很多第一次写的人会漏掉符号扩展,结果低温下读出来是几百万的"怪异正数",然后绕一大圈弯路。这个操作虽然只有一行,但最容易出错。
提示:如果读到的数据在0℃附近反复横跳,先检查符号扩展那一步,再看后面公式里的比例系数。
3.2 为什么RTD优先直接算阻值,而不是先算电压
在比值测量模式下,如果基准电压来自与RTD串在同一电流路径上的RREF,输出码其实和电压值、增益的关系都摊平了,可以直接写:
R_RTD = (raw / 2^23) × R_REF
比如raw读出是2_000_000,RREF=430Ω,那么R_RTD = (2000000 / 8388608) × 430 ≈ 102.5Ω,对应PT100大约6.6℃。这里用2^23而不是2^24,是因为24位有符号数的正满量程对应+VREF,负满量程对应-VREF,幅度轴是±2^23个LSB。工程上先用2^23做比例基准,剩下的系统偏差交给校准环节修正。
3.3 RTD温度反演:Callendar-Van Dusen方程
得到阻值之后,PT100的阻温关系用Callendar-Van Dusen方程描述:
- 0℃到850℃区间:R(t) = R0(1 + A·t + B·t²)
- -200℃到0℃区间:R(t) = R0(1 + A·t + B·t² + C·(t-100)·t³)
其中R0=100Ω,A=3.9083e-3,B=-5.775e-7,C=-4.183e-12。
反算温度时,因为方程里有t的二次和三次项,直接解比较麻烦,MCU里一般用牛顿迭代,三五次就能收敛:
// 给定R_RTD,解出温度t(0℃以上简化版) double t = (R_RTD / R0 - 1.0) / A; // 初值 for (int i = 0; i < 4; i++) { double err = R0 * (1 + A*t + B*t*t) - R_RTD; double dRdt = R0 * (A + 2*B*t); t = t - err / dRdt; }如果不想用迭代,也可以预先做一张-50℃到200℃的分度表,线性插值。HVAC这种温区,一张100点的表,做到0.1℃分辨率很轻松。
3.4 热电偶怎么从电压走到温度
热电偶计算分两步:第一步,用内部温度传感器读到的冷端温度T_cold,查分度表得到冷端对应的热电偶电压E_cold;第二步,把热端测到的电压E_hot加上E_cold,得到相对于0℃冷端的等效电压,再用分度表反查温度。K型热电偶在MCU里通常先存一个查找表,几十个点,插值计算,速度快、代码简单。也可以用一元多次多项式拟合,但K型在宽温区非线性很强,单项式拟合阶数太高,不如查表实用。
4. STM32L4A6RG驱动落地:UART帧读写、寄存器配置与状态检测
4.1 UART与DMA的基础配置
我习惯用USART1连ADS122U04,波特率9600。有人会问为什么不拉高波特率?ADS122U04的数据速率本身不高,9600bps足够传完24位结果,而且低波特率抗干扰更稳。初始化代码:
huart1.Instance = USART1; huart1.Init.BaudRate = 9600; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; HAL_UART_Init(&huart1);如果想省CPU,可以用DMA接收。DMA循环缓冲配合UART空闲中断,把一帧3字节自动收进缓冲区,CPU只在空闲中断里取走并处理。ADS122U04的帧很短,这套方式跑起来非常舒服。
4.2 配置寄存器的写入时序
把寄存器配置全部写好再启动转换,是稳定工作的前提。ADS122U04支持写寄存器命令WREG,命令字节通常为0x40加上寄存器地址编码,后面跟配置值。代码里可以这样抽象:
void ads122u04_write_reg(uint8_t reg, uint8_t val) { uint8_t buf[2]; buf[0] = 0x40 | (reg << 2); // WREG命令,具体编码以数据手册为准 buf[1] = val; HAL_UART_Transmit(&huart1, buf, 2, 100); }以PT100四线比值测量为例,配置里关键几项包括:输入MUX选AIN0/AIN1差分;PGA设1,因为比值测量不需要放大;基准电压选外部基准REF1,跨接在RREF两端;IDAC1开启并设置250µA激励电流,路由到RTD回路。这些位分布在寄存器0到4,具体的bit定义不同版本数据手册略有差异,务必对着手册逐位核对。很多"配置对了但读数不对"的问题,最后查下来都是某一位写反。
4.3 连续转换模式下的数据读取
我一般用连续转换模式:启动后ADC自己按设定数据速率转换,MCU随时发RDATA命令取最新结果。RDATA命令字节为0x10,然后读3字节:
uint8_t cmd = ADS122U04_CMD_RDATA; uint8_t raw[3]; int32_t value; HAL_UART_Transmit(&huart1, &cmd, 1, 50); HAL_UART_Receive(&huart1, raw, 3, 50); value = ((int32_t)raw[0] << 16) | ((int32_t)raw[1] << 8) | raw[2]; if (value & 0x800000) value |= 0xFF000000;如果ADS122U04封装上有数据就绪引脚,可以把该引脚接到STM32L4的EXTI,数据一准备好MCU立刻读取;没有就用系统tick周期读。温度是慢变量,1秒读一次都够。
4.4 通信异常恢复与传感器断线判断
实际运行中UART可能因为干扰丢一帧,不能因为一帧失败就让整个系统傻掉。我的做法:每次读取设超时;连续5次读取失败就发RESET命令重新初始化ADC;再不行就置故障标志,等待人工处理。
传感器开路和短路也有特征。RTD开路时,激励电流无处可走,ADC输入被拉向不可控位置,输出往往打满或接近满量程;RTD短路时,差分输入接近0,输出码接近0。代码里做一个上下限判断,超出合理电阻范围的读数直接丢弃并报故障,这比让错误值参与控制可靠得多。
5. 现场精度实践:校准方法、噪声抑制与HVAC部署注意点
5.1 两点校准:一套简单但有效的增益和偏移修正
就算有24位ADC,系统里还有参考电阻精度、运放偏置、导线电阻等误差,两点校准是快速提升整体精度的办法。操作思路:
- 在标准温度源或冰水槽中放好传感器,记录第一次换算后的温度读数T_raw1,记下标准温度T1;
- 换一个准确的第二温度点,记录T_raw2与T2;
- 计算修正系数:a = (T2 - T1) / (T_raw2 - T_raw1),b = T1 - a × T_raw1,之后系统温度 = a × T_raw + b。
举个例子:0℃点系统初步读成0.3℃,50℃点系统初步读成49.8℃,那么a = 50 / (49.8 - 0.3) ≈ 1.0101,b = -0.303。这套线性修正在HVAC温区里完全够用。测RTD时,我会把探头浸入0℃冰水混合物和100℃沸水做两点,效果很直观。
5.2 数字滤波:滑动平均、中值与限幅的组合
24位ADC分辨率高,低位跳动是常态,不加滤波直接上数据会很难看。工程上常用组合拳:
- 限幅滤波:相邻两个合法采样差超过阈值就丢弃新值,比如温度变化超过5℃/s就视为异常;
- 中值滤波:取5个值排序取中间值,抗脉冲干扰;
- 滑动平均:对窗口内数据求平均,平滑趋势。
温度是慢变量,窗口大一点也不怕。我在风道温度采集里用了32点滑动平均,1秒输出一次温度,曲线非常干净。需要注意,如果数据速率本身较高,要先做限幅和去界外值,再平均,否则一个尖峰能污染整个窗口。
5.3 HVAC现场电磁干扰:屏蔽、接地和布线三件事
HVAC现场干扰源主要是变频器和继电器。几条经验:
- 传感器线用屏蔽双绞线,屏蔽层一端接地,通常在采集箱侧,不要两端都接,避免地环路;
- UART信号线和强电电缆分开走线,避免平行贴在一起;
- 如果现场电磁环境特别恶劣,UART物理层可以换成RS485或加磁环;
- ADC供电如果来自24V转3.3V模块,注意纹波,必要时加LC滤波。
有一次现场数据周期性跳动,查了一下午,最后发现是UART线缆和一根220V电缆扎在同一个线槽里。把两者分开后问题立刻消失。这类事只有经历过才记得住。
5.4 低功耗与长期运行策略
HVAC控制器往往7x24小时通电,低功耗不能只挂在嘴上。STM32L4A6RG的停止模式配合RTC唤醒,可以让MCU大部分时间睡觉,醒来读一次ADC,处理完继续睡。ADS122U04这边,如果不用连续转换,可以配置成单次测量,或者在不测量时进入睡眠模式,电流能降到微安级。
对温控应用,一秒采集一次已经绰绰有余,甚至5秒一次都够。采样率、功耗和电磁暴露是绑定的,能慢则慢,这是系统长期稳定的一大法宝。
6. 试运行中的典型故障:从现象到根因的排查记录
6.1 读数一直在跳动,怎么都压不下来
这类问题我碰到过两次,根源完全不一样。第一次是参考电阻用了普通贴片电阻,温漂大,空调一开、板子温度一变,读数就跟着飘;换成25ppm的精密电阻之后就好了。第二次是ADC参考电压脚上的滤波电容放得太远,PCB走线拉出长线,高频噪声耦合进基准,给REFP/REFN脚就近放100nF电容后,读数立刻稳定。数字端再怎么追求24位精度,前端一个缺陷就能把结果毁掉。
6.2 UART偶尔丢帧、初始化失败
排查顺序别乱:
- 示波器看UART波形,确认波特率误差在2%以内。STM32L4用HSE配9600通常没问题,用内部RC可能会偏;
- 检查ADC和MCU是否真正共地,UART的GND线不要借别处的回路;
- 检查开机时序,MCU复位期间UART线如果有杂波,可能把ADC的状态机搞乱。最直接的解法是初始化前先发RESET。
6.3 温度整体偏高或者偏低
先别怪ADC,先检查MUX和增益配置。常见问题包括差分输入接反,此时低温读数变负、高温变正,严重不对称;或者PGA增益没设成预期值,满量程比例错了一位。其次看校准:如果直接用理论公式但没加校准系数,板级误差自然会表现为整体偏移。我一般先用精密电阻箱代替传感器做整链路自检,把ADC、基准、软件全流程验证一遍,再上真实探头,这样能快速定位问题出在模拟前端还是传感器本身。
6.4 传感器长时间运行后读数异常
RTD探头老化、接线端子氧化、电缆接头进水,这类软故障在HVAC现场很常见。软件上要给自己留一手:定期自检,给系统插一路精密电阻作为参考通道,定期比对,发现偏移超限就报维护;开机自诊断,检查是否有开路短路特征;变更留痕,记录每次校准参数,便于回溯。
我在这个项目里的最后一道工序,是给每个温度通道板载了一路精密电阻作参考通道,定期轮询比较。三个月运行下来,数据基本都在设计范围内。以后回访调试,先把参考通道读数调出来,就能判断是探头老了还是链路漂了,省了不少现场拆装时间。
| 现象 | 优先排查方向 | 常见根因 |
|---|---|---|
| 读数跳动 | 基准脚电容、RREF温漂 | 基准噪声、电阻温漂 |
| 丢帧 | UART波形、共地情况 | 波特率偏差、地电位差 |
| 温度偏移 | MUX/增益配置 | 输入接反、校准丢失 |
| 长期漂移 | 探头、端子、参考通道 | 老化、氧化、进水 |