在做工业级温度采集的时候,很多人第一个想法就是“传感器输出接单片机ADC,读一下就好了”,但真到了HVAC这种既有精度要求又有强干扰的现场,这条路走不通。我在一套中央空调控制器项目里,最初就是用了NTC加运放的方案,结果被共模干扰和温漂折腾得够呛;后来换成ADS122U04IPWR 加 STM32F405RG的组合,测量链路才算真正稳定下来。这篇文章就把这套基于UART接口的24位ADC温度测量的完整做法,包括硬件前端、固件流程、线性化标定和抗干扰处理,整理出来供大家参考。
这套方案适合做HVAC控制器、工业数据采集模块、设备状态监测的工程师。如果你正纠结“用内置ADC简单省事,还是外挂ADC更稳”这个问题,文中也会给出我的判断依据。
1. 为什么是“ADS122U04IPWR + STM32F405RG”?温度测量不是查表那么简单
1.1 ADS122U04IPWR 到底提供了什么
ADS122U04IPWR 是 TI 的 24 位低功耗 Delta-Sigma ADC,带 UART 接口。单看型号后缀里的 U04,很多人容易把它和 SPI 接口的 ADS1220 弄混,但 U04 最大的特点就是把 SPI 换成了串口。这个差别在工程上非常实用:SPI 接线多、时序要求高,而且单片机侧还要专门腾出引脚和中断;UART 只要两根线,任何一个串口都能接,连 DMA 读取都好写得多。
芯片内部集成的东西也不少:可编程增益放大器 PGA(常见档位 1~128 倍)、两个可编程激励电流源 IDAC、内部基准、内部温度传感器,还支持 2 个差分输入或 4 个单端输入(实际接法取决于你的通道规划)。这些资源放在一起,意味着你不需要单独设计仪表放大器、恒流源和基准电路,一颗芯片就把 RTD 和热电偶的前端全包了。
对我个人来说,最看重的其实是 IDAC。PT100 这类电阻型传感器需要激励电流,之前用分立器件搭恒流源,温度一变电流就飘。ADC 自带 IDAC 后,激励源和测量通道在同一颗芯片里,配合比例测量法,整个测量链路对电源和温漂的敏感度都大幅下降。
1.2 STM32F405RG 在里面扮演什么角色
STM32F405RG 是一颗 Cortex-M4 内核的单片机,主频 168 MHz,资源非常充裕。很多人觉得测个温度用这么强的 MCU 有点浪费,但 HVAC 控制器的实际需求远不止“读温度”这一件事:要有 PID 调节阀输出,要驱动压缩机变频逻辑,要跑通信协议(Modbus、BACnet 都可能),还要带人机界面。在这种场景下,F405 的 UART、DMA、FPU 和 Flash 容量反而是刚需。
它的分工很明确:ADC 芯片负责“把模拟量变成数字量”,STM32 负责“把所有数字量变成有用的工程数据并做控制决策”。测量通路数据通过 UART 进来,MCU 侧直接 DMA 搬运,CPU 几乎不参与等待;算温度、查表、滤波、PID 这些计算则放在 FPU 上跑,整个系统响应速度很快。
1.3 为什么不用 STM32 内置 ADC
STM32F405 内部其实就有 12 位 ADC,采样率还不低,那为什么还要外挂一颗?如果你只是做一个 0.5°C 精度级别的室温检测,内置 ADC 确实能用;但工业和 HVAC 现场的要求通常更苛刻——温度分辨率要高、长期漂移要小、传感器要用 RTD 或热电偶而不是 NTC。内置 ADC 在这种场景下有几个硬伤:
- 12 位分辨率直接限制了电能分辨的温度粒度。接 PT100 时,在 0~100°C 区间大约对应 38.5Ω 电阻变化,12 位再加上参考噪声,一个 LSB 的温度当量通常超过 0.1°C,余量很小。
- 输入范围有限,内置 ADC 无法直接测毫伏级热电偶信号,你必须加外部运放放大,这又回到温漂和共模问题。
- 通道间切换串扰明显,多个传感器轮询时读数会跳。
- 无内置 PGA 和激励源,RTD 的前端电路会复杂得多。
把这些问题加在一起,你就会发现外挂一颗像 ADS122U04IPWR 这样的 ADC,不只是提升位数,而是把模拟前端的设计复杂度也一起解决了。
2. 硬件前端设计:RTD 与热电偶接入的关键细节
2.1 PT100/PT1000 的三线制与四线制接法
RTD 接法里我优先推荐四线制,精度最高。两根线给 RTD 提供激励电流,另外两根线测量电压,因为测量回路里几乎没有电流,所以导线电阻不影响读数。实际项目里如果受端子数量和线缆成本限制,三线制就必须做导线电阻抵消,最简单的工程做法是用两个 IDAC:
- IDAC1 电流流过一根励磁线进入 RTD,然后从另一根励磁线返回;
- IDAC2 输出等大电流同时流过一颗精密参考电阻 RREF;
- 测量差分电压时,RTD 上的压降和 RREF 上的压降都包含了导线电阻的影响,两路相减后导线电阻的影响就基本抵消了。
具体到 ADS122U04IPWR,通道规划可以参考这种模式:一个差分通道接 RTD 或扩展信号线,另一个差分通道接 RREF,然后通过比例公式计算 RTD 阻值。比例公式的形式是:
R_temp = (ADC_rtd_code / ADC_ref_code) × RREF
这个公式的精髓在于:只要 IDAC 是同源电流,激励电流的漂移会同时影响分子和分母,最后约掉。ADC 基准电压的漂移也不会影响比值。真正决定精度的只剩一颗电阻——RREF,所以这颗电阻必须用低温度系数精密电阻,至少 25 ppm/°C 起步,预算够就上 10 ppm 甚至 5 ppm 的金属膜电阻。
激励电流的选取也值得单独说。IDAC 大一点,RTD 上的差分信号就大,抗噪声能力强,但功耗和自热也随之上升。PT100 在 100Ω 时,IDAC 取 500 μA 的话信号只有 50 mV,配合 PGA 倍数的提升可以解决;取 1 mA 信号到 100 mV,自热在大多数散热条件下约 0.02~0.1°C。我实测下来,500 μA 是精度和自热的平衡点。如果你做的是耐热流体管道测量,散热好,可以放大到 1 mA;如果传感器贴在小体积空气腔里,还是用 250~500 μA 更稳。
2.2 热电偶接入与冷端补偿
热电偶和 RTD 是两类完全不同的传感器。K 型热电偶灵敏度大约 41 μV/°C,信号极其微弱,所以 PGA 倍数最好直接拉到 64 或 128。在内部基准 2.048V、24 位、PGA=128 的情况下,一个 LSB 对应的电压大约是 0.19 μV,理论上温度分辨率可以干到 0.005°C 级别。当然这是理想值,实际噪声会把有效位数拉下来,但至少信号的动态范围是够的。
热电偶真正的麻烦在冷端补偿。热电偶输出的电动势对应的是热端和冷端之间的温度差,你必须知道冷端温度才能算出真实温度。冷端补偿的做法分两步:一是测量冷端温度,二是把冷端温度换算成等效电动势加回去。
冷端温度怎么测?可以用一颗 NTC 或者 DS18B20 放在热电偶端子附近,也可以用 ADS122U04IPWR 内部温度传感器。内部温度传感器省事,但精度一般只有 ±2°C 量级,对冷端补偿来说会导致整体误差变大。我的做法是在主板上靠近端子位置放一颗高精度 NTC,经过三线或四点校正后,冷端误差控制在 ±0.3°C 左右,对于 K 型热电偶来说已经能保证系统整体精度在 ±1°C 以内。
信号通路设计上要注意,热电偶的输入共模电压不能随便接。很多人直接把热电偶负极接地,这在有 PGA 的 ADC 上容易出问题——输入共模太靠近负电源的时候,PGA 内部偏置点会漂移,导致增益失真。稳妥的做法是给每个模拟输入提供一个偏置电阻网络,把共模电压抬到接近电源中点,比如用两颗 100 kΩ 电阻分压,把 AIN 输入偏置到 (AVDD+AVSS)/2 附近。
2.3 输入滤波与保护电路
温度测量虽然是低频信号,但工业现场的干扰是高频为主的,所以前端必须做低通滤波。每个模拟输入串联 1 kΩ 电阻并到差分端并联一个 10 nF 电容,可以构成简单的 RC 低通滤波器,截止频率大约 8 kHz 级别,用来滤掉变频器和开关电源的骚扰。
不过这里有个坑:Sigma-Delta ADC 的输入端不是纯电阻,而是开关电容,输入阻抗是动态变化的。如果你把串联电阻加得太大,ADC 内部采样电容在转换周期内充不满,测量结果就会出现和输入电阻相关的偏置误差。所以串联电阻一般控制在几百欧到 2 kΩ 之间,再配合稍微延长一些的采样设置。
保护电路方面,开关电源、继电器触点、电机绕组引入的瞬态浪涌能直接打坏 ADC,所以输入端需要加钳位。比较常见的做法是:模拟输入串接限流电阻,然后对电源和地各接一个低漏电流的 TVS 管,或者用 BAV199 这类低漏二极管对做钳位。防止大电流灌进芯片的同时,保证常温下漏电流不引入可感知的测量误差。
3. 固件实现:UART 通信、配置流程与数据解析
3.1 ADS122U04 的 UART 通信基础
ADS122U04IPWR 的通信方式是标准的 UART 帧格式,主机是 STM32,从机是 ADC。使用 UART 的好处是两线就能跑,数据速率不需要太高,工程上常用 9600 到 115200 bps 都能正常通信,具体波特率按照数据手册要求配置。每次通信包含一个命令字节和相应的数据字节;读取转换结果时,芯片会把状态信息和 24 位 ADC 数据组成数据帧发回来。具体帧大小和字节序建议对照手册时序图确认,我在这里重点讲逻辑框架,因为不同固件版本对命令封装可能有差异。
通信配置上有一个工程细节值得注意:UART 数据位长度、校验位和停止位最好和芯片一致。ADS122U04 支持无校验模式,也可以用偶校验增强抗干扰,但一旦开启,MCU 侧也必须同步配置,否则数据完全对不上。我建议在 Modbus 和主从控制较多的 HVAC 项目里开启校验,虽然每帧多一个 bit 开销,但现场总线出现毛刺时能提前拦截一部分坏帧。
3.2 初始化流程:上电、复位、寄存器配置
ADC 初始化时序非常重要,尤其是上电后的时序。直接贴一段我常用的初始化逻辑,以 STM32 HAL 库为例:
uint8_t cmd_reset = CMD_RESET; // 复位命令,具体数值见数据手册 HAL_UART_Transmit(&huart4, &cmd_reset, 1, 100); HAL_Delay(5); uint8_t cfg[3] = {0x0?}, ; // 配置寄存器内容,按你的通道、PGA、IDAC、误差设置决定 HAL_UART_Transmit(&huart4, cfg, sizeof(cfg), 100); // 单次转换模式:发启动命令 uint8_t cmd_start = CMD_START; HAL_UART_Transmit(&huart4, &cmd_start, 1, 100);这几步看着简单,但有一个讲究:上电后先等电源稳定再发复位命令。ADS122U04 的 AVDD 如果直接从 DC-DC 输出取电,上电瞬间会有振铃,此时发复位和配置命令很容易丢失。我的做法是在硬件上加一个 RC 延时电路控制 EN,或者干脆在软件里把上电后的首个延时做到 50~100 ms,稳定之后再初始化。
寄存器配置要说清楚几个重点:
- PGA 增益:RTD 用 4~16 倍足够,热电偶用 64~128 倍。
- 数据速率:默认速率低噪声好,但 HVAC 扫描多个通道时又希望快点,实际选 20 SPS 到 100 SPS 比较合理,具体看噪声指标。
- 激励电流:RTD 场景选 500 μA 量级,热电偶场景如果不需要 IDAC,就把它关掉,避免自热和功耗浪费。
- 转换模式:我喜欢用单次转换加轮询的模式,每个通道读一次就切换,方便做多传感器扫描;连续转换模式吞吐高但要处理数据粘包,复杂度更高。
3.3 转换结果的数据处理与换算
读取数据时,STM32 通过 UART 发读取命令,从 ADS122U04 返回的是一段数据帧,其中包含状态位和 24 位转换结果。状态位里通常含有转换状态、超范围标志等,建议在代码里先检查再使用,防止异常数据进入算法。
24 位 ADC 数据是按二进制补码存储的,需要先扩成有符号 32 位整数,再按下面的公式换成电压:
int32_t code = (int32_t)((raw[0] << 16) | (raw[1] << 8) | raw[2]); if (code & 0x800000) { code |= 0xFF000000; } // 24位全量程对应 ±2.048V(内部基准) float voltage = (float)code / 8388607.0f * 2.048f / (float)PGA;如果是 RTD 比例测量,那就不需要关心绝对电压,直接把 RTD 通道的 code 和 RREF 通道的 code 做比例运算,算出来的电阻值再查表得到温度。
多通道轮询时,要注意切换到新的输入通道后,第一次转换结果里面带有前一个通道的残余影响,应该丢弃第一帧数据,从第二帧开始采。这个细节在数据手册的建立时间参数里有写,但很多人不看,实测会发现在温度突变时读数出现一个明显的“拖尾”,就是这个原因。
3.4 用 DMA 减轻 CPU 负担
既然 STM32F405 是一颗主频很高的 MCU,数据接收就不该用阻塞式等待。我建议直接用 UART + 空闲中断 + DMA 的方式接收数据帧:
HAL_UARTEx_ReceiveToIdle_DMA(&huart4, rx_buf, RX_BUF_SIZE);当一帧数据接收结束后产生空闲中断,在回调里判断帧长度、解析数据。这样主循环可以专心做滤波和控制计算,不需要不断轮询串口。对ADS122U04这种固定长度的数据帧来说,这个方法尤其合适,整帧直接进 DMA 缓冲区,拷贝一次就能解析。
我实际跑下来的情况是,ADS122U04 单次转换的吞吐量在低压状态可以达到极高的速率,虽然实际项目中 20~100 SPS 的采样率不算高,但 DMA 的方式依然值得用,因为 HVAC 整机里通常会挂多路传感器、多路开关量和多路通信任务,CPU 空闲时间永远不够用。
4. 线性化与标定:从 ADC 数值到真实温度
4.1 RTD 电阻到温度的换算
PT100 的温度-电阻关系不是完全线性的。在 0~100°C 区间,平均每摄氏度大约变化 0.385 Ω,但用这个斜率直接算,全量程误差会到零点几摄氏度,对 HVAC 控制器这种目标精度在 ±0.2°C 的系统来说不够。所以工程上一般用查表法,或者用 Callendar-Van Dusen 方程。
Callendar-Van Dusen 方程是这样的:
R(t) = R0 × [1 + A×t + B×t²],t > 0°C R(t) = R0 × [1 + A×t + B×t² + C×(t-100)×t³],t < 0°C
其中 A=3.9083×10⁻³,B=-5.775×10⁻⁷,C=-4.183×10⁻¹²,R0 是 0°C 时的标称阻值(PT100 就是 100Ω)。
从 ADC 算出的阻值反解温度时,这个方程不能直接求逆,需要用牛顿迭代法。我一般先猜一个初始温度,比如 25°C,然后不断迭代,几次循环就能收敛到 0.001°C 精度。在 STM32F405 的 FPU 上跑这个计算毫无压力,即使是多通道 RTD 轮询也完全来得及。
如果嫌迭代麻烦,也可以把 PT100 的分度表做成 1°C 间隔的查找表,再配合线性插值。表越大精度越高,但 Flash 占用也会增加。对存储容量不敏感的 F405 来说,放一个 0~200°C 的表格没问题。工业测量场景下,我两者都用:查找表用于快速出值,牛顿迭代用于对特殊温度点复核。
4.2 热电偶的查表与冷端补偿计算
热电偶的电压-温度关系用多项式表达比较繁琐,工程上更常用分度表。比如 K 型热电偶,一张 -50°C 到 500°C 的分度表,每 1°C 一个点,表格本身很小,查表加线性插值的精度完全可以满足家用和轻工业 HVAC 需求。
前面说过,热电偶测的是温差,所以冷端补偿的算法要严格按下面的顺序:
- 从 ADC 读取热电势 Vmeas。
- 读取冷端温度 Tref(NTC 或板载传感器)。
- 查表或多项式求出冷端温度对应的补偿电压 Vcom。
- 真实热端电动势 E = Vmeas + Vcom。
- 再用 E 反查温度。
这个顺序看着简单,但冷端温度某些时候变化很快,而 ADC 通道是轮询的,如果你先读热电偶电压,等几个通道扫完再读冷端温度,冷端已经变了好几度,补偿结果就会偏差。所以我的经验是:热电偶和冷端温度的读取时间间隔必须控制在极短范围内,最好在同一个采样循环里连续完成,或者使用更高频率的冷端采样。
4.3 标定实操:零点、满度和重复性
不管 RTD 还是热电偶,ADC 本身的失调和增益误差都会引入最终温度误差。芯片在出厂时有校准,但装配到板子上后,参考电阻、PCB 走线、冷端传感器的安装误差都会改变实际特性,所以整机标定是躲不过的。
我的标定流程是:
- 零点标定:把传感器探头放到恒温槽或者冰点槽里,让它稳定 15 分钟以上,记录 ADC 值,算出零点偏移系数。
- 满度标定:在 60°C 或 100°C 的干体炉里重复同样过程,算出增益修正系数。
- 中点多点验证:至少测 3 个中间温度点,检查线性度误差是否在指标内。
修正系数保存到 STM32 内部 Flash 或者外挂 EEPROM 里,每次上电加载。如果系统有多块板子,每块板的标定系数可能都不同,所以生产流程里最好为每台设备单独烧录一套校准参数。这个“组装之后必须标定”的工序很容易被开发阶段忽略,但它直接影响最终交付的精度,真正做了量产调试的工程师都懂这一步的分量。
5. HVAC 和工业现场的干扰怎么扛
5.1 干扰来源:变频器、继电器和开关电源
HVAC 系统里产生干扰的东西太多了:变频压缩机、风机电机启停、电磁阀继电器、开关电源的高频纹波。这些干扰可以分几类:
- 共模干扰:电机地线和控制板地线之间的电压差,通过传感器线缆传导到 ADC 输入端。
- 差模干扰:导线耦合的磁场和电场在两根信号线之间产生压差。
- 电源纹波:开关频率几十 kHz 的高频噪声灌进 AVDD,直接影响内部基准和 PGA。
其中共模干扰是最隐蔽的。信号线往往很长,一跟到电机旁,你的地和电机的地之间就可能出现几十伏的瞬态电压,两个输入引脚对地的共模电压都在跳。Sigma-Delta ADC 本身对共模有抑制作用,但这个抑制能力是有限度的,超出范围后转换结果会直接出现通道串扰或偏置突变。
5.2 PCB 布局与滤波的实战取舍
PCB 布局可能是成本最低但效果最明显的抗干扰手段。几个关键原则:
- 模拟区域和数字区域尽量分开,AVDD 和 DVDD 分别用 LDO 供电,两个 LDO 的输出之间加磁珠隔离。
- ADC 放在靠近传感器接线端子一侧,模拟走线要短而宽,不要在下方走数字信号线。
- RTD 和热电偶的输入走线做成差分对,两线紧贴走,减少环路面积。环路面积越大,电磁感应进来的噪声越多。
- 传感器线缆在外部用屏蔽双绞线,屏蔽层单端接地,通常是在控制板端接地,避免形成地环路电流。
在滤波方面,除了输入端 RC 滤波器,UART 信号线也建议加小型共模电感。之前遇到过一种情况:温度读数正常,但串口数据偶尔出错,用逻辑分析仪看才发现是 UART 线上被灌入了变频器的开关噪声,本来稳定的串口帧出现了毛刺。加一个共模扼流圈和 100 pF 电容,问题就消失了。
5.3 系统隔离与电源设计
如果控制板直接驱动压缩机或大功率继电器,信号地和功率地之间只靠铺铜连接是不够的。我的建议是:温度测量通道和主控制回路做电气隔离。方法上可以做数字侧隔离,用数字隔离器把 UART 信号隔开,ADC 的电源也单独用隔离式 DC-DC 供电。这样即使功率部分有瞬间高压干扰,也不会通过模拟地串进测量链路。
如果不做隔离,至少要保证单点接地:模拟地和数字地在 ADC 芯片下方一点连接,不要多点搭接到功率地。同时 AVDD 的 LDO 输入输出都要加足够容量的滤波电容,通常输入 10 μF,输出 1 μF 加 100 nF。电源纹波这个东西在万用表上不好测,但在 ADC 的转换结果里看得清清楚楚——读数最后几位一直抖,多半是电源惹的祸。
6. 实测数据与踩坑记录
6.1 实测定点效果
我在这套组合上跑过一轮比较完整的测试,传感器用的是 PT100 铂电阻,激励电流 500 μA,PGA 16 倍,数据速率 40 SPS,参考电阻 RREF 用 25 ppm/°C 精密电阻。分别在 0°C 冰水混合物、25°C 室温、60°C 恒温箱里测了长时间稳定性,典型的结果如下:
| 环境温度 | 读数均值 | 最大波动 | 备注 |
|---|---|---|---|
| 0°C | 0.02°C | ±0.05°C | 恒温后稳定 |
| 25°C | 25.06°C | ±0.08°C | 室温波动导致 |
| 60°C | 60.01°C | ±0.04°C | 恒温箱稳定后 |
这个水平对 HVAC 来说相当充裕。热电偶通道用 K 型热电偶在 100°C 干体炉里校验,全量程误差大约 ±1.0°C,瓶颈主要出在冷端补偿的 NTC 精度上,如果换更高精度的冷端传感器,还能进一步压缩。
6.2 几个真实的坑
这里面有几个坑完全是“不实测根本发现不了”的类型,值得单独说。
第一个是 IDAC 自热的问题。最开始我把激励电流设成 1.5 mA 想提高信号幅度,结果发现在空气流通差的温度传感器里,读数比实际温度偏高约 0.2°C。刚开始还以为是标定问题,后来把电流降到 500 μA,同样的环境下读数立刻降回来。自热效应不是你可以事后修正的,因为它和传感器所在介质的导热系数相关,修正系数本身就会漂。所以选激励电流宁小勿大,信号幅度不够就靠 PGA 去补。
第二个是输入共模电压。刚开始做热电偶接入时,我把负极直接接到了系统地,结果发现读数和调试台上差别很大,尤其在增益倍数高的时候。后来仔细看了一下 PGA 的输入范围,才明白共模电压太低会导致内部偏置失效。解决办法就是前面提过的用偏置电阻把共模抬高,改完之后读数立刻正常。
第三个是参考电阻的温漂。这是最容易忽略但影响最狠的。比例测量法能把 ADC 的参考和激励电流漂移都抵消掉,但 RREF 自身的温漂抵消不了。如果你用了普通厚膜电阻当 RREF,环境温度从 25°C 变到 50°C,阻值可能漂几十 ppm,对 0.1°C 精度目标来说是不可接受的。所以 RREF 一定要选精密低漂电阻,并且尽量远离功率原件和发热元件。
第四个是上电顺序。ADS122U04 如果在 AVDD 还没有完全稳定时收到配置命令,不是报错而是直接忽略,之后寄存器处于默认状态,你读到的数据全是按默认增益和通道来的,表现就是“数据没变化但就是不对”。这个现象排查起来很头疼,因为你反复发命令都觉得没问题,其实是芯片还没醒。解决就是上电后延时 100 ms 再复位,然后再写配置。
6.3 这套方案还能往哪里扩展
这套硬件和固件框架的扩展性比想象中好。同样的电路,把 RTD 通道去掉其中一路,就可以直接接入 NTC、热敏电阻或者 0~10V 传感器的分压信号,只是 PGA 和换算公式要改一下。ADC 丰富的通道数也支持同时接多路 PT100 和多路热电偶混合测量,配合轮询机制做多区温控很合适。
软件层面,F405 上的 FPU 跑 PID 和滤波算法非常顺手,后续如果要加 Modbus 从站或者云网关,直接用这颗 MCU 的 UART/USART 资源就够,不需要额外换主控。整套方案从做样板到小批量试产,大概两周就能跑通,还是很值得投入的。
如果觉得精度还不够,下一步可以做两点:一是把内部基准换成外置精密基准,进一步压低参考温漂;二是给每个传感器接入前做独立校准系数并写入 EEPROM,让系统支持“现场换探头不重新标定”。这两件事做完,这套方案基本可以往医疗级和实验室级精度靠了。