ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

基于ADS122U04IPWR与PIC18F4685的高精度温度采集模块

基于ADS122U04IPWR与PIC18F4685的高精度温度采集模块

前阵子给一套冷水机组做改造,现场要测冷冻水供回水温度、风管送风温度,精度要求控制在±0.2℃以内,配电柜里的PLC模拟量通道已经全占满了,只剩一个RS-485口。正好手里有TI的ADS122U04IPWR和Microchip的PIC18F4685,就用这两个芯片搭了一个高精度温度采集模块。文章把这个项目从选型、硬件连接、软件配置到标定调试的完整过程记录下来,给正在做工业测温或者HVAC系统监控的朋友一个可以直接抄作业的参考。

这个方案的核心思路很简单:用ADS122U04IPWR做24位高精度模拟前端,负责把PT100、PT1000、NTC热敏电阻甚至热电偶的信号变成数字量,再通过UART送给PIC18F4685;PIC18F4685负责初始化ADC、读取转换结果、做温度线性化和冷端补偿,最后通过RS-485把温度值发给上位机或者PLC。这么做的好处是,整个模块不需要太多周边器件,一块不大的PCB就能搞定,而且24位ADC的分辨率足够应付大部分工业和暖通现场的测温需求。

1. 为什么选这套方案:从需求和选型说起

1.1 先看清楚工业和HVAC测温的差别

HVAC系统里最常见的温度测量点是风管送风温度、回风温度、冷冻水供回水温度、冷却水温度,温度范围通常不宽,大多在-20℃到85℃之间,但是对长期稳定性和漂移要求很高。冷冻水系统如果温度测不准,混水、水泵变频逻辑都会出问题,最后直接反映在能耗上。工业现场的情况更复杂,可能同时有管道温度、轴承温度、电机绕组温度、环境温度,传感器类型也更杂,两线制、三线制、四线制RTD都有。

两个场景的共同点是传感器线缆往往比较长,现场电磁干扰强,而且最终都要把温度值转换成数字量再送到控制器。普通单片机自带的10位或12位ADC,量化噪声和参考电压漂移都太大,在±0.2℃的精度要求面前基本不够用。所以外置高精度ADC是更合理的选择,这也是项目里引入ADS122U04IPWR的直接原因。

1.2 为什么放着SPI不用,专门挑UART接口的ADC

市面上24位ΔΣ ADC很多,绝大多数是SPI接口,比如ADS1220。SPI不是不能用,但在工业设备里SPI有三四个问题需要额外处理:引脚占用多,长线传输时SCK容易被干扰,主控和ADC之间的时序必须严格对上,否则偶发通信错帧很难排查。ADS122U04IPWR的特性是UART接口,只需要两根线,和PIC18F4685自带的EUSART模块直接对接,而且最终要接RS-485,所以从MCU出来经过一个485收发芯片就能上总线,整条链路非常顺。

ADS122U04IPWR本身集成了24位ΔΣ调制器、可编程增益放大器(PGA)、内部高精度参考电压、电流源激励,这些对温度测量都很关键。24位分辨率配合合适的PGA增益,理论上可以分辨零点几毫欧级别的电阻变化,对应到PT100上就是几毫摄氏度的分辨率,实际系统噪声会把这些优势吃掉一部分,但做到0.1℃级别的稳定读数没有问题。

1.3 PIC18F4685在这种项目里到底要干什么

PIC18F4685并不是什么高性能主控,工作频率不算高,Flash和RAM也不算大。但温度采集模块本质上不需要跑算法,不需要操作系统,不处理图形界面,它的任务就是稳定地跟ADC通信、做简单算术、再通过串口发数据。这个工作量用PIC18F4685绰绰有余。

选择PIC18F4685还有一个很实际的原因:老产品库存里有大量这个型号,工具链和底层驱动都是现成的。对于一个成熟的工程产品,有时候“稳定可靠、团队熟悉”比“性能参数漂亮”重要得多。如果从零选型,我会考虑PIC18F26K83或者PIC16F18857这类新一些的型号,但在这个项目里继续用PIC18F4685完全没有问题。

2. 硬件电路设计与连接细节

2.1 传感器输入通道和激励电流源怎么接

硬件上最需要认真对待的是RTD的接入方式。PT100和PT1000在工作时需要一个恒流源或者恒压源激励,靠测量电阻值来换算温度。如果直接用外部基准电压和普通运放,激励电流的变化会直接进入误差。正确做法是比例式测量:用一个低温漂精密参考电阻RREF和RTD串联,让同一个IDAC电流源同时流过这两个电阻,然后分别采样RTD和RREF上的电压,再把两个电压的比值乘以RREF得到RTD当前阻值。

