ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于ADS122U04与PIC18F85K90的HVAC高精度温度采集方案

基于ADS122U04与PIC18F85K90的HVAC高精度温度采集方案

做 HVAC 控制柜联调那阵子,最烦的不是通讯,是温度读数飘。风管里一路 PT100,读数一会儿 24.8,一会儿 25.3,节能逻辑靠这个温度去变频调速,结果压缩机和风机来回打架。后来我把温度采集从单片机片上 ADC 换成ADS122U04IPWR 加 PIC18F85K90的组合,现场才算稳住。这套方案核心是“高精度独立 ADC + 自带段码 LCD 驱动的 8 位 MCU”,非常契合工业和 HVAC 应用中的温度测量。这篇文章把这个方案从芯片原理、硬件连接、固件换算到现场调试的完整流程捋一遍,想走通温度采集这条路的可以参考。

1. 为什么温度采集不直接用单片机内置 ADC

1.1 PIC18F85K90 片上 12 位 ADC 的实际精度账

很多工程师第一反应是:PIC18F85K90 这种 80 脚大芯片上自带 ADC,够用了吧?但你把账算完之后就会明白,12 位 ADC 做温度前端是非常勉强的。

假设系统使用 5V 参考电压,12 位 ADC 的量化台阶是:

LSB = 5V / 4096 ≈ 1.22 mV

PT100 在 0°C 时电阻是 100Ω,温度系数大约 0.385Ω/°C。如果用 1mA 恒流源激励,温度变化 1°C 产生的电压变化只有:

dV/dT = 0.385Ω/°C × 1mA = 0.385 mV/°C

也就是说,片上 12 位 ADC 的一个 LSB 对应的温度约为3.2°C。就算你采 16 次平均,理想情况下有效位数增加 2 位,等效分辨率也才大约 0.8°C。HVAC 的节能控制通常要求温度稳定在 ±0.2~0.5°C,这种精度显然是撑不起来的。

更麻烦的是,片上 ADC 的参考源通常是电源轨或内部参考,温漂和噪声都不小。PIC18F85K90 的内核、LCD 驱动、UART 都在同一颗芯片里,数字噪声很容易窜进模拟测量的结果中。就算你买的是 24 位外部 ADC,如果在布局上处理不好,效果也会大打折扣,这是后话。

1.2 UART 接口 ADC 比 SPI 更适合工业传感器

那为什么选ADS122U04IPWR,而不是更常见的 SPI 接口 24 位 ADC,比如 ADS1220?

很直接的原因:工业现场传感器和主控板之间往往有几十厘米到十几米的距离。SPI 的四根线(SCLK、MISO、MOSI、CS)时序要求高,线一长波形就圆润了,抗干扰能力很差。而 UART 从本质上是异步串行,容忍时钟相位差异,只需要两根数据线,还能很方便地通过 RS-485 变成差分信号做长距离传输。

ADS122U04 是一颗带 UART 接口的 24 位 ΔΣ(delta-sigma)ADC,它的数据输出直接走标准 UART 帧。主控端用 PIC18F85K90 的硬件 UART 就能读取转换结果,不需要软件模拟时序。PIC18F85K90 这颗 MCU 本身有多个 UART,片上还带了最高 192 段的段码 LCD 驱动,正好把温度显示面板一起解决。这是当初选它的一个重要理由:一颗 MCU 既干通信,又干显示,前端精度交给独立 ADC。

2. ADS122U04 这颗 24 位 ADC 为温度传感器设计了什么

2.1 双 IDAC 电流源与外部基准电阻:比例式测量的基础

ADS122U04 内部有两个匹配的激励电流源(IDAC),这是它为温度测量准备的最有价值的资源。RTD 测量不能没有恒流源,而恒流源的绝对精度和温漂直接决定了电阻测量的精度。如果用一个普通运放搭恒流源,电流精度能到 0.5% 已经算不错,这意味着 RTD 电阻测量误差可能接近 0.5%,对应 PT100 大约 1.3°C 的误差,这在工业温度测量里很难接受。

ADS122U04 的做法很聪明:两个 IDAC 电流源高度匹配,而且可以分别路由到不同的模拟输入引脚。测量 RTD 时,让 IDAC1 的电流流过 PT100,同时让 IDAC2 或者同一路电流流过一只精密基准电阻 R_REF。这个 R_REF 电压接到 ADC 的外部参考引脚 REFP/REFN。转换结果是输入电压和参考电压的比值:

电阻值 R_rtd = code × R_REF / (2^23 × G)

