
做 HVAC 温度采集这一行时间久了你会发现大部分控制板的温漂问题根本不是算法问题而是信号链选型没到位置上。前阵子在一个风柜控制项目里我用 TI 的 ADS122U04IPWR 搭配 Microchip 的 PIC18F85J50做了一块四路温度采集模块精度做到了接近 0.1°C 级别而通信接线比以往 SPI 方案简单得多。这个组合让我想认真写一篇工程笔记ADS122U04IPWR 本质上是一颗四通道 24 位 ADC但对外接口是通用 UART特别适合 PIC18F85J50 这类 8 位主控在工业和 HVAC 场景下做多点温度采样。如果你正在纠结“MCU 自带 ADC 够不够用”“SPI 温度芯片怎么总是受干扰”这类问题这篇文章会把方案论证、硬件连法、软件实现、误差校准和现场排查一次性讲透。1. 方案拆解为什么是 ADS122U04IPWR 与 PIC18F85J501.1 温度测量链路的核心矛盾温度传感器输出的信号天然很小。K 型热电偶在室温附近的灵敏度大约 41µV/°C哪怕温度变了 1°C电压变化也只有几十微伏。NTC 热敏电阻和 PT100 铂电阻虽然信号稍大但要把 0.1°C 的温差分辨出来需要的信号检测能力同样在微伏级别。如果你直接用单片机的 10 位或 12 位 ADC输入范围又是 0 到 3.3V那么一个 LSB 对应的电压可能是毫伏甚至是十几毫伏根本无办法稳定测出 0.1°C 的变化。所以工业测温和 HVAC 高精度控制场景里前端必须有一颗高分辨率、低噪声的 ADC。ADS122U04IPWR 这颗芯片的核心优势就在这里。它是 24 位分辨率内部还集成了可编程增益放大器用 PGA 把微弱信号放大之后再做量化这样小信号也能在 ADC 的满量程范围里充分展开。配合内部的低漂移基准源整个模拟前端不再依赖外部精密电阻或独立基准芯片这对 PCB 面积和 BOM 成本都很友好。再说直接一点它不是“一颗 ADC”而是把仪表放大器、基准、温度传感器和四路输入选择器打包在一起的前端方案。1.2 为什么 ADS122U04IPWR 能省掉一半麻烦我最初想用 SPI 接口的 ADS1220 或类似芯片但项目里主控是 PIC18F85J50本身带 SPI 外设接线也不复杂。真正的问题出在 HVAC 控制柜的复杂环境里。柜子里有继电器、接触器、变频器SPI 的 SCK 和 MOSI 长距离连线容易耦合噪声时序稍微被干扰就会出现“数据移位、读回全 0、写寄存器失败”这种玄学问题。把时序调稳定要花不少时间而且每个板子布线不一样现象还不一样。ADS122U04IPWR 改成 UART 接口后通信只有 TXD 和 RXD 两根线协议又是异步字符帧对时序裕量要求低得多。尤其放在 2 米到 5 米的传感器线缆场景里UART 只要波特率正确基本不用担心时钟边沿被干扰。它的内部设计其实也保留了 24 位 ADC 和 PGA 的全部能力四路模拟输入可以做差分或伪差分配合内部集成的传感器温度检测功能还可以顺便做热电偶的冷端补偿省掉一个贴在端子排上的 NTC。这些特性组合起来让“一颗芯片管四路温度”成为现实。1.3 PIC18F85J50 在这个项目里能干什么PIC18F85J50 是一颗 8 位 MCU但它有多个 UART 模块、足够的内存和工业级温度范围。最初有人质疑 8 位机做高精度测量会不会算不过来实际真正需要主控参与运算的只有查表、线性化和数字滤波。比如 NTC 的 Beta 公式计算用 32 位浮点也就是几十条指令的事PIC18F 完全跑得动。更重要的是 J50 系列的工作电压范围宽IO 电平也能和 3.3V 传感器系统兼容不用额外做复杂电平转换。选择它还有一个很现实的原因很多 HVAC 控制器项目对成本敏感8 位 MCU 在供应链上更成熟开发资料也齐全。你不需要为了一路温度测量去上一颗 Cortex-M4F把资源和成本浪费在 CPU 性能上。主控真正要做的就是初始化 UART、解析 ADS122U04IPWR 返回的数据帧、把原始码值换算成工程温度值然后通过 Modbus 或者 CAN 送出去。这种分工很符合工业控制里“模拟前端负责测量、主控负责通信和控制”的经典架构。1.4 为什么不直接用 MCU 内置 ADC我见过不少工程师直接拿 MCU 内置 ADC 做 NTC 温度采集配合 10kΩ 上拉电阻到电源精度做到 1°C 到 2°C 也不是不行。但 HVAC 系统里温度控制经常涉及 PID 调节如果温度波动在 ±0.5°C 以内很多设备是不动作的可内置 ADC 的非线性、参考电压漂移和电源噪声叠加起来可能在满量程范围内造成几十个 LSB 的误差反映到控制上就是压缩机频繁起停、房间温度震荡。另一个问题是 MCU 内置 ADC 的采样保持电路切换时间不够灵活多路复用时通道间串扰也会影响精度。独立 ADC 芯片的优势在于模拟部分可以做得更干净。ADS122U04IPWR 的 PGA 输入端有完善的 EMI 滤波能力数据输出采用数字通信方式传输模拟地到数字地之间的相互干扰更容易隔离。这也是我坚持用外部 24 位 ADC 的原因把敏感模拟测量和嘈杂数字控制彻底分开系统设计思路清晰后续维护也好定位问题。2. 硬件连接与电路设计要点2.1 不同温度探头的接入方式ADS122U04IPWR 虽然是四通道输入但具体怎么接传感器要看实际测温类型。如果接的是热电偶直接把热电偶的正负极接 AINx 和 AINx1利用 PGA 的高增益模式放大微伏级信号。热电偶信号本身是直流的但现场会叠加工频干扰和射频噪声所以输入端最好串联一个几百欧姆的电阻再接一个 100nF 到 1µF 的电容到地构成低通滤波避免高频噪声在 PGA 之前就饱和。如果接 PT100 或 PT1000情况要复杂一点。它们本质上是电阻传感器必须先有一个激励电流流过电阻再把电阻两端电压送到 ADC。ADS122U04IPWR 不像上一代 RTD 专用芯片那样自带恒流源所以需要外接精密电流源或者用简单的桥式电路。我自己常用 1mA 恒流源激励 PT1000°C 时电阻 100Ω两端电压 100mV300°C 时电阻约 215Ω两端电压 215mV。PGA 增益设成 8 或者 16这个范围的信号就能被放大到接近满量程。如果只是测 HVAC 的风管温度NTC 热敏电阻反而是最简单的方案。NTC 和精密电阻组成分压电路把分压点接到 ADC 输入通过查表或者 Beta 公式换算温度。不过 NTC 的非线性很大低温段和高温段的分辨率完全不一样建议尽量选择阻值变化平缓的型号并把分压电阻的温漂控制在 25ppm/°C 以内不然 ADC 再准也会被分压电阻拖累。2.2 UART 通信与电平匹配细节ADS122U04IPWR 的工作电压一般是 2.3V 到 5.5VPIC18F85J50 可以选择 3.3V 供电。最稳妥的做法是把两颗芯片都用 3.3V 供电IO 电平直接兼容TXD 和 RXD 交叉相连就行。这里必须注意一个问题UART 的 TXD 在空闲时是高电平如果 MCU 和 ADC 的电源上电时序不一致MCU 的 IO 可能会被 ADC 拉到一个不确定状态。所以我在实际电路里会在 TXD 和 RXD 上各加一个 10kΩ 上拉电阻接到 3.3V同时在 MCU 侧把相关引脚配置成数字输入或开漏输出避免上电瞬间出现总线冲突。ADS122U04IPWR 的 UART 通信是带地址和校验的。它支持同时挂多颗芯片在同一条总线上通过地址字节区分具体设备。这个特性对多路温度采集很有用比如四个模块挂在一条 UART 总线上只要每个模块用拨码开关设置不同地址主控就能顺序访问。接线距离长了以后建议把波特率降到 9600 或 19200信号完整性会好很多。9600 波特率下一帧温度数据大约耗时 3ms 到 5ms四路轮询下来完全够用。2.3 电源、PCB 布局与 HVAC 机箱的抗干扰整个测温模块最忌讳的是电源不干净。HVAC 柜子里有 220V 交流电继电器闭合瞬间会产生很大的电流跳变地线也会跟着抖。我给 ADS122U04IPWR 供电用的是单独的 LDO输入来自 24V 电源模块LDO 输出端并一个 10µF 陶瓷电容和一个 0.1µF 高频小电容做到宽带去耦。模拟电源和数字电源如果允许尽量用磁珠隔开至少要让 ADS122U04IPWR 的 AVDD 和 DVDD 引脚都有独立的去耦电容。PCB 布局上我习惯把模拟输入放在板子边缘传感器线缆通过端子排接入从端子到 ADC 的走线尽量短。模拟地和数字地在 ADC 芯片下方单点连接避免数字信号回流穿过模拟区域。如果板子上还有继电器驱动电路一定要把继电器线圈的驱动地单独走一路不要和传感器模拟地混在一起。再一个容易踩的坑是传感器线缆屏蔽层接地屏蔽层最好在控制柜侧单端接地不要在传感器侧也接地否则会形成地环路低频干扰反而更严重。3. 软件层面从 UART 初始化为一次完整的温度读取3.1 初始化序列与寄存器配置软件的第一步是初始化 PIC18F85J50 的 UART。波特率 96008 位数据无校验位1 位停止位。ADS122U04IPWR 的 UART 协议是帧格式包含设备地址、命令、数据和校验段。我不会在这里逐字节抄手册因为不同版本芯片的帧定义会略有差异但驱动骨架是一样的发送读寄存器命令、等待响应、解析状态字节、根据状态判断转换是否完成。我习惯先做一次上电复位然后读回 ADC 的默认寄存器值确认通信链路能正常工作。再写配置寄存器把输入多路选择器设置为任意通道组合PGA 增益按传感器类型设定基准选择为内部基准转换模式设为单次转换。对于 HVAC 现场我一般不上连续转换因为温度变化本身很慢单次转换可以做到“随时唤醒、测完就睡”对整机功耗和电磁干扰都有好处。下面这段代码是按“可读性优先”写的驱动骨架具体命令帧请对照你手头数据手册的时序图做二次封装。uint8_t uart_send_byte(uint8_t dat) { while (!TXSTAbits.TRMT) {}; // 等待发送寄存器空 TXREG dat; return 0; } uint8_t uart_recv_byte(uint8_t *dat) { while (!RCSTAbits.FERR) {}; // 等待接收完成 *dat RCREG; return 0; } void adc_reset(void) { uart_send_byte(DEV_ADDR); uart_send_byte(CMD_RESET); // CMD_RESET 以手册为准 __delay_ms(10); } void adc_write_config(uint8_t addr, uint8_t value) { uart_send_byte(DEV_ADDR); uart_send_byte(CMD_WRITE_REG); // 写寄存器命令 uart_send_byte(addr); uart_send_byte(value); uart_send_byte(calc_crc(value)); // 简单校验 }配置完成后我会再读一遍所有寄存器确认写入值和实际值一致。这一步能解决现场非常多的“通信时好时坏”问题。如果写入失败多半是接线松动或者地址配置错误提前发现总比在测量阶段抓瞎强。3.2 发起转换并读取测量结果单次转换模式下初始化后 ADC 不会自己开始采样。你要发送启动转换命令然后等待转换完成标志。有的芯片有 DRDY 引脚有的芯片需要在状态字节里查询标志位具体以数据手册为准。我在代码里采用轮询方式每 20ms 发一次状态查询发现转换完成后再读取转换结果。这样做的好处是主控可以插空处理其他任务不会被 ADC 阻塞。读出来的结果一般是 24 位二进制补码高字节在前。手动合并三个字节时注意符号位扩展。如果芯片输出的是 24 位无符号码用 32 位整数接收然后判断最高位是否为 1如果是 1 就需要转成负数。转换完成之后最好检查状态字节里的错误标志比如输入超量程、PGA 饱和或者基准电压异常。这些错误标志在工业现场太重要了不用白不用。3.3 原始码值换算成电压和温度得到原始 ADC 码后先换算成输入电压。24 位 ADC 的 LSB 大小取决于 PGA 增益和基准电压。以内部基准 2.048V、PGA 增益 8 为例输入满量程相当于 ±2.048V / 8 ±0.256V。也就是说ADC 码值变化 2^24 次对应电压变化 0.512V那么每个 LSB 对应的电压约为 0.512V / 16777216 ≈ 30.5nV。这个分辨率拿来测热电偶绰绰有余。int32_t raw_code merge_3_bytes(data_buf); float voltage_v raw_code * (2.0 * 2.048 / 8.0 / 16777216.0); float voltage_mv voltage_v * 1000.0;电压变成温度就要看传感器类型了。PT100 的阻值随温度近似线性变化0°C 时 100Ω100°C 时 138.5Ω斜率约 0.385Ω/°C。先用电压和激励电流算出电阻再用线性公式或查表得到温度。NTC 热敏电阻则用 Beta 公式T 1 / (1/T0 ln(R/R0)/B) - 273.15其中 T0 是 25°C 对应的开尔文温度R0 是 25°C 时的标称阻值。热电偶稍微麻烦需要先由电压查对应分度表得到仪表温度再减去冷端温度补偿。3.4 数字滤波与数据稳定性24 位 ADC 本身分辨率很高但也意味着它会把微伏级的噪声全部量化出来。HVAC 现场的温度信号变化很慢我通常会做两级滤波先做中值滤波取连续 5 次采样去掉最大最小值再求平均值把脉冲干扰滤掉再做一阶低通让控制环路看到的温度曲线平滑变化。一阶低通的系数可以设成每次更新 20% 新值这样时间常数大约几十毫秒到几百毫秒既不迟钝也不毛躁。需要特别提醒的是滤波不能放在校准之前。所有滤波算法都必须针对被测温度本身而不是针对原始 ADC 码。否则零点漂移和增益误差也会被平均进去让系统看起来稳定但实际不准。我见过很多现场工程师把原始码值做平均后来校准时才发现平均出来的结果跟真实温度差了一大截就是这个原因。4. 误差分析与校准策略4.1 误差来源不要只看 ADC很多人在评估系统精度时只盯着 ADC 的位数这是个大误区。24 位 ADC 的量化噪声非常小但整个测量链路的误差往往来自传感器、基准电压、激励电流和连接器接触电阻。下面我列了一张实际评估时常用的误差来源表供大家在方案阶段估算用。误差来源典型影响应对方式传感器自身精度PT100 可达 ±0.1°C 到 ±0.3°C选用更高等级传感器或做两点校准内部基准温漂影响增益精度造成约 ±0.05%FS使用低漂移参考模式并做软件校准激励电流温漂RTD 测温中每 10ppm/°C 至少引入 0.02°C选用精密恒流源或定期校准电流PGA 零点漂移输入短接时仍有几十到几百 nV 偏差初始化后做硬件自校准或软件减偏移冷端温度不准热电偶测量直接引入等值误差利用片上温度二极管并做平移校准端子接触热电势可能达到 1°C 级别使用同种金属端子并保持温度一致这张表说明ADC 只是提供了一个高分辨率的测量平台真正的系统精度要靠外围和校准拼出来。HVAC 应用如果只追求 0.5°C 精度放宽校准要求问题不大但如果是工艺冷却水或者恒温恒湿箱这类要求 0.1°C 的场景就得认真做校准流程。4.2 零点校准和增益校准怎么做零点校准最简单把 ADC 输入通道短接并在固件里记录当时的测量值作为偏移量。每次换算温度前先减去这个偏移量。注意短接时要使用与传感器相同的切换方式不能直接把 AINx 和 AINx1 长时间缩在一起最好用一个继电器或者杜邦线临时连接记录完偏移量再恢复。否则你校准的是一个“短路状态”而不是“传感器接入状态”仍然会有残余误差。增益校准就需要更精确的手段。如果你有高精度电压源可以给输入通道加一个已知电压比如 100mV 或者 200mV然后根据 ADC 读数计算实际增益和理想增益的比例系数。这个比例系数会存储在 EEPROM 里每次上电加载到固件中。没有高精度电压源时可以用电阻箱模拟 RTD 的已知阻值配合 1mA 恒流源产生已知电压效果等同。校准最好是两点同时做低点取零点附近高点取测量范围的上限两点之间做线性插值。4.3 热电偶冷端补偿的工程处理热电偶本身是差分测量器件它测的是热端和冷端之间的温差冷端参考点接在 ADC 输入端子的位置。如果冷端温度就是板上温度我们可以直接用 ADS122U04IPWR 内部温度传感器的读数做冷端补偿。但内部温度传感器测的是芯片内部温度和端子温度之间可能有一个固定差值这个差值会随气流或柜内温度变化。所以更稳妥的做法是在端子排附近再放一个高精度 NTC标定出它和热电偶冷端之间的差值。现场实测时我用电烙铁加热一个金属块对比热电偶读数、NTC 读数和参考温度计读数得到冷端补偿修正量。修正量可以是常数也可以做成分段表。因为 HVAC 控制柜内温度一年四季变化很大只做固定平移可能夏天准、冬天偏分段表更可靠。记住冷端补偿的误差是 1 比 1 加到最终温度上的热电偶测量想做到整体 0.5°C冷端补偿必须控制在 ±0.2°C 以内。4.4 自热效应和长期漂移任何激励电流流过传感器都会产生热量温度传感器本身被自己热到测量值就会偏高。PT100 在 1mA 电流下自热一般小于 0.1°C但如果传感器封装很小且风管里风速很低热量散不出去自热会更大。解决方法是降低激励电流比如 PT100 用 0.5mAPT1000 用 0.1mA前提还是 ADC 的 PGA 增益要调到足够高小信号也能分辨。NTC 更敏感建议激励电流不超过 0.2mA。长期漂移方面PCB 上任何焊点、连接器和端子都存在缓慢氧化的过程几年后接触电阻可能变大。我在产品里做了一项“定期自检”每个月把内部校准电阻切换到输入端记录 ADC 读数变化如果和出厂值的偏差超过阈值就通过 Modbus 上报“传感器需要维护”。这套逻辑平时不引人注意但真正发生老化问题时能省去大量现场排查时间。5. HVAC 现场调试的常见坑与排查实录5.1 UART 通信不稳定时序好像没问题但线路偶发异常这个问题在 HVAC 柜子里太常见了。故障现象是上电后能通信一阵子但压缩机或继电器一动作通信就丢帧。排查第一步看供电继电器线圈断电瞬间会产生反电动势把 24V 电源拉出毛刺如果 LDO 压差又不够就会直接干扰 ADC 电源。解决方法是给继电器线圈并联续流二极管并把 LDO 的输入输出电容加大。第二步看线缆UART 的 TXD 和 RXD 如果和继电器驱动线并行走线干扰会直接感应进来改走不同层或加屏蔽就能解决。如果你用的是 9600 波特率还出现少量丢帧多半是总线上拉电阻太大或者分布电容太大导致波形边沿变缓。把上拉电阻从 10kΩ 改到 4.7kΩ或者降低波特率到 4800往往就好了。最后再查一下地址配置多颗 ADC 挂在同一总线上时如果有两个模块地址撞了会出现偶尔读到 0xFF 或错误帧的情况。5.2 温度读数像“心电图”一样抖动读出来的温度短时间内在 ±0.5°C 之间来回跳说明噪声没有被充分压制。先不要怀疑 ADC 芯片拿出示波器看 AIN 引脚的波形。如果是 50Hz 工频干扰在输入端并联 1µF 电容能把干扰压到可接受范围。如果是高频毛刺输入端串联几欧姆到几百欧姆的电阻做 RC 滤波时间常数设置不要超过软件采样周期的五分之一免得信号被滤平。另一个常见原因是在测量过程中还开着继电器扫描或者数码管动态刷新。这些数字电路的瞬态电流会在电源地上反弹而 ADC 的模拟输入又跟它共用参考地读数自然不稳定。我的做法是让温度采样发生在“安静窗口期”比如数码管刷新的间隙或者继电器切换完 20ms 之后再进行转换。这样软硬件都不需要大动稳定性却能明显提升。5.3 校准之后过几天又偏移了如果你做了零点校准和增益校准但过几天精度又漂了大概率是校准系数被写进了 RAM掉电就丢或者校准时用了不稳定的参考源。校准系数一定要存进 EEPROM 或者 Flash 模拟 EEPROM 区域并加上校验字。如果参考源本身随温度变化比如用普通稳压管搭的基准校准效果当然只能维持几天。把参考基准源换成内部基准或者选用低温漂的参考芯片重复性会好很多。还有一个小坑是校准时的读数次数太少。单次读数偏差可能达到几个 LSB直接写进校准系数就会引入新的误差。比较稳妥的做法是每次校准时连续读 100 次再取平均平均值作为校准基准。我甚至在校准程序里加入了统计方差判断如果 100 次读数的方差超过阈值就提示“校准环境噪声过大请降低干扰后重试”这样保证了校准动作可信。5.4 温度范围显示得对但控制就是慢半拍系统显示的温度在理想范围可 PID 控制响应还是有滞后这种情况要检查采样周期和滤波时间常数。HVAC 温度变化本来就是分钟级的但如果在算法里叠加了 500ms 甚至 1s 的软件低通滤波传感器又包在厚金属套管里整个控制环的惯性会大得离谱。解决方案是滤波时间常数和传感器热时间常数分开考虑如果传感器热时间常数是 10 秒软件滤波就不要超过 2 秒否则你会觉得“显示很稳但控制永远跟不上”。在工程现场我一般把原始采样周期设为 200ms 一次中值滤波窗口取 5 个点滑动平均再取 4 次。这样整体数据延迟大约在 1 秒左右对 HVAC 的控制完全够用。如果未来要做变风量快速调节可以再缩短采样周期但一定要保证电源安静、端子可靠不然快采样只会快吃到噪声。5.5 最后分享一个“土办法”用温度梯度代替绝对值在很多 HVAC 项目里大家真正关心的不是绝对温度是多少而是温度变化趋势和差值。这时我更倾向于先测四路温度的梯度也就是通道间的相对值再调控制逻辑。因为相对值测量可以把 ADC 的共模误差、参考电压误差都抵消掉精度反而比绝对值有意义。比如你要判断风管前后温差是否达到 2°C只需要保证两路通道用相同增益、相同滤波参数差值测量往往能做到 0.05°C 的稳定度。这种思路的工程价值在于它不需要高精度基准源甚至不需要做繁琐的增益校准只需要保证系统的重复性。先把“相对温度准确”做到极致再通过一次简单的偏移校准把绝对值拉回来会比一开始就死磕绝对精度省力很多。我在这个项目里的实际体会是ADS122U04IPWR 与 PIC18F85J50 的搭配恰好适合这种“先保证低噪声、再追求高精度”的开发路径。如果你也正在做类似的工业或 HVAC 温度测量不妨先把这条路走通再回头优化成本。