这一步的设计非常关键。因为RTD阻值计算公式是RTD_R = RREF × ADC_RTD / ADC_RREF,所以激励电流源是否漂移、参考电压是否稳定,都会在分子分母里被约掉。这样就不需要特别高精度的外部基准,只需要RREF本身阻值精确且温度系数低。RREF我选了0.1%精度、25ppm/℃的金属箔电阻,阻值选PT100用100Ω、PT1000用1kΩ,这样测量范围的中间值附近分辨率最优。

三线制RTD在工业现场用得最多,因为两根导线电阻长度相等,可以用ADS122U04IPWR的两个可编程电流源IDAC1和IDAC2分别接到两根引线上,在ADC输入端测电压时,导线压降能基本抵消。实际接法要特别注意,电流源必须先流过RTD,再接输入通道,不能让激励电流先经过接触电阻再进入ADC采样,否则线阻会直接叠加进测量结果。

NTC热敏电阻的接法简单很多,一个固定分压电阻加一个输入通道就够了。但由于NTC阻值和温度的关系是非线性的,后期需要用Steinhart-Hart方程或者查表法处理。如果现场用热电偶,输入级要加共模和差模滤波,还要在模拟输入端并联一对背靠背二极管做钳位保护,防止热电偶线缆感应到浪涌电压打坏ADC。

2.2 UART接口连接与电平匹配

ADS122U04IPWR和PIC18F4685的接口电路不复杂,UART需要两根线:ADC的DOUT/DT接到单片机的一个接收脚,ADC的DIN/DRDY接到单片机的一个发送脚,另外还有一根可以用于复位或者同步信号。真正要注意的是电平匹配,ADS122U04IPWR的供电电压范围是2.3V到5.5V,PIC18F4685工作在5V,所以理论上可以把两个芯片都挂在同一个5V电源上,UART逻辑电平一致,不用做电平转换。

我这次为了减少电源种类,把数字部分统一用5V,模拟部分单独用LDO供电。如果读者用的是3.3V单片机,那就必须在UART线上做电平转换,最简单的做法是串电阻分压,或者加一颗双向电平转换芯片。千万别直接把5V信号灌进3.3V器件的IO口,长期使用容易损坏端口。

2.3 电源系统与PCB布局的几条硬规矩

整板电源是从24V工业电源进来的,先用DC-DC降到5.5V左右,再经过一颗低噪声LDO降到5V给模拟电路。数字5V和模拟5V之间用磁珠连接,模拟地和数字地单点相连,避免数字开关噪声通过地平面串进ADC。

ADS122U04IPWR这类高精度ΔΣ ADC对参考电压和电源去耦非常敏感。我在AVDD和DVDD引脚旁边都放了0.1µF陶瓷电容加10µF钽电容的组合,陶瓷电容尽量靠近引脚放置。外部参考电压使用内部参考,但参考引脚REF/NREF之间仍然并联了1µF电容和10nF电容,用来滤除内部参考的高频噪声。

RTD和RREF的走线要短而宽,输入通道附近不要走数字信号线,尤其是UART的TX/RX,如果实在避不开,就用地线隔开。这些细节在原理图上看不出差异,但装到现场后读数的稳定程度完全不一样。

3. 软件架构与核心代码实现

3.1 PIC18F4685的UART初始化

PIC18F4685自带的EUSART使用起来非常简单,配置几个寄存器就能跑UART。我这里以16MHz晶振、波特率9600为例,设置BRGH=1工作在16分频模式,SPBRG的计算公式是SPBRG = Fosc/(16×Baud) - 1,算下来是103,十六进制就是0x67。