其中 G 是 PGA 增益,code 是 ADC 输出的 24 位二进制补码。这个公式里完全没有激励电流的参数,因为电流同时流过 RTD 和参考电阻,电流的绝对精度被抵消了。R_REF 的温度系数就成了整个测量链路里最关键的指标,所以选 R_REF 时必须用低温漂电阻,后面我会专门讲。

内部还有一个 2.048V 基准,适合不需要极高精度的场合,比如热电偶冷端补偿用的环境温度测量。但在 RTD 高精度测量中,我更建议用外部基准模式,走比例式测量,把激励电流的漂移彻底消掉。

2.2 热电偶模式与冷端补偿

热电偶信号比 RTD 小得多。K 型热电偶在室温附近灵敏度大约 41µV/°C,如果直接进 24 位 ADC 的 1 倍增益,分辨率虽然够,但前端噪声和失调也会被读进结果里。ADS122U04 片内有一级可编程增益放大器(PGA),增益从 1 到 128 可调,这正是为热电偶小信号准备的。

测量热电偶时,PGA 增益的选择要按你的量程来。比如 HVAC 压缩机排气温度最高 180°C,K 型热电势大约 7.3mV,如果外部参考电压是 1V,增益选 64,满量程是 1V / 64 ≈ 15.6mV,覆盖 380°C 的量程,余量合理。如果盲选 128 增益,满量程只有 7.8mV,稍微超温就会削波,数据直接飞掉。

热电偶还有一个冷端补偿问题。ADS122U04 内部集成了一个温度传感器,可以读取芯片自身温度,进而算出冷端温度,再折算成热电势。如果你的冷端温度稳定性要求高,也可以外接 PT1000 或者 NTC 放到端子排上,测量更接近实际的冷端温度。在 HVAC 面板这种环境温度变化不大的场合,内部传感器基本够用。

2.3 数据速率与数字滤波:20SPS 不是慢,是聪明

ADS122U04 的转换速率从 20SPS 到 1000SPS 可选,还有一档 FIR 滤波器。很多人一看 20SPS 觉得太慢,但在工业温度测量里,这恰恰是最有用的档位。

20SPS 意味着一次转换窗口是 50ms,这个时间长度正好对 50Hz 工频干扰形成整周期积分,对 60Hz 也有很强的抑制。温度对象本身是慢变量,风管里的气温十几秒才变化 0.1°C,20SPS 的采样率完全够用,还能带来更高的有效分辨率。我做 HVAC 时序控制时,喜欢把 ADC 配成 20SPS + FIR 滤波,读出来的码值非常干净,基本不需要再叠软件滤波。

如果用在电机绕组温度监测这类需要快速响应的场景,可以提升到 90SPS 或 175SPS,噪声会增加一些,但响应时间更短。这个折中需要根据实际控制周期来定,没有绝对标准。

3. 硬件电路搭建:从传感器到 PIC18F85K90 的完整链路

3.1 三线制 PT100 前端设计

RTD 最常见的是三线制接法,它能在成本可接受的前提下抵消导线电阻。HVAC 现场的风管温度探头导线通常有几米,两线制接法会把导线电阻直接算进 RTD 电阻里,导致指示偏高。三线制的原理是:电流从一根线过去,再从另外两根线回来,其中一根线承担激励电流,另外两根线分别接到差分输入 AINP 和 AINN,ADC 读到的电压差就是 RTD 两端电压加上两路线阻的差值,只要两路线阻接近,误差就能被消掉。

具体连接上,我习惯这样安排:

  • IDAC1 电流设为 500µA,路由到 AIN2,再接 PT100 的红色激励线。
  • PT100 另外两根线分别接 AIN0 和 AIN1,也就是 ADC 的差分输入。
  • IDAC2 同样 500µA,流经 R_REF(取 2000Ω),R_REF 电压接 REFP/REFN。
  • 所有电流最终在 AGND 汇合。

R_REF 的选择有一个约束:IDAC 电流乘 R_REF 的压降不能超过 ADC 允许的外部参考范围。600µA 以下电流配合 2kΩ 电阻,参考电压约 1V,离内部 2.048V 还有余量,也低于模拟供电轨,很稳妥。

增益我一般选 8。这样满量程输入大约是 125mV,而 PT100 在 -40°C 到 150°C 范围内的信号只有约 44mV 到 65mV,PGA 输出在 0.35V 到 0.52V,接近满幅 1V 的中间区域,既不会饱和,又保持了足够的分辨率。

3.2 热电偶接入与冷端处理

