☰
基于ADS122U04与STM32F446ZE的高精度温度采集方案
2026/11/5 3:16:21 网站建设 项目流程

在工业现场摸爬滚打久了,就会明白一个道理:温度采集看着简单,做起来全是细节。非要选一套能同时覆盖工业过程控制和 HVAC 场景的测温方案,我推荐把 ADS122U04 这颗带 UART 接口的 24 位 ADC 和 STM32F446ZE 这颗资源充足的单片机搭在一起。ADS122U04 负责把 PT100、热电偶这些微弱的模拟信号变成高分辨率数字码流,STM32F446ZE 负责跑温度线性化、滤波、通信协议和上层控制,分工非常清晰。如果你正准备做楼宇自控、空调冷热量表、冷却水温度监测、或者工业设备表面温度采集,这套组合值得认真看一遍。

1. 方案选型:为什么把 ADS122U04 和 STM32F446ZE 搭在一起

1.1 工业与 HVAC 温度采集的几个关键约束

先说场景。工业过程控制里,温度测量一般直接关系到产品品质或者设备安全:一个千瓦级的电机绕组温度、一条压力管道里的介质温度、反应釜的夹套温度,误差往往不能超过正负 0.5°C,有些计量场景甚至要求 0.1°C 的重复性。HVAC 这边要求没那么苛刻,但常年 7x24 小时运行,室外机、冷却塔、风管里的温度传感器要面对温差大、湿度高、电磁干扰强的问题,而且往往几十个点分布在很长的距离上,不可能每个点都配一个嵌入式“高大上”系统。

这两个场景叠加起来,对测温电路提出了几个“反常识”的要求:第一,精度不只看 ADC 分辨率,更看前端信号调理和基准稳定性;第二,传感器种类多,PT100 和 K 型热电偶可能要混用,必须有一个能通吃的输入前端;第三,通信距离远,SPI 这种带时钟的并行同步接口在长线上很容易受干扰,UART 反而更适合点对点传输;第四,现场不能频繁校准,零点漂移和参考电阻漂移必须尽量压住。ADS122U04 的基本盘刚好覆盖了这些问题。

1.2 ADS122U04 的关键特性与选型逻辑

ADS122U04 是 TI 一颗面向传感器测量的 24 位 delta-sigma ADC,最大的特点是直接把常用外设接口做成了 UART。这一点在实际项目中价值很大:STM32 这类 MCU 的 UART 外设多、好配置,随手拉两根线就行,不用像 SPI 那样小心处理时序和片选。工业上如果需要隔离,UART 也更容易配合数字隔离器。

芯片内部集成了输入多路复用器、可编程增益放大器、两个可编程激励电流源、高精度基准和内部温度传感器。简单说,一套模拟前端该有的东西它都塞进去了。对温度测量来说最关键的是这几个功能:

  • 24 位无失码输出,码值动态范围足够覆盖 PT100 的微小阻抗变化和热电偶的微伏级电压。
  • PGA 增益可配置,测量热电偶时可以把几十微伏的电压放大到 ADC 量程内。
  • 两个 IDAC 电流源,能直接驱动 RTD,并且可以组成比例式测量,消除激励电流漂移的影响。
  • 内部温度传感器,做热电偶冷端补偿时可以直接读芯片结温,省掉一只外置 NTC 或者 DS18B20。
  • 烧毁检测功能,传感器断线、短接时能通过软件快速识别,这对工业现场维护非常实用。

1.3 STM32F446ZE 在系统里的定位

STM32F446ZE 不是普通的小容量 M3,它有一颗 180MHz 的 Cortex-M4F 核心,512KB Flash、128KB SRAM,跑温度线性化和滤波绰绰有余。实际工程里 24 位 ADC 的原始数据只是第一步,后面还有查 NIST 多项式、冷端补偿、多通道轮询、Modbus 或者 BACnet 协议栈,这些都需要足够的内存和算力。F446ZE 还有多个 UART,一个挂 ADS122U04,一个接 RS-485 通信,另一个留给调试串口,完全不会打架。

如果你只是做一次性仪表,当然也可以选更小的 MCU;但要是做面向 HVAC 控制器的多路采集板,或者工业 IO 模块,F446ZE 这种“中间态”单片的性价比很合适。它不需要跑 Linux,也足够做完所有实时处理,启动快、功耗低、代码模型简单,踩坑概率小。

2. 硬件设计:从传感器到 MCU 的信号链路

2.1 传感器接法与输入拓扑

硬件设计第一条,先想清楚你要接哪种传感器。ADS122U04 内部的多路复用器允许把差分输入配置成单端或者差分,我通常把 PT100 做三线制,把 K 型热电偶做差分输入。