void uart_init(void) { TRISCbits.TRISC6 = 0; // TX引脚输出 TRISCbits.TRISC7 = 1; // RX引脚输入 TXSTA = 0x24; // BRGH=1,8位数据,使能发送 RCSTA = 0x90; // 串口使能,连续接收使能 BAUDCON = 0x00; // 常规8位波特率模式 SPBRG = 0x67; // 9600 @ 16MHz SPBRGH = 0x00; }

这个初始化代码不复杂,但实际项目里要留意一个问题:PIC18F4685的UART发送是阻塞式的,如果发送的字符串太长,会占用单片机大量时间。由于ADC的转换数据不断产生,我建议在代码中把温度数据打包成定长帧再发送,不要频繁使用printf,否则很容易造成数据处理不及时。

3.2 ADS122U04IPWR的寄存器配置与命令交互

ADS122U04IPWR上电后,默认是休眠状态,需要先发RESET命令复位到已知状态,然后通过WREG命令配置寄存器。因为UART接口没有片选,每次命令都是MCU主动发起,ADC根据收到的字节流执行操作。下面的代码是示意性质,寄存器位定义不同版本可能略有差异,实际要对照数据手册逐位确认。

#define CMD_RESET 0x06 // 复位命令 #define CMD_RDATA 0x10 // 读取转换结果 #define CMD_WREG 0x40 // 写寄存器命令 #define CMD_START 0x08 // 启动转换 void ads122u04_init(void) { uint8_t cfg[4]; // 寄存器配置示意: // Reg0:输入多路复用器选AIN0/AIN1差分对 // Reg1:PGA增益和转换模式设置 // Reg2:数据速率和数字滤波设置 // Reg3:IDAC电流源和参考电压设置 cfg[0] = 0x00; cfg[1] = 0x28; cfg[2] = 0x08; cfg[3] = 0x12; ads122u04_write_regs(0x00, cfg, 4); // 从Reg0开始连续写4个寄存器 ads122u04_start(); }

寄存器配置的核心是通道选择、增益和电流源。温度测量使用差分输入,PGA增益不需要太高,因为RTD信号本身经过比例测量后,动态范围不大。增益设置过高会把传感器长线上的工频共模干扰也一起放大,所以第一版我设置为1倍增益,实测下来效果最好。数据速率我选了20SPS,这个速率能提供较好的50Hz/60Hz工频抑制比,对HVAC这种慢温度变化场景完全够用。

3.3 读取转换结果并做符号扩展

ADS122U04IPWR输出的是24位二进制补码,但单片机一次只能读一个字节,所以需要用RDATA命令连续读3个字节,然后拼成一个有符号整数。读取结果的代码片段如下:

int32_t ads122u04_read_code(void) { uint8_t raw[3]; int32_t code; ads122u04_byte(CMD_RDATA); raw[0] = ads122u04_byte(0xFF); raw[1] = ads122u04_byte(0xFF); raw[2] = ads122u04_byte(0xFF); code = ((int32_t)raw[0] << 16) | ((int32_t)raw[1] << 8) | ((int32_t)raw[2]); if (code & 0x800000) // 24位负数扩展成32位有符号数 code |= 0xFF000000; return code; }

这里的符号扩展很容易被忽略,如果忘记处理,温度计算出来的结果在负温区间会完全错误。另一个容易踩的坑是RDATA命令连续读取时,要保证在转换完成之后再去读,否则读到的是上一次的旧数据。我用PIC18F4685的一个IO口检测ADS122U04IPWR的DRDY信号,这个信号变低表示新数据准备好,再去读。如果MCU引脚不够,也可以靠延时去估算转换结束时间,但那个方法不推荐在现场使用。

3.4 从ADC码值到温度值的完整换算

比例法测量下,RTD阻值计算公式是:

R_rtd = RREF × code_rtd / code_ref

这个公式简单可靠。code_rtd是RTD两端电压对应的ADC码值,code_ref是参考电阻两端电压对应的ADC码值。我在软件里每次都先测量RREF的电压,再测量RTD的电压,然后相除。这样可以消除放大器和ADC本身的增益误差,长期稳定性非常好。

拿到RTD阻值后,温度换算我用的是查表加线性插值。把PT100或PT1000的标准分度表存成数组,在数组中二分查找阻值所在区间,然后按线性关系算出温度。这个方法比解方程快,而且分度表密度足够大时,插值误差远小于传感器本身的误差。

NTC部分我用的Steinhart-Hart方程,温度单位是开尔文:

1/T = A + B×ln(R) + C×(ln(R))^3

系数A、B、C要由厂家提供,或者自己用三个标准温度点拟合。HVAC里面NTC一般用于风管温度测量,精度要求不高,所以用25℃下的B值公式简化成两参数版本也可以接受。

4. 标定、实测与问题排查实录

4.1 使用精密电阻箱做一次完整标定

现场没有高精度温度源的时候,我用0.01%精度的电阻箱模拟PT100在不同温度下的阻值,直接验证整条ADC链路。把电阻箱接到模块的RTD输入端,分别设置几个关键温度点,记录ADC原始码和计算温度。下面是一组实测数据:

设定温度(℃)PT100理论电阻(Ω)计算温度(℃)误差(℃)
0100.000.03+0.03
20107.7919.98-0.02
50119.4050.02+0.02
100138.51100.04+0.04

这组数据没有做软件修正,误差主要来自RREF的初值和分度表插值。如果现场要求更高,可以在标定后给每个通道做一个两点或者多点校准曲线,把系统误差进一步压缩。标定过程有个注意点:电阻箱的残余电阻和接触电阻会直接进入测量链路,所以最好使用四线制接法连接电阻箱,或者接线后用万用表实测引出端的电阻值再计入。

4.2 干扰问题:变频器一启,读数就跳

模块在现场遇到最典型的问题是变频器刚启动时,温度读数会瞬间跳变几个数字,持续时间大约一两秒后又恢复正常。这个现象看起来是ADC不稳定,实际上是共模干扰把输入通道电位整体抬高了。

排查过程从三方面入手:先在ADC输入端对地测量交流电压,发现变频器启动时输入端有几十毫伏的50Hz到几kHz的噪声;再测UART通信波形,发现通信线也受到干扰,偶发错帧;最后检查布线,发现电缆屏蔽层在配电柜一端没有接地,等于白接。

解决办法是把RTD信号线换成屏蔽双绞线,屏蔽层在控制柜侧单端接地,入力信号在模块入口端子处并联一个100nF的共模滤波电容。软件上把ADC数据速率从100SPS降到20SPS,开启内部数字滤波器。处理完以后,变频器连续启停,读数都能稳定在0.05℃以内。这个经验说明,硬件抗干扰和软件滤波必须同时做,只靠一头很难根本解决问题。

4.3 常见问题速查表

项目调试和现场运行中遇到过的几类典型问题,整理成一个速查表,方便后来人直接对照:

现象可能原因解决办法
读到的ADC值是0xFFFFFF通道开路,或输入信号超过模拟供电范围检查传感器接线、端子虚接
UART返回乱码或偶尔无响应波特率不匹配、干扰导致错帧用示波器看UART波形,检查波特率设置
温度整体偏差固定参考电阻RREF精度不够或标定错误换0.1%精密电阻,重新标定
温度读数缓慢漂移传感器自热、参考电阻温漂降低IDAC电流,换低温漂电阻
变频器启动时读数跳变共模干扰、屏蔽层未接地加屏蔽接地和共模滤波,降低数据速率
连续运行几天后读数变大接线端子氧化、接触电阻变化改用镀金端子或压接处理

这个表看起来简单,但每一条背后都是我实际踩过的坑。尤其是端子氧化那种软故障,现场不拆线很难发现,最后是用手动红外测温枪逐点对温度才发现偏差来自接线电阻。

5. 从这个小模块延伸出的几个工程建议

5.1 多点测温时如何扩展

ADS122U04IPWR的输入通道数量有限,如果HVAC项目里需要同时测十几个点,最简单的办法是每个温度点配一个ADC,共享同一条RS-485总线。这看起来成本高,实际算下来比一大块多通道采集板更灵活,而且单点故障不会影响其他通道。也有同行用模拟开关切换多路RTD,共用同一个ADC,这样做节省了成本和PCB面积,但模拟开关的导通电阻和漏电流会引入新的误差,需要在硬件上做补偿。

我在另一套系统里做过类似的扩展方案:每个温度采集模块只负责四五个点,通过RS-485总线并联,上位机按地址轮询。这种架构维护起来非常方便,哪里坏了换哪里,不需要整条产线停机。

5.2 电源和通信隔离不要省

工业现场如果测温点距离控制柜比较远,建议在RS-485通信线上加隔离。我用的是带隔离的RS-485收发模块,隔离电压可以到2500Vrms,电源端用DCDC隔离模块。这一步不是为了提高精度,而是保护控制柜里的PLC和单片机,防止雷击浪涌从总线端口耦合进来。很多设备只在实验室里工作良好,一到现场就坏,问题往往就出在隔离被省掉了。

5.3 固件里预留参数校准接口

最后一条建议是给软件架构加一个在线校准通道。我在固件里保留了通过UART修改RREF标称值、NTC系数等参数的私有命令,这样现场调试时不需要重新烧录程序,直接用串口工具发一条指令就能修正系统误差。对生产维护来说,这个设计省下大量时间,也避免反复开箱刷固件带来的机械损坏风险。

项目做到这一步,我个人最深的体会是:高精度温度测量在原理上看似简单,实际落地的难点全在“系统误差”四个字里。ADS122U04IPWR和PIC18F4685的组合,把模拟前端和主控之间的通信做得非常直接,省掉了SPI时序的烦恼,但同样需要认真对待参考电阻、地平面、屏蔽线和寄存器配置这些基础环节。只要把这些细节一条一条抠到位,工业现场那种恶劣环境里拿到0.1℃级别的稳定温度数据,并不是什么玄学。

RELATED READING

延伸阅读

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