热电偶输入是差分的,直接把热电偶正极接 AIN0,负极接 AIN1 就可以。注意热电偶属于低阻抗小信号源,输入端要加 RC 滤波,典型值 100Ω 串阻加 100nF 对地电容,既抑制射频干扰,又不至于让信号衰减太多。

冷端处理我分两种情况。如果热电偶端子就在 PCB 上、离 ADC 很近,直接用 ADS122U04 内部温度传感器算冷端补偿,最省事。如果热电偶通过延长线接到端子排,冷端实际在端子排上,那就需要在端子排附近放一个 PT1000 或 NTC,采集真正的冷端温度。HVAC 控制柜里这两种情况都会遇到,我的建议是设计时预留一个 NTC 接口,调试现场灵活切换。

3.3 UART 电平、复位与 PCB 布局

ADS122U04 的数字接口电压由其 DVDD 决定。如果 PIC18F85K90 工作在 5V,而 ADC 的 DVDD 用 3.3V,两者 UART 直连时最好加电平匹配,至少 MCU 的 TX 到 ADC RX 之间要加电阻分压,防止 5V 高电平灌进 3.3V 器件。更稳妥的做法是让 ADC 的 DVDD 和 MCU 同电压,省去转换电路。

复位和就绪脚不要省。RESET 引脚接到 MCU 的普通 IO,上电后由固件主动复位一次,确保 ADC 处于已知状态。DRDY 引脚接 MCU 的外部中断输入,转换完成会产生一个下降沿,这样固件不需要轮询 UART 数据,减少 CPU 占用。

PCB 布局上,ADC 的模拟部分要远离 MCU 的数字 IO 和 LCD 驱动走线。R_REF 必须紧贴 REFP/REFN 引脚,走线越短越好。AGND 和 DGND 在 ADC 下方单点汇合,整板再通过磁珠或者 0Ω 电阻连接模拟地和数字地。传感器进来的屏蔽线,屏蔽层只在控制柜端子侧单端接地,不要在 PCB 上再接地,否则会形成地环路,引入共模电流。

4. 固件实现:与 ADS122U04 的通信和温度换算

4.1 芯片初始化与寄存器配置要点

ADS122U04 的 UART 通信遵循命令帧方式,主控先发命令字节,芯片再响应。不同版本的寄存器映射可能有差异,我强烈建议大家写代码前把官方数据手册的命令表打印出来对照一遍,尤其是地址字节位和校验位。初始化流程一般是:复位 → 等待 DRDY 稳定 → 写配置寄存器 → 启动转换。

下面是一个典型的 RTD 三线制配置框架,用 C 伪码表示:

// 配置 PT100 三线制测量 // REG0: 输入 MUX = AINP=AIN0, AINN=AIN1; PGA 增益 = 8 // REG1: 数据速率 = 20SPS, 单次转换模式 // REG2: IDAC 电流 = 500uA; IDAC1 -> AIN2; IDAC2 -> AIN3 // REG3: 选择外部参考 REFP0/REFN0 static uint8_t regs[4] = { (0 << 6) | (4 << 3) | (0 << 0), // REG0: 增益8, MUX AIN0/AIN1 (0 << 3) | (0 << 0), // REG1: 20SPS, 单次模式 (1 << 5) | (2 << 2), // REG2: IDAC=500uA, IDAC1->AIN2, IDAC2->AIN3 (0 << 0) // REG3: 外部参考 }; uart_write(CMD_RESET); // 0x06 delay_ms(10); uart_write(CMD_WREG | 0x00); // 写寄存器 uart_write(0x03); // 写 4 个寄存器 uart_write(regs[0]); uart_write(regs[1]); uart_write(regs[2]); uart_write(regs[3]); uart_write(CMD_START); // 启动转换

每个芯片的具体寄存器位可能因为硅片版本不同有差异,比如参考源选择位和 IDAC 路由位,所以代码里我通常留一个adc_read_reg的调试函数,上电后先把配置读回来核对一遍。不要盲目信任第一次写的寄存器内容,工业产品最怕“明明没写进去,结果却跑得像是写进去了”。

4.2 RTD 数据的比例换算与线性化

读取转换结果时,ADS122U04 返回 3 个字节,也就是 24 位有符号数据。PIC18F85K90 是 8 位 MCU,拼完 3 个字节之后一定记得做符号扩展,否则 0xFFFFFF 会被当成 16777215,而不是 -1。

比例换算可以直接套我前面给的公式:

#define R_REF 2000.0f #define PGA_GAIN 8.0f float pt100_resistance(int32_t code) { return ((float)code * R_REF) / (8388608.0f * PGA_GAIN); }

