先说结论:这个标题看起来像是一串普通的元器件采购清单,但它在工业和 HVAC 行业里其实是一个很典型的测温方案缩影。ADS122U04IPWR 是 TI 一颗带 UART 接口的 24 位 Δ-Σ ADC,而 STM32F412ZG 是 ST 家的高主频 Cortex-M4 主控。把这两颗芯片搭在一起,解决的是“多通道、高精度、抗干扰、能走线传输”的温度采集难题。这篇文章就围绕这套组合,从芯片选型逻辑、硬件电路、寄存器配置、数据换算到实际踩坑,完整拆一遍。
我最早接触这个组合是在一个冷冻站的温度巡检项目上,当时要测 6 路 PT100 和 4 路 4-20mA 变送器信号,主控选的就是 STM32F412ZG,ADC 选了 ADS122U04。用下来最大的感受是:这颗 ADC 的 UART 接口在工业现场真的省了很多事,但也因为不是常见的 SPI 接口,很多人第一次调的时候会被它的命令帧格式卡住。这篇就把这些细节一次性讲透。
1. 项目拆解:为什么是 ADS122U04 配 STM32F412ZG
1.1 ADS122U04 到底是什么芯片
ADS122U04 是 TI 推出的 24 位 Δ-Σ ADC,最大的特色是集成了 UART 接口。它有 4 个差分输入通道,内部自带可编程增益放大器(PGA)、两个可配置的激励电流源(IDAC)、一个内部温度传感器、一个 2.048V 基准电压源,还带 50/60Hz 工频抑制滤波器。这些资源集成在一起,意味着做 RTD、热电偶、热敏电阻测温时,外围电路可以做得非常精简,很多时候连仪表放大器都不用外挂。
这颗芯片的封装是 TSSOP-16,IPWR 后缀代表环保无铅封装,工作温度范围覆盖 -40℃ 到 +125℃,在工业环境里属于很常规的规格。UART 接口的数据速率最高可以跑到 1Mbps,对于温度采集这种慢变量来说绰绰有余。和它长得几乎一样的还有个兄弟型号 ADS1220,区别就是 ADS1220 是 SPI 接口,ADS122U04 是 UART 接口,其他模拟前端部分基本一致。
1.2 选 UART 接口而不是 SPI,核心是传输距离和隔离
很多人不理解:为什么放着又快又简单的 SPI 不用,非要选 UART?我在实际项目里对比过后,体会非常深。SPI 是同步串行接口,需要时钟线、数据线、片选线,而且时钟线在长距离传输时很容易引入噪声和振铃,通常只能在 PCB 板级近距离通信。UART 是异步串口,只需要 TX 和 RX 两根线,配合 RS-485/RS-422 收发器,轻松就能做到几十米甚至上千米的可靠传输。
在 HVAC 和工业控制现场,温度传感器往往分布在风管、水管道、配电柜等不同位置,ADC 和主控之间经常隔着好几米甚至跨房间。用 UART 接口的 ADC,可以直接把 ADC 就近放在传感器附近,通过 RS-485 和主控通信,这样模拟信号走很短一段线,数字信号走长线,抗干扰能力完全不是一个量级。这是选型时最重要的一条理由。
1.3 STM32F412ZG 在方案里的定位
STM32F412ZG 属于 STM32F4 系列里带 ZG 后缀的型号,即 LQFP-144 封装、1MB Flash、256KB SRAM。它主频 100MHz,带 6 个 USART,其中一个 USART 可以专门挂 ADC 的 UART 接口,还有足够的定时器资源做采样节拍控制,跑 RTOS、做数据处理、驱动显示屏或触摸屏都没压力。
在这个项目里,STM32F412ZG 承担几个角色:通过 USART 和 ADS122U04 通信,发配置命令、收采样数据;执行温度换算算法(RTD 查表、热电偶冷端补偿、线性化);把结果打包成 Modbus 协议通过另一个串口传给上位机或者网关。F412ZG 的功耗比 F407 低,价格也更亲民,对这种不以浮点大运算为主的采集类项目,性能留足余量,性价比很合适。
提示:STM32F412ZG 的 USART 支持 RX 超时中断和 DMA,用 DMA 接收 ADS122U04 的数据帧,可以做到 CPU 零负担,这在多路连续采样时非常重要。
1.4 和常见替代方案的横向对比
| 方案 | 接口 | 通道数 | 分辨率 | 典型特点 | 适合场景 |
|---|---|---|---|---|---|
| ADS122U04 | UART | 4 差分/7 单端 | 24 位 | 集成 IDAC、基准、内部温度传感器 | 远程分散测温、HVAC、工业变送器 |
| ADS1220 | SPI | 4 差分/7 单端 | 24 位 | 同 ADS122U04 模拟前端,但接口为 SPI | 板级近距离多通道测温 |
| ADS1247/48 | SPI | 4/8 通道 | 24 位 | 通道数更多,寄存器更复杂 | 多通道 RTD 采集卡 |
| MAX31865 | SPI | 单通道 | 15 位 | 专为 PT100/PT1000 设计,内部自动处理 | 单路 PT100 简单测温 |
| 模拟运放+片内ADC | 模拟 | 依 MCU | 12 位 | 成本最低,精度和抗干扰差 | 对精度无要求的简单控制 |
从表格能直观看到,ADS122U04 最突出的竞争力是 UART 接口和高度集成的模拟前端。对 HVAC 这种设备分散、走线距离长的应用,它几乎是量身定做的。
2. 测量原理与关键电路设计
2.1 RTD 测温的核心是比例测量法
铂电阻 RTD(PT100/PT1000)的阻值随温度近似线性变化,测温度本质上是测电阻。但这里有个坑:直接测电阻时,ADC 的参考电压源如果有温漂,会直接折算成测量误差。所以 ADS122U04 内部采用比例测量(ratiometric)架构:激励电流源 IDAC 同时流过参考电阻和 RTD,参考电阻两端的电压作为 ADC 的参考电压,RTD 两端的电压作为输入信号。
这样做的好处是,IDAC 的电流值即使有波动,甚至电源电压有变化,参考电压和输入电压会同步变化,最后的数字输出只取决于两个电阻的比值,和绝对电流值无关。这个设计的数学表达很简洁:当选定参考电阻 R_REF 后,RTD 的阻值等于 R_REF 乘以 ADC 的数字码与满量程码的比例。温度测量精度因此核心取决于 R_REF 的精度,建议选用精度 0.1% 以下、温漂系数 TCR 小于 10ppm/℃ 的精密电阻,比如 Vishay 的 Z 箔电阻或金属箔电阻。
实操心得:我第一次做 PT100 测量时随手用了普通 0805 贴片电阻当基准,结果温度在室温附近还行,到 100℃ 时偏差能到 2℃ 以上。换成品精密电阻后,全温区误差立刻压到 0.2℃ 以内。基准电阻的钱千万不能省。
2.2 二线制、三线制还是四线制
RTD 传感器的探头本身只有几欧姆到几百欧姆,但连接导线的电阻可能就有 1-5 欧姆,这个值在 PT100 上直接对应几度的误差。所以要根据现场条件选择接线方式,这一条如果在方案设计初期没想清楚,后面再看传感器和电缆就麻烦。
二线制最简单,但导线电阻全算进测量值里,只适合导线很短、精度要求不高的场合。四线制最准,需要传感器本身带 4 根引线,用开尔文接法把电流回路和电压采样回路完全分开,工业标准实验室里基本都用四线制。三线制是工程上的折中方案,它假设两根导线的电阻相等,通过差分输入结构的共模抵消原理消掉线阻误差,是工业现场最常用的接法。
ADS122U04 支持二、三、四线制。配置四线制时,用 IDAC1 给 RTD 供电,然后用差分输入 AIN0/AIN1 测 RTD 电压,AIN2/AIN3 可以做第二路或者空闲。为了方便描述,我给出三线制接法的一个典型配置思路:IDAC1 从 AIN0 注入电流流经 RTD 后从 AIN2 回流到地,同时在 AIN2 到地的导线路径上,把第三根导线引入到 ADC 的负输入端作为补偿,这样正负输入端的线阻压降近似相等,在差模计算中被抵消。
2.3 热电偶测温的冷端补偿细节
除了 RTD,ADS122U04 还能直接接热电偶。热电偶输出的是微伏级别的电压信号,比如 K 型热电偶在常温附近灵敏度大约是 40μV/℃,如果不用 PGA 放大,这么小的信号基本淹没在噪声里。ADS122U04 内部 PGA 最高可以做到 128 倍增益,配合 24 位 Δ-Σ 调制器,可以满足 K、J、T、E 型热电偶的测量需求。
热电偶测量有个绕不开的问题:冷端补偿。热电偶产生的是热端和冷端的温差电动势,如果要测绝对温度,必须知道冷端的温度。这时候芯片内部的集成温度传感器就派上用场了。把热电偶的冷端放在 PCB 上靠近 ADC 的位置,用芯片内部的温度传感器测量冷端温度,软件里再把对应的电动势加上,就能还原出热端温度。
这里要特别提醒一个细节:冷端温度传感器测的是芯片自身的结温,而芯片结温和 PCB 上热电偶冷端的实际温度可能存在 0.5-1℃ 的偏差。为了减少这个偏差,PCB 布局时要把热电偶的冷端连接器尽量靠近芯片,同时在两者之间铺铜接地,让热量快速平衡。如果项目对精度要求很高,可以在冷端连接器旁边贴一颗高精度 NTC 或数字温度传感器,用外部测量值替代内部传感器,效果更可控。
2.4 供电、滤波与 PCB 布局注意事项
模拟前端的性能好不好,一半看芯片,一半看 PCB。ADS122U04 的数据手册里对电源和滤波有明确建议,我实际执行下来,遵守下面几条基本可以避免 90% 的噪声问题。
电源端要在 AVDD 和 DVDD 引脚就近放 0.1μF 和 1μF 的陶瓷电容,形成低阻抗去耦路径。模拟地和数字地建议单点连接,避免数字噪声窜入模拟回路。输入信号线上各串联一个 1kΩ 左右的电阻,再并联一个 1nF 的电容组成低通滤波,可以有效抑制射频干扰和工频谐波。这个 RC 滤波器的截止频率约为 160kHz,对 ADC 的采样速率不会产生明显影响,但对高频噪声的衰减非常明显。
另外,UART 的 TX/RX 走线要远离模拟输入引脚,尤其不能和 IDAC 的电流路径并行长距离走线。我遇到过一次实际案例:板子上的串口线和 RTD 输入线在 PCB 背面平行走了 4 厘米,结果采样数据里出现了一个有规律的尖峰,最后把串口线包地、模拟输入绕开才解决。这类问题在原理图上完全看不出来,只能靠布局经验规避。
3. UART 命令与寄存器配置实战
3.1 引脚定义与接线
ADS122U04 的 TSSOP-16 封装里,核心引脚包括模拟输入 AIN0-AIN3、IDAC1/IDAC2 输出、UART 通信引脚(具体标注为 TXD/RXD,兼容标准串口电平)、复位引脚 RESET、数据准备好引脚 DRDY(实际为 DRDY/DOUT 复用)以及电源引脚。
和 STM32F412ZG 连接时,直接把 ADC 的 TXD 接 MCU 的 RX,ADC 的 RXD 接 MCU 的 TX,注意这是交叉连接。DRDY 引脚接 MCU 的一个外部中断输入,用于在数据准备好时触发读取。如果现场传输距离较长,中间加 RS-485 收发器,此时要注意方向控制信号 DE/RE 的切换时序,建议在 MCU 的发送完成中断里立即拉高/拉低方向脚。
复位引脚 RESET 默认内部上拉,低电平有效。上电后为了保证状态机可靠,建议在主控初始化时先给一个低电平脉冲,宽度不小于 10μs,然后释放。实测中,如果省略这步,偶尔会出现首帧命令无响应的现象。
3.2 命令帧格式与四条核心命令
ADS122U04 的 UART 通信是基于命令帧的,而不是像 SPI 那样直接读写寄存器。每条命令由 1 个命令字节开头,部分命令附带数据字节,帧之间需要留出一定的静默时间。
命令字节的格式自己学习时容易绕,因为在不同资料里对命令的定义符号不完全一样。我这里把常用的四条列清楚:
| 命令名 | 命令字节 | 功能 |
|---|---|---|
| RDATA | 0x12 | 读取最新的转换结果,返回 3 字节数据 |
| RREG | 0x20 或 0xA0 | 读寄存器,需要指定寄存器起始地址和数量 |
| WREG | 0x40 或 0xC0 | 写寄存器,需要指定寄存器地址和数量 |
| START | 0x08 | 启动连续转换或单次转换 |
具体说 WREG 的用法:0x40 是写单个寄存器,0x60 是写两个寄存器,0x80 是写三个,0xC0 是写四个。地址通过低 6 位传入。比如写入 4 个寄存器时,首字节为 0xC0 | 起始地址(如 0x00),接着一个字节说明要写的寄存器数量减一,后面跟着每寄存器一个字节的数据。理解这个“数量减一”的规则很重要,很多初次调通的人在这里栽过跟头。
常见错误:如果这条指令该用 0xC0 写四个寄存器,误用成了 0x40,芯片只更新一个寄存器,其余寄存器停留在默认值。而且因为 MCU 端把后面的数据字节全发出去了,芯片会把它当新命令解析,严重时造成总线状态错乱。初学阶段建议先只用 RREG 回读校验。
3.3 四个核心寄存器的每一位作用
配置寄存器 0(地址 00h)主要负责输入多路选择器、PGA 增益和输入模式。其中低三位选择输入通道,中间位设置 PGA 增益(范围 1/2/4/8/16/32/64/128),最高位决定单端还是差分模式。比如我测 PT100,选择差分模式、增益 8,通道 0/1:这一个寄存器填入 0x28 即可。
配置寄存器 1(地址 01h)负责数据速率和滤波。数据速率可选 5SPS 到 1000SPS,低速率下的 50/60Hz 工频抑制滤波器效果非常好。在 HVAC 现场,电源噪声往往同时存在 50Hz 和 60Hz 分量,选择 20SPS 是最稳妥的配置,因为它在 50Hz 和 60Hz 处都有至少 80dB 的陷波深度。如果追求速度,可以选择 400SPS 或 1000SPS,但这时候需要在软件里额外加平均滤波。
配置寄存器 2(地址 02h)是基准源和 IDAC 设置。基准源选择内部 2.048V,或者外部基准(即比例测量模式)。IDAC 的电流档位可选择 50μA 到 1500μA,具体选多大取决于 RTD 的阻值和 PGA 增益。比如 PT100 在 0℃ 时是 100Ω,如果 IDAC 选 500μA,RTD 上压降是 50mV,匹配 PGA 增益 8 时,在 2.048V 基准下的满量程范围接近 256mV,能覆盖到 RTD 全温区。
配置寄存器 3(地址 03h)控制内部温度传感器、VREF 监控、GPIO 模式和掉电模式。测热电偶时,把内部温度传感器使能,利用它做冷端补偿。GPIO 模式可以根据需要配置,有的设计会把 GPIO 引脚拿来控制外围电路,比如多路开关或风扇。
3.4 上电初始化序列推荐
上电后,我推荐的初始化顺序是:先复位 RESET 引脚,等待约 2ms;然后发送 WREG 写入四个配置寄存器;紧接着发 RREG 回读校验,确保写入生效;之后根据需求发送 START 开启连续转换,或者等待 DRDY 触发单次读取。给出一个片段示例:
void ADS122U04_Init(void) { // 1. 复位 HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_RESET); HAL_Delay(1); HAL_GPIO_WritePin(RESET_GPIO_Port, RESET_Pin, GPIO_PIN_SET); HAL_Delay(2); // 2. 配置寄存器0-3 uint8_t txBuf[6]; txBuf[0] = 0xC0; // 写4个寄存器,起始地址0x00 txBuf[1] = 0x03; // 寄存器数量-1 txBuf[2] = 0x28; // REG0: 差分AIN0/AIN1, PGA=8 txBuf[3] = 0x20; // REG1: 20SPS,工频滤波最大 txBuf[4] = 0x28; // REG2: 外部基准比例模式,IDAC1=500uA txBuf[5] = 0x00; // REG3: 禁用内部温度传感器,正常模式 HAL_UART_Transmit(&huart1, txBuf, 6, 100); HAL_Delay(5); // 3. 回读校验 uint8_t cmd[2] = {0x80, 0x03}; // 读4个寄存器 HAL_UART_Transmit(&huart1, cmd, 2, 100); HAL_UART_Receive(&huart1, rxBuf, 4, 100); // 4. 启动连续转换 uint8_t start = 0x08; HAL_UART_Transmit(&huart1, &start, 1, 100); }这段代码里的寄存器值需要根据你的项目微调,但整体流程是一个可以直接用的模板。注意 REG2 中如果选择内部基准,数据手册不建议用于比例测量模式,两者不要混用。
4. 数据读取与温度换算
4.1 利用 DRDY 中断读取数据
ADS122U04 完成一次转换后,DRDY 引脚会拉低,表示数据已准备好。MCU 可以在这个下降沿触发外部中断,然后在中断里发送 RDATA 命令读取三字节结果。这样的优点是 MCU 不用轮询数据状态,采样时序完全由 ADC 内部决定,画在系统的时间线上非常干净。
需要留意的是,RDATA 读回来的是 24 位数据,要考虑符号位。ADS122U04 在配置成差分输入时,输出码是二进制补码,最高位是符号位。如果直接把它当作无符号数拿来算,负温度区域的数据会完全错乱。正确做法是先把三字节拼成一个 32 位整数,然后判断最高位是否为 1,如果为 1 就向左扩展符号位,再进行后续运算。
4.2 从原始码到电压的换算公式
ADS122U04 的输出码与输入电压的关系为:
输入电压 = 原始码 × 满量程电压 / (2^23 × PGA增益)
其中满量程电压就是基准电压。如果采用比例测量模式,基准电压等于 IDAC 电流乘以基准电阻,即 VREF = I_IDAC × R_REF。这时候把输入电压公式代入,再结合 VIN = I_IDAC × R_RTD,最终可以得到:
温度对应的 RTD 阻值 R_RTD = 原始码 × R_REF / (2^23 × PGA增益)
这个公式最重要的意义是:I_IDAC 在计算中被消掉了。也就是说 IDAC 电流的绝对值精度不影响温度结果,真正决定精度的只有 R_REF 的绝对精度和 ADC 本身的积分非线性。
验证一下量程:PT100 在 100℃ 时阻值约为 138.5Ω,如果 IDAC 为 500μA,压降 69.25mV;PGA 增益 8,等效电压 554mV,低于基准 2.048V,满量程范围内还有明显余量,说明配置合理。如果换成 PT1000,100℃ 时阻值 1385Ω,同样 IDAC 下压降 692.5mV,增益改到 4 就能覆盖。
4.3 PT100/PT1000 阻值转温度:查表与多项式
阻值转温度有两条路:查表和多项式拟合。查表适合有 Flash 资源的 MCU,把 PT100 的 IEC 60751 标准分度表按 1℃ 间隔存成一个数组,每个分度 4 字节浮点,从 -50℃ 到 200℃ 也就 1KB 左右,查表加线性插值精度可以做到 0.01℃ 以内。
多项式拟合适合不想占太多存储空间的场景。IEC 60751 标准给出了两个区间的多项式,0℃ 以下和 0℃ 以上分开计算。0℃ 到 850℃ 范围内,电阻值和温度的关系是 R = R0 × (1 + A×t + B×t²),其中 A = 3.9083e-3 /℃,B = -5.775e-7 /℃²。反过来,知道电阻 R 求温度 t,可以用求根公式:
t = (-A + sqrt(A² - 4×B×(1 - R/R0))) / (2×B)
这段数学过程在数据手册的标准库里都能找到,实际用时我推荐把几个关键温度点先对照着验证一下公式是否正确。比如 R=100Ω 时代入应该得到 0℃,R=138.5Ω 时代入应该约等于 100℃,发现对不上就检查括号和单位换算。
4.4 一个完整的取数与换算代码骨架
下面的骨架展示了从 DRDY 中断到温度值的完整链路,方便直接移植到自己的工程中:
volatile int32_t adc_raw_value = 0; volatile uint8_t data_ready_flag = 0; void EXTI_DRDY_IRQHandler(void) { uint8_t cmd = 0x12; // RDATA uint8_t rx[3]; HAL_UART_Transmit(&huart1, &cmd, 1, 10); HAL_UART_Receive(&huart1, rx, 3, 10); int32_t raw = (rx[0] << 16) | (rx[1] << 8) | rx[2]; if (raw & 0x800000) { raw |= 0xFF000000; // 符号扩展 } adc_raw_value = raw; data_ready_flag = 1; } float adc_code_to_rtd_resistance(int32_t raw) { const float R_REF = 1000.0f; // 基准电阻 1000Ω const float PGA = 8.0f; return (raw / 8388608.0f) * R_REF / PGA; } float resistance_to_temperature(float R) { float R0 = 100.0f; float A = 3.9083e-3f; float B = -5.775e-7f; float z = R / R0; float disc = A * A - 4.0f * B * (1.0f - z); if (disc < 0) return -999.0f; return (-A + sqrtf(disc)) / (2.0f * B); }这段代码的核心是先还原出原始码,再按比例关系算出电阻,最后查公式得到温度。代码里需要注意的地方是 HALUART 函数在中断里使用可能会遇到阻塞问题,在 RTOS 环境或高速采样时建议改成 DMA 接收,或者把读数据操作放到主循环里由标志位触发。
实操心得:中断里直接调 HAL_UART_Transmit 不是最好的写法,偶发情况下会阻塞中断导致 DRDY 信号丢失。我更推荐在中断里只置标志位,主循环里处理 UART 收发的方案,本质上是把串口操作移出中断上下文,可靠性高很多。
4.5 精度分析与校准方法
整个链路里的误差来源主要是基准电阻 R_REF 的初始误差、ADC 的偏移误差、增益误差,以及 PCB 上引入的热电动势。其中偏移误差可以很容易校准:把输入短接,读一次码值作为零偏,在每次换算时把它减掉。
增益误差则需要在已知电阻下校准:接一个精度 0.01% 的标准电阻,比如精确的 100Ω,读到的码值跟理论码值比较,得到一个增益校正系数。这个系数在同一个 PCB、同一颗 ADC 上是相对恒定的,但会因为温度不同而有细微漂移,高精度项目建议做两点或三点温度校准。
冷端补偿的热电偶项目里还要校准芯片内部温度传感器的读数,具体的做法是把板子放进恒温槽,读取内部温度传感器码值和外部标准温度计的差值,做成一个补偿偏移量写进 Flash。这套校准流程做完,整套系统在 -20℃ 到 150℃ 范围内做到 ±0.3℃ 的综合误差是可以实现的。
5. 实测中遇到的坑与排查技巧
5.1 典型问题速查表
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 数据始终为 0x7FFFFF 或 0x800000 | PGA 增益过高导致输入饱和,或输入接线开路 | 降低增益;用万用表量 RTD 两端电压是否在量程内 |
| 数据呈周期性突变 | 电源纹波或数字噪声耦合 | 查去耦电容;把 UART 走线与模拟输入分开;在输入加 RC 滤波 |
| 写入寄存器后读回来全是 0xFF | UART 波特率不匹配或帧同步错误 | 用逻辑分析仪抓 UART 波形,确认波特率、帧格式、静默时间 |
| 温度跳变剧烈 | 传感器引线接触不良或冷端温度突变 | 检查端子压接是否牢固;确认传感器线径足够;看冷端是否被气流直吹 |
| 首帧命令无响应 | RESET 时序未满足 | 拉低 RESET 后至少等待 1ms 再释放,释放后等待 2ms 再发命令 |
| 与 RS-485 通信间歇性失败 | 方向控制引脚切换太慢 | 检查 DE/RE 信号和 TX 完成事件是否同步,必要时在空字符间插入 20μs 延时 |
表格里的每一条都是从实际调试中总结出来的,其中 UART 帧同步问题出现频率最高,单独再展开说一下。
5.2 UART 帧同步与波特率偏差的问题
ADS122U04 的 UART 命令帧对时序有要求,连续两条命令之间必须满足最小静默时间。如果 MCU 的波特率有偏差,比如用内部 RC 振荡器跑串口,而温度变化又比较剧烈,波特率可能漂出芯片的容忍范围,表现就是偶发性的数据错位。
解决办法有几个层级。最基础的是使用 MCU 外部晶振,把波特率误差控制在 1% 以内。其次是在硬件上不要偷懒,用 16MHz 或 25MHz 的晶振配合标准的 UART 分频得到精确波特率。第三是在软件上,如果混用 DMA 和中断,注意避免缓存未清导致下一帧数据混入上一帧的尾部字节。
针对帧同步本身,我习惯于在每次复位或通信异常后执行一次“清空接收缓存 + 重新初始化 UART + 发送 RREG 回读”的恢复流程。这个流程能解决绝大多数由于上电时序或外部干扰造成的通信卡死,比不断硬复位芯片更优雅,也不用等 2ms 的稳定时间。
避坑技巧:在发完一条写寄存器命令后,不要立刻读数据,在 STM32 侧至少留出 1ms 的间隔。我一开始因为发送和接收无缝衔接,导致芯片还没处理完上一条命令就收到下一条,产生漏字节,后来在所有命令之间加了一个千分之一秒的固定延时,问题消失。
5.3 电源纹波导致的测量波动
ADS122U04 对电源噪声的抑制能力不错,但它不是神仙,开关电源的大纹波仍然会通过基准或模拟前端渗透进测量结果。在 HVAC 项目里,MCU 和 ADC 常共用一路 24V 转 5V 的电源,而这个 5V 同时带着继电器和风扇,干扰尤其严重。
我处理这个问题时,首先在 ADC 电源入口串联一个 10Ω 电阻,配合钽电容形成一级 π 型滤波,把高频噪声压掉。其次用示波器看 AVDD 和 DVDD 的纹波,目标是把纹波控制在 10mV 以内,超过这个值就要加 LDO 或加一级 LC 滤波。最后,如果 ADC 和继电器共用电源,在继电器线圈两端必须并联续流二极管,否则每次继电器释放瞬间的尖峰足以让 ADC 数据掉好几个 LSB。
5.4 提升整体稳定性的几条工程建议
第一,所有温度传感器信号线用屏蔽线,屏蔽层单端接地,接在 ADC 侧的模拟地上。第二,ADC 的采样速度能低就低,HVAC 温度变化一秒一度都算剧烈,根本不需要 1000SPS。20SPS 既能有 50/60Hz 陷波,又能减少后级软件滤波负担。第三,MCU 端的数据处理尽量用整数运算,除最后显示阶段再转浮点,避免浮点计算带来的微小不确定性和主频开销。
另外建议设计一个简单的自检机制:使用内部温度传感器周期性读取芯片自身温度,一旦发现超过 85℃ 或低于 -35℃,说明板级环境异常,主动降低采样率或报警。虽然这一步只护住了 ADC,但很多现场事故就是从局部过热开始的。
5.5 这个方案还能怎么扩展
ADS122U04 的四个通道足够覆盖大多数 HVAC 场景:2 路 PT100 做回水温度,1 路热电偶测排烟温度,剩 1 路做 4-20mA 变送器输入,一个芯片全搞定。想再扩展通道数,可以用两片 ADS122U04 并联,共享同一个 UART 总线和不同的地址配置,或者用模拟多路开关把 AIN 通道复用成仪表通道扫描。
针对物联网方向,这套硬件可以直接接 NB-IoT 或 LoRa 模组,冷端补偿和线性化在 MCU 里做完之后直接上送 JSON 格式的温度数据。设计上唯一需要额外考虑的是长期无人值守时的看门狗策略,UART 通信卡死后除了串口恢复,MCU 侧还应该定时喂狗,确保一整年不下电也不会假死。
最后再分享一个我在这个项目上的细节收获:STM32F412ZG 的浮点性能虽然足以支撑实时计算,但我在一次需要 16 通道 40Hz 采样的版本中,改用查表插值和定点公式,CPU 占用率从 37% 降到了 11%,新增了一个进展后处理功能还有充足余量。算力这件事,永远是把“够用”留给软件,而不是把“吃紧”留给系统。