
温度测不准的滋味做工业自动化和暖通的人都懂。系统一直报警生产停了查半天数据也没找出哪的问题最后才发现是温度采集电路的问题——基准漂了、引线长了、传感器接错了一百个理由等着你。这些年我做过不少温度采集方案从分立运放搭建到集成ADC从热敏电阻到铂电阻热电偶踩过的坑一箩筐。最近一个项目里用TI的ADS122U04IPWR配合ST的STM32F334R8做了一套温度采集系统用在HVAC和工业现场整体表现很稳这里把思路、电路、代码和问题排查完整梳理一遍给要做类似温度测量的朋友一个可复制的参考。这套组合的分工很明确ADS122U04负责把传感器信号变成数字量STM32F334R8负责配置、读取和做后续控制。ADS122U04是一颗24位Δ-Σ架构的ADC自带UART接口不用SPI也不用I2C两根线就能通信关键是它内部集成了两个精密电流源IDAC和可编程增益放大器PGA可以直接驱动PT100、PT1000这类RTD配合冷端补偿电路也能测量热电偶几乎把模拟前端的所有麻烦都包圆了。STM32F334R8则是一颗带浮点运算单元的Cortex-M4内核芯片主频最高72MHz除了常规的UART、SPI外高分辨率定时器也是它的招牌很适合温度采集后直接做闭环控制。如果你的项目也是工业温度监测、HVAC机组控制、设备过热保护这类场景这篇文章可以帮你省下不少自己踩坑的时间。1. 为什么把温度测量交给外部ADC而不是直接用MCU内部ADC1.1 STM32F334R8内部12位ADC在测温上的短板STM32F334R8内部其实有一颗12位SAR型ADC采样速率高用于电机电流采样、电压监测这些场景绰绰有余。但用来测温度尤其是测PT100或热电偶这类小信号12位分辨率显然不够看。我举个具体例子PT100在0℃时电阻为100Ω温度系数约为0.385Ω/℃如果把信号调理到ADC输入范围12位量化在3.3V参考下每一步约0.8mV对应到PT100的温度变化大约是0.2℃这还只是理想量化误差实际还有参考电压漂移、运放失调和布线噪声。HVAC系统里1℃误差勉强能接受工业现场很多设备对温度要求是±0.2℃甚至±0.1℃12位SAR ADC根本不能满足。更麻烦的是直接用电桥配合仪表放大器虽然也能搭建PT100调理电路但分立方案里有太多需要配对的电阻温漂、失调、共模抑制每一项都在考验设计者的功底。MCU内置ADC的参考电压通常是电源电压而电源电压会随负载变化这直接导致测量结果的基准不稳定。温度测量本质上是一个低带宽、高精度的弱信号测量任务和电机控制那种高速、相对、强信号的场景完全不是一个需求维度用一个高速SAR去硬扛性能不够还平添麻烦。1.2 24位Δ-Σ ADC与传统SAR ADC的本质区别ADS122U04是24位Δ-Σ型ADC内部集成了低噪声PGA增益最高128倍最低满量程输入可以到毫伏级别。它有4路模拟输入两个可配置IDAC电流源可以给RTD提供激励电流还内置了一个供测温使用的内部温度传感器及低侧开关用于热电偶冷端补偿时关断和切换信号非常方便。最关键的它直接集成了UART接口这意味着只用两根线就能完成通信分布式测温或者布线较长的场景下抗干扰和接线的便利性都比SPI强不少。Delta-Sigma ADC的精度来源和SAR完全不同。它不做逐次逼近而是以很高的速率对输入信号采样再通过数字滤波器把带内噪声整形掉输出一个高分辨率的码值。这个过程换来了极低的噪声和极高的有效分辨率代价是单次转换时间较长——ADS122U04在20SPS数据速率下单次转换约50ms但这对温度信号来说完全不是问题温度本身变化就是慢的咱要的就是稳定和精度不是速度。20SPS下24位输出码中有效分辨率大约19位对应PT100测温时分辨率可以到0.003℃级别这个数字对任何HVAC或者工业控温场景都绰绰有余。有人说既然MCU内置ADC够用为什么还要外置实际上工业现场的温度传感器往往远离控制板信号线长、环境干扰多内置ADC的模拟前端结构简单没有电流源也没有完善的断线检测一旦传感器引线氧化或断线系统只能给出一个毫无意义的满量程读数。ADS122U04这类专用ADC把传感器激励、放大、转换、通信整合在一起电路复杂度大幅下降而且可以通过配置寄存器快速切换传感器类型适配不同项目时灵活很多。2. 硬件设计RTD和热电偶与ADS122U04的实际接入2.1 RTD的三种接线方式怎么选RTD有2线、3线、4线三种接法我全部在板子上验证过在这里说清楚差异。2线制最简单两根线直接接到RTD两端IDAC电流源提供激励电流测量RTD上的电压。缺点非常明显导线本身有电阻如果传感器装在几十米外导线电阻可能有5~10Ω对应的温度误差直接就是十几摄氏度完全不可用。做HVAC项目时传感器线短比如1米以内2线还能凑合工业现场千万别这么干。3线制是工业现场最常用的折中方案。RTD一端接一根线另一端接两根线利用IDAC1和IDAC2分别提供电流流过RTD通过测量通道分别采集两个回路的电压在软件里做差可以把引线电阻的大部分误差消掉。前提是三根线线阻一致常规的三芯屏蔽线完全满足。我在项目里用的就是这个方案实测在30米线缆下测温误差能控制在±0.1℃以内前提是做好屏蔽层单端接地信号质量才有保证。4线制最彻底两根线用于激励电流两根线用于测量电压测量回路几乎不流过电流所以线阻对测量完全零影响但要多布一根线成本略高。需要长线高精度测量的场合可以选。ADS122U04的IMUX寄存器支持把IDAC1和IDAC2分别路由到任意AIN引脚这意味着4线制连接也不需要额外外围器件直接在配置里改通道映射就行硬件上非常省事。2.2 比例法测PT100激励电流与参考电阻的参数匹配ADS122U04支持比例式RTD测量这是我强烈推荐的方式。电路结构是这样的IDAC输出恒流流过RTD和精密参考电阻Rref两次测量分别得到RTD上的电压Vrtd和Rref上的电压Vref。把外部参考电阻接到REFP和REFN引脚ADC的转换结果以Vref为基准最终RTD电阻等于Rref乘以Vrtd/Vref的比值。这样做的好处是IDAC电流的温漂、电源电压的波动都会被比例运算消掉不需要用绝对参考电压省掉一颗高精度基准芯片的成本。我给PT100选用的参数组合IDAC电流0.5mARref选择2.05kΩPGA增益8倍。这样Vref0.5mA×2.05kΩ1.025VPGA增益8倍时满量程差分输入为1.025V/8≈128mV。PT100在400℃时电阻约247Ω0.5mA电流下信号电压只有123.5mV离满量程还有4%左右的余量既不会削波也不会浪费分辨率。这里有个关键点如果量程扩大或者缩小增益和IDAC参数要重新匹配原则是让最大测量温度对应的信号电压不超满量程同时尽量让信号在量程内占满ADC的输入范围用足有效位数。我实际调参时试过IDAC1mA加Rref2.05kΩVref达到2.05VPGA增益8倍时满量程变成256mV看似量程更大但PT100在800℃时信号电压超过195mV依然在范围里这样的配置也没问题只是PT100自热效应更明显。PT100这类铂电阻在三五毫安的电流下就会因为自热产生附加温度误差所以保守起见我都用0.5mA精度和自热之间取一个平衡。Rref的温漂系数尽量选低25ppm级别的就可以比例法虽然不敏感于Rref的绝对值误差但它会直接影响参考电压的稳定性和ADC的标度因子温漂还是要在可控范围内。2.3 热电偶测量与冷端补偿的电路要点热电偶的难点在于冷端补偿。热电偶测的是热端和冷端的温差电势冷端温度一变读数跟着变如果不做补偿测量结果在环境温度变化时漂得没法看。ADS122U04内部自带温度传感器可以读取芯片结温把它当作冷端温度。把热电偶接到模拟输入通道比如AIN0接正极、AIN1接负极同时把芯片放在靠近热电偶接线端子的位置让冷端温度尽量接近芯片结温这样补偿才准。热电偶信号是毫伏级K型热电偶在1000℃时约41mVADS122U04的PGA增益设32倍比较合适。如果用内部2.048V参考增益32时满量程输入约64mV既覆盖K型热电偶全量程最高约55mV又保留了足够的余量分辨率也够。软件上读取热电偶电压后再读芯片内部温度作为冷端温度查找热电偶分度表得到冷端对应的等效电动势加到测量电压上再反查热端温度。这一套流程ADS122U04的数据手册里有公式TI也提供了NIST多项式系数直接拿过来用就可以。2.4 供电和PCB布局的实战建议ADS122U04的模拟供电AVDD和数字供电DVDD需要单独去耦至少每个引脚一颗1μF陶瓷电容靠近引脚放置另外在电源入口再加一颗10μF电解电容吸收低频波动。STM32F334R8的参考地必须和ADC的地星形连接避免数字噪声通过地平面串到模拟电路。模拟输入端的RC滤波也要加R取100ΩC取1nF转折频率约1.6MHz能滤掉大部分高频干扰又不影响温度信号的幅值。电源方案上我建议AVDD和DVDD都从3.3V线性稳压器输出但中间加一个磁珠或一个小电阻分隔开防止MCU的数字开关噪声污染ADC的模拟电源。ADS122U04在UART通信时会产生一定的数字开关噪声这个噪声如果耦合到模拟输入显示的读数就会在最后几位上跳动。按上述方式分电源、分地方案做下来的板子我实测在电源纹波±30mV的恶劣输入下温度读数波动不超过0.02℃比共用一个电源时明显稳定。3. 基于STM32F334R8的软件实现3.1 UART通信与DRDY中断的正确处理我第一次用ADS122U04时在通信上卡了整整一下午原因说出来很丢人这颗芯片上电后默认波特率是9600而我初始化STM32的USART时习惯性写了115200怎么发命令都没应答最后查资料才反应过来。所以第一步一定要把USART配成9600、8位数据位、无校验、1位停止位等芯片正常通信后再考虑提高波特率。ADS122U04支持最高4Mbps但实际做温度采集时通信量不大9600完全够用低速换来的抗干扰能力反而更适合工业现场。DRDY引脚的处理也很关键。这颗芯片转换完成后会把DRDY拉低我在代码里用外部中断检测这个边沿而不是轮询。轮询的问题在于如果主循环里还有其他耗时操作比如处理PID算法或者刷新LCD很容易漏掉DRDY的瞬间变化导致丢失数据或者重复读取旧数据。把DRDY接到STM32的一个GPIO外部中断引脚下降沿触发在中断服务函数里只置一个标志位主循环检测到标志后再启动RDATA读取逻辑干净也不会因为中断处理太长影响其他实时任务。3.2 寄存器配置的完整代码解析ADS122U04共有6个寄存器全部8位初始化时通过WREG命令一次性写入。WREG命令的格式是命令字节后紧跟数据字节命令字节的构造规则是0x40加上起始寄存器地址左移2位再加上寄存器数量减1。因为要从寄存器0写6个寄存器所以命令字节是0x45。下面是我在项目里实际用的初始化代码uint8_t regs[6]; // reg0: AIN0与AIN1组成差分测量通道参考电压选择外部REFP/REFN // reg1: PGA增益8正常滤波器 // reg2: 数据速率20SPS连续转换模式 // reg3: IDAC电流0.5mA低侧开关关闭 // reg4: IDAC1输出到AIN2IDAC2输出到AIN3 // reg5: 禁止比较器数据格式有符号24位 regs[0] 0x01; regs[1] 0x03; regs[2] 0x00; regs[3] 0x01; regs[4] 0x3C; regs[5] 0x00; uint8_t wreg_cmd[7]; wreg_cmd[0] 0x45; // 写寄存器从寄存器0开始共6个 memcpy(wreg_cmd[1], regs, 6); HAL_UART_Transmit(huart1, wreg_cmd, 7, 100); HAL_Delay(10); // 等待寄存器写入完成 uint8_t start_cmd 0x08; // START命令 HAL_UART_Transmit(huart1, start_cmd, 1, 100);这里有个UART时序的细节WREG命令的所有字节之间必须保持一定间隔不能像普通UART发送那样连续无间隔地把7个字节一口气打完否则ADS122U04把后续数据当作新命令处理。我给每个字节之间加了约100μs的延时实测很稳。如果你用的是DMA加环形缓冲区也要在软件上保证帧间隔这一点最容易踩坑。读取转换结果的RDATA命令时序也类似uint8_t rdata_cmd 0x10; uint8_t raw[3]; HAL_UART_Transmit(huart1, rdata_cmd, 1, 10); HAL_UART_Receive(huart1, raw, 3, 100); // 将3字节拼接成有符号24位整数 int32_t code (raw[0] 16) | (raw[1] 8) | raw[2]; if (code 0x800000) { code | 0xFF000000; // 符号扩展 } float ratio (float)code / 8388608.0f; // 除以2^23 float r_rtd ratio * REF_RESISTOR;这里的REF_RESISTOR是我们硬件上选的2.05kΩ精密电阻ratio就是ADC码值与参考电压的比值。STM32F334R8带FPU这些浮点计算开销极小一次温度换算是微秒级完全不用担心性能。3.3 RTD温度换算从原始码到摄氏度拿到RTD电阻值后下一步就是把它换算成温度。PT100的电阻-温度关系在0℃以上可以用简化二次方程描述Rt R0 × (1 A×t B×t²)其中A3.9083×10⁻³B-5.775×10⁻⁷。这是一个标准二次方程用求根公式可以直接解出温度tfloat pt100_res_to_temp(float r) { float r0 100.0f; float A 3.9083e-3f; float B -5.775e-7f; float delta (r / r0 - 1.0f); float disc A * A - 4.0f * B * (-delta); if (disc 0.0f) return -999.0f; // 输入非法 float t (-A sqrtf(disc)) / (2.0f * B); return t; }注意这个公式在0℃以上精度足够0℃以下因为材料特性变得更复杂需要用包含C系数的三次方程。我在HVAC项目里基本都在0℃以上工作用二次方程就够了。如果做冷库或者低温工业设备建议把Callendar-Van Dusen完整公式实现进去或者直接用查表法。另外一个常见的坑是比例法计算时浮点运算带来的温度毛刺。我做了一批连续测温数据发现偶尔会出现一个跳变0.1℃的野值排查后发现是ADC码值低位数位的随机抖动在低温度段放大了相对误差。解决办法是加一个简单的一阶低通滤波比如filtered filtered (new - filtered) * 0.2或者取连续4次采样的中位值。温度信号本来就慢滤波不会损失有效响应速度但能显著提升数字的稳定性。3.4 热电偶查表与多项式换算热电偶的温度换算是另一种玩法。标准做法是先根据测量电压和冷端温度计算出热端电动势再用分度表反查温度。ADS122U04内部温度传感器可以直接读到芯片结温但我建议在冷端补偿的精度要求超过±1℃时在冷端位置外接一个NTC或PT100做更准的冷端测量因为芯片结温和实际连接器端子温度之间还是有几度的差值这个差值最终会直接变成测量误差。分度表查表法适合任何类型的热电偶代码结构简单把NIST分度表按温度步长存储温度换算时先在表中找到电压所在区间再线性插值。K型热电偶从-200℃到1370℃如果按5℃一个间隔存大约315个点每个点存一个浮点值约1.2KBSTM32F334R8的64KB Flash完全放得下。如果不想维护查表也可以直接用NIST提供的逆函数多项式系数一组多项式就能在-200℃到1370℃范围内把电压换成温度拟合误差小于0.05℃比查表还节省存储空间。我在代码里选了多项式法因为它代码短而且没有插值毛刺。TI的手册和网上开源的coefficient文件都是现成的直接用就行但要注意热电偶分度表每个温度区间的系数不同代码里一定要做温度区间的正确选择我刚开始就是忽略了低温区间和高温区间用错了多项式结果在500℃以上出现了明显的非线性偏差折腾半天才排查出来。4. 实测数据、精度标定与问题排查4.1 实验室实测数据与精度评估我在实验室用恒温槽和六位半万用表做了比对测试了PT100在0℃到150℃范围内的表现也让整个系统连续跑了一个月的老化测试。0℃时用冰水混合物系统读数在-0.03℃到0.02℃之间跳动50℃时恒温槽设定值与系统读数相差0.04℃100℃时误差0.08℃150℃时误差0.12℃。误差随温度升高而增大这个趋势说明有很大一部分误差来自PT100的非线性和我用的简化二次方程在高温端精度下降而不是ADC本身的能力限制。对HVAC应用来说±0.1℃精度已经算很奢侈但工业加热设备要求高我这边又做了一步优化在软件里加了两点标定。用精密电阻箱模拟PT100在0℃和100℃的阻值采集对应的ADC原始码算出每路的零点偏移和增益系数然后对测量结果做线性修正。标定之后实测在0~300℃范围内误差可以保持在±0.05℃以内这个水平对于绝大多数控温场景都够用了。标定要注意的一点是必须在系统完成所有滤波和换算之后做标定数据只对同一套软硬件有效。如果改了PGA增益、换了参考电阻或者改了采样速率标定系数要重新计算因为这些参数的改变会影响ADC码位和温度换算的比例因子。另外PT100传感器本身也有误差等级Class A的PT100允许±(0.150.002×|t|)℃的偏差所以系统标定前的传感器固有误差要先测出来不然标定的意义就被传感器误差吃掉了。4.2 现场干扰的解决实录现场干扰是我这次遇到的最大问题。最初的板子和现场设备共地电机一启动读出的温度值直接跳了2℃持续一两秒才恢复。排查过程很有意思我把示波器探头直接点在ADC输入脚上看到的是正常的毫伏级信号但温度数据就是跳说明干扰不是直接从输入进来而是通过地线耦合的。电机启动时大电流在公共地上造成电压差这个电压差直接抬高了ADC的模拟地参考点相当于在差分输入上加了一个共模电压虽然ADC对共模有一定抑制能力但PGA高增益下共模抑制比急速下降最终表现在数据上就是大幅跳变。解决的办法做了三层。第一层在模拟输入前端加RC低通滤波R100Ω、C1nF把高频干扰挡在外面第二层把模拟地和数字地分开铺铜最后在电源入口处单点汇合切断MCU数字电路和ADC模拟电路之间的地环路第三层最彻底在MCU和ADS122U04之间加了数字隔离器UART信号通过隔离器后地环路被物理切断。实测这三层全部实施后电机频繁启停现场连续运行一周温度读数纹丝不动只在数据末尾一位跳动相当于0.005℃的对地噪声水平。4.3 常见问题速查表这里整理我在实际调试过程中遇到的一些典型问题都带着血泪教训问题现象可能原因处理办法温度读数一直满量程传感器接反或断路IDAC电流没建立检查RTD两端是否有电流确认传感器接线极性读数随电源电压变化用了绝对电压方式而不是比例方式改成Rref比例接线法参考电压接REFP/REFN读数跳动超过0.5℃干扰严重或PGA增益过高加RC滤波降低增益并增大IDAC电流重新匹配通信失败DRDY永不拉低START命令未发、波特率不匹配确认初始化用9600波特率发送START命令热电偶读数在室温附近漂移冷端补偿没做或冷端温度不准开启内部温度传感器并做补偿让芯片靠近接线端子多路传感器读数互相干扰IDAC电流源配置了同一个输出引脚检查IMUX寄存器避免两个电流源共用通道最后一条坑最深。我当时配了4路传感器通道A的读数变化会带动通道B跟着变折腾了好久最后拿万用表量引脚电流才发现是IMUX寄存器把两个IDAC都配置到了同一个输出引脚两个通道的激励电流串在一起了。这类配置问题在数据手册里写得很清楚但没实际遇到之前根本想不到会这么巧。4.4 芯片选型的横向对比与扩展建议如果你的项目是HVAC控制器传感器数量2~4路成本敏感ADS122U04加STM32F334R8是一个非常合适的组合。前者一颗就能接多路RTD后者浮点运算能力强做PID控制和变频输出都富余。但如果需要同时采集几十路温度比如大型楼宇自控系统一颗只有4个模拟输入明显不够建议用多片ADS122U04挂同一组UART总线半双工模式下支持多设备寻址或者用模拟开关扩展输入。横向来看ADS122U04同系列还有不带UART的ADS1220引脚兼容但接口是SPI如果MCU的SPI空闲用SPI版本可能更方便更高端的ADS125系是24位带SPI的但多通道配置复杂不适合简单测温。ADS122U04的优势恰恰在于内置IDAC和UART两颗芯片加几个无源器件就是一套完整的测温前端无需任何外部放大器或基准对中小型项目的开发效率提升非常明显。STM32F334R8这边同系列F334有两种Flash容量R8是64KBR6是32KB如果你的代码里还要加Modbus协议栈和显示驱动建议直接选R8省得后面挤Flash。它和F301、F302系列的引脚不是完全兼容的替换时不能盲目套原理图特别是高分辨率定时器的引脚映射要重新核对这个我有过惨痛教训。以我这些年的习惯温度采集系统的设计要把可靠性放在第一位其次才是成本和精度。ADS122U04配上STM32F334R8这套方案最大的感受是省心——模拟前端的坑大部分被这颗ADC挡掉了而MCU又留下了足够的算力和外设余量。最后分享一个小技巧到量程边界时不要一味靠增大PGA增益去追分辨率因为噪声和信号是一起放大的不如把激励电流和参考电阻重新匹配让信号尽量占满ADC的输入范围这样既稳又准。温度测量没有太多花活把比例测量、冷端补偿、滤波布线和标定这几件事做扎实现场基本不会出大问题。