搞工业现场的温度采集,尤其是 HVAC 冷站和暖通空调设备里的多点测控,我以前也是习惯用运放搭信号调理电路再进单片机自带的 ADC。直到前阵子做冷站控制项目改造,传感器有几十路 PT1000,还有一部分 K 型热电偶,控制器用的是 Microchip 的 PIC18F86K22,模拟采集方案最终换成了 TI 的 ADS122U04IPWR。这个组合看起来跨度挺大:24 位 Δ-Σ ADC 加一颗 80 引脚的 8 位单片机,很多同行第一反应是“8 位机是不是太老了”。我的回答一直是:在工业和 HVAC 现场,能用最简单可靠的方式把温度和通信做稳,就是好方案。
ADS122U04IPWR 这颗料本身就是冲着温度测量去的,内部集成了可编程增益放大器、两个可编程激励电流源、2.048V 低漂移基准,甚至还有一个芯片结温传感器用来做热电偶冷端补偿。和它配对之后,PIC18F86K22 不需要再承担任何模拟信号调理的脏活,只管通过 UART 接口配置 ADC、读结果,然后把所有精力放到线性化、PID 控制、Modbus 通信这些东西上。这篇文章就当一次项目复盘,从选型、硬件、固件到现场踩坑,把这套方案从头到尾拆开讲清楚。
1. 选型逻辑:温度 ADC 搭配高端 8 位单片机的价值所在
1.1 温度信号有多难采,先看微伏级的物理事实
很多人不理解为什么普通单片机的 ADC 测温度不够用,问题不是位数,而是信号幅度。
以 PT100 为例,0℃ 时电阻约 100Ω,温度每升高 1℃,电阻增加约 0.385Ω。如果用 1mA 激励电流,对应的电压变化只有 0.385mV/℃。如果想让系统分辨出 0.01℃,前端就需要能稳定分辨 3.85μV。
再看热电偶更夸张,K 型热电偶灵敏度大约 40μV/℃,J 型大约 52μV/℃,如果现场环境不好,几十微伏的噪声就能吃掉一大截精度。常规单片机的 12 位 ADC,参考电压按 3.3V 算,一个 LSB 是 0.8mV,对温度信号来说这个分辨率完全不够看。即便把前端运放增益拉高,运放自身的失调电压温漂、零点漂移又成了新问题。
ADS122U04IPWR 这类温度专用 ADC 解决的就是这个矛盾。24 位分辨率配合 PGA,以增益 32 为例,等效满量程只有 ±64mV,理论 LSB 大约是 7.6nV,完全覆盖温度传感器的信号基。当然实际有效位数受噪声限制,不可能真的到纳伏级,但做到 0.01℃ 级别的重复性和稳定性,比用“运放+普通 ADC”的离散方案靠谱得多。
1.2 ADS122U04IPWR 自带哪些“温度测量外挂”
这颗 ADC 最值得圈出来的几个资源,我列成了表格,做方案选型时可以直接对照:
| 内部资源 | 功能 | 对温度测量的意义 |
|---|---|---|
| 4 通道模拟输入 | 支持差分或单端输入 | 可接多路 PT100/PT1000、热电偶 |
| 可编程增益 PGA | 增益 1 到 128 | 热电偶这类微伏信号也能有效放大 |
| 两个 IDAC 电流源 | 0.25mA 到 1.5mA 可编程 | 给 RTD 提供激励,省掉外部恒流源 |
| 内部电压基准 | 2.048V,低漂移 | 结合比例测量消除基准温漂 |
| 内部温度传感器 | 测量芯片结温 | 配合热电偶做冷端补偿,省一个外部温度芯片 |
| 传感器断路检测 | Burn-out 电流源 | 现场排查断线非常有用 |
| UART 串行接口 | 命令/响应帧结构 | 比 SPI 少了时序约束,长线传输更稳 |
其中 UART 接口是选择 ADS122U04IPWR 而不是 ADS1220 或者 ADS122C04 的主要原因。SPI 接口在板内短距离没问题,但如果 ADC 板和控制器板是分开放置,中间隔着几十厘米甚至更长的排线,SPI 时钟线容易因为反射造成通信异常。UART 接口天生就是为跨板通信准备的,两根线就能解决问题,而且 PIC18 系列本身把 EUSART 外设做得很成熟,115200 波特率下几乎不用调时序。
1.3 PIC18F86K22 在这个系统里到底扮演什么角色
一颗 80 引脚的 8 位单片机,在今天看来好像有点“复古”,实际上 PIC18F86K22 的外设资源非常充裕:五个 EUSART、两个 SPI、两个 I2C、多个 16 位定时器、还有足够的 I/O 去控制继电器和读取面板按键。对于空调机组、冷冻站这类设备,控制逻辑并不需要跑到 GHz 级,更需要的是外设稳定、抗干扰强、工具链成熟。
ADS122U04IPWR 负责把物理温度变成数字量,PIC18F86K22 负责其余的批量工作:
- 通过 UART 与 ADS 通信,管理配置寄存器和转换结果;
- 对原始码做比例换算、查表、多项式拟合,得到工程单位温度值;
- 执行 PID 或者开关量控制逻辑;
- 通过另一个 UART 挂载 RS-485 收发器,对外走 Modbus 协议;
- 驱动显示面板、蜂鸣器、故障指示灯,处理看门狗和上电自检。
如果把温度采集也塞给单片机裸跑,模拟部分会占用大量开发时间,而且环境一变精度就崩。芯片 ADS 把模拟难题封装好,MCU 只做自己擅长的数字控制,这是成熟工业产品的典型分层思路。
2. 硬件搭建:从前端传感器到 PCB 布局的完整思路
2.1 ADS122U04IPWR 与 PIC18F86K22 的引脚级连接
先画接口连接思路。ADS122U04IPWR 的串行接口是 UART 电平,TXD、RXD 直接和 PIC18F86K22 的 EUSART1 对应交叉连接。数据就绪引脚 DRDY 这种信号不一定每个项目都接,但我强烈建议接上,否则就要靠轮询或者固定延时去读数据,既浪费 CPU 又容易读到不完整的转换结果。
| ADS122U04IPWR 引脚 | 方向 | PIC18F86K22 接线 | 说明 |
|---|---|---|---|
| UART_TX | 输出 | 接 EUSART1 的 RX | ADC 回传数据和寄存器内容 |
| UART_RX | 输入 | 接 EUSART1 的 TX | MCU 发送命令 |
| DRDY | 输出 | 接 RB0 或任意外部中断引脚 | 下降沿表示新转换数据就绪 |
| RESET | 输入 | 接普通 I/O | 上电复位或软件复位 |
| AVDD/DVDD | 电源 | 统一 3.3V | 模拟/数字电源分开走线再汇合 |
| AVSS/DGND | 地 | 单点连接 | 避免数字电流污染模拟地 |
接 DRDY 的设计有一个实际好处:PIC18F86K22 的外部中断可以在数据准备好时立刻读取,不用去猜 ADC 到底转完没有。调试阶段如果你把 DRDY 悬空,后续几乎一定会碰到“偶发读到一个中间值”的灵异问题。
2.2 RTD 的比例测量接法
RTD 温度测量,我优先推荐比例法。原理不复杂:让同一个 IDAC 电流同时流过待测 RTD 和一个高精度参考电阻,RTD 上的电压送到 ADC 的模拟输入,参考电阻上的电压作为 ADC 的基准输入。
这样做的好处是,IDAC 电流的温漂、电源电压的波动,都会同时对 RTD 电压和参考电压产生影响,而 ADC 测量的是两者的比值,误差被天然抵消掉。这正是 ADS122U04IPWR 内部两个 IDAC 存在的意义。
强烈建议参考电阻选温漂系数低的金属箔电阻或精密薄膜电阻,阻值选 3.9kΩ 或者 4.02kΩ,精度 0.1% 起步,温漂 5ppm/℃ 以下。这个电阻的稳定性直接决定整个温度链路的最终精度,不能随便在普通电阻箱里抓一个。
四线制接线如图所示:IDAC1 电流从 RTD 的一端流入,从另一端流出回到 AVSS;测量线直接并接在 RTD 两端,采样回路没有电流流过,所以导线电阻不影响测量结果。如果是两线制,导线电阻会直接加进 RTD 阻值,长距离布线时误差会很可观,HVAC 现场能上四线就上四线。
2.3 热电偶输入的微伏级信号保护
热电偶输出的是微伏级直流信号,最怕的是外界干扰串入。工程上我习惯在 ADC 输入引脚和热电偶端子之间加两级处理:第一级是串联电阻限流,每根线上串 10Ω 到 100Ω,防止意外高压冲击烧毁芯片;第二级是滤波电容,差分位置放一个 100nF 的 C0G 电容,每根线与 AGND 之间再放一个 1nF 到 10nF 的电容,构成低通滤波器。
这里有一个容易忽略的点:热电偶是浮地信号,探头外壳有时会碰到金属管道,可能引入共模电压。如果现场接地系统比较复杂,最好在 ADC 输入前加 TVS 管,把共模电压钳位在安全范围内。我实测过一台变频器旁边的冷水机组,不加保护时热电阻读数能上下跳 0.3℃,加了差分电容和共模电容之后,波动基本回到了 ADC 本身的噪声底附近。
2.4 PCB 布局里的数字地和模拟地处理
ADS122U04IPWR 这种混合信号芯片,布局的核心思想是“不要把数字信号的回流电流赶到模拟回路里”。
我的做法是把板子分成明显的模拟区和数字区。ADS 芯片和它周围的去耦电容、参考电阻、传感器端子全部放在模拟区,PIC18F86K22、RS-485 收发器、电源模块放在数字区。两层板时,模拟地铺一个完整区域,数字地铺另一个区域,最后在电源输入端的公共点位置做单点连接。
别学那些把地平面整体一片铺完的做法,看起来漂亮,但是 PIC18F86K22 在大电流翻转 I/O 时产生的数字噪声会通过地平面直接灌进模拟区域,ADC 的有效分辨率立刻打折扣。另外,连接 ADS 模拟输入的前端走线尽量短而粗,传感器线不要和 220V 强电线路走同一个线槽,这在 HVAC 设备里尤其重要,因为现场线束往往非常密。
3. PIC18F86K22 侧固件:初始化、寄存器配置与数据解析
3.1 初始化 UART 与数字引脚
先说 PIC18F86K22 这一侧的初始化。我的项目里 EUSART1 用于和 ADS 通信,波特率选 115200,8 数据位、无校验、1 停止位。代码示意如下:
void uart1_init_115200(void) { TRISC6 = 0; // TX1 输出 TRISC7 = 1; // RX1 输入 BAUDCON1 = 0x08; // BRG16 使能 SPBRGH1 = 0; SPBRG1 = 34; // 64MHz 系统时钟下 115200 对应的 SPBRG 值 TXSTA1 = 0x24; // 使能发送,8 位数据 RCSTA1 = 0x90; // 使能接收,8 位数据 }GPIO 方面,DRDY 引脚配置为输入并打开内部上拉,用外部中断或者轮询都可以。我的建议是用事件驱动:数据就绪产生下降沿,在中断里置一个标志位,主循环看到标志再发起读取。这样不会因为 ADC 转换时间不定而阻塞主循环。
3.2 ADS122U04IPWR 寄存器配置思路
ADS122U04IPWR 与主机的交互是基于命令帧的,配置寄存器和读取数据都通过 UART 完成。寄存器组分成 REG0 到 REG3 四个主要配置字节,分别负责输入多路复用和增益、转换模式和数据速率、IDAC 与基准、以及传感器检测等选项。
我给出一个典型的 PT1000 场景配置流程:
void ads_rtd_init(void) { ads_write_reg(ADS_REG0, 0x16); // AIN0/AIN1 差分输入,PGA=32 ads_write_reg(ADS_REG1, 0x24); // 连续转换模式,数据速率 20SPS ads_write_reg(ADS_REG2, 0x10); // IDAC1=1mA,电流从 AIN0 输出 ads_write_reg(ADS_REG3, 0x50); // 使用内部基准,开启内部温度传感器 }其中的寄存器值,具体配置需要按产品数据手册中寄存器位定义的顺序进行编排,不同版本或不同测量模式会有变化。重点是思路:先把输入通路选好,再定增益,接着确定电流源大小和流向,最后选择基准源。顺序错了经常会出现“ADC 读数乱跳”或者“转换结果满量程”的假故障。
如果是热电偶应用,PGA 一般选 64 或者 128,数据速率可以适当提高。冷端补偿方案是把 ADS 芯片自身的结温传感器读出来,因为 ADS122U04IPWR 的芯片温度就是热电偶冷端温度,只要有精度要求,这个内部传感器能省掉一块外部 NTC 和对应标定。
3.3 读取转换结果并换算成温度值
转换后的数据是 24 位有符号整型,读取时按命令帧把四个字节收齐再拼装成 int32_t。示意代码如下:
int32_t ads_read_conversion(void) { uint8_t buf[4]; int32_t raw; ads_send_command(ADS_CMD_READ_DATA); // 发起读数命令 uart_receive_bytes(buf, 4); // 接收 4 字节结果 raw = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | buf[2]; // 24 位有符号数扩展 if (raw & 0x800000) raw |= 0xFF000000; return raw; }得到原始码之后,最重要的换算公式来了。因为我使用比例测量,RTD 电阻不是靠电压绝对值算的,而是靠 ADC 码值和参考电阻的比值算:
R_rtd = (raw / 0x7FFFFF) × R_ref
其中 0x7FFFFF 对应满量程编码,R_ref 就是那颗 3.9kΩ 精密电阻。算出电阻之后,再根据 PT1000 或者 PT100 的 ITS-90 标准表进行线性化查表,或者用 Callendar-Van Dusen 方程做多项式拟合,牛顿迭代几轮就能得到温度值,误差小于 0.01℃ 量级完全够用。
3.4 与主控制逻辑融合
拿到温度值之后,剩下的活就交给 PIC18F86K22 的控制程序了。我的做法是温度采集模块独立成一个文件,向上提供 get_temperature_channel(ch) 接口,向下只依赖 UART 接收状态。这样写 PID 控制逻辑时不需要关心 ADC 内部状态,调试时也能单独打印通道数据。
为了增强现场稳定性,I/O 处理里必须加看门狗。如果 ADS 长时间没有响应,或者 DRDY 中断长时间不触发,就让 MCU 重启并重新初始化 ADC。这类设备装到机房、屋顶、地下室之后,往往几个月都没人去碰,自动恢复能力比调试时的优雅更重要。
4. 校准与精度提升:把 24 位分辨率变成真精度
4.1 实验室标定的基本套路
ADS122U04IPWR 能做到很高的理论分辨率,但“分辨率”和“精度”是两回事。现场装机之前,我会在实验室里做一次完整的静态标定,标准设备用恒温油槽或者干体炉,配上级别足够的铂电阻温度计来读取真实温度。
标定流程不复杂:把待测通道接到标准铂电阻上,传感器放进恒温槽,从 -20℃ 到 120℃ 每隔 10℃ 取一个点,每个点稳定 10 分钟以上,记录 ADC 解算温度和标准铂电阻温度。最后做线性拟合并补偿偏移:
T_corrected = a × T_raw + b
a 和 b 通过最小二乘法算出。这个偏移主要来自参考电阻精度和传感器个体差异,不校正的话,哪怕 ADC 线性度再好,整体绝对误差也可能到 0.5℃ 以上。对 HVAC 控制来说,0.5℃ 可能勉强能接受,但如果是冷冻水出水和回水温差控制,0.5℃ 的误差会直接让机组能效计算失真。
4.2 热电偶冷端补偿的特殊处理
K 型热电偶测量的是热端和冷端的温度差,要把热端真实温度算出来,必须先知道冷端温度。ADS122U04IPWR 自带内部温度传感器,刚好可以让冷端补偿做在一块芯片内。
实际工程里有个细节:内部温度传感器测到的芯片结温,不一定等于热电偶接线端子的真实温度,因为芯片自身会发热,PCB 周围也有器件散热。如果对补偿精度有高要求,我建议把电路板上的热电偶端子靠近 ADS 芯片,并且让 MCU 周边电路尽量远离热电偶端子,减小热源干扰。同时,可以单独在接线端子旁边贴一颗高精度 NTC 做冷端温度参考,用两路温度取平均来减少热梯度误差。
HVAC 现场还有个常见问题:室外机组冬天可能夜间降到 -20℃,控制柜内如果没有加热器,PCB 温度会跟着骤降。ADS 芯片内部温度传感器虽然有标定,但快速温度变化时,热电偶端子和芯片之间可能出现动态温差,导致开机电热偶读数异常。这种场景下建议在上电后等待几分钟,等板内温度稳定后再启用热电偶补偿。
4.3 数字滤波与统计处理
即使模拟端做得再好,工业现场也不可能是无噪声环境。我常用的滤波策略是“中值滤波 + 一阶低通”,两级搭配:
- 中值滤波:连续采集 5 个数据,排序后取中间值,物理含义是丢掉那些突然的尖峰毛刺;
- 一阶低通:中值输出再过一个 IIR 滤波器,加权系数根据响应速度需求来定,比如 y = 0.7 × y_prev + 0.3 × x。
这样处理后,温度显示值的跳动量会明显收敛。代价是响应速度变慢,所以像回水温度这种需要快速报警的场景,我会把低通系数调大一些;而像水箱温度这种大惯性对象,则可以把系数调小一些,滤得更深。
有一点要提醒:滤波是放在 ADC 原始码之后、PID 控制器之前做的,不要只滤最终显示值。因为 PID 控制器内部用的温度如果带太多毛刺,积分项会被反复冲刷,导致阀门或压缩机的执行机构频繁动作。
5. 现场踩坑复盘:工业/HVAC 场景下必须注意的细节
5.1 激励电流过大引起的 RTD 自热
第一次硬件调试,我图省事把 IDAC 设成了 1.5mA,因为觉得电流越大信号越强、抗干扰越好。结果实测下来,PT1000 在 25℃ 水浴里读数会持续缓慢上升,等几分钟后稳定下来比真实温度高 0.2℃ 左右。
原因很简单,电流流过 RTD 会产生 I²R 热功率,把传感器自身烧热了。PT1000 在 1.5mA 下的自热功率大约 2.25mW,裸装热阻比较大的传感器足以造成明显温升。后来把激励电流降到 0.5mA,读数和标准温度计的偏差明显缩小,但同时噪声略有增加,解决方案是适当增加 PGA 和滤波深度。
所以 RTD 激励电流需要谨慎平衡:电流太小信噪比不足,电流太大自热严重。我的推荐起点是 PT100 用 1mA,PT1000 用 0.5mA,遇到封装比较大的传感器再往下调。
5.2 共模干扰让有效位掉了不少
项目第二阶段,把样板装进冷站控制柜做测试。柜里同时有变频器、接触器、电磁阀,一动作温度读数就周期性跳动。最初以为是电源不稳,后来用示波器看 ADS 输入引脚波形,发现是几十伏的共模尖峰从传感器长线耦合进来。
排查思路做了三件事:
- 确认传感器屏蔽层单端接地,不能两端接地形成环路;
- 在 ADC 输入和传感器端子之间增加共模短截滤波电容;
- 把 PCB 的模拟地和现场线槽的接地参考点理清,避免地电位差直接加在传感器回路上。
处理后同样工况下再测,温度跳动从 0.3℃ 降到 0.02℃ 以内。这类问题在实验室很难复现,只有设备真正靠近动力线时才会暴露,所以设计前期就应该预留好滤波电容位置和屏蔽层接地柱。
5.3 UART 通信“偶发乱码”的真相
第三个坑出在通信链路。系统长时间跑下来,偶尔会出现某个通道温度突然跳到几百度,然后下一次转换又恢复正常。查了很久才发现问题不在 ADS 硬件,而在命令帧处理:UART 通信偶尔会有字节丢失或者错位,如果固件没有做帧同步判断,就会把残留的旧数据当成新数据组装。
解决方法是完善帧协议和超时处理:
- 每个命令帧增加固定帧头和 CRC 校验;
- 接收数据时先找字节边界,当接收长度和校验值不一致时,丢弃整个帧并要求重发;
- 用定时器做超时判断,DRDY 标志置位后超过 10ms 还没有收到完整数据,就主动复位 UART 并重新初始化 ADS。
这个改动看起来小,但对长期运行稳定性影响巨大。 HVAC 设备往往要求全年无休地运行,任何偶发性毛刺只要没有自动恢复机制,最终都会变成凌晨三点被电话叫醒的售后事故。
5.4 关于系统上电顺序和掉电保护
最后补一个容易被忽视的上电顺序问题。ADS122U04IPWR 和 PIC18F86K22 共用 3.3V 电源,如果系统断电瞬间 MCU 闪存还在写参数,而 ADC 已经掉电,复位之后配置寄存器可能处于不可预知的状态。我后来在固件里加了一个标志量,每次上电都强制重新配置 ADS,不做“沿用上次配置”的假设。
另外,如果要支持热插拔传感器,建议开启烧毁电流检测或者定期检查通道是否断线,现场维护人员经常拔错线,一次误接可能把模拟输入口打坏。加一级 TVS 保护、加一个自恢复保险丝,成本很低,但能省掉大量返修成本。
这套方案跑到现在,机组冷热水温控制精度稳定在 ±0.1℃ 以内,几十个通道的长期漂移也在可控范围。如果在项目里遇到类似需求,不妨也试着把 ADS122U04IPWR 和 PIC18F86K22 组合起来,先把模拟前端的问题交给专用芯片,再让单片机专注做它擅长的控制逻辑。最后想提醒的是,数据手册上的寄存器位定义一定要对着具体型号的最新版本反复核对,哪怕只漏掉一个 IDAC 路由配置位,现场调试也可能花掉你足足一下午。