STM32F410RB与ADS122U04的RTD高精度温度采集设计与校准全解析
前段时间帮一个暖通改造项目做了套温度采集板卡,主控选了 STM32F410RB,前端 ADC 则是 TI 的 ADS122U04IPWR。这套组合解决的是工业和 HVAC 测温里最典型的一类问题:传感器出来的信号非常微弱,现场又有电机、变频器和继电器干扰,同时还得考虑长线传输和后续协议对接。做完之后我发现,ADS122U04 这种带 UART 接口的 24 位 ADC,配合 STM32F410RB 两个串口刚好一个吃数据、一个吐数据,整体思路非常适合做分布式温度节点。
这篇东西不是复述数据手册,而是把我实际踩坑、调板、校准的过程整理出来。内容包括芯片选型逻辑、RTD 前端电路、固件通信框架、温度换算公式以及完整的标定步骤,最后附上我这块板子的实测数据和故障排查表。无论是做工业过程测温、HVAC 冷冻水温差测量,还是自己折腾高分辨率数据采集,这套框架都能直接拿去改。
1. 为什么是 ADS122U04IPWR + STM32F410RB
1.1 先看懂 ADS122U04 这颗芯片
ADS122U04 是 TI 推出的一款 24 位 Δ-Σ ADC,和常见的 ADS1220 不同,它把 SPI 通信封装成了 UART 帧格式。芯片内部集成了可编程增益放大器(PGA,1 到 128 倍)、两个精密激励电流源、一个内部温度传感器和 2.048V 基准电压源。输入侧有双通道差分输入,也可以配置成四路单端输入,对大多数温度采集场景来说通道数已经够用。
很多人第一次看到 UART 接口的 ADC 会有点懵,因为传统 ADC 基本都是 SPI 或 I2C。ADS122U04 的巧妙之处在于物理层走串口,但协议层仍然是寄存器读写和命令帧。也就是说,MCU 这边用普通 USART 发送命令字节,芯片负责剥离 UART 起始位和停止位,还原出完整的 SPI 指令流。这么做最大的好处是现场部署时只需要两三根信号线,不用拉 SCLK、DIN、DOUT、CS 四条线,长距离传输时也不容易因为时钟线干扰导致通信失败。
这个芯片的另一个实用特性是激励电流源(IDAC)。RTD(热电阻)测温本质上要测电阻值,你必须给它一个恒定的激励电流,再测量两端电压。ADS122U04 内置了两个可配置的 IDAC,典型输出 250μA 到 1.5mA 可调,省掉了外部恒流源电路。芯片还支持比例式测量(ratiometric),也就是用同一个 IDAC 电流流过 RTD 和参考电阻,ADC 的参考电压也取自参考电阻两端。这样电源电流的波动会被自动抵消,这是工业测温里非常关键的一点。
1.2 STM32F410RB 的角色定位
STM32F410RB 属于 STM32F4 系列中的基础型号,Cortex-M4 内核,主频 100MHz,LQFP64 封装,片上资源够用但不冗余。它最让我满意的是有多个 USART,这对“ADC 读数 + 对外通信”这种业务模型非常友好:一个串口挂 ADS122U04,另一个串口跑 Modbus 协议或者接无线模块,互不干扰。
F410RB 片上还带了 12 位 ADC,理论上可以直接采传感器电压,但实际面对 PT100 这类信号时,12 位分辨率远远不够。PT100 在 0℃ 时阻值 100Ω,温度每变化 1℃ 阻值大约变化 0.385Ω,如果用 500μA 激励电流,温度每变化 1℃ 对应的电压变化只有 0.1925mV。12 位 ADC 在 3.3V 参考下,一个 LSB 约 0.8mV,换算成温度差不多是 4℃,这种精度做 HVAC 控制勉强,做工业测量完全不行。所以在 MCU 之外必须加一颗高分辨率 ADC,STM32 在这里扮演的是数据处理、协议转换和系统管理角色。
用 F410RB 还有一个很实际的理由:它的 USART 支持 DMA,在连续采样模式下,每秒几十个点的数据量 CPU 负载几乎可以忽略,剩余资源可以跑滤波算法、维护温控逻辑、处理异常报警。对于做小体积温度变送器或者楼宇控制器来说,这种资源分配方式非常舒服。
1.3 方案选型对比
选型阶段我还对比过几类方案,这里直接列一个表格,方便大家判断自己的项目该走哪条路。
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| MCU 内置 12/16 位 ADC | 成本低、布线简单 | 分辨率不足、基准精度差 | 对温度精度要求不高的 HVAC 粗略控制 |
| 专用温度芯片(如 MAX31865) | 集成度高、直接出 RTD 数值 | 灵活性差、通道少、价格偏高 | PT100/PT1000 单点快速测量 |
| SPI 接口 24 位 ADC(ADS1220) | 速率高、生态成熟 | 需要 4 根信号线、长线施工麻烦 | 板内集成、PCB 距离短 |
| 本方案:UART 接口 ADC + MCU | 线少、精度高、灵活 | 通信速率受波特率限制 | 分布式工业测温、HVAC 现场 |
我的建议是,如果传感器和主控板之间的线缆超过 30 厘米,就优先考虑 UART 接口的 ADC。因为 SPI 的时钟线在长线上容易反射,而且多一根线就多一个故障点。ADS122U04 把通信简化为串口后,哪怕现场用普通双绞线走几十米,只要波特率不要拉太高,稳定性都有保障。
2. 硬件设计:从传感器到 ADC 再到 MCU
2.1 温度传感方式选型
工业测温最常见的传感器是 PT100、PT1000 和热电偶。HVAC 领域现在 PT1000 用得越来越多,因为它的阻值更高(0℃ 时 1000Ω),同样的激励电流下产生的电压信号是 PT100 的十倍,对线阻的敏感度也低得多,非常适合长线测温。工业场合则更习惯 PT100,探头尺寸小、响应快,但必须用三线制或四线制接法消除导线电阻。
如果做热电偶测量,ADS122U04 也支持,但需要用内部温度传感器做冷端补偿。热电偶输出电压非常小,K 型热电偶大约 40μV/℃,冷端补偿不准会直接形成几度的误差。我的经验是,HVAC 系统里优先用 RTD,别给自己找麻烦;工业现场如果温度超过 400℃ 必须用热电偶,再单独考虑冷端补偿问题。本文后面的电路和代码以 RTD 为主,因为这是最主流的应用。
2.2 RTD 比例式测量电路
ADS122U04 做 RTD 测量最推荐四线制比例接法,电路结构不复杂但有几个关键点。四线制的思路是两根线给传感器送激励电流,另外两根线单独测电压,电压检测线上没有电流流过,所以导线电阻不会引入误差。
具体接法是:将 ADS122U04 的 IDAC1 输出连接到 RTD 的电流激励正端,RTD 的电流返回端接回 AVSS;RTD 的电压检测正端接 AIN0,检测负端接 AIN1。参考电阻 Rref 接在 IDAC1 输出和 AVSS 之间,REFP 和 REFN 分别并接在这个 Rref 两端。这样一来,ADC 的参考电压就是 IDAC 电流在 Rref 上产生的压降,而输入电压是同一个 IDAC 电流在 RTD 上产生的压降,两个电压都由同一个电流源驱动,电流波动的影响在比例计算中自动抵消。
Rref 的阻值选择有讲究。假设 IDAC 设为 500μA,Rref 取 1.8kΩ,那么参考电压就是 0.9V。PT100 在 100℃ 时阻值约 138.5Ω,500μA 电流下电压只有 69.25mV,经过 PGA 8 倍放大后约 0.554V,不会超过 0.9V 的参考电压,留有余量。如果选更大的 Rref,参考电压升高,传感器信号占比变小,分辨率会下降;选太小则可能超过 ADC 满量程。实际设计中,参考电阻精度至少要 0.1%,温漂系数要控制在 25ppm/℃ 以内,因为它直接决定整机温度精度。
输入端的滤波电容也需要认真处理。我习惯在每个模拟输入引脚对地并联一个 100nF 的电容,同时在 AIN0 和 AIN1 之间并联一个 10nF 的差分电容,滤除共模和差模噪声。需要注意差分电容不宜太大,否则会和传感器阻抗形成低通滤波,降低响应速度,甚至在高 PGA 增益下引入增益误差。
2.3 电源、地线和通信线
ADS122U04 是模拟混合器件,电源处理得好不好直接影响有效分辨率。我的板子上用了 LDO 给 3.3V 供电,AVDD 和 DVDD 分别通过磁珠和 10Ω 电阻隔离,模拟地和数字地在 ADC 芯片下方单点汇合,然后通过覆铜连回电源输入地。这样做能有效避免数字开关噪声窜进模拟前端。
通信接线上,STM32F410RB 的 USART1 TX/RX 分别接到 ADS122U04 的 RX/TX,交叉连接,同时把芯片的 DONE/DRDY 引脚接到 MCU 的一个 GPIO,用于查询数据转换完成状态。需要注意的是 ADS122U04 和 STM32F410 都是 3.3V 电平,可以直接互连,不需要电平转换。如果板子上还有 5V 器件,务必加逻辑电平转换电路,否则会烧引脚。
波特率选择方面,ADS122U04 支持比特率配置,可通过外围引脚或命令设置。我实际用 115200bps,在这个速率下读取 20SPS 的采样数据完全没有压力。现场干扰比较大的环境,可以把波特率降到 9600,牺牲一点通信速度换取更强的抗干扰能力。数据手册给出的是命令帧收发模型,所有寄存器读写都靠发送字节完成,不存在严格的上位机时序约束,新手反而更容易上手。
3. 固件实现:UART 通信与温度换算
3.1 ADS122U04 的命令帧结构
ADS122U04 的通信协议并不复杂,主机通过 UART 发送命令字节,芯片执行后返回响应。常用命令包括写寄存器(WREG)、读寄存器(RREG)、读转换数据(RDATA)等。命令帧格式沿用了类似 SPI 的规则:首字节是命令码,后面是寄存器地址和数据内容。
以写寄存器为例,命令结构是:第一个字节为命令码 0x40 并携带寄存器起始地址,第二个字节表示要写入的寄存器数量减一,第三个字节开始依次是寄存器数据。读寄存器命令类似,把命令码换成 0x20 即可。读转换数据则直接发送 0x10,芯片会返回 24 位补码格式的转换结果。实际编程时不需要死记这些字节,TI 数据手册里有完整表格,按位填就好。
有一点要注意:ADS122U04 的 UART 是半双工方向控制的,主机发送命令前要把总线方向置于发送态,发完再切回接收态等待芯片响应。如果用的是带方向控制引脚的接法,需要操作 GPIO 切换方向;如果芯片型号内已经集成了方向仲裁,则不需要额外操作。调试时最好先用 USB 转串口直接对芯片发命令,确认通信正常后再接 MCU,这样能快速定位问题出在协议层还是电气层。
3.2 STM32F410RB 串口驱动配置
STM32F410RB 这边我用的是 USART1 接 ADC,USART6 接上位机或触摸屏。工程上使用 STM32CubeMX 初始化,MCU 运行主频 100MHz,串口波特率 115200,数据位 8 位,无校验,1 位停止位。下面给出 USART1 的初始化参考代码,以及最简单的命令发送和响应接收逻辑。
// 初始化 USART1,用于连接 ADS122U04 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); }发送命令和接收响应时,我用了阻塞式接口配合超时保护。ADS122U04 的响应速度很快,通常几毫秒内就能返回,所以超时时间设置为 100ms 足够。对于 20SPS 的采样率,一个采样周期是 50ms,串口读写完全跟得上。
// 发送写寄存器命令:写寄存器0,共1个寄存器,数据为0x10 uint8_t writeCmd[3]; writeCmd[0] = 0x40; // WREG + 寄存器0地址 writeCmd[1] = 0x00; // 寄存器数量 - 1 writeCmd[2] = 0x10; // 寄存器0的配置值 HAL_UART_Transmit(&huart1, writeCmd, 3, 100);初始化寄存器时,我把输入多路选择配置为 AIN0 和 AIN1 差分输入,PGA 增益设为 8,数据率设为 20SPS。这里要注意芯片的“等效噪声分辨率”和数据率挂钩,数据率越低噪声越小。HVAC 这种缓慢变化的温度对象,20SPS 甚至 5SPS 都够用,换取更低噪声更划算。
3.3 读取数据与温度换算公式
ADS122U04 返回的 24 位数据是有符号补码格式,范围从 0x800000 到 0x7FFFFF。读取后需要存成 int32_t 变量,再右移或直接按比例换算成电压和电阻。比例测量的换算公式很简单:
R_rtd = (code / 2^23) × Rref / PGA
举个例子验证一下:假设参考电阻 Rref 为 1801Ω,PGA 为 8,如果读到的 code 是 419430(即满量程的 1/20),那么 RTD 阻值 = (419430 / 8388608) × 1801 / 8,算出来大约是 11.26Ω。这个公式在 RTD 测温项目里用了很多次,比用电压绝对值换算更不容易出错,因为它自动消除了基准电压漂移。
得到 RTD 阻值之后,再用 IEC 60751 标准公式把电阻转换成温度。PT100/PT1000 都遵循相同多项式,只是系数不同。为了在单片机上高效运行,我使用了一段分段线性查表程序,在 -20℃ 到 150℃ 范围内分成 17 个区间,每个区间用线性插值逼近,误差控制在 0.01℃ 以内。如果不想查表,也可以用 Callendar-Van Dusen 方程的简化版直接算,但要注意二次项的截断处理。
代码里我还会做一次简单的数字滤波。温度信号是缓变量,最实用的是滑动平均加中值滤波:每五个采样点去掉最大值和最小值,剩下三个取平均。这样既滤掉了随机噪声,也能剔除继电器吸合瞬间产生的尖峰干扰。
4. 校准流程:把 ADC 精度变成系统精度
4.1 校准的必要性
很多 DIY 玩家做完板子直接上电读数,发现显示温度和实际温度总有偏差,第一反应是 ADC 坏了,其实大概率是没做校准。ADS122U04 是 24 位 ADC,但系统精度不只是 ADC 分辨率决定的。参考电阻 Rref 的误差、PGA 的增益误差、PCB 漏电流、接线端子接触电阻,都会叠加进最终结果。
举一个直观的例子:如果 Rref 用普通 1% 精度的 1.8kΩ 电阻,实际阻值可能是 1782Ω 或者 1818Ω,比例误差直接顺着测量链传递。PT100 在 25℃ 时阻值约 109.73Ω,1% 的比例误差换算到温度大约是 0.28℃ 到 0.30℃,这还没算 ADC 自身的增益误差。所以我的板子上 Rref 用了 0.05% 精度、10ppm/℃ 温漂的金属膜电阻,并且在校准时把它的实际阻值测出来填进固件参数表。
4.2 单点失调校准
失调校准的目的是消除 ADC 输入失调电压和 PGA 零点误差。操作流程很简单:把 ADC 输入短接(AIN0 和 AIN1 直接连通),确保输入电压为零,然后读取转换结果。理想情况下 code 应该为 0,实际会有几十到几百个 LSB 的偏移。把读到的偏移值保存下来,之后的每次测量都减去这个偏移。
这里有个小坑:短接输入端时,如果 PGA 增益太高,失调会被放大到饱和,反而不准。我的做法是在正常使用的 PGA 设置下做失调校准,也就是增益 8 时短接读取,然后把这个偏移记录到 Flash。更严谨的方案是用一个精密电阻模拟零点温度,比如用 100Ω(对应 PT100 的 0℃)精密电阻替换 RTD,读取偏差并修正,这样零点修正和增益修正能一次性完成。
4.3 两点增益校准
增益校准通常叫“两点标定”。我准备了两只精密电阻,一只是 100Ω(模拟 0℃ 附近的 PT100),另一只是 138.5Ω(模拟 100℃ 附近的 PT100),精度都是 0.01%。把第一只电阻接入测量通道,读取 ADC code,记为 code1;再把第二只电阻接入,读取 code2。实际测量时,用两点来确定一条直线,对测量结果做线性修正。
修正公式可以很朴素:把 ADC 计算出的电阻值 R_measured 代入下列线性校正关系:
R_corrected = R_measured × K + B
其中 K = (R2_true - R1_true) / (R2_measured - R1_measured),B = R1_true - R1_measured × K。把这些修正系数预存到 STM32 的片内 Flash,每次开机加载。校准环境需要恒温,至少要做到温度变化幅度不超过 ±0.5℃,否则两只精密电阻本身的电阻值漂移会混入校准结果。
校准完成后,我习惯再用第三只阻值(比如 200Ω)进行验证,如果实测误差仍然控制在 0.05℃ 以内,这条测量链路就算合格。整套校准流程做完大约需要十分钟,但能换来稳定可靠的长期精度,这笔时间花得很值。
5. 实测数据、故障排查与避坑经验
5.1 一块板子的实测数据
我手头这块板子配置如下:PT100 传感器,IDAC 电流 500μA,PGA 增益 8,Rref 实测 1801Ω(0.05% 精度),数据率 20SPS,供电 3.3V。在恒温实验室里用高精度温度计做参照,连续运行一个小时后,抓取了一段稳定状态的数据。
| 统计项 | 数值 |
|---|---|
| 设定温度 | 25.000℃ |
| 测量均值 | 25.013℃ |
| 标准差 | 0.003℃ |
| 峰峰值 | 0.014℃ |
| 最大偏差 | 0.021℃ |
这个结果说明,经过校准之后,系统的短期稳定性相当好。0.003℃ 的标准差在 HVAC 环境里绰绰有余,工业上做精密温差测量也够用。需要注意的是,长期漂移主要看参考电阻的温度系数和 PCB 的应力释放情况,所以对高精度应用来说,Rref 的选型真的不能省钱。
5.2 典型故障速查表
整理这块板子时,我也翻了一遍调试初期踩过的所有坑,汇总成下面的故障排查表,遇到问题可以按表逐级排查。
| 故障现象 | 可能原因 | 排查思路 |
|---|---|---|
| 通信完全无响应 | 波特率配置错误、TX/RX 接反、芯片供电异常 | 先用 USB 转串口直接连芯片,发送读寄存器命令验证 |
| 读回数据恒为 0 | 输入悬空、IDAC 未使能、寄存器配置被覆盖 | 检查配置寄存器,确认输入通道和 IDAC 配置位 |
| 数据跳动超过 0.1℃ | 电源纹波大、参考电容缺失、数字地噪声窜扰 | 用示波器抓 AVDD 波形,补滤波电容,检查单点接地 |
| 读数整体偏小 | 参考电阻偏大、PGA 配置错误 | 用万用表实测 Rref 值,核对寄存器 PGA 倍率 |
| 高增益时数据异常 | 输入超共模范围或 PGA 输出饱和 | 检查输入电压是否在允许范围内,降低增益或调整 IDAC |
| 温度读数长期漂移 | 参考电阻温漂大、焊点应力释放 | 换用低 TCR 电阻,对焊点做热循环老化处理 |
最典型的坑就是输入引脚悬空。ADS122U04 的 PGA 输入阻抗很高,悬空时引脚电位不定,读数会是随机乱码或者直接饱和到满量程。不用的模拟输入通道一定要接一个固定电平,不能任其飘着。
5.3 几个独家避坑经验
首先是长线传感器的屏蔽层接地。很多工程师习惯两端都接地,这会在屏蔽层上形成地环路电流,反而把噪声耦合进信号线。正确做法是屏蔽层在采集板一端单点接地,传感器端悬空。如果现场干扰极强,可以在传感器端通过 1nF 电容接地,但不能直接连通。
其次是上电时序。STM32F410RB 初始化完成后再给传感器桥路供电,或者至少保证 MCU 复位期间 ADC 的输入不会收到异常激励。否则上电瞬间传感器线缆可能捡到浪涌,把 ADC 输入打坏。我现在的板子用一个 GPIO 控制传感器电源开关,MCU 起来后再打开,实测很稳。
第三是不要迷信“24 位分辨率”这个参数。ADS122U04 的 24 位是无噪声分辨率远达不到的,8 点平均之后的有效分辨率在 20SPS 下大概 20 到 21 位,对应温度分辨率约 0.001℃ 到 0.002℃。如果看到有人宣传“24 位温度测量精度 0.0001℃”,直接忽略就好。系统精度的天花板由参考电阻、线性误差和校准残留误差共同决定,而不是 ADC 位数。
最后再分享一个调试工具上的建议:给板子留一个 UART 调试口,不接 ADC 只接调试信息,独立用打印温度、code 和配置状态。我吃过一次亏,ADC 的 USART 和调试串口混用,导致协议相互干扰,花了大半天才定位。从那以后所有测量板都强制留两个独立串口,一个干活,一个说话,问题定位效率提升不少。这套设计我现在直接放进模板里,后续扩展多路温度采集、接入 Modbus 网关或者蓝牙配置,工程量都不大,拿来就能用。