前阵子给一套冷水机组做改造现场要测冷冻水供回水温度、风管送风温度精度要求控制在±0.2℃以内配电柜里的PLC模拟量通道已经全占满了只剩一个RS-485口。正好手里有TI的ADS122U04IPWR和Microchip的PIC18F4685就用这两个芯片搭了一个高精度温度采集模块。文章把这个项目从选型、硬件连接、软件配置到标定调试的完整过程记录下来给正在做工业测温或者HVAC系统监控的朋友一个可以直接抄作业的参考。这个方案的核心思路很简单用ADS122U04IPWR做24位高精度模拟前端负责把PT100、PT1000、NTC热敏电阻甚至热电偶的信号变成数字量再通过UART送给PIC18F4685PIC18F4685负责初始化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.5VPIC18F4685工作在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为例设置BRGH1工作在16分频模式SPBRG的计算公式是SPBRG Fosc/(16×Baud) - 1算下来是103十六进制就是0x67。void uart_init(void) { TRISCbits.TRISC6 0; // TX引脚输出 TRISCbits.TRISC7 1; // RX引脚输入 TXSTA 0x24; // BRGH18位数据使能发送 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差分对 // Reg1PGA增益和转换模式设置 // Reg2数据速率和数字滤波设置 // Reg3IDAC电流源和参考电压设置 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.030.0320107.7919.98-0.0250119.4050.020.02100138.51100.040.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℃级别的稳定温度数据并不是什么玄学。