1. 项目概述工业与HVAC测温为什么不能随便糊弄我在实际项目里折腾温度测量也不是一两年了从最初拿单片机内置ADC采个NTC就能交差到后来发现工业现场和HVAC系统对温度数据的准确性、稳定性和抗干扰要求完全不是一个量级才慢慢理解为什么很多人最终会走向独立ADC加微控制器的方案。这次用到的 ADS122U04IPWR 搭配 PIC18F47K42就是一套非常典型的组合专门解决“既要精度又要成本”的测温需求。先说清楚这套方案能做什么。ADS122U04IPWR 是德州仪器出的24位低功耗ADC关键它是带UART接口的不需要SPI或者I2C那种还要操作线序、时钟的麻烦事直接用串口就能读数据。另一颗 PIC18F47K42 是Microchip的8位单片机片上的模拟外设非常丰富。两颗芯片凑在一起可以覆盖热电偶、PT100/PT1000铂电阻、NTC热敏电阻、甚至桥式传感器的测温场景量程从-200℃到1800℃都做得下来。在HVAC领域可以测风管温度、冷水机组进出水温、制冷剂管路温度在工业领域可以测电机绕组、轴承座、加热炉表面温度。适合谁来参考如果你在做温控设备、数据采集终端、HVAC控制器或者想把手头的MCU方案升级到更高精度这篇文章能帮你少踩很多坑。我会把选型思路、硬件接线、寄存器配置、温度计算、常见问题全部拆开讲一遍照着我给的方法搭基本能跑通。2. 方案选型ADS122U04和PIC18F47K42凭什么搭到一起2.1 ADS122U04自带UART的24位ADC到底香在哪大部分工程师选ADC的时候第一反应都是SPI接口的比如ADS1220、ADS1248之类。SPI当然成熟但实际布局布线时你可能要为了隔离、长线传输或者芯片引脚复用折腾半天。ADS122U04这个“U”后缀就是UART的意思它把模拟前端和数字通信整合在一起你只要给它发一串ASCII指令它就把转换结果以ASCII格式串行输出连协议解析都可以省一大截。这颗芯片的精度参数很能打24位分辨率内部集成可编程增益放大器PGA增益从1到128倍可调输入噪声在PGA128时能低到有效分辨率20位以上。它内部还带两个可调电流源专门用来给RTD或者热敏电阻提供激励省掉外部精密恒流源。对于热电偶测量它内置冷端补偿用的温度传感器虽然不是特别准但配合校准能达到够用的水平。另一个优势是功耗。ADS122U04在单次转换模式下电流只有几百微安适合需要电池供电的便携温度记录仪。对于HVAC那种24小时不间断运行的设备功耗低也意味着发热小不会因为芯片自热把测量搞漂。我用它最大的体会是调试方便。SPI出问题要拿示波器抓时序UART出问题拿串口助手看打印就行。尤其是现场调试带着笔记本打开串口工具就能实时看温度值这体验比SPI舒服太多。2.2 PIC18F47K42这个MCU其实是个模拟采集小钢炮PIC18F47K42单看型号可能不起眼但它的定位很明确面向混合信号处理的低成本8位MCU。它内置12位差分ADC、4个采样保持器、两个8位DAC、两个比较器、一个运算放大器模块还带我印象很深的“信号测量计时器”SMT这些功能组合起来可以直接配合外部ADC做后处理。选它做ADS122U04的主控第一理由是UART资源充裕。PIC18F47K42有多个UART外设其中一个可以专门接ADS122U04另一个留作调试或者上位机通信。第二理由是它主频最高64MHz跑温度线性化的浮点数学运算虽然比不上一线ARM但配合编译器优化算热电阻的查表或多项式并不吃力。第三理由是它内部有EEPROM和Data EEPROM可以把校准系数、非线性偏移表存下来量产时不需要外挂存储芯片。当然了用这颗MCU也有一点需要注意它的供电电压范围是1.8V到5.5V而ADS122U04的数字IO最高可以扛到5.5V所以两者可以直接用同一个3.3V或者5V电源域不用电平转换。省一路电源对小PCB板很友好。2.3 两颗芯片组合起来的互补关系ADC负责把物理世界的电压变成数字MCU负责把数字变成温度值、做协议输出、故障诊断。ADS122U04的UART接口天然适合跟PIC这类通用MCU对接你甚至不需要写复杂的驱动库配置好波特率往串口发个“RDATA”指令就有数据回来。更重要的是这种分工让系统具备隔离条件。工业现场经常需要隔离栅因为传感器线缆可能长达几十米共模干扰和地电位差很致命。UART接口做数字隔离比SPI容易得多——隔离器只有两个方向信号不像SPI还有SCK、MOSI、MISO多根线需要同步。我用过ISO7763之类的高速数字隔离器接在UART线上效果很稳。选型时不必追求这颗ADC有多高端反而是看它是否贴合你的传感器类型。如果你只测NTCPGA小点也没关系如果测热电偶就要压到微伏级别PGA和低噪声就很重要。ADS122U04在这两者之间取得了均衡所以我最后定了它。3. 硬件设计与接线照着搭就能跑3.1 传感器接线与前端电路先拿应用最广的几种传感器说接线。热电偶T型/K型热电偶输出是毫伏级直流电压K型大约40uV/°C所以要用差分输入模式把热电偶两根线接到ADS122U04的AIN0和AIN1PGA设64到128倍。热电偶的共模电压要小尽量接近地电位最好加一个偏置电阻到GND防止输入悬空导致读数漂移。冷端补偿的话PCB板上靠近端子放一个温度传感器比如LM45或者NTC把冷端温度读出来喂给MCU做补偿。ADS122U04内部虽然有个用于冷端补偿的温度传感器但我的经验是外部传感器更准因为内部传感器的测温点离接线端子有距离热阻不一样。PT100/PT1000铂电阻需要恒定电流激励ADS122U04内部有IDAC电流源可以把IDAC1接到RTD的一端同时把RTD的电压通过差分输入接进ADC。典型接法是用三线制一根激励线两根电压采样线这样能抵消导线电阻。PT100的灵敏度大约是0.385Ω/°C激励电流通常选1mA这样在0°C时电压是100mV左右PGA设8到16就够。注意电流源驱动的是精密电阻要选低温漂的。NTC热敏电阻最简单用内部IDAC做电流源或者用电阻分压后接到单端输入。NTC的B值需要做查表或者Steinhart-Hart方程拟合。接线时的关键点输入线尽量短要屏蔽线缆屏蔽层在传感器端单点接地。如果现场干扰强在ADC输入端并一个100nF陶瓷电容加一个1nF到10nF的差模电容滤掉射频噪声。注意ADS122U04的输入阻抗会受PGA影响外部滤波电容不能太大不然会造成建立误差。3.2 MCU与ADC的UART通信ADS122U04的UART接口是标准的3V3电平不需要额外的RS232芯片。把PIC18F47K42的UART1_TX接到ADS122U04的DIN/RXUART1_RX接到它的DOUT/TX两个芯片共地。ADS122U04上还有一个DRDY引脚表示转换完成可以接PIC的INT外部中断脚也可以不接用轮询或定时读。我建议把DRDY接上。因为UART是字符流的你不知道对方什么时候更新数据如果直接读寄存器可能赶上数据更新途中虽然ADS122U04内部有FIFO和锁存机制但用DRDY做事件触发更可靠。实际接法是DRDY接PIC的RB0设置为下降沿中断进中断后发UART指令取数据。这样MCU可以睡得死死的只在转换完成时醒来读一次。波特率建议选9600或者19200。ADS122U04启动后默认是9600,8,N,1。有人图快想把波特率调到115200但工业长线环境下波特率越高越容易出错我实测9600最稳反正温度信号变化不快几十毫秒一次转换完全够用。3.3 供电与去耦ADS122U04的模拟电源AVDD和数字电源DVDD最好分开走。我习惯用LC滤波器给AVDD供电一个10Ω电阻加10uF钽电容再加100nF陶瓷电容能抑制电源开关噪声。PIC18F47K42的供电也会反噬到ADC因为两者共地所以PIC的数字地要跟ADC模拟地单点汇合不要让数字电流流过模拟回路。还有一个容易忽略的PIC的UART TX引脚在启动瞬间可能是高电平或浮空如果它抢先输出乱码可能把ADS122U04误触发。我在UART_TX线上串联了一个1kΩ电阻同时把PIC的UART引脚在初始化前配置成输入上拉防止误操作。4. 固件实现配置、采集、计算一发入魂4.1 ADS122U04寄存器配置ADS122U04的寄存器组很简洁主要配置寄存器有6个。我给出一组适合热电偶测温的配置例子。// 伪代码通过UART发送配置字节 // 寄存器0: 输入多路复用器选择AIN0和AIN1差分输入 uint8_t reg0 0x00; // AIN0AINP, AIN1AINN // 寄存器1: PGA128, 增益128, 用于热电偶微弱信号 uint8_t reg1 0x80; // PGA_EN1, GAIN128 // 寄存器2: 数据速率 20SPS, 滤波模式 50/60Hz抑制 uint8_t reg2 0x28; // DR20SPS, FIR滤波 // 寄存器3: 内部温度传感器关闭不使用IDAC用外部传感器补偿 uint8_t reg3 0x00; // 寄存器4: 上电模式连续转换模式 uint8_t reg4 0x10; // 寄存器5: 关闭内部基准偏置等用内部2.048V基准 uint8_t reg5 0x00; // 发送指令序列 // WREG指令指令字节 0x40 | (0 5) | 0x05即写6个寄存器写寄存器之前建议先发送“复位”指令编码0xFE让芯片回到默认状态防止上次掉电前配置残留。然后逐字节写寄存器每写一个寄存器可以读一次验证这样排查问题很快。我踩过的坑是寄存器1默认增益是1如果你不配置就直接读数据热电偶信号只有几十微伏读出来的码值波动在数百个LSB完全看不出温度变化。所以PGA一定要先设好别急着读数据。4.2 PIC18F47K42配置UART与中断PIC18F47K42用MPLAB X IDE开发用MCCMicrochip Code Configurator图形化配置很快。我在MCC里配置UART1为异步模式波特率9600数据位8无校验1停止位。使能接收中断接收要读的数据包。同时设置一个定时器每200ms发送一次“RDATA”指令或者用DRDY中断触发。// 初始化UART1 void UART1_Initialize(void) { // 设置波特率寄存器假设Fosc32MHz // SPBRGL (Fosc/(16*9600)) - 1 207 SPBRGL 207; TXSTAR 0x24; // 8-bit mode, BRGH1, TXEN1 RCSTA 0x80; // SPEN1 } void __interrupt() sys_interrupt(void) { if (PIR1bits.RC1IF) { char c UART1_Read(); // 读数据 // 处理字节 } // DRDY中断处理 }需要注意的是读取ADS122U04的温度数据时通常要发送“RDATA”指令然后连续读3个字节24位加上一个状态字节。状态字节里有参考电压溢出、PGA溢出等标志一定要检查。4.3 温度数据计算与线性化示例代码ADS122U04的原始码值是二进制补码格式。以内部2.048V基准、PGA128为例1个LSB代表的电压是( V_{LSB} \frac{2.048}{128 \cdot 2^{23}} \approx 1.5259 \times 10^{-8} , V )实际用浮点计算时需要把24位有符号数转成电压float adc_to_voltage(int32_t raw, float vref, float gain, uint32_t bits) { float scale vref / (gain * (float)((1UL (bits-1)))); // 用2^23作为满幅一半 return (float)raw * scale; }热电偶测温计算步骤读取热端电压 ( V_{hot} )读取冷端温度 ( T_{cold} )一般来自板载温度传感器查热电偶分度表把 ( T_{cold} ) 对应的热电势 ( E_{cold} ) 查出来把 ( V_{cold} E_{cold} V_{hot} ) 作为总热电势查表反推热端温度。这个过程用查表插值即可。比如K型热电偶可以存一个从-200°C到1370°C的温度-毫伏表步进10°C然后用线性插值。对于PT100计算公式可以用Callendar-Van Dusen公式在0°C到850°C( R_T R_0 (1 A T B T^2) )在-200°C到0°C( R_T R_0 [1 A T B T^2 C (T-100) T^3] )其中标准系数( A 3.9083 × 10^{-3} )( B -5.775 × 10^{-7} )( C -4.183 × 10^{-12} )。用迭代法反算温度。我把这个函数做了优化因为PIC18F47K42是8位机浮点运算慢但如果数据速率只有每秒20次浮点运算时间是够的。实测一个Kalman滤波浮点计算循环大约2ms完全能跑。5. 调试实录噪声、断线、温漂怎么破5.1 典型问题与定位方法先列一个速查表都是我实际遇到的问题。现象可能原因排查步骤读回数据为0x7FFFFF或0x800000输入开路、PGA配置不对、输入共模超范围用万用表量传感器两端电压确认PGA增益数值跳动超过几位电源噪声、滤波电容缺失、线缆过长示波器看ADC基准引脚加去耦电容温度读数整体偏移冷端补偿错误、热电阻引线电阻未扣除校准冷端传感器改用三线制UART收不到数据TX/RX接反、波特率不匹配、芯片进入低功耗模式用逻辑分析仪看TX引脚确认电平翻转转换速率慢于预期读数方式错误、DRDY没触发检查寄存器2的数据速率位改为连续模式特别强调一个容易看走眼的点ADS122U04的UART不单单传输数据还接受控制指令比如DIN引脚管发送DOUT管接收。你如果把DIN和DOUT接反了芯片也不会报错就是没响应。用万用表测DIN空闲电平应该在3.3VDOUT空闲电平也是3.3V但如果驱动后出现差分波形就有信号了。5.2 校准与滤波经验温度通道一般要做两点校准。零点校准把传感器探头放进冰水混合物0°C记录ADC读数计算偏移量。满度校准用精密电阻箱模拟传感器电阻比如PT100在100°C时是138.5Ω接上精密电阻源记录读数计算增益误差。校准系数建议保存在PIC的Data EEPROM里。我遇到过零漂在几个月后变化几十个微伏的情况主要是因为PCB应力释放和元件老化。如果产品要求0.2°C精度建议出厂前做两温区校准并且把器件安装在应力较小的位置。滤波上我在ADC数据后面套了一个一阶低通滤波等效时间常数约1秒。公式很简单( y_n y_{n-1} \alpha (x_n - y_{n-1}) )其中 ( \alpha ) 约为 0.02 ~ 0.05。这种方式能有效滤掉HVAC系统里压缩机启动造成的电源毛刺比单纯取平均值响应快又不牺牲实时性。如果现场工频干扰强建议打开ADS122U04的50/60Hz抑制滤波器我的经验是开启后读数跳动能从2~3个LSB降到0.5个LSB以内。还有一个经验在ADC的参考电压输入处放置一个大电容和一个小电容参考电压是内部基准但外部引脚要接退耦电容否则数据低几位会反复横跳。我吃过这个亏后来在REFP和GND之间放了10uF电容数据立刻稳了。6. 延伸从原型到量产还要补哪些东西6.1 板级可靠性和生产测试原型跑通之后量产阶段要关注几个点。第一是PCB布局。ADS122U04的模拟输入走线要远离数字信号和电源开关节点。我在一层板上布线时把模拟输入走在内层用铺地包围。另外热电偶的信号线若经过连接器连接器输入点要留TVS管或ESD保护二极管。第二是MCU代码的固件保护。PIC18F47K42有Code Protection熔丝位量产时必须开启防止固件被读走。另外要留一个引导程序升级能力方便现场校准或修复算法。第三是温度标定。每个温度通道都应在至少三个温度点上标检-20°C, 25°C, 85°C视应用范围并记录误差曲线。如果误差呈线性可以在固件里做二点偏移修正如果呈非线性就要拟合多项式。线的连接器也很重要。工业现场振动大端子容易松。我建议用带锁扣的接线端子或者直接焊接传感器线避免按压式端子。曾有客户反映温度读数偶发跳变最后定位是端子氧化导致接触电阻变化了几十毫欧影响PT100读数好几度。6.2 同一套硬件还能扩展哪些传感器既然ADC和MCU的资源都还有富余我可以把同一块主控板扩展成多参数采集器。ADS122U04本身有4个模拟输入通道理论上可以同时测4路单端信号。用PIC18F47K42的其他GPIO控制多路模拟开关比如CD74HC4067可以扩展成16路温度采集。对HVAC楼宇自控来说一个区域控制器需要采集十几路的温度这么做能把单路成本压到很低。如果需要同时测压力、湿度等其他模拟量ADC输入可以切换成其他传感器输出。只需要改固件里的通道选择和线性化函数硬件不用动。我做过一个变体用同样的板子同时测了PT1000温度和压力变送器的4-20mA信号——4-20mA要加一个250Ω采样电阻把电流转成1-5V电压再经过分压或输入范围调整接到ADC输入。ADS122U04的内置PGA甚至可以处理小信号但要注意4-20mA信号地可能和采集板地电位不同最好用隔离式的配电模块。6.3 通信组网和上位机对接温度数据除了在本地显示往往要上报到PLC或者云平台。PIC18F47K42还剩下一个UART和SPI可以接工业级无线模块比如LoRa、NB-IoT或者RS485收发器。这里的关键是数据帧格式要自定义得简单清晰我常用的帧格式是帧头0xAA 0x55 通道号1字节 温度值浮点型4字节 状态标志1字节 CRC16校验2字节。总长度9字节。这样的帧无论是走串口还是无线都能被上位机快速解析。在HVAC应用里如果对接BACnet MS/TP协议RS485物理层是标配但协议栈就得加大存储。PIC18F47K42的Flash是32KB跑精简BACnet从站勉强够但更推荐只做透明转发把协议处理交给上位机。把温度数据按Modbus RTU格式映射到保持寄存器是很多工控项目的通用做法。我把寄存器里地址0x0000定义成温度值有符号整数单位0.01°C调试时用Modbus Poll工具就能读不用自己写上位机非常方便。我个人在实际项目里的体会是ADS122U04与PIC18F47K42这套组合最打动人的地方不是单点性能而是“够用”和“顺手”。电压测量、串口通信、线性化计算、数据上送每一环都有成熟方案兜底。如果你手里有类似项目建议先按我上文的方式画个最小系统板把热电偶和PT100两路分别拉出来跑通再考虑扩展通道。只要前期的电源和布局不出问题后面的调试会很顺畅。最后再分享一个小技巧所有寄存器配置都留一个可修改的参数表放在EEPROM里生产时不需要重新烧录固件来修正标定偏差这一招能省很多售后电话。