做HVAC控制柜的工程师多数都被“温度测不准”这件事折磨过。上一版我用的还是MCU内置ADC加分立仪表放大器的老路子到项目后期光是标定就花掉两周。这版直接换成TI的ADS122U04IPWR搭配Microchip的PIC32MZ1024EFH064把工业温度测量中那些容易跑偏的环节从硬件链路到软件协议重新搭了一遍。这篇文章就是这次实践的完整记录。ADS122U04IPWR是一颗24位Delta-Sigma ADC带UART接口把可编程增益放大器、激励电流源、电压基准、冷端温度传感器全部集成在TSSOP封装里PIC32MZ1024EFH064则是Microchip经典的MIPS内核32位MCU200MHz主频、1MB Flash、512KB RAM外设和中断系统都非常成熟。两个芯片一个管模拟前端、一个管通信协议分工干净。如果你是做工业数据采集、楼宇自控、HVAC控制器或者传感器模组的工程师这篇内容可以直接当参考设计来用硬件接线、寄存器配置、UART通信状态机、温度换算和校准流程都会讲到。1. 选型逻辑为什么受够了分立模拟前端最终锁定ADS122U04 PIC32MZ1.1 工业/HVAC温度测量的真实难点空调和HVAC系统里温度测点看着简单实际拆开全是坑。首先是传感器类型杂。风管送风、回风常用NTC盘管进出水管用PT100或PT1000锅炉排烟或者压缩机排气管温度可能直接用热电偶。一套控制器往往要同时支持两三种传感器每种传感器的激励方式、信号幅度、接线方式都不一样。其次是现场干扰。控制柜里随便一数就是一堆24V继电器、接触器、变频器感性负载一动作电源线上就是一顿电压尖峰。模拟信号哪怕只有几十厘米的走线都会感受CMOS电平跳变带来的耦合噪声。第三个难点是精度要求。你看着HVAC好像是个舒适性控制但盘管水温的PID调节对温度分辨率要求并不低工程上经常要做到0.1°C量级的稳定分辨率。拿PT100举例它的灵敏度大约是0.385Ω/°CIDAC激励电流取500µA时每摄氏温度只对应约192µV的信号。这个量级的电压如果交给普通MCU内置ADC加上参考电压的温漂和噪声基本就没法看了。更隐蔽的是长线传输问题。柜内变送器和主控之间有时候线缆要拉好几米甚至几十米。SPI信号在这种距离上时序会被线缆电容和串扰毁掉而UART虽然也是并行时序无关但它对电平的容忍度更高甚至可以再挂RS-485驱动器延长到百米级。ADS122U04IPWR选择UART接口而不是传统的SPI本质上就是为了照顾工业现场的线缆距离和检修便利性。1.2 为什么是ADS122U04IPWR而不是“MCU内置ADC运放”在ADS122U04之前我做过一版方案8位MCU配一颗24位ADC再外置仪表放大器、精密基准、恒流源。那版方案的问题在于每一个外置器件都是误差来源而且PCB空间和BOM成本都压不住。ADS122U04IPWR核心价值是把整个模拟信号链压缩进一颗16脚TSSOP芯片。它内部有PGA增益从1到128可选有两个可编程激励电流源专为RTD和NTC设计有内部基准标称2.048V还有一个内部温度传感器可以拿来给热电偶做冷端补偿。这些模块中间的匹配、温漂、失调都在出厂前校准过比我自己搭的分离方案稳定得多。还有一个现实原因功耗。HVAC控制柜虽然不缺电但面板式温控器、无线传感器节点对功耗敏感。ADS122U04有单次转换和休眠模式待机电流能到微安级别配合PIC32MZ的低功耗模式一套电池供电的采集终端是可以考虑的。这就是为什么我从ADS1220系列选到了带UART的ADS122U04IPWR——它保留了ADS1220的模拟性能接口却从四线SPI简化成两线UART还省掉片选线。1.3 PIC32MZ1024EFH064在这一项目里的角色MCU这端我最初试过一颗Cortex-M0的芯片价格确实便宜但跑起浮点换算和协议栈之后发现留给业务逻辑的余量太少了。PIC32MZ1024EFH064是MIPS M5150内核带硬件FPU主频最高200MHz1MB Flash和512KB RAM在嵌入式温度采集里算得上奢侈但正是这种“富余”让我后面开发省了很多事。硬件上PIC32MZ1024EFH064提供6个UART、DMA控制器、丰富的中断优先级以及成熟的外设库。我在项目里用一颗UART和ADS122U04通信另一颗UART跑Modbus RTU和上位机对接还留一颗给调试串口打印日志。FPU则用来做热电偶查表线性插值、NTC的Steinhart-Hart公式计算这些浮点运算如果交给软件浮点库CPU占用会高好几倍。两颗芯片的分工非常清晰ADC负责把微伏级模拟信号变成数字码值MCU负责通信协议、数据滤波、温度换算和上层控制逻辑。模拟部分不需要碰寄存器级的运算数字部分也不需要关心差分走线阻抗开发效率高很多。2. 模拟前端设计从PT100/热电偶端子到ADC输入引脚的完整链路2.1 电源、基准与地分割模数混合电路的电源处理是第一个关键点。工业现场进来的是24V我会先经过DC/DC降到5V再通过低噪声LDO分别给模拟和数字供电。ADS122U04IPWR的AVDD我单独用了LDO输出数字电源和PIC32MZ可以用同一路但要加磁珠隔离。模拟地和数字地在PCB上做单点汇接所有模拟信号走线都压在完整地平面之上这一点不做的话后面读数飘到天际都别奇怪。基准电压我用的是ADS122U04内部基准。这颗芯片的内部基准温漂指标在数据手册里写的是相当低的对HVAC这种-20°C到60°C环境来说完全够用。如果你的项目要求更苛刻比如做实验室级计量设备那就换成外部基准源通过寄存器把基准选择位改到外部基准引脚上精度可以再拉高一个等级。成本上多一颗基准芯片但换来的是长期稳定性是否值得看产品定位。给模拟前端供电还有一个细节24位ADC对电源纹波极其敏感。LDO的输出端我会放一个π形滤波典型值是10µF陶瓷电容加1µH电感再加10µF。不要图省事只放一颗100nF低频段的电源噪声是滤不干净的。2.2 PT100两线/三线/四线接法解析PT100是HVAC里最常用的温度传感器。它的阻值从0°C的100Ω到100°C的138.51Ω变化范围小信号幅度小所以接线方式直接影响精度。两线制最简单传感器两端各一根线但这两根线的电阻直接串在RTD回路里。铜导线每米电阻和线径有关0.5mm²的线每米约35mΩ10米线来回就是0.7Ω换算成温度接近1.8°C误差在HVAC里不可接受。三线制的原理是用两根线走恒流源电流同时在差分输入端正极端和负极端分别测量电压。ADS122U04IPWR有两个IDAC电流源我把IDAC1接到正激励线IDAC2接到负激励线两个电流大小设成相同这样两条引线上的压降会在差分测量时相互抵消。理想情况下只要两个IDAC电流完全相等引线电阻的误差就被消掉了。实际芯片两个IDAC之间会有微小失配但都已经折算进ADC增益误差整体偏差远小于两线制。四线制是实验室级别两条线激励、两条线检测完全消除引线电阻。但四线传感器和接线端子成本高HVAC场景里用到的不多。我常用的做法是产品默认支持三线制但PCB上预留四线制的跳线焊盘需要高精度时直接贴四线探头。电流源和PGA的搭配要根据量程算。PT100接500µA激励0°C时信号电压50mV100°C时69.2mV我把PGA设为16此时ADC的满量程是±Vref/PGA ±128mV信号正好落在中间偏上的区间既不会削波也不会浪费分辨率。如果你接的是PT1000阻值是PT100的10倍激励电流可以降到250µA电压信号幅度接近PGA配置不变。2.3 热电偶输入与冷端补偿设计热电偶是差分小信号K型热电偶灵敏度约41µV/°C0到400°C输出大约16mV。这信号太小PGA我会开到64以上满量程变成±32mV刚好覆盖常用工业温度区间。热电偶测量最核心的问题不是放大而是冷端补偿。热电偶测的是热端和冷端之间的温差产生的热电动势冷端在接线端子处温度会随着柜内温度变化必须实时补偿。ADS122U04IPWR内部有一个温度传感器通过MUX切到内部通道读出一个ADC码值换算成芯片温度。这个温度可以近似当成冷端温度再根据热电偶分度表把冷端对应的电动势补回去。具体步骤是先读热电偶通道电压再读内部温度传感器通道把内部温度转成K型热电偶在那个温度下的电动势加到实测电压上再去查温度-电压分度表。我用的是NIST ITS-90标准多项式查表用二分法加线性插值K型热电偶在0到1200°C范围内误差可以控制在0.5°C以内。需要注意芯片内部温度传感器测到的是PCB周围的温度而冷端真正的温度在接线端子上。如果探头接线端子离芯片很远两者之间会有温差补偿就不准。所以PCB布局时要把端子放在芯片附近并在同一片铜箔区域减少温差。更讲究的做法是用外部NTC贴在端子上通过MUX的另一路差分输入测量。2.4 NTC热敏电阻与输入端滤波保护NTC在HVAC里常用于回风和送风温度价格便宜、灵敏度高但非线性很严重。NTC测量我用IDAC恒流源激励恒流流过NTC产生电压通过ADC测量电压后再用Steinhart-Hart公式换算温度。恒流源的好处是信号不依赖电源电压比电阻分压法稳定得多。为了让NTC在ADC量程中间有较好的分辨率我会根据NTC的标称阻值选激励电流比如10kΩ的NTC在25°C时用100µA恒流电压1VPGA设为2能满足-40°C到85°C的测量范围。输入端滤波和保护是必须有的。模拟输入引脚前各串一个1kΩ电阻再加一个1nF差模电容组成RC低通截止频率约160kHz作用不是滤工频而是抑制射频干扰和采样电荷注入产生的毛刺。输入对地还要加TVS管防止传感器线缆被雷击或碰高压时把ADC打坏。RC滤波器要注意电阻不能太大因为24位Delta-Sigma ADC的输入是一个开关电容网络等效阻抗会吸收电流外部电阻大了会产生额外的电压降和误差。一般不超过几kΩ配合PGA输入架构影响可以忽略。3. 软件通信设计PIC32MZ如何与ADS122U04稳定对话3.1 ADS122U04的UART命令帧与寄存器配置ADS122U04IPWR用UART代替了传统ADC的SPI接口主机通过发送命令帧来写寄存器、读寄存器、触发转换和读取数据。命令帧通常由命令类型、寄存器地址、数据字节和校验字段构成具体帧结构、支持的命令集和CRC多项式以你手里的数据手册版本为准但工程实现思路是一样的。我先把芯片初始化的流程理清楚。上电后先给模拟电源和数字IO电源稳定的时间然后发送复位命令或者进行一次完整的寄存器初始化。关键配置在四个寄存器里通道多路复用器选择AINx接哪个引脚、PGA增益、数据速率和工作模式、IDAC电流源配置、内部温度传感器开关、基准选择。我把常用配置整理成下表手册里的位定义虽然要对号入座但逻辑顺序是一致的配置项典型值作用MUXAIN1-AIN2 差分选择热电偶或三线RTD输入通道PGA16PT100 / 64热电偶预放大微伏级信号数据速率20 SPS配合50Hz陷波抑制工频干扰IDAC电流500µAPT100 / 100µANTC提供RTD和热敏电阻激励内部温度传感器使能热电偶冷端补偿基准内部2.048V降低BOM温漂可接受配置完成后可以工作在连续转换模式也可以由PIC32MZ发送命令触发单次转换。单次转换模式适合低功耗场景转换完成后芯片自动进入休眠连续模式适合工业控制回路数据更新稳定。我在HVAC项目里用连续模式因为控制器需要周期性读取多个温度点懒得每次重新启动转换。3.2 PIC32MZ的UART初始化与中断接收PIC32MZ1024EFH064这端我用UART2连接ADS122U04波特率选19200。工业现场数据线不长这个波特率既安全又够用。PIC32MZ的外设时钟最高可以到100MHz计算波特率寄存器值的公式是BRG (PBCLK / (16 * baud)) - 1;PBCLK取100MHz时19200波特率对应的BRG约为324实际误差在0.15%以内远小于UART容忍的2%偏差。初始化代码大致是这样#define PBCLK 100000000UL #define BAUD 19200UL void uart2_init(void) { // 关闭并使能UART2 U2MODE 0; U2STAbits.UTXEN 0; // 波特率 U2BRG (PBCLK / (16 * BAUD)) - 1; // 8N1使能UART U2MODEbits.PDSEL 0; // 8位无奇偶校验 U2MODEbits.STSEL 0; // 1位停止位 U2MODEbits.UARTEN 1; // 使能发送和接收 U2STAbits.UTXEN 1; U2STAbits.URXEN 1; // 接收中断使能 IEC1bits.U2RXIE 1; IFS1bits.U2RXIF 0; }接收用中断加环形缓冲区比阻塞轮询可靠得多。环形缓冲区大小我设了256字节足够缓存完整的一轮命令响应。中断服务程序只负责把收到的字节压入缓冲区主循环里的状态机去解析这样不会因为ADC响应时间和上层协议处理互相干扰。3.3 通信协议状态机与CRC校验ADS122U04是异步通信主从之间没有时钟同步所以数据包边界要靠协议框定。我在PIC32MZ里写了一个解析状态机状态流转是这样的空闲状态等待命令字收到命令字后判断是需要读取多少字节的响应然后逐字节接收最后校验CRC。整个状态机代码如下typedef enum { RX_WAIT_CMD, RX_WAIT_LEN, RX_WAIT_DATA, RX_WAIT_CRC } rx_state_t; rx_state_t rx_state RX_WAIT_CMD; uint8_t rx_buf[32]; uint8_t rx_idx 0; uint8_t rx_expect_len 0; void process_uart_byte(uint8_t byte) { switch (rx_state) { case RX_WAIT_CMD: rx_buf[0] byte; rx_idx 1; // 根据命令字推断响应长度例如RDATA命令是3字节ADC数据CRC rx_expect_len get_expected_len(byte); rx_state RX_WAIT_LEN; break; case RX_WAIT_LEN: // 如果有显式长度字段就存起来没有就直接跳到数据态 rx_buf[rx_idx] byte; rx_expect_len byte; rx_state RX_WAIT_DATA; break; case RX_WAIT_DATA: rx_buf[rx_idx] byte; if (rx_idx rx_expect_len) { rx_state RX_WAIT_CRC; } break; case RX_WAIT_CRC: rx_buf[rx_idx] byte; if (crc_check(rx_buf, rx_idx)) { handle_ads122u_frame(rx_buf, rx_idx); } else { crc_error_count; // 连续错帧时需要重新同步 } rx_idx 0; rx_state RX_WAIT_CMD; break; } }CRC必须做。ADS122U04IPWR本身在工业场合设计的目标就是长距离可靠通信手册里给出的帧格式一般都会带CRC字节。我遇到过一次接线老化导致偶发误码的情况没有CRC的时候温度偶尔跳几十度被PID控制器当成真实温度一顿猛调加上CRC之后错帧直接被丢弃温度曲线再也没出现过毛刺。就算你的芯片手册说CRC可选我也建议打开。3.4 连续读取与DMA优化连续模式下PIC32MZ需要周期性读取ADC的最新转换结果。最简单的办法是每次等到ADS122U04的DRDY信号如果有拉低后发送RDATA命令或者更保险的做法是定时器定时轮询。我在HVAC控制器里用10ms定时中断触发一次读取请求20SPS的转换速率下每50ms才能拿到一个新有效数据10ms查一次完全来得及。如果后续要扩展更多ADC通道或者多个ADS122U04PIC32MZ的DMA就派上用场了。DMA可以把UART接收的数据直接搬到内存数组CPU在收到完成中断后再解析负载会大幅降低。我实测200MHz主频的PIC32MZ就算不优化UART中断方式接收也才占用2%左右DMA主要留给同时跑Modbus主从和PID运算时用。4. 温度换算、滤波与校准把原始码值变成可信的温度4.1 从ADC码值到电阻和电压ADS122U04是24位Delta-Sigma ADC输出码值是有符号补码格式。满量程是±Vref/PGA对应的码值是±2^23。换算电压的公式是float convert_code_to_voltage(int32_t code, float vref, float pga) { // 码值满量程对应 ±Vref/PGA return (float)code * (2.0f * vref / pga) / 8388608.0f; }以PT100为例IDAC电流设为500µA测得的电压除以电流就得到电阻值。然后按照IEC60751标准PT100的电阻在0°C是100Ω100°C是138.51Ω。嵌入式里最实用的是分段查表加线性插值。我用的表间隔是50°C一档在-50°C到400°C之间覆盖常用HVAC场景插值误差远远小于传感器本身的误差。const float pt100_table[] { // 温度, 电阻 -50.0f, 80.31f, 0.0f, 100.00f, 50.0f, 119.40f, 100.0f, 138.51f, 150.0f, 157.33f, 200.0f, 175.86f, }; float pt100_res_to_temp(float res) { uint8_t i; for (i 0; i 5; i) { if (res pt100_table[i*21] res pt100_table[i*23]) { float t0 pt100_table[i*2]; float t1 pt100_table[i*22]; float r0 pt100_table[i*21]; float r1 pt100_table[i*23]; return t0 (res - r0) * (t1 - t0) / (r1 - r0); } } return 0; }热电偶的换算比RTD复杂因为电压和温度是非线性的。我的做法是把K型热电偶分度表放在Flash里温度间隔5°C先根据热电偶电动势查表中位置再做线性插值。5°C间隔的插值误差很小对工业控制绰绰有余。4.2 数字滤波与50Hz工频抑制ADS122U04内置的数字滤波器本身就带工频陷波。把数据速率选在20SPS、50SPS等档位时滤波器的陷波点对准50Hz工频串扰能被压掉很大一块。这也是为什么我坚持把数据速率设低而不往上调的原因——在HVAC这类电源环境中工频干扰的量级远超ADC自身的分辨率。但内置滤波器挡不住脉冲型干扰比如继电器动作时耦合到传感器线缆上的尖峰。我会在ADC输出后加上一层级联的中值滤波和移动平均。中值滤波窗口取5负责剔掉偶尔跳变移动平均窗口取4进一步平滑噪声。实测下来一个温度点在稳定状态下原始波动的峰峰值能从±0.15°C压到±0.03°C以下。滤波会影响响应时间。5点中值加4点平均按20SPS计算算法层引入的延迟大约在0.4秒左右。对HVAC这样的大惯性系统来说完全不是问题但如果你要做快速响应的温度保护回路这个延迟就要注意了可能需要把数据速率提高到200SPS并缩短平均窗口。4.3 校准流程从出厂校准到现场校正ADC芯片本身有偏移和增益误差虽然出厂做过校准但在工业温度范围内还是会有残余误差。我的做法是在产品出厂前做一次两点校准校准源不用冰水混合物因为这种办法不稳定、可复现性也差。我会用精密电阻箱模拟PT100的标准电阻值先在100Ω0°C处读一次码值再在138.51Ω100°C处读一次码值。根据两次读数可以算出ADC链路当前的增益系数和偏移量把它们存到PIC32MZ的Flash里。之后每次上电读取校准参数在实际换算前先校正一遍电压值float calibrated_voltage(float raw_voltage) { return (raw_voltage - cal_offset) * cal_gain; }校准的关键是让ADC工作在它实际的量程区间不要用满量程去校。还有一种做法是利用ADS122U04内部的偏移校准寄存器直接把测出的偏移写回芯片让ADC输出本身修正。SPI版本的ADS1220有自校准命令UART版本同样提供类似机制用起来更省事但我会在MCU侧保留软件校准参数作为备份芯片坏了更换时不用改程序。4.4 误差预算怎么算把整个链路的误差源列出来心里就有底了。PT100在0°C的互换性误差通常是±0.3°C如果选A级探头可以到±0.15°CIDAC的温漂和失配会引入零点漂移典型在0.05%以内ADS122U04的积分非线性指标大概在±0.003%量级参考电压温漂和基准老化也会贡献误差。把这堆加起来板级综合误差做到±0.3°C以内是没有问题的足够支撑HVAC的PID控制和能耗计量需求。如果要做得更准硬件上换外部精密基准和低温漂电阻软件上做多点分段校准精度可以往±0.1°C靠。但HVAC场合真到那一步问题往往已经不在这套采集链路而在传感器自身的安装方式和热接触热阻上了。5. 实测记录那些让读数漂移和跳变的坎5.1 上电读数乱跳先把链路逐级排查我第一次把整板点亮时串口打印出来的温度在现实温度和100多°C之间疯狂横跳一开始怀疑是雷蛇蛇的寄存器配置问题后来查了一圈发现是模拟电源纹波超标。DC/DC输出后面我直接接了ADS122U04的AVDD纹波在几十毫伏量级对于24位ADC来说等于直接把一个高频抖动叠在信号上。解决办法就是前面说的π形滤波LDO输出加磁珠加低ESR电容。电源修好之后ADC码值的波动立刻从几十个数下降到两三个数对应温度稳定在±0.05°C以内。这一步让我意识到24位ADC对电源的敏感程度远超想象电源处理好比换更强的滤波算法管用得多。排查顺序我建议是先看电源纹波再看AVDD和DVDD是否隔离然后把ADC输入端直接短路测量零点最后才怀疑传感器。很多人一上来就改程序滤波实际是把电源的锅让算法背了。5.2 UART帧错乱波特率偏差和接线线序都有份压力测试时发现偶尔一两个字节会解析失败。我先用示波器抓了UART发送端的波形正常再抓MCU接收端的输入发现有轻微的信号振铃。问题出在PIC32MZ的UART引脚离传感器输入布线太近传感器线上的共模干扰耦合到了UART信号上。处理办法是隔离布线区域UART线走在远离模拟输入的一侧同时把波特率从115200降到19200信号完整性问题肉眼可见地减少。另一个隐蔽坑是借用PIC32MZ的内部RC振荡器跑UART温度变化时RC频率漂移超过容差就会偶发错位。我用外部8MHz晶振锁相环生成的时钟源波特率误差长期稳定在0.1%以内再也没出现错过帧。5.3 RTD引线电阻和端子氧化长期漂移的元凶项目试运行了一个月后用户反馈有个测点温度缓慢往上漂。排查时发现不是ADC的问题而是现场端子板上的螺丝端子氧化松动了。松动的端子等于在RTD回路上引入几十毫欧甚至更大的接触电阻对三线制RTD来说虽然两条激励线上的接触电阻可以被抵消但接线端子本身发热也会带来额外的热电动势于是温度读数跟着漂。这个教训让我在后续版本里强制使用弹簧端子并提高了校准提醒频率。软件里也加了合理性检查相邻两次读数突变超过设定阈值就报警防止漂移的温度数据进入PID控制。传感器接线端子选用的镀金端子虽然贵一点但在潮湿的空调机房环境里长期稳定性完全值得。5.4 屏蔽层接地方式解决模糊的地环路干扰传感器信号线用的是屏蔽双绞线最开始我把屏蔽层两端都接地结果低频干扰反而更严重了。这是典型的地环路屏蔽层两端跨接不同电位的接地点本身就形成了一根电流环路把噪声电流引入了信号地。屏蔽层正确的做法是单点接地在柜内电源地这一端接地另一端悬空。改成单端接地之后工频干扰和模拟量抖动都有明显改善。这个事情看起来小却直接影响测量稳定性我在项目复盘时把它列进了规范后续所有传感器线缆都按这个标准做。最后再分享一个工程习惯我在这套方案里额外加了一个“原始码值”调试通道。PIC32MZ在跑正常温度换算的同时会把ADC的原始24位码值、换算后的电阻值、校准增益参数一起通过调试串口打印出来。后面遇到任何温度异常不用瞎猜是ADC坏了还是算法错了直接把现场日志拿回来对一下问题定位非常快。ADS122U04IPWR和PIC32MZ1024EFH064这套组合我跑下来最大的感受是高精度测量不是靠某颗神仙芯片而是把电源、布局、协议、校准各个环节都按工业现场的标准去对待。芯片选对了剩下的功夫一点都不能省。希望这篇实践记录能让你少走几个弯路。
阅读完成 · 觉得有帮助?