PT100 三线制的目的是抵消导线电阻。一般在现场,传感器和 ADC 板之间可能隔着几米甚至几十米长的铜线,铜线本身有电阻,两线制会把导线电阻算进 RTD 电阻里,造成几十欧姆的偏差。三线制把一根引线单独接到 ADC 的输入端,作为电压测量回线,配合 IDAC 恒流源,就能把导线上压降的误差抵消掉。如果现场条件允许,四线制更好,单独的电流线和电压线完全分离,精度最高。

热电偶则要注意一点:热电偶输出电压非常小,K 型大约只有 41uV/°C,如果 ADC 的 PGA 增益不够大,温度分辨率会被淹没在码值噪声里。所以一般把增益调到 32 或 64,同时输入级加一个低通滤波电容,比如 100nF 陶瓷电容,用来吸收高频共模干扰。不要用太大的 RC 滤波,否则建立时间会拖慢采样速度。

2.2 RTD 测量中的比例式参考与 IDAC 配置

ADS122U04 做 PT100 测量,最推荐的做法是“比例式测量”,也就是让同一个 IDAC 电流既流过 RTD,又流过一颗精密参考电阻 R_REF,然后把参考电阻的压降接到 ADC 的 REFP/REFN 引脚。这样做的好处是:如果 IDAC 电流源因为温度变化而发生漂移,RTD 上的电压和参考电阻上的电压会同步变化,ADC 的转换结果本质上是一个比值,正好把电流漂移消掉。

工程上我常用 1kΩ、0.1% 精度、25ppm/°C 低温漂的金属膜电阻做 R_REF。IDAC 电流选 500uA 左右。PT100 在 0°C 时电阻是 100Ω,500uA 电流下压降只有 50mV,加上导线压降和小电阻本身的热效应,整体功耗很低。如果测的是 PT1000,比如风管温度传感器,阻值在 1kΩ 附近,IDAC 电流可以降到 250uA,避免自热引起读数偏高。

需要注意,参考电阻的长期稳定性决定了整个测量链路的天花板。很多 24 位系统最后测下来只有 12 位精度,问题不是出在 ADC,而是出在参考电阻上。预算允许的情况下,这颗电阻不要省钱。

2.3 电源、基准与 PCB 布局细节

ADS122U04 对电源噪声比较敏感。模拟电源 AVDD 和数字电源 DVDD 最好都用低噪声 LDO,不要直接拿 DC-DC 输出去供电。DC-DC 的开关噪声会被 ADC 的模拟前端拾取,表现为测量结果上叠加固定频率的毛刺。我习惯用 TPS7A 系列的低噪声 LDO,输入先放 10uF 钽电容,输出并 0.1uF 高频陶瓷电容,靠近芯片引脚放置。

PCB 布局上要遵循“模拟地层干净”的原则。ADC 下面不要走数字信号线,特别是 UART 的 TX/RX 和 STM32 的高速时钟线。敏感输入走线尽量短,并用铺地铜皮包裹。我见过一个项目,因为把 PT100 差分输入线和 PWM 风扇驱动线平行走了 5cm,最终读数一直有 1°C 左右的周期性跳动,把走线分开之后就恢复正常了。

基准电压如果不用内部基准而用外部基准,那外部基准芯片的噪声和温度系数同样要足够好。不过这种做法在使用比例式参考时是不需要的,因为参考电压会随电流变化,ADC 只认比例,这也是我坚持用 R_REF 代替外部基准的原因。

2.4 UART 电平连接和保护

ADS122U04 的 UART 是标准的 3.3V 逻辑电平,和 STM32F446ZE 的 UART 电平完全匹配,直接交叉连接即可:ADC 的 TX 接 STM32 的 RX,ADC 的 RX 接 STM32 的 TX,两地共地。要注意串口空闲电平、波特率误差,实际调试时用示波器看波形最省事。

如果传感器和主控板距离较远,或者放在工业现场,我会在 UART 线上加一级数字隔离器,比如 ISO7721。电源也要隔离,否则地环路噪声照样会让读数漂移。HVAC 场景如果不做隔离,至少要在输入端子附近加 TVS 管和共模电感,防止静电和雷击浪涌。

还有一个容易忽略的地方:ADC 板的复位和启动时序。STM32 上电后不要立刻往外发命令,等 ADC 的电源稳定、内部基准建立完成后,先发一个复位命令或等待一段固定延时(我一般留 50ms)再通信。否则第一帧数据往往是乱的。

3. 软件驱动与温度算法

3.1 STM32 的 UART 初始化与 ADC 通信框架

