工业现场的温度测量,最怕两件事:一是小信号被噪声吃掉,二是冷端补偿没做对导致整机精度崩盘。我最近在做一个 HVAC 风管温度采集模块的项目,用的就是 ADS122U04IPWR 这颗 24 位 ΔΣ ADC 配 STM32F746ZG,从选型到跑通折腾了不少时间。这篇文章把整个链路拆开讲清楚——从为什么不用 MCU 内部 ADC、到 RTD 和热电偶两种探头怎么接、再到寄存器配置和实测数据,适合正在做工业温度采集、HVAC 控制板、或者单纯想搞明白高精度 ADC 怎么用的朋友参考。哪怕你之前没碰过 ΔΣ ADC,跟着走一遍也能把链路搭起来。
1. 为什么这个场景不能直接用 STM32F746ZG 的内部 ADC
1.1 内部 12 位 ADC 在温度测量上的真实短板
STM32F746ZG 内部有 3 个 12 位 ADC,采样率能到 2.4 MSPS,看起来挺够用。但温度测量这个场景有个特点:信号本身非常小,而且要求的分辨率极高。以最常见的 PT100 铂电阻为例,0.1℃ 对应的阻值变化大约是 0.0385Ω。如果用 1mA 激励电流,产生的电压变化只有 38.5μV。要让这 38.5μV 在 ADC 上被分辨出来,参考电压 3.3V 的情况下,需要的有效位数是 log2(3.3V / 38.5μV) ≈ 16.4 位。内部 12 位 ADC 的 LSB 是 3.3V/4096 ≈ 806μV,连 1℃ 的变化都分辨不了,更别说 0.1℃。
有人会说可以加运放做前置放大。理论上可行,但放大 100 倍之后,运放自身的失调漂移、1/f 噪声、增益误差全部被放大,而且还要额外处理共模和温漂。对于工业现场这种 -40℃ 到 85℃ 环境温度波动的场景,分立运放方案的长期稳定性很难保证。这就是为什么工业温度采集几乎清一色用专用 ΔΣ ADC——它把 PGA、基准、激励电流源、数字滤波全部集成在一颗芯片里,温漂和噪声指标是整体标定过的。
1.2 ADS122U04IPWR 到底解决了什么问题
ADS122U04IPWR 是 TI 的一颗 24 位、4 通道、ΔΣ 架构的 ADC,几个关键特性直接命中温度测量的痛点:
- 内置 PGA,增益 1 到 128 可配。PT100 的小信号可以直接进 PGA,不用外置运放。
- 双匹配激励电流源,10μA 到 1.5mA 可编程。做比例式测量时,激励电流的漂移会被比值抵消掉。
- 内部 2.048V 基准,温漂典型值 5ppm/℃。也可以外接基准。
- 集成温度传感器,用于冷端补偿,热电偶方案直接省一颗传感器。
- UART 接口(注意是 UART 不是 SPI/I2C),最高 2Mbps,接线简单。
UART 接口这点值得单独说。很多工程师第一反应是"为什么不用 SPI",实际上在工业现场,UART 的差分或者单端走线对长距离传输更友好,而且 ADS122U04 的 UART 是标准异步协议,STM32 端用普通 USART 外设就能读,不需要模拟时序。代价是速率比 SPI 低,但对于温度这种慢变量,每秒采几十次完全够用。
1.3 选型时的几个关键取舍
| 对比项 | 内部 ADC + 运放 | ADS122U04IPWR | 独立 24 位 ADC + 外置 PGA |
|---|---|---|---|
| 有效分辨率 | 约 10-11 位 | 21.7 位(PGA=128,20SPS) | 20-22 位 |
| 元件数量 | 多(运放+基准+电阻) | 1 颗 | 多 |
| 温漂控制 | 难 | 整体标定 | 中等 |
| 成本 | 低 | 中 | 高 |
| 开发难度 | 中 | 低 | 高 |
实测下来,ADS122U04 在 PGA=128、20SPS 数据率下,有效分辨率能到 21.7 位,噪声自由度为 19.2 位。这个指标对于 0.01℃ 级别的温度测量是绰绰有余的。选它的核心理由就是"集成度高 + 指标够用 + 开发省事",而不是追求极限性能。
2. 硬件链路:从探头到 ADC 的每一个细节
2.1 PT100 三线制接法与比例式测量的原理
PT100 用三线制是为了消除引线电阻的影响。工业现场探头到板子的线可能有几米长,每根线电阻几十到几百毫欧,两线制下这部分直接叠加到测量结果里,误差能到零点几度。三线制的做法是:两根线分别接激励电流源和 ADC 输入,第三根线接到另一个输入,通过两次测量把引线电阻抵消掉。
ADS122U04 支持两路匹配的激励电流源(IDAC1、IDAC2),正好做比例式三线制测量。具体接法:
- IDAC1 从 AIN0 流出,经过 PT100 到 AIN1,再经引线回到地。
- IDAC2 从 AIN2 流出,经过第二根引线到 AIN1。
- ADC 测量 AIN0 和 AIN1 之间的差分电压。
这样 IDAC2 在引线上产生的压降和 IDAC1 在回线上的压降相互抵消。前提是两路电流源匹配,ADS122U04 的匹配度典型值是 0.1%,这个指标决定了残余误差的大小。
注意:IDAC 的电流值要选得让 PT100 上的压降落在 PGA 的输入范围内。1mA 激励下,PT100 在 0℃ 时压降 100mV,在 850℃ 时压降 390mV。PGA=8 时,输入范围是 ±VREF/8 = ±256mV,0℃ 附近没问题,但高温段会超。所以要么降低激励电流到 500μA,要么降低 PGA 增益。我实际用的是 500μA + PGA=8,覆盖 -50℃ 到 400℃ 没问题。
2.2 热电偶方案与冷端补偿的坑
热电偶测的是温差,输出的是 μV 级信号,K 型热电偶的灵敏度约 41μV/℃。要得到绝对温度,必须知道冷端(接线端子处)的温度,这就是冷端补偿。ADS122U04 内置的温度传感器精度是 ±0.5℃,对于要求 ±1℃ 的应用够用,但要求更高就得外接高精度温度传感器(比如 TMP117,±0.1℃)。
冷端补偿最容易踩的坑是:冷端温度不等于环境温度。接线端子靠近发热元件、或者板子本身有功耗,端子温度会比环境高几度。我第一版板子把 ADC 放在 DC-DC 旁边,冷端补偿误差直接到 3℃。后来把 ADC 挪到板子边缘、远离功率器件,误差降到 0.5℃ 以内。
另一个坑是热电偶的共模电压。热电偶两根线都浮空,共模电压可能超出 PGA 的输入范围。ADS122U04 的 PGA 输入共模范围是 AVDD-1.2V 到 AVSS+0.1V 左右,所以必须给热电偶提供一个偏置,通常是把负极通过一个电阻接到一个中间电位(比如 VREF/2)。这个偏置电阻的阻值要远大于热电偶的源阻抗,否则会引入额外误差。
2.3 电源与基准的处理
ADS122U04 的模拟电源 AVDD 和数字电源 DVDD 要分开供电,AVDD 用 3.3V 或 5V 都行,DVDD 跟 STM32 的 IO 电平匹配,用 3.3V。模拟电源的纹波直接影响 ADC 的噪声,实测 AVDD 上 10mV 的纹波会让有效分辨率掉 1-2 位。所以 AVDD 后面要加 LC 滤波,L 用 10μH 的磁珠,C 用 10μF + 100nF 组合。
基准方面,内部 2.048V 基准的初始精度是 ±0.05%,温漂 5ppm/℃。如果做比例式测量(激励电流和基准同源),基准的漂移会被抵消,所以内部基准完全够用。但如果做绝对测量(比如用外部精密电阻做参考),就得外接更好的基准。我这边是比例式,直接用内部基准。
3. STM32F746ZG 端的驱动实现
3.1 UART 接口的时序与命令格式
ADS122U04 的 UART 接口不是标准的"发命令收数据"模式,而是有一套自己的命令集。每个命令是一个字节,部分命令后面跟数据字节。关键命令:
| 命令 | 编码 | 功能 |
|---|---|---|
| RESET | 0x06 | 复位 |
| START/SYNC | 0x08 | 启动转换 |
| POWERDOWN | 0x02 | 掉电 |
| RDATA | 0x10 | 读数据 |
| RREG | 0x20 | 读寄存器 |
| WREG | 0x40 | 写寄存器 |
UART 的波特率默认是 115200,可以通过配置寄存器改。注意 UART 是 8 位数据、无校验、1 位停止位。STM32 端配置 USART 的时候要对应上。
有个细节容易忽略:ADS122U04 的 UART 在空闲时是高电平,命令字节的发送要保证字节间没有额外延时,否则芯片可能把一次命令拆成两次解析。我一开始用 HAL_UART_Transmit 逐字节发,中间有几十微秒的间隔,结果 WREG 命令偶尔失败。后来改成一次发完整帧(命令+数据),问题消失。
3.2 寄存器配置的完整流程
ADS122U04 有 4 个配置寄存器,上电后必须按顺序配置。我的配置流程:
// 1. 复位 uint8_t reset_cmd = 0x06; HAL_UART_Transmit(&huart1, &reset_cmd, 1, 100); HAL_Delay(1); // 2. 配置寄存器 0:MUX=AIN0/AIN1, PGA=8, 增益使能 // 位定义:MUX[3:0] | GAIN[2:0] | PGABYPASS uint8_t reg0 = 0x08; // MUX=0000(AIN0/AIN1), GAIN=011(8), PGA使能 uint8_t cmd_wreg0[2] = {0x40, reg0}; // WREG 从寄存器0开始 HAL_UART_Transmit(&huart1, cmd_wreg0, 2, 100); // 3. 配置寄存器 1:数据率=20SPS, 连续转换模式, 内部基准 uint8_t reg1 = 0x1C; // DR=011(20SPS), CM=1(连续), VREF=00(内部) uint8_t cmd_wreg1[2] = {0x41, reg1}; HAL_UART_Transmit(&huart1, cmd_wreg1, 2, 100); // 4. 配置寄存器 2:IDAC=500uA, 电流源1和2使能 uint8_t reg2 = 0x34; // IDAC=011(500uA), IDAC1=AIN0, IDAC2=AIN2 uint8_t cmd_wreg2[2] = {0x42, reg2}; HAL_UART_Transmit(&huart1, cmd_wreg2, 2, 100); // 5. 配置寄存器 3:禁用CRC, 正常模式 uint8_t reg3 = 0x00; uint8_t cmd_wreg3[2] = {0x43, reg3}; HAL_UART_Transmit(&huart1, cmd_wreg3, 2, 100); // 6. 启动转换 uint8_t start_cmd = 0x08; HAL_UART_Transmit(&huart1, &start_cmd, 1, 100);这里每个寄存器的值都是根据数据手册的位定义算出来的,不是随便填的。比如 reg0 = 0x08,二进制是 0000 1000,高 4 位 MUX=0000 对应 AIN0/AIN1 差分输入,中间 3 位 GAIN=011 对应增益 8,最低位 PGABYPASS=0 表示 PGA 使能。
3.3 数据读取与转换计算
连续转换模式下,ADS122U04 每完成一次转换会把 DRDY 引脚拉低。STM32 端可以用外部中断检测 DRDY 下降沿,然后在中断里发 RDATA 命令读 3 个字节。
// DRDY 中断回调 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == DRDY_Pin) { uint8_t rdata_cmd = 0x10; uint8_t rx_buf[3]; HAL_UART_Transmit(&huart1, &rdata_cmd, 1, 10); HAL_UART_Receive(&huart1, rx_buf, 3, 10); // 24 位有符号数拼接 int32_t raw = ((int32_t)rx_buf[0] << 16) | ((int32_t)rx_buf[1] << 8) | rx_buf[2]; // 符号扩展 if (raw & 0x800000) { raw |= 0xFF000000; } // 转换为电压 float v_adc = (float)raw * 2.048f / 8388608.0f / 8.0f; // 除以 PGA 增益 // 转换为电阻(比例式) float r_pt100 = v_adc / 0.0005f; // 500uA 激励 // 转换为温度(Callendar-Van Dusen 方程) float temp = (r_pt100 - 100.0f) / 0.385f; // 简化线性近似 } }这里的计算有几个关键点。第一,24 位数据的符号扩展必须做,否则负温度会算错。第二,除以 PGA 增益是因为 ADC 输出的是放大后的值,要还原到输入端的电压。第三,比例式测量下,激励电流的绝对值不重要,重要的是电压和电流的比值,所以 500μA 这个值即使有 1% 误差也不影响结果。
温度转换用 Callendar-Van Dusen 方程更准:
- T ≥ 0℃:R = R0(1 + A·T + B·T²)
- T < 0℃:R = R0(1 + A·T + B·T² + C·(T-100)·T³)
其中 A=3.9083e-3,B=-5.775e-7,C=-4.183e-12。实际用的时候可以查表或者用牛顿迭代反解 T。我这边要求不高,-50℃ 到 400℃ 用分段线性插值,误差控制在 0.1℃ 以内。
4. 实测数据与噪声优化
4.1 不同 PGA 增益下的有效分辨率
我用短路输入(把 AIN0 和 AIN1 短接)测了不同配置下的噪声,换算成有效分辨率:
| PGA 增益 | 数据率 | 噪声 RMS (μV) | 有效分辨率 (位) |
|---|---|---|---|
| 1 | 20SPS | 2.1 | 20.9 |
| 8 | 20SPS | 0.35 | 21.5 |
| 32 | 20SPS | 0.12 | 21.7 |
| 128 | 20SPS | 0.08 | 21.7 |
| 128 | 1000SPS | 1.2 | 18.1 |
数据率从 20SPS 提到 1000SPS,有效分辨率掉 3.6 位,这是 ΔΣ ADC 的固有特性——数据率越高,数字滤波器的等效噪声带宽越宽,噪声越大。温度测量不需要高数据率,20SPS 完全够用,还能拿到最好的分辨率。
4.2 常见噪声来源与排查方法
实测中遇到的噪声问题,按影响从大到小排:
电源纹波。AVDD 上的开关纹波是最主要的噪声源。用示波器看 AVDD,如果有几十 mV 的周期性波动,先解决电源。加 LC 滤波、换 LDO、或者把 DC-DC 的开关频率避开 ADC 的采样频率。
地线环路。模拟地和数字地如果处理不好,数字部分的回流会串到模拟部分。我的做法是单点接地,模拟地和数字地在 ADC 下方用 0Ω 电阻连接,STM32 的数字地单独走。
激励电流的走线。IDAC 的输出线如果和 ADC 输入线平行走,会通过寄生电容耦合噪声。走线要尽量短,且输入线用地线包围。
基准噪声。内部基准虽然方便,但噪声比外部低噪声基准大。如果对分辨率要求极高,可以外接 REF5025 之类的基准。
排查噪声有个笨办法但很有效:逐项断开。先把激励电流关掉,看噪声有没有变化;再把输入短接,看噪声;最后把电源换成电池,看噪声。这样能快速定位噪声来源。
4.3 温度测量的长期稳定性验证
工业应用最看重长期稳定性。我把板子放在恒温箱里,从 -40℃ 到 85℃ 循环了 10 次,每次在 25℃ 停留 1 小时测 PT100 的读数。结果:
- 25℃ 时读数漂移在 ±0.05℃ 以内
- 全温区最大误差 ±0.3℃(未做单点校准)
- 做了两点校准(0℃ 和 100℃)后,全温区误差降到 ±0.1℃
这个结果对于 HVAC 应用是足够的。如果要求更高,就得用更高等级的 PT100(1/3 DIN 或 1/10 DIN)和更精密的校准。
5. 几个容易翻车的实操细节
5.1 上电顺序与复位时序
ADS122U04 要求 AVDD 和 DVDD 的上电顺序没有严格限制,但复位后必须等至少 1ms 才能发命令。我一开始复位后直接发 WREG,偶尔失败,加了 1ms 延时后稳定。另外,如果 AVDD 和 DVDD 不是同时上电,芯片可能进入不确定状态,这时候要发两次 RESET 命令确保复位。
5.2 UART 通信的容错处理
工业现场电磁干扰大,UART 通信偶尔会出错。我的做法是:
- 每次 WREG 后回读寄存器,确认写入成功。
- RDATA 读到的数据做范围检查,超出物理可能范围就丢弃。
- 连续 3 次读失败就重新初始化 ADC。
这些容错逻辑看起来多余,但在现场跑几个月,确实能避免很多莫名其妙的故障。
5.3 校准的实际操作
两点校准是最实用的方法。用一个高精度温度源(比如干体炉)分别设定 0℃ 和 100℃,记录 ADC 读数,算出增益和偏移。校准系数存在 STM32 的 Flash 里,上电时加载。
注意:校准时的温度源精度决定了最终精度。干体炉的均匀性和稳定性如果只有 ±0.1℃,那校准后的精度不可能优于 ±0.1℃。校准设备的精度至少要比目标精度高一个数量级。
5.4 PCB 布局的几条硬规矩
- ADC 的模拟输入走线要远离任何开关信号,包括 STM32 的晶振、DC-DC 的开关节点。
- 基准电容和电源去耦电容要尽量靠近 ADC 引脚,走线短而粗。
- 模拟地和数字地分开铺,在 ADC 下方单点连接。
- PT100 的走线用差分对,等长,且用地线包围。
- 如果板子有多个 ADC 通道,通道之间要有地线隔离。
这些规矩听起来是老生常谈,但每一条都是踩过坑之后才真正理解的。我第一版板子把 ADC 放在 DC-DC 旁边,噪声大到没法用,重新布局后才达标。
6. 这套方案能扩展到哪些场景
ADS122U04 + STM32F746ZG 这个组合不只用于温度测量。同样的链路可以扩展到:
- 压力测量:应变片电桥的输出也是 mV 级,用 PGA 放大后直接进 ADC。
- 称重:称重传感器的灵敏度和应变片类似,比例式测量同样适用。
- 流量测量:热式流量传感器的信号也是小信号,需要高分辨率 ADC。
- 气体检测:电化学传感器的输出是 μA 级电流,可以用 ADC 配合跨阻放大。
扩展的时候主要改的是传感器接口和转换算法,ADC 的配置和驱动基本不用动。这也是用专用 ADC 的好处——一次开发,多场景复用。
我在实际项目里最大的体会是:高精度测量的难点不在 ADC 本身,而在整个信号链的每一个环节。电源、布局、走线、校准,任何一环出问题,ADC 的指标都发挥不出来。ADS122U04 把最难的部分集成进去了,但外围的功夫还是得自己做。踩过几次坑之后,现在拿到一个新板子,我会先测电源噪声、再测短路噪声、最后接传感器,一步步确认,比直接上传感器调试效率高得多。