做工业现场的温度采集,从来都不只是把传感器接上、读个数值那么简单。尤其在 HVAC 和工业控制场景里,测温点往往分布在风管、冷水机组、换热站、配电柜这些噪声大、温差大、接线又长的位置,主控还要随时跟风机、阀门、变频器配合。这个项目把 TI 的 24 位 ADC 芯片 ADS122U04IPWR 和 STM32F101ZG 组合在一起,用串口 UART 把高精度采集链路串起来,做了一套能从 PT100 / PT1000 或热电偶直接读到工程温度值的采集方案。
这套组合解决的核心问题,是"传感器到单片机之间这一段信号链"的可靠性和一致性。ADS122U04IPWR 负责把微伏级别的模拟信号变成 24 位数字量,STM32F101ZG 负责通信、解析、滤波和逻辑控制。整个过程涉及前端传感器接线、ADC 寄存器配置、串口协议、数据滤波、温度标定等多个环节。这篇文章我按自己的实际项目流程来写,把整体思路、硬件设计、驱动写法、标定办法和调试中真正踩过的坑都梳理一遍。适合正在做温度采集、变风量控制、冷水机组监测,或者准备在嵌入式项目里用外置高精度 ADC 的朋友参考。
1. 项目背景:工业 HVAC 温度测量为什么不能含糊
1.1 现场采集的几个硬骨头
HVAC 系统的温度点看着简单,实际上每个点位都有各自的脾气。冷冻水供回水温差只有两三度,温度漂移一点点,机组能效计算就差一大截;风管里的温度传感器离变频器近,工频干扰随时可能串进信号线;机房里几十个测温点分布在几百米范围内,走线缆、过端子排、再接插头,每一段都会引入接触电阻和噪声。
更麻烦的是传感器类型不统一。老项目里大量用 PT100,新项目里喜欢用 PT1000,还有一部分测高温的场合必须用热电偶。如果每一路都配一块独立的变送器,成本高、柜内空间不够,而且变送器本身的精度和温漂也要额外评估。所以我在这个项目里的目标是:用一块多通道高精度 ADC 加上一颗通用 MCU,把不同类型的传感器直接接进来,靠软件配置来适配,而不是换硬件。
另一个硬骨头是信号链太长。前端的模拟信号经过端子、线缆、滤波电路才能到 ADC,中间任何一个节点的阻抗不匹配都会导致满量程误差和共模噪声。ADS122U04IPWR 这类带 PGA 和电流激励源的 Δ-Σ ADC,优势就在于能把前端调理电路集成进芯片内部,把以往需要独立运放和恒流源电路的工作直接省掉,同时保持较高的分辨率。
1.2 方案选型:ADS122U04IPWR + STM32F101ZG 的组合逻辑
为什么选 ADS122U04IPWR 而不是常见的 ADS1115 或者内部 ADC?关键看三点:分辨率、通道数、接口形式。
ADS1115 是 16 位,I2C 接口,在这类项目里精度勉强够用,但抗噪能力一般;STM32 内部 ADC 是 12 位,配合 DMA 做多次采样也能用,但只有把 PGA 和基准源都做好了才能达到 0.1℃ 级别的测量,板子上要堆不少外围器件。ADS122U04IPWR 是 24 位 Δ-Σ ADC,内置可编程增益放大器 PGA(增益范围 1 到 128),4 通道模拟输入,还带两个用于 RTD 激励的电流源,可以直接驱动 PT100/PT1000,热电偶的冷端补偿也能靠内置温度传感器完成。这就等于把信号链的大部分工作在芯片内部解决了。
它还有一个让我最终定下方案的特性——这个芯片采用的是 UART 异步串口接口,而不是 SPI 或 I2C。SPI 对时序要求高,线一长就容易出问题,I2C 速率慢,且地址冲突的事情也不少。UART 接口在工业现场非常成熟,可以走更长距离,电气隔离也好做得多。配合 STM32F101ZG 上的 USART 外设,哪怕不加额外的协议芯片也能直接通信。而且 UART 是异步的,不依赖时钟线,抗干扰能力确实比同步串口要强一截。
MCU 选 STM32F101ZG,主要看重的是大容量 Flash 和丰富的外设资源。F101 系列虽然主频没那么激进,但在这个项目里完全够用:一个 USART 跟 ADC 通信,一个 USART 留在调试口,再留几个定时器做 PWM 去控制风机、比例阀或者报警输出。整机跑下来,Flash 空间还能剩下不少,后续想加 Modbus 从站协议也绰绰有余。
2. 硬件整体设计与前端信号链
2.1 STM32F101ZG 在系统里的角色
在这个系统里,STM32F101ZG 不是单纯的"读数据",它还承担着整个设备的大脑角色。温度采集只是输入侧,真正让系统闭环的是 MCU 里的控制逻辑:读取多路温度 → 滤波和换算 → 跟设定值比较 → 输出 PID 调节量 → 控制风机频率或阀门开度。
我把 F101ZG 的引脚大致分了几组:
- 一组 USART 接 ADS122U04IPWR 的 UART 接口,负责命令下发和数据读取;
- 一组 USART 做调试日志输出,方便在现场通过串口助手观察实时温度;
- 一组 SPI 或 GPIO 接显示模块和按键,做成本地人机接口;
- 几路 PWM 输出接风机调速和电动阀执行器;
- 剩余 GPIO 接报警、状态指示灯和拨码设定。
从整体架构上看,F101ZG 的 512KB Flash 对这个应用来说比较宽裕。我推荐把固件分成 bootloader 和应用 App 两个区,方便后期通过串口升级。HVAC 现场经常要求不停机维护,有这个升级通道能省很多事。
硬件上需要注意的地方是模拟电源和数字电源的隔离。ADS122U04IPWR 的模拟电源 AVDD 应当单独用 LDO 供电,避免跟 MCU 的数字电源直接共用。如果系统里有 24V 转 5V 的 DC-DC,还要考虑开关噪声。我实测中发现,DC-DC 的纹波会直接通过 AVDD 耦合到 ADC 的测量结果里,导致转换数据上有规律的毛刺。最稳妥的办法是把模拟 3.3V 用低噪声 LDO 从 5V 单独拉一路,并在靠近 ADC 电源脚的位置放 10μF 和 0.1μF 去耦电容组合。
2.2 ADS122U04IPWR 的 UART 接口和寄存器交互
ADS122U04IPWR 的 UART 接口跟普通单片机串口对接时,有几个细节需要提前搞清楚。
这个芯片的 UART 协议是基于命令-响应的。主机发送命令帧,芯片处理后返回响应帧。命令里包含读写寄存器、启动转换、读取数据、复位等操作。默认波特率常见配置是 115200,也可以根据软件需求改成 9600 或 38400。波特率越低,抗干扰能力越强,但转换数据的读取会慢一些。在 HVAC 这种实时性要求不算极端的场景里,我建议用 9600 或 19200,尤其是传感器线缆比较长的时候,低速通信更稳。
通信接口的电平需要注意:ADS122U04IPWR 是 3.3V 器件,STM32F101ZG 的 GPIO 也是 3.3V,二者可以直接连。但如果你的系统里还有其他 5V 器件,务必不要混接,否则轻则通信乱码,重则烧坏输入引脚。长线传输时,我建议在 USART 的 TX 和 RX 上各串一个 100Ω 电阻,并在对方设备的 RX 端加上拉电阻,这样能减少振铃效应。
寄存器配置方面,这个芯片需要设置几个关键项:
- 模拟输入选择:AIN0-AIN3 对应的通道和测量模式;
- PGA 增益:根据传感器信号幅度选择 1、2、4、8……最高 128;
- 数据速率:从 20SPS 到 1000SPS 可调,实际需要根据信号带宽和滤波要求取舍;
- 电流源配置:PT100/PT1000 要选择合适的激励电流,电流太大传感器会自热,太小信号幅度不够;
- 温度传感器使能:用于热电偶冷端补偿或环境温度监测。
我习惯是在初始化时一次性把所有寄存器写好,然后循环读取转换结果,避免频繁写寄存器引入的干扰。上电之后先发复位命令,等待一段时间,再写入配置,最后才开启连续转换或单次转换模式。
2.3 传感器输入与前端调理电路的接法
传感器类型不同,接法差别很大,工程上的坑也最容易出在这里。
先说 PT100 / PT1000 热电阻。这类传感器阻值随温度变化,要用电桥或恒流源将它变成电压信号。ADS122U04IPWR 内置的电流源正好派上用场。三线制接法是工业现场最常用的,它能消除导线电阻的影响:一根线提供激励电流,一根线采样电压,另一根线作补偿。四线制精度最高,但需要多布一根线,适合实验室或关键测量点。两线制省钱,但导线电阻会直接叠加到传感器电阻上,对于 PT100 这种低阻值的传感器误差非常大,我不建议在精度要求高的场合用两线制。
接线的时候还要注意激励电流大小。PT100 的典型激励电流是 500μA 到 1mA,PT1000 用 250μA 到 500μA 就差不多了。电流太大,传感器自身发热会带来明显测量误差,电流太小,噪声会凸显。在需要做 0.1℃ 分辨率的应用里,我一般选 500μA,功耗和噪声平衡得比较好。
热电偶的情况不一样。热电偶输出的是毫伏级别的电压信号,不是阻值变化。好处是不需要激励电流,坏处是测量非常依赖冷端补偿。ADS122U04IPWR 内置温度传感器可以感知芯片附近的环境温度,配合经过校准的冷端温度,再通过查表或多项式计算得到真实温度。热电偶的信号幅度很小,K 型热电偶在室温附近只有几十微伏每摄氏度,所以 PGA 一定要开高增益,建议设置成 32 或 64 倍。如果现场离热源很近,热电偶引线最好用屏蔽线,屏蔽层单端接地,避免共模干扰。
热敏电阻也是 HVAC 里常见的传感器,成本低、响应快,但是非线性严重。用 ADS122U04IPWR 测量时,同样靠电流源激励,读取阻值后通过 Steinhart-Hart 公式计算温度。要注意的是,热敏电阻的 B 值一致性通常不如 PT1000,批量标定会比较费劲,所以我一般建议优先选择 RTD。
3. 软件设计:从原始码到温度值的流水线
3.1 UART 读写流程与命令帧设计
软件这块是整个项目真正花时间的地方。先说 UART 通信的底层流程。
我用 STM32 标准外设库和 HAL 库都写过这套逻辑。基本思路是:MCU 的 USART 以中断或 DMA 方式接收数据,主循环里定时向 ADC 发送读取命令,然后等待完整的响应帧。
ADS122U04IPWR 的数据手册会说明每个命令的字节格式和响应时长。我这里给一个常用的初始化伪代码,具体寄存器地址和位定义以数据手册为准:
// 伪代码:初始化和读取流程 void ads122u04_init(void) { // 复位 uart_send_cmd(CMD_RESET); delay_ms(10); // 写入配置寄存器 // 这里按项目需求填入寄存器值 // 例如:使能 PGA、选择电流源、配置转换速率等 uint8_t cfg[3]; cfg[0] = 0x00; // 配置寄存器0 cfg[1] = 0x40; // 配置寄存器1,示例值 cfg[2] = 0x20; // 配置寄存器2,示例值 uart_send_cmd(CMD_WREG, cfg, 3); delay_ms(5); } uint32_t ads122u04_read_raw(void) { // 发送读取命令 uint8_t resp[4]; uart_send_cmd(CMD_RDATA); // 等待并接收4字节响应 uart_receive(resp, 4); // 将4字节拼成24位整型 uint32_t raw = (resp[0] << 16) | (resp[1] << 8) | resp[2]; return raw; }很多新手容易卡在一个问题上:UART 是异步的,ADC 的命令响应时间不确定,怎么办?我的做法是给接收加超时机制。每次发送读取命令后,用定时器做一个 5ms 到 50ms 的超时窗口,如果在窗口期内没有收到完整的响应帧,就主动丢弃这一帧并重新发送命令。绝不能在一个错误帧上一直死等,否则整条采集链路会被一个异常点卡死。
命令帧设计上,我建议用固定长度帧,并在帧头加校验字节。这样 MCU 收到数据后,可以快速通过帧头和校验值判断这一帧是否合法。如果通信线路上有干扰,校验能拦下绝大多数错误数据,避免温度跳变甚至控制逻辑误动作。
3.2 数据转换、滤波与温度算法
原始读数拿到之后,还不能直接用。24 位 ADC 的输出码要先换算成电压或电阻值,再换算成温度。
对于 RTD 来说,换算过程一般是这样:
- 从寄存器读数得到有符号的 24 位整型值;
- 用基准电压和 PGA 增益把码值换算成电压;
- 根据激励电流值计算传感器电阻;
- 用 Callendar-Van Dusen 方程或查表法把电阻变成温度。
温度计算里的线性化是重头戏。PT100 在 0℃ 到 100℃ 之间的阻值变化约为 0.385Ω/℃,基本接近线性,但要做到 0.1℃ 精度,还必须做非线性修正。工程上最常见的做法是分段查表加线性插值。把传感器的标准分度表存在 Flash 里,例如每隔 10℃ 存一个阻值点,中间用线性插值。这样误差很小,计算量也不大。
热电偶更麻烦一点,它的电压-温度曲线是非线性的,而且还要进行冷端补偿。简单做法是:先把冷端温度从芯片内置温度传感器读出来,转换成对应的电动势,加上测量端的热电动势,再用反查表得到真实温度。这个流程虽然代码量不大,但是细节决定成败。我建议把查表的数据做成 const 数组,放在只读区,运行时不要修改。
滤波策略这块,我推荐做两级处理。
第一级在代码层面做数字滤波。采集到的原始温度值,去掉明显超范围的坏值后,再做滑动平均。比如采 8 次取平均,能有效滤掉随机噪声。第二级在控制层面做低通滤波,最简单的是一阶惯性滤波,公式是filter = filter * alpha + new_value * (1 - alpha)。alpha 越大,曲线越平滑,但响应越迟钝。HVAC 系统本身是慢变量,我把 alpha 选在 0.8 左右,既能看到温度趋势,又不会让 PID 控制器被噪声带着走。
3.3 多点校准和线性化补偿
硬件上的误差主要来源有三个:基准电压误差、PGA 增益误差、传感器本身的精度偏差。每个环节都会最终反映到温度值上,所以正经项目一定要做校准。
我的做法是在实验室里做两点或三点校准。比如用高精度恒温槽把传感器分别放在 0℃、50℃、100℃ 三个点,记录 ADC 读数和实际标准温度,然后算出偏移量和增益系数。在代码里,把校准后的系数写到一个配置结构体里,运行时对测量结果做线性修正。
校准公式很简单:
calibrated_temp = raw_temp * gain_cal + offset_cal;别小看这一步。一块 ADS122U04IPWR 本身的线性度是不错的,但反馈电阻、基准电压、传感器批次这些外部因素却各有个性。不做校准,可能整体偏差 0.5℃ 以上;做了两点校准,项目内的一致性通常能控制到 ±0.2℃ 以内。
还要提醒一句:校准数据的存储要带校验。我在 EEPROM 里存校准参数时,多存了一份 CRC 校验值。现场如果发现温度异常漂移,可以快速判断是不是 EEPROM 里的标定数据被篡改或丢失了。
4. 实测与调试:我踩过的坑
4.1 串口超时和电平不匹配问题
第一个让我折腾最久的问题,是 UART 通信不稳定,表现为偶发乱码和响应超时。
一开始我怀疑是波特率误差。STM32F101ZG 内部晶振精度一般,如果系统时钟不是 72MHz 的整数倍分频,波特率会产生微小偏差。实测发送一两个字节时感觉不到,多字节交互时误差就会累积。解决方法是把 USART 的波特率寄存器手动算一遍,或者用外部晶振,确保通信双方波特率尽量一致。
后来发现更大的问题出在电平上。ADS122U04IPWR 的串口是推挽输出,而有些 USB 转串口模块用的是开漏模式,上拉电阻不合适,导致高电平不够高。两者的电平标准不完全一样,直接对接就会出现偶发错位。我的调试思路是用示波器看波形,而不是用万用表量高平电压。示波器能看到上升沿的斜率,如果沿太缓,就要检查上拉电阻和线路电容。最后我在通信线上加了一级 74LVC1G07 之类的缓冲器,问题就彻底消失了。
4.2 50Hz 工频干扰和接地布线
HVAC 现场最典型的外部干扰是 50Hz 工频。传感器信号线只要稍微靠近动力电缆,示波器上就能看到明显的正弦波叠加在直流信号上。
对抗工频干扰有两条路。第一条路是在 ADC 的转换速率上下功夫。Delta-Sigma ADC 的数字滤波器天然对工频有抑制,但不同的数据速率对应的抗工频能力不一样。如果数据速率恰好落在 50Hz 的整数倍附近,工频干扰会以混叠形式进入测量结果。所以现场工频是 50Hz 时,建议选择 20SPS 或 50SPS 这类和数据关系匹配的速率,同时配合软件滤波。
第二条路是走线。我因为前期图省事,把传感器线跟继电器控制线走在同一个线槽里,结果发现继电器一吸合,温度数值立刻跳几个字。后来把模拟信号线单独走屏蔽线,屏蔽层在控制器端单点接地,继电器和动力线远离采集输入端子,问题大幅缓解。做这套系统时,我把强电和弱电走线分道扬镳排进了结构设计规范里,这也算踩坑之后的强制改正。
4.3 ESD 与现场可靠性
工控设备最大的敌人是静电和雷击感应。尤其是传感器端子暴露在机柜外面的时候,人手触摸到端子就会引来一串 ESD。
我在设计电路时,在最前端的传感器输入端加了一级 ESD 保护器件,比如 TVS 管或者压敏电阻,并且串联了限流电阻。别以为 3.3V 系统就安全,HVAC 设备安装和维护过程很粗暴,这个保护环节不能省。
另外还有一个容易被忽略的点:ADC 的模拟输入引脚内部虽然有保护二极管,但耐流能力有限。如果在异常情况下传感器线短路到 24V 电源,轻则 ADC 损坏,重则 MCU 也跟着遭殃。所以我强烈建议在每个模拟输入脚跟地之间加一个低漏电流的 TVS,并在输入路径串一个数百欧姆的电阻,先限流再进芯片。我实测下来,这个做法对常温测量项目几乎没有精度影响,但对可靠性的提升是实打实的。
4.4 常见问题速查表
我把调试中遇到的高频问题整理成了一个速查表,方便大家对照排查:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 温度读数偏大或跳变 | 传感器线接触不良、接线端子氧化 | 断开后在传感器端量阻值,确认接触状态 |
| 读数一直为最大码值 | 模拟输入开路,PGA 输出饱和 | 检查输入通道是否漏接或虚焊 |
| 串口响应超时 | 波特率偏差、电平不匹配、线路过长 | 用示波器观察波形,核对时钟配置 |
| 多路传感器交叉干扰 | 共用地线、多路电流源交叉串扰 | 检查公共地回路,改用独立通道和独立电流源 |
| 数值随温度缓慢漂移 | 基准电压漂移、未做校准 | 检查基准芯片,重新标定增益和偏移 |
| 继电器动作时读数跳变 | 强电干扰串入模拟前端 | 加隔离、改走线、加大滤波时间常数 |
| 低功耗要求下待机电流大 | ADC 未进入休眠模式 | 确认写入休眠命令,关闭不用的电流源 |
这个表里的每一条,我基本都在真实项目里遇到过。很多时候问题并不在 ADC 芯片本身,而在外围接线和系统结构。所以调试时不要急着换芯片,先对照这个表一步步过滤。
5. 扩展与经验收尾
5.1 从单点温度到多通道网络的扩展
这套系统做出来之后,我顺手把它的架构扩展成了多节点方案。ADS122U04IPWR 的 UART 接口支持地址寻址,也就是多个 ADC 可以挂在同一条串口总线上,由主控分别访问。这个特性非常适合 HVAC 项目里几十个温度点集中在机柜但分布在不同区域的情况。
把每个 ADS122U04 设置成不同的地址,通过一根 RS-485 总线接入 STM32F101ZG,就形成了典型的两级采集网络。底层每个节点负责就近采集 4 路温度,顶层主控定期轮询所有节点,汇总数据后做区域控制算法。这样做的好处很明显:传感器线缆长度大大缩短,模拟信号不容易被干扰,数字信号传输距离可以做得很长,抗扰能力也好得多。RS-485 收发器选带隔离的型号,例如带内部隔离电源的成品模块,还能进一步提高整个系统的耐压和抗共模能力。
如果后续还要接入上位机或云平台,STM32F101ZG 的资源也足够直接跑 Modbus RTU 从站协议。这样空调机房的控制柜,既能独立运行,也能远程监控。
5.2 关于这个方案的个人体会
我做了这么多年嵌入式,最大的感受是:高精度 ADC 并不是选个贵芯片这么简单,整个链路才是精度和可靠性的来源。ADS122U04IPWR 和 STM32F101ZG 这个组合之所以让我满意,核心在于它把复杂的前端模拟处理和数字控制分开,再用 UART 这个成熟的接口串联,软硬件调试都相对容易。项目开发过程中,我也曾想在 12 位内部 ADC 上硬扛,最后发现是浪费时间;也曾想直接买一体化温度变送器,最后发现成本和多点部署的灵活性都不可接受。
这个方案做出来的样机,在实验室里温度波动能稳定在 ±0.15℃ 以内,在现场试运行一个月也没有出现通信死机和数据跳变的情况。如果你也在做 HVAC 或者工业测温项目,这个架构可以直接借鉴。最后再提醒一句:开工前一定把传感器类型、精度要求、通信距离和隔离等级都定清楚,再开始画板子,否则后面每一步都会很痛苦。