基于UART接口24位ADC的HVAC多通道温度采集系统设计与实践 做工业或暖通空调HVAC温度采集的工程师迟早会遇到一个问题现场传感器种类又多又杂PT100、热电偶、NTC混着来模拟前端要求高可MCU的片上ADC又撑不住。去年我接手的一个项目就是这样空调箱进出风温度、冷冻水管水温、压缩机排气温度全要采精度要求±0.3°C抗干扰还得过得去。最后定下来的方案是基于TI ADS122U04IPWR24位UART接口ADC加STMicroelectronics STM32F303RECortex-M4F主控的组合。这篇文章就是这个项目的完整复盘从选型、硬件、驱动到实测调参能让你少走不少弯路。如果你也在用UART的精密ADC或者准备做多通道温度采集这里面的寄存器配置、比率测量计算和冷端补偿代码都可以直接抄作业。尤其是HVAC和工业现场那种“传感器分散、干扰大、维护人员还不一定懂电路”的场景把数据链路和算法边界搞清楚比单纯堆料有意义得多。1. 从需求看选型为什么是ADS122U04 STM32F303RE1.1 工业和HVAC温度测量的真实痛点先说说现场情况。HVAC项目里的温度点通常有这么几类回风温度、送风温度、冷冻水供回水温度、换热器盘管表面温度、压缩机排气管温度。前几个属于常规温区-40°C到150°C就够用但数量多、线缆长、安装位置分散。工业场景就更严苛了可能是烤箱、冷库、反应釜、干燥设备传感器可能要扔到-200°C到850°C的PT100或者上千度的热电偶上。这些点如果全部用专用温控仪表成本立刻爆炸如果用PLC模拟量模块通道数和精度又常常互相打架。真正做一次系统设计就会明白难点从来不在“把温度读出来”而在于三件事一是传感器种类多前端必须灵活可配二是现场干扰大微弱信号很容易被电机、变频器、接触器的噪声淹没三是长期稳定性工业设备一开就是三五年温度漂移和器件老化必须提前考虑。ADC选型一旦贪便宜后面调试和售后能把成本吃回来。1.2 ADS122U04IPWR自带UART的24位ADC省事在哪ADS122U04IPWR是TI推出的一颗24位Δ-Σ型ADC带4路输入通道、内置PGA、内置2.048V基准电压源、内置温度传感器和可编程激励电流源。和常见的SPI接口ADC不同它走的是UART接口这是我最看重的一点。SPI接口在板内短距离没什么问题但一旦传感器板和主控板之间隔着几十厘米甚至几米线缆SPI的时钟同步、片选时序、信号完整性问题就全来了。UART是异步串行通信只需要TXD和RXD两根线时序容错性好抗干扰能力强现场走线短了可以直连长了加个RS485或者数字隔离器也方便。这颗ADC内置的PGA增益范围是1到128RTD和热电偶都能直接接内置的IDAC电流源可以给PT100提供激励省掉外部恒流源内置基准源虽然在追求极致精度时不如外部基准但作为默认方案已经能把系统焊点数量降下来一大截。它的封装是TSSOP-16也不算大非常适合放在传感器采集板上通过UART把数据回传给主控。1.3 STM32F303RE为什么不用普通MCUSTM32F303RE是意法半导体的Cortex-M4F内核芯片主频72MHz带512KB Flash和64KB SRAM。单纯看跑分它不算惊艳但它有一堆非常适合模拟信号处理的外设内置多个运算放大器、比较器、DAC以及5Msps的12位ADC。这意味着什么意味着在同一个系统里你不仅能通过UART把ADS122U04的数据收回来做温度算法还能顺手用片上运放做电流采样、用比较器做阈值保护、用PWM和PID算法直接驱动加热器或调节阀。M4F内核带FPU和DSP指令这在温度算法里非常实用。RTD的温度换算要做浮点运算和多项式迭代热电偶冷端补偿要查表插值这些用带FPU的M4F来处理几微秒就能算完完全不需要额外配一颗DSP。另外F303的USART资源丰富一路给ADS122U04一路给RS485一路给屏或者上位机调试互相不抢资源。如果你只是读个温度用8位单片机也行但要做到多通道、多协议、带控制逻辑F303这个级别是性价比很稳的选择。1.4 同类方案对比方案精度接口典型场景主要坑点ADS122U0424位UARTRTD/热电偶多通道、长线传输寄存器资料要仔细读UART帧解析很关键ADS124S0824位SPI16通道RTD采集通道多但价格高SPI时序调试费时间AD779324位SPIPT100测温仪表SPI要处理同步问题三相线接法有讲究STM32片上ADC12位内部总线普通电压/温度粗测精度和温漂不够干扰下有效位数更低同样的24位方案SPI接口芯片本身性能不差但在“传感器板与主控板分离”的场景下UART接口能少两根时钟线抗干扰和布线难度都降一个量级。ADS122U04在通道数量上不如ADS124S08那么多但工业HVAC通常一个采集点就近放一个ADC通道多了反而浪费。归根结底选这个组合是冲着“信号链完整、接口简单、主控运算能力强”去的。2. 硬件设计拆解传感器、基准与保护电路2.1 传感器类型与前端接口配置ADS122U04有4个模拟输入通道AIN0到AIN3可以配置成双差分输入或者四路单端输入。我实际项目里用两路差分一路接PT100做水管温度和风管温度另一路接K型热电偶做压缩机排气管温度。这样一路运行、一路备用后期加测点也不用改板子。PT100的接法建议用三线制或四线制。四线制精度最高但现场线缆成本高大部分HVAC场合三线制已经足够。三线制的优势是把导线电阻影响的路径做了闭环抵消。如果你贪便宜用两线制线阻1欧姆就会引入约2.5°C误差这个在工程上是绝对不能接受的。ADS122U04的IDAC电流源从内部流出后经RTD再到参考电阻配合差分输入和PGA天然适合三线制/四线制接法。原理图上我每个通道都预留了一个位置为二线制传感器短接用的跳线方便现场应急。热电偶前端要特别注意两点一是热电偶输出电压是微伏级别K型大约40μV/°C所以PGA增益必须拉高同时走线要短屏蔽层要在传感器端单点接地二是必须加偏置电阻做开路检测。热电偶断线在高振动工业现场是常事没有开路检测的话断线后ADC会漂到一个随机值控制系统可能误判成超温直接停机这个后果比读不到数据还可怕。我在AIN到GND之间放了1MΩ偏置电阻配合寄存器里的断线检测功能三毫秒内就能报出“传感器开路”。2.2 激励电流与参考电阻的匹配计算这部分是整个模拟链路设计的核心。以PT100测温为例我选IDAC激励电流500μA为什么不是1mA因为自热效应。500μA在100欧姆的PT100上只有25mW功耗放进水里或者金属表面影响不大如果用1mA功耗到100mW风管里的细径探头会明显自热读数能偏0.1°C以上这在追求±0.3°C的工况里已经不可接受了。激励电流确定后再算参考电阻。ADS122U04的比率测量思想是让参考电压来自同一个IDAC电流在外部精密参考电阻上产生的压降。假设选RREF4.096kΩ那么500μA×4096Ω2.048V正好和内部基准电压一致这组参数配合起来非常顺手。再算PGA增益。PT100在0°C时是100Ω在850°C时约390Ω。500μA激励下最大信号电压是500μA×390Ω0.195V。如果让PGA8输入到ADC调制器的电压就是0.195×81.56V距离2.048V满量程还有余量既不会饱和又不会浪费分辨率。这组计算的结果就是激励电流500μA参考电阻4.096kΩ温漂≤10ppm/°CPGA增益8理论满量程电阻4096Ω/8512Ω参考电阻的精度和温漂直接决定系统精度。我选了0.1%精度、10ppm/°C的金属箔电阻焊在距离ADC的REFP引脚很近的位置。如果参考电阻本身漂了后面软件怎么校准都救不回来这是硬件设计里最不能省的元件。热电偶的电压范围则不一样。K型热电偶在0~1350°C时输出大约0~54.9mV。如果PGA128满量程是2.048V/12816mV只能测不到400°C显然不够。所以宽温区热电偶要用PGA32满量程64mV覆盖主流的测温范围HVAC里如果只测排气管温度一般也就-40~200°C用PGA128反而能拿到更高的有效分辨率。这个取舍必须在原理图定稿前算清楚因为PGA增益是寄存器配置项但前级抗混叠滤波器的截止频率和布局是按PGA档位设计的。2.3 电源、参考、隔离与保护电路ADS122U04的模拟电源AVDD和数字电源DVDD我建议分开走各自接一个1μF贴片陶瓷电容再加一个0.1μF高频去耦电容电容尽量靠近电源引脚。模拟供电建议用低噪声LDO比如TI的TPS7A4700或者国产的低噪声LDO别直接拿开关电源的输出接AVDD否则24位ADC的噪声性能会被散粒噪声毁掉。数字侧隔离是我这个项目特别坚持的一点。工业现场温度传感器经常从几十米外拉过来一旦设备端发生浪涌或者共地干扰主控板就是第一个牺牲品。我选了单芯片双通道数字隔离器ISO7741放在STM32和ADS122U04中间UART的TXD/RXD各占一路电源隔离用隔离DC-DC模块。HVAC场景如果主板和采集板距离很近隔离可以省掉但接口保护不能省每路模拟输入对地并联TVS管串联1kΩ限流电阻防止误接220V时直接打坏ADC。实际项目里还加过一个教训参考电阻的两个引脚旁边必须铺地铜皮做热平衡。因为参考电阻会随温度漂移如果一边靠近发热器件一边靠近风口温差会让ADC读数随开机时间缓慢移动。我把RREF两边各放了几个接地过孔让热量均匀散掉实测漂移小了很多。2.4 PCB布线要点模拟信号优先ADS122U04的封装引脚间距不算大焊接时要控制好温度但这颗芯片的稳定性相当不错焊接问题主要出在参考电压引脚上。布线时有几条硬性规则模拟输入走线尽量短远离数字信号线和电源开关节点。每个模拟输入串联RC滤波推荐1kΩ电阻加1nF电容到模拟地形成低通。REFP/REFN走线要短且等长参考电容必须紧贴引脚。STM32的晶振和USB/串口区域尽量远离ADS122U04的参考网络。模拟地和数字地在STM32下方单点汇接然后大面积铺地。我第一版PCB因为偷懒把参考电阻放在了板子边缘结果发现只要手指靠近板子读数就跳。后来把参考网络包进地平面问题就消失了。这种模拟细节经验不足时真的会反复踩。3. 寄存器配置与软件实现从初始化到温度换算3.1 初始化流程与时序ADS122U04上电后先不要急着发配置先把AVDD和DVDD稳定起来我一般加一个至少1ms的延时。然后通过UART发送RESET命令确保芯片处于已知状态。接着依次写入多个配置寄存器最后把CS引脚拉低使能UART通信芯片进入连续转换模式每完成一次转换就自动推送一个数据帧。如果你用过SPI接口的ADC可能会习惯“发命令、读数据”这种一问一答的方式。ADS122U04用UART做连续模式之后MCU这边的软件模型更简洁——你只需要开一个UART接收中断在中断里收帧、校验、解析温度计算放到主循环或者低优先级任务里。这样不会占用CPU轮询等待的时间实时性反而更好。初始化顺序我总结成一套固定的上电延时1ms发送RESET命令写寄存器配置地址加配置数据拉低CS进入连续转换等待第一帧数据一般要等几倍于转换周期的时间如果5ms内收不到帧重新检查CS电平和波特率配置。3.2 关键寄存器配置示例与位域解释ADS122U04的寄存器按地址从REG0到REG4每个寄存器控制一组功能。下面是我项目里的实际配置思路具体位排列以数据手册为准但功能含义是一致的REG0输入多路复用器选择AIN0为正输入、AIN1为负输入构成差分对。REG1数据速率与IDAC通道分配数据速率设为20SPSIDAC1电流源接到AIN2引脚IDAC2保持禁用或接到AIN3。REG2PGA与基准PGA增益设为8基准源选择外部REFP/REFN引脚即参考电阻两端开启断线检测。REG3IDAC电流值设为500μA。REG4温度传感器与偏置内部温度传感器默认关闭偏置电压禁用比较器功能不启用。RISK提示ADS122U04有几个寄存器位在不同数据手册版本里的命名有细微差异强烈建议在写代码时从数据手册里把每个寄存器的位图抄出来写成宏定义注释。我当时就是因为只看了一个老版本截图把IDAC通道分配的位序写反了导致激励电流没有流经PT100读数一直在零附近跳后来对照最新手册才查出来。3.3 UART协议解析与数据帧处理ADS122U04输出的数据帧是长度固定的一组字节包括错误标志、通道信息、24位转换结果和校验状态。我的驱动里用中断逐字节收满一个帧然后做校验解析。#define FRAME_LEN 5 volatile uint8_t rxFrame[FRAME_LEN]; volatile uint8_t rxIdx 0; void USART1_IRQHandler(void) { uint8_t b USART1-RDR; if (rxIdx FRAME_LEN) { rxFrame[rxIdx] b; } if (rxIdx FRAME_LEN) { rxIdx 0; if (frameCheck((uint8_t*)rxFrame)) { int32_t code ((rxFrame[1] 0x7F) 16) | (rxFrame[2] 8) | rxFrame[3]; if (rxFrame[1] 0x80) { code | 0xFF800000; // 24位二进制补码符号扩展 } temperatureProcess(code); } } }这段代码的关键点是24位数据的符号扩展。ADS122U04输出的是二进制补码正数最高位为0负温度对应负电压时最高位为1。如果忘了做符号扩展负温度会被解析成一个很大的正数曾经有同事因此把-10°C读成327°C控制系统差点直接把加热器关掉。3.4 RTD与热电偶温度换算算法拿到ADC码之后第一步是算出电阻值。比率测量公式是R_RTD (ADC_CODE / 8388608) × R_REF / PGA_GAIN8388608对应24位ADC的正满量程码。比如PGA8RREF4096Ω那么满量程对应的电阻是512Ω。实测某个温度点读到码值2097152电阻就是(2097152/8388608)×4096/8128ΩPT100在约70°C时的阻值。电阻算出来之后用PT100的ITS-90标准多项式反算温度。0到850°C范围使用Callendar-Van Dusen公式的简化形式R(t) R0 × (1 A×t B×t²)其中A3.9083e-3B-5.775e-7。这个方程没法直接解出t我用牛顿迭代做一般迭代四五次就收敛到0.01°C以内float resistanceToTempPT100(float rtd) { const float R0 100.0f; const float A 3.9083e-3f; const float B -5.775e-7f; float t 0.0f; for (int i 0; i 8; i) { float rt R0 * (1.0f A * t B * t * t); float dt (rt - rtd) / (R0 * (A 2.0f * B * t)); t - dt; if (fabsf(dt) 0.001f) break; } return t; }热电偶的换算稍复杂。K型热电偶电压和温度的关系是非线性的工程上最稳妥的办法是查表线性插值把NIST ITS-90表按1°C间隔烧进Flash实测电压查表得到热端温度。冷端补偿怎么做要特别注意ADC自己测到的冷端温度是参考结温度总热电动势等于实测热电动势加上冷端温度对应的电动势。写成公式就是E_total E_measured E_at(T_cold_端)然后再用E_total反查热端温度。如果直接用“实测电压冷端温度×40μV/°C”这种粗略补偿误差在冷端漂移大的场合能到好几度所以我是用LUT插值算冷端对应电动势再回头查热端温度计算量稍大但对精度要求高的HVAC项目值得。3.5 数字滤波与抗干扰策略ADS122U04的Δ-Σ调制器自带数字滤波在20SPS数据速率下对50Hz工频干扰有不错的抑制。但工业现场还有变频器、继电器吸合产生的尖峰脉冲单纯靠ADC内部滤波不够。我在主循环里对温度结果做了一阶IIR低通float filtered 0.0f; void filterUpdate(float input) { filtered 0.15f * input 0.85f * filtered; }这个滤波系数大概对应几十毫秒的时间常数对快速响应的压缩机排温监控来说足够快又能把大部分随机噪声抹掉。如果被测点本身热惯性就大比如水管温度可以把系数调到0.05、0.95曲线会非常平滑。要注意的是滤波会带来滞后PID控温时不能只看滤波后的曲线否则容易振荡。4. 实测数据、校准与常见问题4.1 实测环境与数据记录整机调好后我用恒温水槽做了从0°C到150°C的对比测试参考温度计是二等标准铂电阻温度计。测得的典型数据如下标准温度(°C)ADC计算电阻(Ω)算法输出温度(°C)误差(°C)0.00100.020.050.0525.00109.7125.030.0350.00119.3849.96-0.04100.00138.55100.120.12150.00157.28150.200.200°C附近误差很小温度越高误差越大的趋势主要来自参考电阻的温漂和PT100传感器的线性度偏差。这个结果在没有做多点修正时已经能满足HVAC的±0.3°C要求工业上要更高精度就得做校准。4.2 误差来源分析别只盯着ADC位数很多人以为用了24位ADC精度就一定高其实系统误差大头常常在ADC之外的环节。参考电阻精度和温漂是最直接的影响因素如果RREF用的是1%精度的贴片电阻温度系数25ppm/°C环境变化10°C就会引入0.25%的读数误差对应PT100在100°C时大约0.6°C这比ADC量化误差大多了。第二个大头是PT100的自热效应。激励电流流过传感器必然产生焦耳热PT100探头周围介质导热系数不同自热表现完全不同。空气流动环境里的自热比浸水环境明显很多这也是我不把电流源调到1mA以上的原因。第三个大头是连接导线电阻。三线制已经把大部分线阻抵消掉了但三根线如果线径不一样或者接线端子氧化导致接触电阻不一致仍会有残余误差。两线制接法在这个项目里列为禁用现场调试如果遇到温度偏高或偏低首先怀疑线缆接头。4.3 校准方法一点修正还是两点修正如果现场对精度要求更高可以在软件里做两点校准。我在Flash里保存了每个通道的增益校准系数和偏移校准系数校准公式是T_corrected T_raw × gain_coeff offset_coeff具体做法是把探头放到冰水混合物里记录T_raw1此时真值是0°C再放到100°C沸水槽记录T_raw2此时真值是100°C。两个点解出增益系数和偏移系数之后所有读数都用这个公式修正。这个方法能同时补偿参考电阻偏差和传感器误差实测可以把常温段的误差压到±0.1°C左右。要注意校准点必须稳定沸水槽海拔不同沸点会有偏差最好用恒温槽。4.4 常见问题排查速查表症状可能原因排查方法UART完全收不到数据CS引脚未拉低波特率/数据位不一致芯片进入复位状态量CS电平用示波器看UART波形重新发送RESET命令数据全为0激励电流没流过传感器MUX配置选错通道PGA输入饱和在低端检查IDAC通道分配量PT100两端电压确认REG0配置数据在满量程附近跳传感器开路输入超共模范围PGA增益过高先断开传感器测偏置电压再查开路检测标志温度读数比实际高且缓慢漂移参考电阻受热传感器自热线缆端子接触电阻变大检查RREF周围热源降低激励电流重插接线端子读数跳动超过0.5°C电源纹波太大数字信号干扰模拟走线数据速率挡位太低换低噪声LDO调整布线提高20SPS数据速率并开滤波热电偶冷端补偿不准冷端位置实际温度与ADS内部温度传感器不一致在端子附近放置导热铜块或者用外部NTC做冷端测量上电后第一个读数异常寄存器配置还没生效UART帧同步丢失初始化时先收一帧“脏数据”丢弃然后再解析有效帧5. 总结与个人实操感悟这套ADS122U04 STM32F303RE的组合在我手头已经稳定跑了半年多HVAC风管温度和水温两条通道的曲线非常平稳压缩机排气管的K型热电偶在高温高振动环境下也没有再出现读数乱跳的情况。回头复盘最值的几件事是坚持了三线制PT100、坚持了外部参考电阻、坚持了数字隔离这三个决定在现场都兑现了价值。最后再分享两个项目里实打实的经验。第一个是芯片资料一定要看最新版ADS122U04的寄存器位域在早期版本手册里和后期版本有差异我吃过一次亏花了两天时间在代码里查来查去最后发现是手册版本不对。第二个经验是设计时给每个通道预留跳线传感器接线方式在项目现场经常会被甲方要求改有四线/三线/两线切换的硬件冗余调试时会非常从容。温度测量这东西看起来就是读一个数但把信号链的每个环节都抠到位系统才会真正省心。