为什么要除以 2^23 而不是 2^24?因为ΔΣ ADC 的输出是双极性二进制补码,正满量程是 0x7FFFFF,接近 2^23 - 1,对应 +Vref;负满量程是 0x800000,对应 -Vref。所以归算到满量程的系数是 2^23。

拿到电阻值之后,再用查表或者 Callendar-van Dusen 方程换算温度。在 0°C 以上,PT100 的拟合方程是:

R(t) = R0 × (1 + A×t + B×t²)

其中 R0 = 100Ω,A = 3.9083e-3,B = -5.775e-7。0°C 以下还要加上 C 项。我把牛顿迭代直接写在固件里,MCU 的 Flash 空间完全够用:

float pt100_temperature(float r) { float t = 100.0f; for (int i = 0; i < 8; i++) { float rc = PT100_R0 * (1.0f + PT100_A * t + PT100_B * t * t); float dt_err = r - rc; float slope = PT100_R0 * (PT100_A + 2.0f * PT100_B * t); t += dt_err / slope; if (fabsf(dt_err) < 0.0001f) break; } return t; }

实际 HVAC 面板显示一位小数就够,但内部计算我保留到 0.001°C,这样报警和回差值判断不会因为舍入误差来回抖动。

4.3 热电偶数据的冷端补偿算法

热电偶的处理逻辑和 RTD 不一样,核心是:先把 ADC 读到的电压转换成热电势,再加上冷端对应的热电势,得到总的等效热电势,最后查分度表得到真实温度。

ADS122U04 内部温度传感器的数值也可以直接作为冷端温度。得到冷端温度 t_amb 后,用 K 型分度表反向查表得到冷端热电势 E_amb,然后:

E_total = E_meas + E_amb T = 查表(E_total)

我一般在 ROM 里放一张 K 型 -200°C 到 1370°C 的 ITS-90 分度表,步长 1°C 或 2°C,二分查找加线性插值。这样做的误差远小于用多项式拟合的截断误差,代码也直观。冷端补偿精度每差 1°C,最终温度就会差 1°C 左右,所以不要把冷端温度随便用整数算,至少保留一位小数。

5. 干扰、校准与故障诊断

5.1 变频器和继电器干扰怎么挡

HVAC 控制柜里最不缺的就是干扰源:变频器输出侧的高 du/dt、继电器通断产生的电弧、还有 485 通讯的串扰。ADS122U04 虽然是 24 位 ADC,但它不是魔法,前端该做的防护一点都不能省。

传感器进线到 ADC 输入之间,RC 滤波是必须的,100Ω 串阻加 100nF 对地电容是最低配置。如果你的现场变频器多,可以在传感器端和 ADC 端各加一级共模电感。TVS 管我建议选双向的,钳位电压按传感器电源电压的 1.5 到 2 倍选,防止静电打坏 ADC 输入。

电源入口用磁珠加 10µF 加 100nF 的组合,ADC 的 AVDD 和 DVDD 之间加一个小功率电感隔离。曾经有客户把模拟地和数字地在 PCB 上大面积连成一片,结果数字噪声直接灌进模拟地,20SPS 下的数据都还有 1°C 的跳动。改回单点接地之后,问题消失了。

UART 侧如果通讯距离超过 1 米,建议加光耦隔离,或者直接转成 RS-485。ADS122U04 的 UART 总线上支持挂多片,地址引脚可以配置芯片地址,这样一套主控可以接多路高精度温度采集,总线上每一帧带地址字节,互不干扰。这是 SPI 方案很难做到的。

5.2 现场校准:从单点到三点

24 位 ADC 的线性度通常很好,真正影响误差的是参考电阻精度、PGA 失调和增益误差。所以出厂前我一般做两步校准。

第一步是零点校准。把 ADC 的输入端短路,记录此时的码值,作为硬件失调值。这个值会影响低温端的读数。

第二步是增益校准。用一只 0.01% 精度的标准电阻替换 PT100 接入电路,记录 ADC 换算电阻值和标准电阻的偏差,得到增益系数。如果有条件,可以做三个点:0Ω、100Ω、200Ω,用最小二乘拟合一条校正曲线,校准系数存入 PIC18F85K90 的 EEPROM,上电时自动加载。

校准的时候要注意,整个测量链路需要足够长的时间充分热稳定。我曾经调试时刚换完标准电阻就校准,结果芯片自热导致 5 分钟后漂了 0.02°C,这种量级的误差就在校准点附近晃,让人非常头疼。校准完成后,把 R_REF 的选择也记录到固件非易失区,避免批次电阻差异造成系统性偏差。