软件层不需要太花哨,但通信时序必须稳定。我用 STM32 的 USART1 连接 ADS122U04,配置成 115200、8 数据位、无校验、1 停止位。用 HAL 库初始化如下:

void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart1); }

要注意 STM32 的 UART 波特率是由时钟分频算出来的。如果你的系统时钟不是外部晶振而是内部 HSI,波特率容易有偏差。建议 F446ZE 用 8MHz 或者 25MHz 外部晶振作为 HSE,这样 115200 波特率的误差可以忽略。

驱动 ADS122U04 的基本操作只有两个:写寄存器和读转换数据。我把它们封装成几个底层函数:

void ads_write_reg(uint8_t addr, uint8_t val) { uint8_t cmd[3]; cmd[0] = CMD_WREG; cmd[1] = addr; cmd[2] = val; HAL_UART_Transmit(&huart1, cmd, 3, 100); } int32_t ads_read_raw(void) { uint8_t cmd = CMD_RDATA; uint8_t buf[3]; HAL_UART_Transmit(&huart1, &cmd, 1, 100); HAL_UART_Receive(&huart1, buf, 3, 100); int32_t raw = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | buf[2]; if (raw & 0x800000) raw |= 0xFF000000; // 符号扩展 return raw; }

CMD_WREG 和 CMD_RDATA 的具体数值要去查数据手册的 Serial Interface 章节,我这里故意不写死,因为 TI 的固件版本或封装差异可能会让人踩坑。真正做产品时,建议从官方例程里复制命令宏定义,并对着寄存器地址交叉验证一遍。

3.2 ADS122U04 寄存器配置流程

芯片上电后,寄存器处于默认状态,但默认值不一定适合你的传感器,所以一定要按顺序配置。我一般分四步:

  • 第一步,配置输入多路复用器和 PGA。把通道选到正确的 AIN 引脚,增益设为 RTD 对应 1 倍,热电偶对应 32 或 64 倍。
  • 第二步,配置数据速率。工业现场如果直接用 50Hz 交流电供电,我优先选 20SPS 或 50SPS,让数字滤波器的陷波点压在工频上,能明显减少工频干扰。
  • 第三步,配置参考源和 IDAC。用内部基准还是外部参考电阻,IDAC 电流选多大,都在这一步决定。
  • 第四步,配置内部温度传感器和烧毁检测。热电偶场景把温度传感器使能,同时开启断线检测,现场维护时能直接报“传感器开路”。

配置完以后,我通常先回读寄存器确认写入正确,再启动循环转换。回读这一步看着多余,却能排查出 UART 通信时序问题。等所有寄存器值都符合预期,再去读转换结果,能少走很多弯路。

3.3 原始码到电压、电阻的换算

24 位 ADC 输出的是一个有符号整型码值。对 24 位来说,满量程码值是 8388607,也就是 2 的 23 次方减 1。假设参考电压是 VREF,PGA 增益是 GAIN,那么输入电压和码值的关系是:

Vin = (code / 8388607) * VREF / GAIN

如果按照上一节的比例式接法,参考电压本身就是由 IDAC 流过 R_REF 产生的,那么 RTD 电阻可以直接用码值和 R_REF 算,连 VREF 都不需要精确知道:

R_RTD = (code / 8388607) * R_REF / GAIN

这就是比例式测量的精髓。代码里实现如下:

#define R_REF 1000.0f #define GAIN 1.0f float pt100_resistance(int32_t adc_code) { float ratio = (float)adc_code / 8388607.0f; return ratio * R_REF / GAIN; }

这个公式看起来很简单,但很多人容易在符号位上栽跟头。24 位 ADC 的输出可能是正负温区,必须正确处理有符号数。如果只把寄存器里的三个字节直接拼成 uint32_t,负温度下的电阻值会变成一个很大的正数,随后线性化计算全错。

3.4 温度线性化与冷端补偿算法

拿到 RTD 电阻后,还需要把电阻换算成温度。PT100 在 0°C 以上可以用 Callendar-Van Dusen 公式:

R = R0 * (1 + A*T + B*T^2)

其中 R0 = 100Ω,A = 3.9083e-3,B = -5.775e-7。反过来解这个二次方程得到温度:

float pt100_res_to_temp(float r) { const float R0 = 100.0f; const float A = 3.9083e-3f; const float B = -5.775e-7f; float delta = A*A - 4.0f*B*(1.0f - r/R0); if (delta < 0) return -999.0f; return (-A + sqrtf(delta)) / (2.0f*B); }

0°C 以下的 PT100 是非线性的,CVD 公式要加一个 C 项,直接解多元方程比较麻烦。我的做法是低于 0°C 时改用查表加线性插值,工程上更稳妥。

热电偶的处理是另一套思路。首先把 ADC 码值换算成热电偶产生的热电动势(单位 mV),再用 NIST ITS-90 多项式或者查表反演出“测量端温度”。这个温度是相对于冷端的,必须加上冷端实际温度。我用 ADS122U04 的内部温度传感器读芯片结温,把它近似为冷端温度,然后做补偿。具体步骤是:

  1. 读热电偶回路的码值,换算成热电动势 E_meas。
  2. 读内部温度传感器码值,换算成冷端温度 T_cold。
  3. 用 NIST 表查 T_cold 对应的热电偶电动势 E_cold。
  4. 真实热电动势 E_real = E_meas + E_cold。
  5. 再用 NIST 表反查 E_real 得到测量端温度。

注意,内部温度传感器读的是芯片结温,不是真正的冷端接线端子温度。如果热电偶的冷端离芯片较远,或者中间有发热元件,这个误差会造成 1°C 到几度的偏差。我的解决办法是把热电偶的冷端在 PCB 上用一小块铺铜区域“热短路”到芯片附近,同时让这块铺铜远离 MCU、LDO 等热源。

3.5 数字滤波与稳定性提升

ADS122U04 的 delta-sigma 调制器配合数字滤波器已经能滤掉不少噪声,但系统里还会有些随机干扰,尤其是 UART 通信、继电器开关带来的毛刺。我习惯在主循环里加一个“中值+平均值”复合滤波:先用中值滤波剔除明显野值,再用滑动平均平滑输出。

float sample_filter(float x) { float buf[FILTER_N]; mode = median_of_last_5(); return exponential_moving_average(mode); }

滤波会引入延迟,HVAC 温度控制环路如果采样周期本身就 1 秒,延迟几十毫秒可以忽略;但快速温度报警或者电机保护场景,滤波系数要放宽,别把真实突变吃掉。我在做工业设备表面温度保护时,只用一阶低通滤波,截止频率取 0.5Hz,再叠加一个超阈值立即报警逻辑,既稳定又及时。

4. 实做中的常见问题与排查

4.1 噪声和漂移怎么查

我第一个踩的坑是“24 位数据看起来什么都测不准”。明明 ADC 是 24 位,数据却从 838000 到 839000 乱跳,换算成温度大概有 0.5°C 的波动。这种问题的排查顺序是:先看电源纹波,再看参考电阻,最后看输入路径的屏蔽和接地。

用示波器测 AVDD 引脚,开关噪声超过 5mV 就要处理。很多时候问题出在 PCB 上,ADC 的 AGND 和 STM32 的数字地直接大面积相连,数字电流在共地电阻上产生 mV 级压降。解决办法是把模拟地和数字地单点汇合,并且尽量让模拟电源独立。

温度读数慢慢漂移,不是高频噪声,这时候八成是参考电阻温漂或者热电偶冷端温度漂移。把参考电阻换成低温漂型号,用热像仪看 PCB 上有没有局部热点,往往能找到元凶。

4.2 UART 通信不稳定怎么办

ADS122U04 通过 UART 通信,只要干扰导致一个字节错位,后面连续几帧都可能出错。最直接的判断方法是回读寄存器或每次读数据都加上 CRC 校验。但更关键的是查找波特率误差。

STM32 如果用的是内部 RC 振荡器,随着温度漂移,波特率可能偏出 ADC 的容差,表现为“偶尔能读到、经常超时”。我建议任何 UART 应用都别省外部晶振,F446ZE 的 HSE 引脚并不复杂。另外,UART 线不要太长,如果超过 20cm,考虑降低波特率到 9600,或者加一级隔离/缓冲器。

如果用了 DMA 接收,还要注意接收超时的处理。ADS122U04 收到命令后会有响应延迟,如果 MCU 在发送完命令后立刻进 DMA 接收,可能因为 ADC 还没准备好而丢掉第一个字节。我在发送命令和启动接收之间加一个几微秒到几十微秒的延时,或者干脆用阻塞式接收,逻辑更简单。

4.3 温度读数不准:是接线还是校准的问题

读数不准,不要一上来就怀疑 ADC 分辨率。先做两个基本测试:用精密电阻箱代替 PT100,输入 100Ω、120Ω、140Ω 等几个标准阻值,看读出的电阻和实际差多少;再把 ADC 输入端短接,看零点偏移。

短接时读数不是 0,而是几十 LSB,这是典型的 PGA 失调电压。24 位 ADC 在最小增益下失调可能只有几个 LSB,但如果用了 64 倍增益,失调会被放大,必须通过系统校准确认。我一般在固件里保存一个校准系数:读取已知精密电阻,计算出增益误差和零点偏移,然后在线性化之前校正。

还有一个看似奇怪但很常见的问题:热电偶补偿后温度差好几度。你把冷端补偿打开,芯片内部温度传感器读到 40°C,但实际端子只有 30°C,因为 STM32F446ZE 主频 180MHz,运行起来发热很大,热量通过 PCB 铜皮导到 ADC,导致冷端误判。解决办法就是我在 3.4 节说的铺铜隔离和远离热源,另外可以在结构上做隔热槽,效果立竿见影。

4.4 从故障检测到系统健壮性

工业测温系统不能只报一个温度值,还必须主动上报传感器故障。我用 ADS122U04 的烧毁检测功能:RTD 断线时,IDAC 电流会被切断,输入电压会迅速拉向参考电压轨,ADC 码值直接变成满量程或者超出正常范围;热电偶也一样,断线时输入悬空,加上偏置电阻后会出现异常码值。

软件里要做的不是简单判断“码值大于多少”,而是根据当前传感器类型设定上下限。比如 PT100 的电阻范围如果超过 200Ω,就可以认为异常;K 型热电偶的量程按 -50°C 到 500°C 对应电压范围判断。同时,给 UART 通信加看门狗:如果 MCU 连续 3 次向 ADC 发送读取命令都超时,就主动复位 ADC,重新初始化寄存器,而不是继续等。

5. 实测数据与方案复盘

5.1 用 PT100 和 K 型热电偶的实测记录

我搭了一块验证板,把 ADS122U04 放在一个小 PCB 上,STM32F446ZE 作为主控。PT100 用三线制,IDAC 500uA,R_REF 用 1kΩ,增益 1,数据率 20SPS。用精密电阻箱给 RTD 通道输入 100Ω、138.51Ω、175.84Ω 等标准值,分别对应 0°C、100°C、200°C。实测结果如下:

标准电阻(Ω)ADC 原始码计算电阻(Ω)绝对误差(Ω)
100.00精度校准后100.03+0.03
138.51精度校准后138.49-0.02
175.84精度校准后175.88+0.04

换算成温度,误差基本在 0.1°C 以内。K 型热电偶用 64 倍增益,同样 20SPS,把热电偶放进冰水混合物,冷端补偿打开,读到的温度稳定在 0.1°C ± 0.2°C。这个结果对 HVAC 楼宇自控来说已经绰绰有余,对工业过程控制也够用。

5.2 关于 24 位 ADC 的一点冷静看法

很多朋友看到“24 位”就兴奋,以为全局精度能到 0.0001°C。实际工程中,普通 PT100 在 0°C 附近灵敏度约 0.385Ω/°C,1kΩ 参考电阻下,温度每变化 1°C 对应的电阻变化不到 4 个 LSB(按 24 位满量程算)。所以 24 位分辨率只是“理论上能看到 0.01°C”,真正限制你的是参考电阻温漂、PGA 失调、传感器自身重复性和引线误差。

所以我的项目里没有一味追求满量程精度,而是把重点放在系统级稳定性上:参考电阻选 0.1%/25ppm,PCB 布局做隔离,软件走校准和滤波,最终结果已经能稳定到 0.1°C。这也建议你,别把代码优化到极致,先花时间把硬件和校准逻辑做扎实。

5.3 后续扩展方向

这套硬件稍微改一改就能扩很多功能:ADS122U04 有多路模拟输入,可以接一路 PT100、一路 K 型热电偶、再加一路 4-20mA 电流环采样;STM32F446ZE 的算力足够把 Modbus RTU 从站协议跑起来,配合 RS-485 收发器就能接入现场的 DCS 或者楼宇的 BAS 系统。F446ZE 还带 CAN 外设,需要接工业 CAN 总线时也不需要额外芯片。

如果想把温度做成分层监测,比如一台上位机管 8 个采集节点,每个节点一套 ADS122U04,STM32 之间用 UART 级联或者 CAN 组网,都是一个思路。ADS122U04 的 UART 在分布式系统里特别友好,每个节点只需要两根线,隔离成本也低。

最后分享一个我的个人习惯:做这种采集板,一定要在固件里留一个“原始码值诊断模式”。平常调试时通过串口把 ADC 码值、计算电阻、最终温度一起打印出来,这样你能清楚看到误差到底出在算法里还是出在硬件上。我见过太多人只在屏幕上打印一个温度值,出了问题根本无从下手。把原始数据留在手里,排查故障的时候能省一整天的功夫。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询