这几年做工业现场设备,尤其碰到 HVAC 和冷冻冷藏这块,我越来越觉得“把温度测准”这四个字没那么简单。你不仅要选对传感器,还得考虑引线长度、环境噪声、采集电路的稳定性,最后再通过 MCU 把数据变成真实可用的温度值。最近我在一个冷库数据记录仪和机房精密空调的控制器上,用了一对组合:ADS122U04IPWR(TI 的 24 位 ADC,带 UART 接口)加上PIC32MX664F064L(Microchip 的 MIPS 内核单片机),整套系统测 PT100/PT1000,实测下来效果很稳。这篇我把整个方案的研究过程、硬件设计、固件实现和现场踩坑都整理出来,给准备做高精度温度采集的朋友一个参考。
1. 先把需求搞清楚:工业和 HVAC 的温度测量到底难在哪
1.1 温度测量的几个真实场景
先别急着聊芯片,我们要先知道自己面对的是什么现场。工业和 HVAC 里的温度测量,常见就有好几种形态:
- 风管温湿度传感器:测空调送风、回风温度,一般用 PT1000 或 NTC,距离控制器可能有个三五米。
- 冷媒管路表面温度:空调制冷系统里测压缩机进出口管温,往往用贴片式 PT100,引线细长,干扰源多。
- 冷库环境温度:多路 Pt100 采集,线缆有时穿过保温层、桥架,动不动十几米。
- 机房列间空调的进出风温度:对精度要求高,最好误差在 ±0.1℃ 以内,用于控制风机转速和制冷量。
这些场景有个共同特点:传感器分散、信号弱、干扰杂,而且一旦放到现场连续跑,你还得考虑长期漂移。普通的 MCU 内置 ADC 在这种场景下基本上是撑不住的——12 位、参考电压不稳、没有可编程增益,做做室温显示还行,做控制逻辑就麻烦了。
1.2 为什么要用 24 位 Δ-Σ ADC 而不是 MCU 内置 ADC
MCU 内置 ADC 通常都是逐次逼近型(SAR),比如 12 位,满量程 3.3V 时,一个 LSB 对应大约 0.8mV。而 PT100 在 0℃ 附近灵敏度只有约 0.385Ω/℃,如果激励电流 1mA,也就是 0.385mV/℃。用 12 位 ADC 去量 0.385mV 的变化,一个 LSB 就差不多覆盖 2℃ 了,根本没法用。
所以工业温度采集基本都交给 Δ-Σ 型 ADC。ADS122U04IPWR 是 24 位分辨率,内部有 PGA(可编程增益)、激励电流源、基准源和输入多路复用器。它的核心思路不是“直接看电压绝对大小”,而是通过过采样把量化噪声推到高频段,再用数字滤波把噪声滤掉,换取极低的有效噪声。再加上内部 PGA 把微伏级信号放大后再做转换,实际有效分辨率能做到 18-19 位以上,测 PT100 达到 0.01℃ 量级完全可行。
1.3 为什么选 ADS122U04IPWR 而不是常见 SPI 版本
很多工程师对 TI 的 ADS1220 或 ADS124S08 很熟,那都是 SPI 接口。ADS122U04 这个“U”指的就是 UART 接口。在工业现场,这就是一个很关键的好处:
- SPI 是同步串行接口,时钟线上一个毛刺就能导致数据错位,线一长就特别头疼;
- UART 是异步串口,抗干扰性强,而且可以直接对接工业现场常见的 RS-485 总线,用便宜的收发器就能把 ADC 放到几十米外。
对我这个项目来说,冷库里的传感器探头分散在不同库房,我原本还要在传感器旁边放一块小 PCB 做调理电路。有了 UART 接口的 ADS122U04,我可以把 ADC 直接放在探头附近,通过 RS-485 把数字信号传回主控板,走线长一点也不用担心模拟信号衰减。
2. 核心选型拆解:ADC 与 MCU 如何配合
2.1 ADS122U04IPWR 的关键特性
ADS122U04 是 TI 推出的一款低功耗、24 位 Δ-Σ ADC,带 UART 接口,常见于温度和压力测量。我挑几个和温度测量直接相关的特性来说:
- 4 通道多路复用输入,可以配置成差分或单端模式;
- 内部 PGA,增益 1 到 128 可编程,适合微伏级传感器信号;
- 两个可编程激励电流源(IDAC),用于 RTD 的比例式测量;
- 内部 2.048V 基准电压,也可以使用外部基准;
- UART 接口,支持主机命令配置和转换结果读取;
- 集成内部温度传感器、断线检测功能。
这里尤其要强调“比例式测量”。大家都知道传感器会漂移、基准源也会漂移,但如果我让同一个激励电流流过 PT100 和一个精密参考电阻,ADC 分别测量两个电压的比值,那么激励电流的变化就能被抵消掉。ADS122U04 内部集成了两个电流源,天然就是为 RTD 比例测量设计的。
2.2 PIC32MX664F064L 的角色定位
PIC32MX664F064L 是 Microchip 的 32 位 MIPS 内核 MCU,主频最高 80MHz,带 128KB Flash 和 32KB SRAM,最关键是它有最多 6 个 UART。这对我这个方案很重要:
主控板要同时管理多路温度采集,每一路 ADS122U04 占一个 UART,再加上还要和触摸屏、上位机通信,普通 8 位单片机的外设数量根本不够。PIC32MX 系列的 UART 还支持 FIFO 和 DMA,接收 ADC 返回的数据时不用 CPU 频繁打断。
另外,PIC32 的引脚兼容性也值得夸一句,同一个封装下有不同 Flash/RAM 大小型号,后续如果我要加功能,比如增加 Ethernet 网关,换芯片不用重新画 PCB。
2.3 接口方案权衡:UART 比 SPI 好在哪
有人可能觉得,SPI 不是更快吗?ADS122U04 这种芯片数据速率本来就不是特别高(通常每秒几百次采样以内),UART 完全够用。而且从电路设计角度,UART 的好处实在太多:
- 只需要 TX、RX 两根线就能完成双向通信;
- 可以直接经过 RS-485/RS-422 收发器实现长距离传输;
- 没有时钟线,就没有高速跳变沿引入的串扰;
- 帧格式天然适合带起始位、停止位,容易做接收同步。
我做过一个对比测试:同样一块板子,SPI 版本在电机变频器附近测试,偶尔会出现误码;改成 UART 之后,即使线缆从变频器旁边穿过,通信也一直很稳定。所以别只看 SPI 速率高,现场的可靠性更重要。
3. 硬件设计实操:从传感器到 ADC 再到单片机
3.1 传感器选型与连接方式:RTD、NTC、热电偶
ADS122U04 不是只能测 RTD,它通道多、增益宽,传感器类型基本都能覆盖,但连接方式有讲究。
PT100 和 PT1000 属于电阻式温度传感器,要用电流源激励。PT100 阻值小、灵敏度高,但引线电阻影响大;PT1000 阻值大、功耗低,引线电阻影响相对小。我的经验是:如果测量距离超过三米,优先用 PT1000,或者用三线制 PT100。
NTC 热敏电阻也可以用,但 NTC 的阻值随温度呈指数变化,ADC 的高线性度优势发挥不出来,而且 NTC 一致性较差,批量标定很麻烦。所以我只推荐在要求不高的风管温度测量里用 NTC,精度要求高的地方还是老老实实用 PT100。
热电偶是另一种思路,输出是毫伏级电压,需要用 PGA 放大。ADS122U04 的 PGA 增益范围大,支持热电偶没问题,但要注意冷端补偿——芯片内部有温度传感器,正好可以用来做冷端温度参考。
3.2 三线制 RTD 的引线电阻补偿原理
这是好多人忽略的重点。两线制接线最简单,但两根引线上的电阻会直接叠加到传感器电阻上。假设每根引线电阻 0.5Ω,PT100 在 0℃ 时本来 100Ω,你测出来变成 101Ω,对应温度误差就有大约 2.6℃,根本没法接受。
三线制接线和恒流源配合,理论上可以完美抵消引线电阻。原理很简单:让两个等大的激励电流分别流过传感器和其中一根引线,ADC 用差分输入测量传感器两端的电压,这样引线上的压降正好落在共模电压里,差分测量就抵消掉了。
ADS122U04 有两个 IDAC 电流源,在寄存器配置里分别把 IDAC1 和 IDAC2 接到不同的引脚,就能实现标准三线制接法。实际做硬件时,还要注意两根引线电阻尽量一致,不然补偿不彻底。
3.3 激励电流、增益和基准电阻的计算过程
这段我拿一个真实算例来讲。假设我测 PT100,使用三线制,激励电流设为 1mA。
在 0℃ 时,PT100 阻值 100Ω,两端压降:
100Ω × 1mA = 100mV
在 100℃ 时,PT100 阻值约 138.5Ω,压降约 138.5mV。
如果我选内部基准 2.048V,PGA 设为 8,那么满量程输入范围是:
2.048V ÷ 8 = 0.256V
这个范围刚好覆盖 0-100℃ 的传感器电压,而且留有一定余量。
但比例测量更推荐用外部基准电阻。外部基准电阻接在 REFP 和 REFN 之间,激励电流流过它产生参考电压。如果基准电阻 Rref 取 1.8kΩ,1mA 电流产生的参考电压:
Vref = 1mA × 1.8kΩ = 1.8V
此时再配合 PGA 增益 8,满量程 225mV,和传感器输出范围匹配得更好。关键是,激励电流如果从 1mA 漂到 1.05mA,传感器压降和参考电压会同比例变化,最终 ADC 码值几乎不变,这就是比例测量的精妙之处。
基准电阻的温漂直接影响测量结果,我建议选 ±0.1% 精度、温漂低于 ±25ppm/℃ 的薄膜电阻,贵一点但值得。
3.4 电源与布局注意
ADS122U04 内部有 LDO,电源脚建议加 1μF 和 0.1μF 去耦电容,靠近引脚放置。模拟输入脚附近不要走数字信号线,尤其是 UART 的 TX 线,否则高速跳变会耦合到 ADC 输入端,导致噪声恶化。
我有一块板子初期方案是四层板,ADC 周围故意挖空了铺铜,模拟部分和数字部分用单点连接。实测下来,有效位数比第一版两层板高了不少。如果你预算允许,四层板是温度采集产品的最低标准。
PIC32MX664F064L 的电源同样要重视,我习惯在 MCU 每个电源引脚旁边放 0.1μF 陶瓷电容,再加一颗 10μF 钽电容做总存储。UART 的 TX/RX 对加 10Ω 小电阻串联,可以减少边沿振铃。
4. 固件实现:驱动初始化、命令帧与数据处理
4.1 UART 驱动层:帧格式与字节流处理
ADS122U04 的 UART 命令帧结构我不逐个字节背了,因为每一版手册上都有说明,关键是理解它的通信流程。主机(PIC32)作为总线主设备,发送命令帧给 ADC,ADC 执行完命令后通过 UART 返回数据。实际编程时,我建了一个很简单的状态机来处理接收字节:
typedef enum { RX_IDLE, RX_HEADER, RX_DATA, RX_CRC } uart_rx_state_t; volatile uart_rx_state_t rx_state = RX_IDLE; volatile uint8_t rx_buf[8]; volatile uint8_t rx_index = 0; void UART4_RX_ISR(void) { uint8_t byte = U4RXREG; switch (rx_state) { case RX_IDLE: if (byte == FRAME_HEADER) { rx_buf[0] = byte; rx_index = 1; rx_state = RX_DATA; } break; case RX_DATA: rx_buf[rx_index++] = byte; if (rx_index >= 6) { rx_state = RX_CRC; } break; case RX_CRC: // 检查CRC,然后开始处理转换结果 process_frame(rx_buf); rx_state = RX_IDLE; break; } }接收状态机看着简单,但实际踩过一个坑:如果 ADC 返回的数据帧长度是固定的,一定要用帧头和长度双重判断,不要只依赖帧头。否则一旦遇到 0xFF、0x00 这样的数据,状态机容易错位,后面所有帧都解析错误。
4.2 ADC 初始化配置
ADS122U04 的寄存器配置思路和 ADS1220 类似,核心是设置输入多路复用器、PGA 增益、基准、IDAC 电流值和数据速率。我写了一个初始化函数作为模板:
void ads122u04_init(void) { uint8_t cmd = ADS122U04_CMD_WRITE_REG; // 设置通道:AIN0 = INP,AIN1 = INN,PGA 增益 8 write_register(REG0, MUX_PT100_3WIRE | PGA_GAIN_8); // 设置数据速率、连续转换模式 write_register(REG1, DR_20SPS | CONTINUOUS_CONVERSION); // 设置 IDAC 电流 1mA,内部基准 write_register(REG2, IDAC_1MA | REF_INT); // 设置 IDAC 输出引脚 write_register(REG3, IDAC_ROUTE_1); // 发送启动转换命令 send_command(ADS122U04_CMD_START); }这里有个容易犯的错:寄存器 0 里既包含通道选择,又包含增益设置,很多人改增益的时候不小心把通道也改了,结果转换出来的是另一个输入的信号。我强烈建议把每个寄存器的位域用宏定义拆好,写代码时按位或组合,不要直接填一个魔数。
数据速率也要想清楚。20SPS 时内部数字滤波器抑制 50Hz 工频干扰的效果最好,因为它的陷波点正好落在 50Hz 附近。如果你现场是 60Hz 电网,就选 20SPS 或 15SPS 里能对 60Hz 取整的那个档位。对 HVAC 来说,温度变化本来就慢,20SPS 完全够用。
4.3 温度换算:从原始码到摄氏度
ADC 返回的是 24 位二进制补码,不能直接拿来当温度用。我先把它转成有符号数,再换算成电压,再算电阻,最后查表得出温度。
int32_t raw = (int32_t)((buf[0] << 16) | (buf[1] << 8) | buf[2]); // 24 位有符号扩展 if (raw & 0x800000) { raw |= 0xFF000000; } double vref = 1.8; // 基准电阻上的电压 double pga = 8.0; double code_fs = 8388608.0; // 2^23 // 输入电压 double vin = raw * vref / (pga * code_fs); // 电流源值 double i = 0.001; // 减去引线电阻影响后,PT100 阻值 double r = vin / i; // 根据 PT100 分度表线性近似(0-100℃) double temp = (r - 100.0) / 0.385;线性近似只适合粗算,真要精确应该用 Callendar-Van Dusen 方程,或者直接存一张 -50℃ 到 200℃ 的查表数组。工业上更常见的做法是出厂前做两点校准,把增益误差和零点误差消掉,这时查表就够用了。
4.4 滤波与平均值处理
24 位 ADC 在 20SPS 下本身噪声已经很小,但现场偶尔会有随机干扰,比如压缩机启动瞬间的电流冲击。我习惯在 MCU 里做二级滤波:先做去极值平均,再做一阶低通滤波。
去极值平均的思路是连续采 5 个点,去掉最大和最小,剩下 3 个求平均。一阶低通则是:
filtered = filtered + alpha * (new_sample - filtered);alpha 取值 0.1 到 0.3 之间比较合适。太大会导致输出抖动,太小又滞后严重。对 HVAC 来说,几十毫秒的滞后完全不影响控制,所以我选 0.1,曲线平滑得跟 PID 输出一样。
5. 现场踩坑与调试实录
5.1 通信失败:波特率与帧同步问题
第一次上电调试,我遇到 UART 完全没反应。排查过程从示波器量波形开始,发现主机有数据输出,ADC 没有数据返回。查了半天,最后发现是波特率设置和 ADS122U04 在内部时钟下的配置不匹配。
ADS122U04 的 UART 波特率不是随便设置的,需要根据器件的内部时钟来分频。我在初始化时优先设置了 MCU 的 UART 波特率,却忽略了 ADC 侧对应的波特率配置。解决方法是先读一遍 ADC 的寄存器默认值,确认器件能正常通信,再去配置测量参数。项目里我专门加了一条“通信握手”逻辑:上电后先读设备 ID,读不到就自动重发三次并报警。这个逻辑后来在现场帮了大忙——有一次设备通电后没反应,就是这个报警告诉我们接线松了。
5.2 读数跳变:基准电阻与布局噪声
还有一次测试中,温度值稳定在 20℃ 一阵子后突然跳到 20.5℃ 再跳回来。数值不大,但足够让 PID 控制出现毛刺。我一开始怀疑是 UART 误码,后来一量基准电阻两端的电压,发现它居然跟着现场的变频器负载在波动。
原因是我把基准电阻放得离变压器太近,周围的交变磁场在电阻和走线上感应出了噪声。把基准电阻挪到 ADC 引脚旁边,走线缩短、环路面积减小之后,问题立刻消失。所以基准电阻的位置真的不能随意摆放,它和 ADC 输入同等重要。
5.3 上电异常:电流源与输入建立时间
另一个很奇怪的现象:上电后前几秒温度值偏大,然后慢慢掉到正常值。后来读手册才明白,IDAC 电流源启动后需要时间完成建立,而且输入引脚外面的滤波电容会有一个充电过程。如果程序中只是简单地上电、配置、读数据,第一帧数据必然不准。
我的解决办法是在初始化完成后,等 100ms 再开始读取,并且丢弃前 5 个采样点。这个“热身”逻辑在冷启动和热复位时都很管用。后来我还把它做成了一个软启动流程,面板上显示“预热中”,虽然只是几秒钟,但给人的感觉就很专业。
5.4 常见问题速查表
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 读数始终为 0x7FFFFF | 输入正端超量程 | 检查传感器是否断线、PGA 是否过大 |
| 读数始终为 0x800000 | 输入负端超量程 | 检查传感器接线是否反接、电流源是否流出 |
| 温度显示比实际高几度 | 引线电阻未补偿 | 改三线制,确认 IDAC 路由正确 |
| 温度在两端跳变 | 数字滤波不足或输入共模电压过高 | 增加 MCU 滤波、检查输入共模范围 |
| UART 返回值间歇性丢失 | 波特率微小偏差、帧不同步 | 降低波特率、增加帧头重同步机制 |
| 读数和万用表差很多 | 分度表选取错误 | PT100 和 PT1000 分不清,查传感器规格书 |
还有一个小技巧值得分享:现场调试时,我会用一个 100Ω 精密电阻临时替代 PT100 插到输入端,如果 ADC 读数折算出来是 0℃,说明整个链路从激励电流到 ADC 转换都是对的;再把电阻换成 138.5Ω,应该读到 100℃ 附近。这个“模拟体温计”测试法比任何调试软件都好用。
6. 一些设计上的扩展思路
如果只做单路温度采集,这个组合确实有点大材小用。但实际项目中我往往需要用一块主控板同时管理多路温度、湿度、压力、压缩机状态。这时候 PIC32MX664F064L 的多路 UART 优势就体现出来了。
我现在的做法是:把 ADS122U04 做成一个小模块,模块上自带 RS-485 收发器,用三根线(A、B、GND)和主控板相连。每块模块负责一个区域的温度采集,主控板通过不同的 UART 口或 Modbus 协议轮询所有模块。这样整个系统扩容非常方便,加一个探头就是加一个小模块,不需要改动主控板硬件。
如果未来要做电池供电的无线传感器,ADS122U04 的低功耗特性也支持断续采样模式,平时休眠,定时唤醒测一次温度再睡过去,PIC32 那边也可以对应进入低功耗模式。整个系统的平均功耗能压到微安级,这是很多工业无线测温节点非常看重的能力。
我这里再补一句:如果你担心长时间工作的零点漂移,建议在 ADC 输入端留一个通过继电器切换到校准电阻的位置。每次开机时自动校准一次,把当前 ADC 的零点存进 Flash。虽然 ADS122U04 本身温漂很小,但工程上“提前留好校准手段”永远比事后拆机补要省心。