5.3 断线检测与故障上报

工业现场探头断线是家常便饭,固件必须能识别并上报,而不是显示一个离谱温度让操作员困惑。

ADS122U04 内置了热电偶开路检测功能,内部会对输入施加一个检测偏置电流,开路时 ADC 读数会被拉向满量程。你可以在正常测量流程里周期性地读取该检测位,一旦置位,就在 LCD 上显示“E1”,同时在 485 总线报故障字。

RTD 断线时,激励电流没有回路,输入电压会异常偏高,超出正常量程。固件可以做上下限判断:RTD 电阻小于 80Ω 或者大于 500Ω 就认为是断线或短路。下限阈值要避开真正的低温量程,比如 -40°C 时 PT100 约 84.3Ω,所以下限我取 80Ω,留一点余量。这些阈值不要硬编码到主逻辑里,放配置文件,方便不同量程的机型复用。

6. 实测数据、踩坑记录与选型边界

6.1 一组实测稳定性和精度数据

这套方案我在 HVAC 新风机组上跑过一段时间,环境温度探头采用三线制 PT100,ADC 配置为 20SPS + 外部基准比例模式。连续运行 24 小时,同一位置的温度读数波动范围约 ±0.03°C,对比 0.2 级数显表,最大偏差在 0.1°C 以内。压缩机吸气端用 K 型热电偶,增益 64,读数波动约 0.1°C,完全满足控制要求。

有一个细节值得提:我一开始用两线制 PT100 做测试,导线总长 3 米,读数偏高约 0.8°C,这就是导线电阻直接进了测量回路。改成三线制之后,剩余误差小于 0.1°C。如果你的探头线超过 5 米,可以考虑四线制,虽然多一根线,精度几乎不受线阻影响。

6.2 踩过的几个坑

第一个坑是自热误差。PT100 本身是电阻,通电流就会发热。1mA 激励电流在 100Ω 上产生 0.1mW 功耗,对应 PT100 可能有 0.1°C 自热,在风管里因为有气流散热还好,装在密闭套管里误差就很明显。后来我把激励电流降到 500µA,自热降了一半,读数更稳了。能用 250µA 的地方尽量用 250µA,前提是信号幅度还够 PGA 发挥。

第二个坑是 R_REF 温漂。第一次打样用了 50ppm 温漂的贴片电阻,开机半小时内温度读数自己漂了 0.2°C。换成功率型低温漂电阻后,读数才真正稳定下来。记住:在比例式测量里,R_REF 的温度系数就是这台仪器的温度系数,其他所有高精度元件都是给 R_REF 打工的。

第三个坑是 24 位数据符号扩展。PIC18F85K90 拼数据时如果直接int32_t raw = (b0 << 16) | (b1 << 8) | b2;,当 b0 大于等于 0x80 时,raw 会变成正值而不是负值,整个低温端温度公式全乱掉。必须先判断符号位再扩展:

int32_t raw; raw = (int32_t)((b0 << 16) | (b1 << 8) | b2); if (b0 & 0x80) raw -= (1 << 24);

还有复位时序。ADS122U04 上电后如果立刻写寄存器,寄存器内容不会被正确写入,后续启动转换得到的数据全是 0 或乱码。必须在复位后等 DRDY 出现过一次有效边沿,再发配置命令。把这个等待加进初始化代码,能省去大量现场排查时间。

6.3 什么场景不适合这个方案

这套组合并不是万能的。如果产品是消费级大批量、精度要求 0.5°C 就够、成本极其敏感,那么 24 位 ADC 加 80 脚 MCU 的 BOM 成本会显得偏高,还不如用一颗带内部基准的专用数字温度传感器。如果传感器和主控距离非常近、设备外壳已经做了很好的屏蔽,SPI 接口的 ADS1220 也能胜任,代码更直接,不必为了 UART 特性额外付出成本。

但在工业 HVAC、冷冻冷藏、热泵和机房监控这些场景里,温度传感器分散在现场各个角落,主控相对集中,而且还需要在面板上显示多路温度,这套“ADS122U04IPWR 负责前端模拟、PIC18F85K90 负责通信和显示”的分工,是一个结构清晰、可维护性很好的方案。我个人的体会是:温度测量项目里,真正决定精度的不是 ADC 位数,而是激励源、参考源和传感器连接方式这三个环节有没有被系统性地想清楚。只要你把比例式测量和三线制接线这两个基本功做扎实,即使是 24 位 ADC 配一颗纯 8 位 MCU,也完全可以做出让客户满意的工业测温表。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进