做工业测温这个方向的朋友,应该都遇到过同一个纠结:传感器信号小、现场干扰大、传输距离长,到底用什么方案才能既保证精度又不把成本抬上天。我这几年在工业和 HVAC 项目里折腾温度采集,最后固定下来一套组合——PIC18F87K22 做主控,ADS122U04IPWR 做前端采集,算是把这类需求理得比较顺了。ADS122U04 是 TI 的 24 位 Δ-Σ ADC,带 UART 接口,内部集成了 PGA、激励电流源和参考电压源,而 PIC18F87K22 是 Microchip 的 8 位单片机,外设丰富、抗干扰能力不错,两个配合起来做多路温度采集,很适合那种“精度要求高、实时性要求不高、布线环境复杂”的现场。
这篇文章就把这个方案的完整设计思路、硬件连接、固件流程和我在现场踩过的坑都写出来。不管你是刚接触 24 位 ADC,还是已经在做楼宇自控、机房环境监控、工业过程控制,这套东西都应该能给你一个可以直接落地的参考。
1. 整体设计思路:为什么偏偏是这两位搭档
1.1 ADS122U04IPWR 和 PIC18F87K22 到底是干什么的
ADS122U04IPWR 是 TI 推出的 24 位 Δ-Σ 型 ADC,TSSOP-16 封装。它最特别的地方不是“24 位”这个数字,而是通信接口用的是 UART,不是常见的 SPI 或 I2C。芯片内部还集成了可编程增益放大器(PGA,增益 1 到 128)、两个激励电流源 IDAC、一个内部温度传感器,以及一个 2.048V 的参考电压源。四路模拟输入可以配置成四路单端或者两路差分输入,激励电流源可以直接用来驱动 RTD 这类电阻型传感器,外围电路能省下不少。
PIC18F87K22 是 Microchip 的 8 位高性能 PIC,64 引脚,最高能跑到 64MHz,带两个 EUSART、多个 SPI/I2C 模块、5 个定时器、看门狗和足够多的 GPIO。选它而不是 16 位或者 ARM 内核的片子,主要是这类温度采集任务其实不需要跑复杂算法,8 位 MCU 完全能扛住,而且 PIC 的抗干扰设计和长期供货稳定性在工业圈里口碑一直不错。如果你手头熟悉别的 MCU,比如 STM32,那这套方案里的主控部分完全可以用你自己的板子替代,核心思路是一样的。
1.2 工业和 HVAC 的温度测量到底难在哪
工业现场和 HVAC 场景对温度测量的需求,看似不太一样,内核却高度相似。
先说 HVAC。楼宇自控、机房环境监控、空调机组回风温度这些场景,传感器可能分布在楼层的各个角落,线缆从几米到几十米很常见。温度变化极其缓慢,但需要长期稳定地监视,精度要求通常在 ±0.2°C 到 ±0.5°C 之间。现场还可能有变频器、电磁阀、水泵这类强干扰源,对微弱信号的采集是实打实的考验。
工业过程控制就更不用说了,测温点往往在高温、震动、电磁噪声复杂的区域,传感器线缆不得不和动力电缆并行敷设。有些场景需要测到几百度甚至上千度,或者要求分辨到 0.01°C 级别的微小变化。这些都是“慢信号、高精度、长距离、强干扰”的组合。
这几个关键词合在一起,就决定了对 ADC 的核心要求:分辨率高、噪声低、前端抗干扰能力强,同时还要方便长线传输数据。这时候 ADS122U04 那种 SPI ADC 就显得很有优势了——它的输出数据口就两根线,适合隔离,适合走远路。
1.3 对比 SPI/I2C,UART 接口的优势在哪
市面上的高精度 ADC 大多用 SPI 接口,比如 ADS124S08、ADS1262 这些。SPI 接口的好处是速率高、时序可控,但放到现场环境下问题也不小:至少四根信号线(SCK、MISO、MOSI、CS),走线越长,串扰和共模干扰越明显。隔离成本也高,每一根线都要配一个数字隔离器或者光耦,四根线乘起来,成本直接翻倍。
I2C 更不适合长距离,开漏结构加上线上电容,距离一长信号边沿就变缓,速率必须大幅度降下来,而且从机地址冲突、总线死锁这类问题也够烦的。
UART 不一样,天生就适合点对点远距离传输。两根线(TX、RX),接成 RS-232、RS-485,或者直接用光耦隔离,都很方便。光耦隔离只需隔离两个信号通道,成本几乎是 SPI 方案的一半甚至更低。ADS122U04 走 UART 接口,等于把这个优势直接送到了你我手上。它的通信速率最高支持到 115200bps,温度数据本来就是慢变量,这个速率对吞吐量的影响完全可以忽略。
有人会担心 UART 没有时钟线,主从之间波特率必须严格匹配,其实只要两边用同一个晶振基准,或者 MCU 端用精度足够的外部晶振,就不会出问题。后面固件部分我会专门讲这个细节。
2. 硬件设计:传感器、ADC 和单片机怎么连成一套系统
2.1 传感器选型与接线方式:RTD 和热电偶各有一套讲究
温度传感器这一层决定了整个系统的测量底线。HVAC 项目里 PT1000 用得最多,因为阻值大(0°C 时 1000Ω),引线电阻的影响被天然削弱,对导线材质要求没那么苛刻。工业现场则是 PT100 和 K 型热电偶的天下,PT100 的优点是线性好、互换精度高,热电偶则能覆盖几百度到上千度的量程。
ADS122U04 内部的 IDAC 电流源对 RTD 简直是为之量身定做的。接线方式有个关键点:三线制。
三线制 RTD 的原理是,用一根线给传感器供激励电流,用另外两根线分别检测传感器两端的电压。这样流过检测线的电流近似为零,导线电阻上的压降就不会进入测量回路。再配合 ADC 的差分输入,两根检测线的电阻即使不完全一致,影响也被控制在很小范围。四线制当然更准,但要多拉一根线,成本更高,现场如果不是特别苛刻,三线制已经够了。我之前在 HVAC 项目里全部用三线制 PT1000,配合 IDAC,实测下来根本不需要现场修正引线电阻,省了不少调试时间。
热电偶则要面对另一件事:信号电压极小,K 型热电偶大约每摄氏度只变化 40μV。必须把 PGA 增益拉高,比如 32 倍或 64 倍。同时必须做冷端补偿,也就是要知道热电偶冷端(连接端子处)的绝对温度。ADS122U04 内部自带温度传感器,可以直接读出来做冷端补偿,省掉一个外置 NTC 的接线和标定步骤。不过要注意,内部温度传感器反映的是芯片自身温度,不是真正的冷端温度。如果端子离芯片远,或者环境有热源,最好还是就近放一个外置传感器测冷端温度,这一点在工业现场很重要。
2.2 ADC 外围电路:电源、参考电压和保护滤波一个都不能少
24 位 ADC 这种器件,对电源噪声是出了名的敏感。如果直接在 DC-DC 模块后面供电,开关噪声的纹波会轻松淹没掉 μV 级别的信号。我的做法是:前级 DC-DC 输出后用低噪声 LDO 稳压,比如 LP5907 或者 LM317 之类的常规片子,再在 ADS122U04 的电源引脚旁边放 0.1μF 陶瓷电容和 10μF 钽电容组合,尽最大努力把电源纹波压下去。模拟地和数字地要在 ADC 芯片下方单点连接,不要让数字电流流回模拟地形成环路,这是高频 PCB 布线的基本纪律,但现场改版时最容易忽略。
参考电压决定了 ADC 的刻度基准。内部 2.048V 参考源用起来方便,温漂特性也还行,但对于工业级计量需求还是不够稳。如果精度指标要求高,我建议外接精密参考,比如 REF5025 这类温漂系数低的芯片。需要注意一点:在比例测量方案中,如果 Rref 电阻和 ADC 参考电压用的是同一个激励电流源,参考电压的绝对温漂会被抵消掉。这意味着外部参考的稳定性反而不如一个低温漂的精密电阻重要。这个细节很多人容易搞反。
输入保护也不能省。传感器线缆引到板子上,第一道防线是 ESD/TVS 管,防止雷击浪涌或静电打坏 ADC。之后是 RC 低通滤波,一阶 RC 再配合 Δ-Σ ADC 内部的数字滤波器,抗射频干扰和工频干扰的效果会明显好很多。RC 值不要随便选:R 太大会和 ADC 内部采样电容形成分压,产生建立误差;C 太大会让前端信号驱动能力不足。RTD 场景我常用 R=1kΩ、C=0.1μF,PGA 增益在 8 以下时工作得比较稳。
ADS122U04 的激励电流源 IDAC 设置也有说道。PT100 自热效应比较明显,电流太大会造成传感器自身发热,引起测量误差;电流太小又让信号电压过低,降低信噪比。综合考虑,PT100 我常用 500μA 或者 1mA,PT1000 用 100μA 到 250μA。这个值需要结合传感器手册的自热系数来选,还是那句话:不是越大越好,也不是越小越安全。
2.3 PIC18F87K22 的资源分配与整体系统架构
一块完整的温度采集板,除了 ADC 和 MCU,通常还要有通信接口、显示、按键、报警输出这些部分。PIC18F87K22 的资源在这种系统里是这样分配的:EUSART1 用来和 ADS122U04 通信,这是核心数据通路;EUSART2 留给上位机通信,HVAC 项目里基本都走 RS-485,接 Modbus RTU 协议;几个定时器分别做轮询调度、超时监控和看门狗喂狗;GPIO 控制继电器报警和本地指示灯。
单片机的工作频率我建议直接用外部晶振,而不是内部振荡器。原因很简单:UART 通信对波特率误差敏感,内部振荡器在全温度范围内的精度通常在 ±2% 到 ±5% 之间,到了工业现场环境温度一变化,波特率误差就可能超过 UART 的容错极限。外部晶振选 16MHz 或者 20MHz,再通过 PLL 倍频到 64MHz 或者直接用基础频率,波特率误差能控制在 ±0.5% 以内。这个细节看起来不起眼,但是通信不稳定的头号元凶,很多新人项目就栽在这里。
系统架构上,我习惯把 MCU 的职责分得很清楚:只管发送命令、接收数据、做换算、上报结果,不做过多复杂运算。多路传感器扫描时,MCU 轮流切换 ADC 通道,读取转换值,再在中断或者主循环里做滤波和线性化。整体跑下来,MCU 负载率很低,80% 的时间都在空闲待命,这对长时间稳定运行是很有利的。
3. 固件开发:寄存器配置、数据读取和温度换算的完整实现
3.1 ADS122U04 的 UART 命令协议和帧格式
ADS122U04 的通信协议非常简洁,命令就三类:读数据(RDATA)、读寄存器(RREG)、写寄存器(WREG)。所有命令都是 8 位命令字节开头,根据需要带后续参数。比如写寄存器命令,先发送命令字节 0x40 加上寄存器地址,再发送待写字节数减一,最后跟实际数据;读寄存器则是命令字节 0x20 加地址,然后直接读数据。RDATA 命令则需要先发命令字节,然后从 UART 接收转换结果。
有一点必须提醒:TI 的 UART 接口 ADC 在发送命令前,往往需要先发一个或者多个 0x00 字节来唤醒接口,具体看数据手册。我第一次调这个芯片时就因为没看这句话,直接发命令进去,结果毫无反应,排查了很久才发现是唤醒字节的问题。通信流程建议这样设计:上电后先延时等 ADC 稳定,发送唤醒序列,再发复位命令,然后配置寄存器,最后读取数据。
读回来的转换结果是 24 位有符号数,以二进制补码格式输出。写代码时要注意,MCU 的 UART 驱动要把接收字节拼成三字节的数组,然后按照最高位为符号位进行扩展。三字节拼接这样的操作在 8 位单片机上写起来很自然,用 int32_t 接收,边读取边移位,半天就能调通。
3.2 寄存器配置推算:增益、激励电流、数据速率和参考电压
ADS122U04 有四个配置寄存器,分别控制输入多路选择器和增益、转换模式和数据速率、参考电压和电流源、温度传感器以及 IDAC 输出分配。每次上电都要按顺序写一遍,这也是一个常见坑:芯片上电默认寄存器值不一定是你要的工作模式。
以 PT100 三线制测温为例,配置的推算过程是这样的。
激励电流选 500μA。参考电阻 Rref 选 2kΩ 低温漂精密电阻,那么参考电压就是 0.5mA × 2kΩ = 1V。PT100 在 0°C 时是 100Ω,信号电压是 0.5mA × 100Ω = 50mV;在 400°C 时约是 247Ω,信号电压约 123.5mV。PGA 增益选 4 倍,那么输入级看到的满量程电压范围是 ±1V / 4 = ±0.25V,123.5mV 留足了裕量。这样 24 位 ADC 的分辨率经过 PGA 放大后,温度分辨力可以达到 0.001°C 级别,实际噪声环境里有效分辨率 0.01°C 没太大问题。
这个计算过程可以写成公式:R_rtd = code_value / code_full_scale × Rref / PGA_gain_factor。其中 code_full_scale 和 PGA 增益的关系要参考具体 ADC 的转换公式,项目定型后在样板调试阶段用精密电阻箱做一个两点标定,把比例系数直接标出来,比纯理论推导更踏实。
数据速率方面,温度是慢变量,20SPS 到 100SPS 完全足够。重点要选对滤波模式。ADS122U04 正常滤波模式下对工频干扰有很强的抑制能力,50Hz 和 60Hz 及其整数倍频率上都有陷波。国内现场工频是 50Hz,把数据速率设为 20SPS 或者 50SPS,滤波效果最理想。不要为了追求“实时性”把速率调到 1000SPS,那会把工频干扰毫无保留地放进来,数据跳到你怀疑人生的那种。
3.3 多路通道扫描和 RTD 温度换算的代码实现
多路温度测量需要在不同模拟输入之间切换。切换后 ADC 内部 PGA 和采样电容需要重新建立稳定,前几个转换周期的数据必须丢弃。我在代码里的做法是:每次切换通道后,连续读三个样本,前两个丢弃,第三个才作为有效值。扫描周期和 ADC 数据速率要匹配,不要让 MCU 空转等待,而是用轮询 + 定时器触发的方式,确保每个通道的采样间隔是均匀的。
RTD 换算温度,最直接的办法是分段线性插值。把 PT100 分度表按一定间隔做成表格,代码里查表插值就能用。这个做法适合 HVAC 场景,代码量小,8 位单片机也跑得起。需要更高精度就用 Callendar-Van Dusen 方程,正温度区间用 R(t) = R0[1 + A·t + B·t²],负温度区间再乘上 C·(t-100)·t³ 修正。实际项目中我用的是分段线性表加双线性插值,在 -50°C 到 150°C 范围内,误差可以控制在 0.05°C 以内。这个精度对 HVAC 和大多数工业场景都够用了。
下面贴一段猎狐犬一般好用的分段线性插值框架,完整表格太长,大家按自己的传感器分度表填数据就行。
typedef struct { int16_t temp; // 温度,单位 0.01°C uint32_t res; // 电阻,单位 0.01Ω } rtd_table_t; const rtd_table_t pt100_table[] = { // {-20000, 1852}, {-10000, 6026}, {0, 10000}, ... // 这里只做示例,实际需要补全 }; float rtd_to_temp(float r_ohm) { uint8_t i; float ratio, result; for (i = 1; i < TABLE_SIZE; i++) { if (r_ohm <= (pt100_table[i].res / 100.0f)) { ratio = (r_ohm - pt100_table[i-1].res/100.0f) / (pt100_table[i].res/100.0f - pt100_table[i-1].res/100.0f); result = pt100_table[i-1].temp / 100.0f + ratio * (pt100_table[i].temp - pt100_table[i-1].temp) / 100.0f; return result; } } return 9999.0f; // 超出表格范围 }热电偶的处理思路和 RTD 完全不同:先把 ADC 测到的热电势减去或者加上冷端补偿电压,再查热电偶分度表反算出温度。ADS122U04 内部温度传感器读出来的温度,经过换算后和热电偶冷端的实际温度做比较,修正掉冷端误差。这一步如果做不好,热电偶测量误差会非常大,可能达到好几度。
固件里还有一个不能忘的环节:看门狗。工业现场的东西常年通电,MCU 跑飞了不能没人管。PIC18F87K22 的看门狗定时器一定要打开,并且定期喂狗。喂狗的位置要放在主循环的正常业务路径上,而不是放在中断里——放在中断里喂狗等于掩耳盗铃,程序主循环卡死在中断之外,看门狗照样不会复位。这个经验是我吃了两次亏换来的。
4. 实测数据、问题排查和避坑经验总结
4.1 实测数据的噪声表现和有效位数
24 位 ADC 听起来很大,但实际使用中真正能拿到的有效位数要打不少折扣。放大器噪声、参考源噪声、PCB 布局问题都会吃掉低位。我这套方案在正常工业环境下实测,PGA 增益 4、数据速率 20SPS 时,PT100 通道的峰峰值噪声大约等于 ±0.02°C,换算成 ADC 码值差不多是十几到几十个 LSB 的摆动,有效位数大概到 18 到 20 位。这个水平对于温度测量来说是够用的,但如果你在调试时看到数据低几位跳得像蹦极一样,先别着急骂芯片,检查一下电源纹波和参考电阻温漂,大概率能找到原因。
我把一次现场调试的抽测数据整理成了表格,方便大家直观感受:
| 通道 | 传感器类型 | 参考温度(°C) | ADC 原始码值 | 换算温度(°C) | 偏差(°C) |
|---|---|---|---|---|---|
| CH1 | PT1000 | 25.00 | 824100 | 24.98 | -0.02 |
| CH2 | PT1000 | 50.02 | 856200 | 50.05 | +0.03 |
| CH3 | PT100 | 85.15 | 774300 | 85.11 | -0.04 |
| CH4 | K 型热电偶 | 120.0 | 18760 | 120.3 | +0.3 |
热电偶通道的偏差主要来自冷端补偿精度,0.3°C 在热电偶应用里属于正常水平。RTD 通道的偏差主要来自分度表插值间隔和参考电阻精度,整体控制在 ±0.05°C 以内,对 HVAC 和大多数工业现场完全满足要求。
4.2 项目中最常见的六个问题与排查思路
这套系统调试过程中,零零散散的问题遇到过不少,我把高频问题整理成了一张速查表:
| 现象 | 可能原因 | 排查操作 |
|---|---|---|
| UART 完全无应答 | 唤醒序列未发送、TX/RX 接反、波特率误差过大、ADC 供电异常 | 检查 TX/RX 交叉连接,示波器看命令波形,核对波特率寄存器值,确认 AVDD/DVDD |
| 读数持续满量程或 0 | 输入 MUX 配置错误、RTD 开路/短路、IDAC 未使能、PGA 增益设置溢出 | 用万用表测传感器阻值,回读寄存器确认配置是否写入成功,检查传感器接线 |
| 读数跳变严重 | 电源纹波过大、工频干扰、数据速率过高、滤波模式不对 | 换低噪声 LDO,数据速率降到 50SPS 以下,选用正常滤波模式,确认 RC 滤波参数 |
| 所有通道读数整体偏高/偏低 | 参考电阻偏差、PGA 增益误差、传感器分度表不匹配 | 用精密电阻箱两点标定,修正比例系数,更换更高精度参考电阻 |
| 切换通道后第一个数据异常 | 建立时间不足、采样轮询时序不对 | 通道切换后丢弃前 2-3 个样本,等待至少 3 个转换周期 |
| 长时间运行后数据缓慢漂移 | 参考电阻温漂、传感器自热、PCB 温度升高 | 更换低温漂电阻(5ppm 以下),降低 IDAC 电流,改善板级散热 |
每一个问题我都亲自遇到过。比如“所有通道整体偏高”这个问题,折腾了一个下午,最后发现是手头那批参考电阻温度系数超标,从 25°C 升到 50°C 阻值就漂了接近 0.1%,直接带偏了整个测温链路。换了一批 10ppm 的电阻之后数据立刻老实了。
4.3 几个值得长期保留的设计习惯
PCB 布局上,ADC 的模拟输入信号线一定要和数字信号线隔开,最好包地。传感器线缆在端子处要固定好,不能受力松动,否则接触电阻的微小变化在 24 位 ADC 面前就是很大的读数跳变。每组模拟输入的 RC 滤波电容要用 C0G 或 X7R 材质,不要用 Y5V,不然容量随温度变化会引入非线性误差。
校准环节建议生产时做两点校准:零点用精密电阻箱模拟传感器在 0°C 的阻值,满点用模拟传感器在上限温度的阻值。把校准系数写进 EEPROM,每次上电加载。这个过程不要靠手工记数据,写一个小工具走 UART 自动校准最省事。
最后再分享一个项目扩展方向:这套硬件加了 RS-485 后,直接跑 Modbus RTU 协议就能接入楼宇自控系统。数据速率和协议栈都是现成的,MCU 资源也充裕,把四个温区、报警阈值、校准参数都映射到保持寄存器里,基本就是一个完整的工业温度采集终端了。我在实际项目里就是这么干的,从裸机测温到上位机远程监控,没有换 MCU 也没有改 PCB,硬件的生命周期被拉长了不少。要说这套方案最大的价值,大概就是它足够的朴素、皮实,在“够用”和“好用”之间找了个很舒服的平衡点。