干这行十几年,温度采集是我绕不开的活。工业现场要盯着电机轴承、加热管、冷却水回水温度,HVAC 系统要控风管、水管、回风温度,不管是哪一路,最后都得落到“把温度变成数字量”这一步上。用 ADS122U04IPWR 搭配 STM32F334R8 做多路温度采集,是我近期一个项目里实际跑通的方案,覆盖 RTD、热电偶和 NTC 三类传感器。这篇文章就把这套组合从选型、硬件、软件到调试的完整链路拆开讲一遍,包括我踩过的坑和实测数据。如果你正在做类似工控采集板或者 HVAC 控制器,这套思路可以直接抄作业。
1. 为什么是这两颗芯片:方案选型的核心思路
1.1 ADS122U04IPWR 在温度采集链路里的定位
ADS122U04IPWR 是 TI 的一颗 24 位 Δ-Σ ADC,四通道,最大的特点是集成了 UART 接口,而不是常见的 SPI。后缀里 I 代表工业级温度范围,PW 是 TSSOP 封装,R 是卷带包装。这颗 ADC 内部有输入多路复用器、可编程增益放大器(PGA)、内部基准、两个激励电流源(IDAC),还有一个内部温度传感器。换句话说,它把温度采集链路上最麻烦的模拟前端大部分都集成进去了,外部只需要很少的阻容元件。
我在项目里主要用它承担三类任务:测 Pt100/Pt1000 铂电阻、测 K 型热电偶、测 NTC 热敏电阻。这三类传感器是工业和 HVAC 里最常见的测温元件。如果全部用分离元件搭模拟前端,光放大器、基准源、滤波电路就要占很大面积,调试成本也高。ADS122U04 的 PGA 增益可编程,从 1 到 128 倍,小信号热电偶可以直接接进去;内部 IDAC 可以给 RTD 提供激励电流,配合外部精密电阻做比率测量,能抵消基准电压漂移带来的误差。这颗 ADC 的单通道有效分辨率在低增益、低速率下可以做到很高,配合 SINC3 数字滤波器,对付工业现场的工频干扰也够用。
1.2 STM32F334R8 承担控制和计算
STM32F334R8 是 ST 的 Cortex-M4F 内核 MCU,主频 72MHz,带 FPU 和 DSP 指令,64KB Flash,外设资源对温度采集这种场景非常宽裕。选它不是因为“必须用这颗”,而是因为它在这个价位段提供的资源很均衡:多个 UART 可以挂 ADC 和上位机,内置比较器和高级定时器还能顺便做温度超限断电保护,如果后续想扩展电机控制或数字电源控制,同一颗芯片也不用换。
在这套方案里,STM32F334R8 的角色是主控:通过 UART 和 ADS122U04 通信,把 ADC 原始数据读回来,然后完成温度换算、滤波、超限判断、控制输出以及和上位机的数据交互。Cortex-M4F 的 FPU 在算浮点多项式时很快,DSP 指令可以跑滑动平均滤波、IIR 滤波器,甚至以后要上 PID 温控,运算资源也不会捉襟见肘。
很多人会问,为什么不用 STM32 内部自带的 ADC?STM32F334 内置 ADC 也是 16 位的,精度不错,但和 24 位外置 ADC 不是一回事。内置 ADC 用来采样快速模拟量比如电压、电流做闭环控制很好,但要测温度,尤其是需要分辨 0.01℃ 甚至更小的变化时,外置高精度 ADC 的分辨率和噪声指标要强得多。而且温度采集点数一多,内置 ADC 的多通道扫描时序也会挤占控制代码的时间片。外置 ADC 通过串口隔离,抗干扰能力也更强。
1.3 选 UART 接口 ADC 的工程理由
用串口 ADC 而不是 SPI ADC,是我在这类项目里的一贯偏好。SPI 需要片选、时钟、数据进、数据出四根线,高速时钟在长线传输时容易受 EMI 干扰,对地回路也敏感。而 UART 只要 TX 和 RX 两根线,点对点通信,115200 波特率下也能轻松传几十厘米甚至一两米,在现场机柜里走线比 SPI 容易得多。ADS122U04 内部有时钟振荡器,UART 波特率可配置,不需要外部晶振,MCU 这边只要一个普通串口就能驱动。
当然也有代价。UART 接口的 ADC 一次读回的数据帧比 SPI 长,吞吐率不如 SPI 高,但对于温度测量这种纳秒级变化的应用,每秒读几十次甚至几次完全够用。温度系统的时间常数以秒为单位,测量速率 20SPS 到 100SPS 已经是天文数字了。用串口的另一个好处是电气隔离更容易做,如果需要抗共模干扰,在 UART 两根线上加数字隔离器,成本低效果好,这在工业现场很常见。
2. 硬件设计:从传感器到 MCU 的每个细节
2.1 传感器类型与输入通道规划
ADS122U04 有四个模拟输入通道,标记为 AIN0 到 AIN3,可以配置成两路差分输入或四路单端输入。我在这个项目里用的分配方式是一个通道接 Pt100 做冷端补偿兼测水温,另一个通道接 K 型热电偶测环境温度,再留一个通道做 NTC 备用。对于 HVAC 场景,四路单端输入接 NTC 是最省事的接法,但对于工业 RTD,优先用差分接法,因为铂电阻信号微弱,差分输入可以抵消共模干扰。
通道分配上有一个原则:模拟输入通道要尽量远离数字接口引脚。ADS122U04 的引脚布局里,AIN 在芯片一侧,UART 在另一侧,PCB 布线时要注意让模拟走线不要跨过数字走线,尤其是时钟或串口数据线。如果四路信号都接入,输入多路复用器是单端还是差分工作,会直接影响通道间串扰。我的经验是多路测温系统里,相邻通道之间串联一个几毫秒的建立时间,让 PGA 稳定后再启动转换。
接线方式上,RTD 推荐三线制或四线制,不要用两线制。两线制导线电阻会直接叠加到传感器阻值上,PT100 两米线长可能带来 0.5℃ 以上的误差。三线制用 IDAC 电流源和差动输入可以补偿导线电阻,四线制精度最高。HVAC 里很多现成传感器是两线制的,这时候只能在软件里做线阻补偿,或者干脆改用更高阻值的 Pt1000,降低导线电阻误差占比。
2.2 激励电流、基准电压和比率测量
测 RTD 的标准做法是用 IDAC 提供一个恒流源,电流流过 RTD 产生电压,再被 ADC 采集。ADS122U04 有两个 IDAC,可以配置成 50µA 到 1.5mA 多档。Pt100 阻值大概在 100Ω 到 390Ω,如果选 1mA 电流,最大电压也才 0.39V,PGA 增益 4 倍时满量程约 5V 内,余量充足。但如果用 Pt1000,阻值能到 3.9kΩ,1mA 电流会带来 3.9V 压降,PGA 可能饱和,所以要降到 250µA 或 500µA。电流越大,传感器自热越严重,尤其 NTC 和薄型 RTD 在静止空气中自热可能让读数偏高 0.2℃ 以上,我一般限制在 500µA 以内。
所谓比率测量,是指 ADC 的参考电压也由同一个 IDAC 流过精密电阻产生。这样就算 IDAC 电流随温度变化,传感器电压和基准电压以相同比例变化,最后转换结果几乎不受电流源漂移影响。外部基准电阻 RREF 我选了 0.1% 精度、温漂 5ppm/℃ 的精密电阻,阻值按量程选择,比如 Pt100 用 2kΩ 做基准,这样 ADC 输入范围始终在满量程的合理区间内。内部基准当然也能用,但性能不如外部比率基准稳定,除非是 NTC 这种对精度要求不高的场景。
2.3 模拟前端保护与滤波
工业现场传感器线缆经常长距离走线,浪涌、静电、感应雷都可能从输入线打进来。ADC 输入引脚很脆弱,必须在输入前端加保护。我在每个模拟输入端对地并联双向 TVS 管,串联 1kΩ 限流电阻,再在 ADC 输入端对地并联 10nF C0G 电容。TVS 管选 5V 或 6V 击穿电压的,配合内部 ESD 结构,能承受 IEC 61000-4-2 级别的静电放电。C0G 电容比 X7R 电容在温度变化下容值稳定,噪声性能更好,这个细节很多设计容易忽略。
RC 滤波的截止频率我放在 100kHz 到 1MHz 之间。温度信号变化极慢,不需要太高的带宽,RC 滤波的作用是把射频干扰和数字开关噪声滤掉。要注意电阻值太大会和 ADC 输入漏电流造成直流误差,同时大阻值电阻本身也是噪声源,热噪声和电流噪声都需要权衡。1kΩ 和 10nF 组合的截止频率约 16kHz,实测对 ADS122U04 的采集结果没有明显精度损失。
热电偶信号特别微弱,K 型热电偶的灵敏度大约 41µV/℃,一摄氏度才 41 微伏,所以保护电路的漏电流要尽量小。我在热电偶通道用的是低漏电流的 BAV199 二极管串联电路,而不用普通 TVS,因为普通 TVS 结电容大、漏电流大,会把微伏级的信号吃掉。
2.4 电源、地与 PCB 布局要点
ADS122U04 的模拟电源我用了一颗低噪声 LDO,输入从 24V 或 12V 系统电源经 DC-DC 转换后再稳压到 3.3V,LDO 输出端并联 10µF 陶瓷电容和 0.1µF 高频电容。数字电源和模拟电源之间串一个 10Ω 磁珠做分割,模拟地、数字地在 ADC 底下单点相连,避免数字开关噪声通过地平面串入模拟信号。STM32F334 的电源做成独立的数字电源岛,两个电源域之间不共用走线。
PCB 布局的核心原则是:模拟输入走线尽量短,远离串口线和 PWM 线;RREF 基准电阻靠近 REFP/REFN 引脚;IDAC 输出先过 π 型滤波再接传感器。如果有高频逆变器或电机驱动在旁边,模拟区域最好包一个地环,输入信号走屏蔽线,屏蔽层单端接地。温漂对硬件的影响莫忽略,RREF、分压电阻这类决定精度的器件要选低温漂类型,否则软件怎么校准都没用。
3. 软件实现:初始化、通信与温度计算
3.1 STM32CubeMX 工程配置
我在 STM32CubeMX 里先把串口配好。ADS122U04 接 USART1,波特率默认可以用 9600,后面按需要提到 115200。串口参数 8 位数据、无校验、1 位停止位,这是 TI 串口 ADC 的常用帧格式。另一路 USART2 预留接上位机或 Modbus 网关。GPIO 方面,一个引脚接 ADC 的 /DRDY,用它做数据就绪中断;一个引脚作为 ADC 复位输出,低电平复位 ADS122U04。
工程里开启定时器做周期轮询,我用 100ms 周期的定时器中断,每次触发后发起一次采样,这个节奏对 HVAC 和工业测温足够了。如果后续要接多个 ADS122U04 扩展通道,只需要给每个 ADC 单独分配一组 UART 引脚和 /DRDY 引脚,代码框架不变。CubeMX 生成工程后,我新建了一个ads122u04.c文件,把所有驱动封装好,上层只调ADS122U04_ReadTempC()。
3.2 ADS122U04 寄存器初始化
ADS122U04 的寄存器配置思路参考 ADS1220 系列,核心是四个配置寄存器:CONFIG0 管输入多路复用器和 PGA 增益,CONFIG1 管数据速率和转换模式,CONFIG2 管 IDAC 电流和基准电压来源,CONFIG3 管内部温度传感器开关和低噪声模式。以下是我的初始化序列,直接抄能跑:
#define ADS122U04_CMD_RESET 0x06 #define ADS122U04_CMD_WR_REG 0x40 #define ADS122U04_CMD_RD_DATA 0x1C uint8_t cfg0 = 0x00; // AIN0/AIN1 差分输入,PGA 增益 1 uint8_t cfg1 = 0x04; // 数据速率 20SPS,单次转换模式 uint8_t cfg2 = 0x80; // 使用外部基准,IDAC 电流 500uA uint8_t cfg3 = 0x00; // 禁用内部温度传感器,PGA 正常工作 // 写寄存器 uint8_t buf[4] = {cfg0, cfg1, cfg2, cfg3}; ADS122U04_WriteCommand(ADS122U04_CMD_RESET); HAL_Delay(10); ADS122U04_WriteReg(0x00, buf, 4);寄存器位定义在不同批次里可能有差异,具体务必以数据手册和官方驱动为准。我这里的 cfg0 表示 AIN0 和 AIN1 接成差分对,PGA=1;如果测热电偶,PGA 可以设成 32 或 64,把小信号放大到满量程附近。cfg1 我选 20SPS,这个速率配合 SINC3 滤波器,在 50Hz 工频处有不错抑制。cfg2 里把 IDAC 接到 AIN2 引脚,为 RTD 提供激励电流,基准来自 REFP/REFN 外部引脚。
初始化的时间顺序有讲究:先复位,等 10ms 让内部振荡器稳定,再写配置。如果上电后立刻写寄存器,ADC 内部可能还没从复位状态恢复,命令被吞掉,表现为读回来的寄存器全是默认值。我吃过这个亏,后来一律在复位后加HAL_Delay(50),稳如老狗。
3.3 UART 通信与数据帧解析
ADS122U04 的 UART 通信是主机-从机模式,STM32 作为主机主动发命令,ADC 收到命令后回复数据帧。读取转换结果的典型流程是:主机发送启动转换命令,等待 /DRDY 引脚拉低,再发送读取数据命令,ADC 回复一串字节,里面包含 24 位转换结果和状态信息。
我实际使用的是中断方式接收,串口空闲中断检测一帧结束,然后解析帧内容。框架如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart == &huart1) { ads.rx_done = 1; memcpy(ads.rx_buf, ads.uart_rx_buf, 8); } } void ADS122U04_StartConversion(void) { uint8_t cmd = 0x08; // 启动单次转换命令 HAL_UART_Transmit(&huart1, &cmd, 1, 100); } int32_t ADS122U04_ReadData(void) { // 等待 /DRDY 变低 while (HAL_GPIO_ReadPin(DRDY_GPIO_Port, DRDY_Pin)) ; uint8_t cmd = 0x1C; HAL_UART_Transmit(&huart1, &cmd, 1, 100); // 等待接收完成,解析 24 位有符号数 while (!ads.rx_done) ; int32_t raw = (ads.rx_buf[0] << 16) | (ads.rx_buf[1] << 8) | ads.rx_buf[2]; if (raw & 0x800000) raw |= 0xFF000000; // 符号扩展 ads.rx_done = 0; return raw; }数据帧的字节序和状态位位置要以数据手册为准,我这里按高字节在前的写。新手最容易踩的坑是以为一帧只有三个字节的 24 位数据,结果因为没读完多余的字节,导致后续一帧错位。我建议每次读取不管用什么命令,都按固定帧长把数据读完,必要时在软件里做帧头同步。还有一种做法是在命令帧里加校验字节,ADS122U04 支持 CRC 校验命令,工业现场建议开启,防止串口误码。
通信超时必须有。ADC 偶发不响应是常事,程序里用 DMA+空闲中断设一个 50ms 超时,超时后重新发送命令,连续三次失败就认为通信异常,置报警标志。否则一旦 ADC 死机,整个系统会卡死在读数据的 while 循环里。
3.4 RTD、热电偶、NTC 温度换算
拿到 24 位原始码后,第一步先换算成电压或电阻。ADC 的双极性输出码范围是 -2^23 到 2^23-1,满量程对应正负参考电压除以 PGA 增益。公式:
VIN = (Code / 0x7FFFFF) × (VREF / PGA)
如果是 RTD 比率测量,直接算电阻更方便。因为激励电流同时流过 RTD 和基准电阻,参考电压 VREF = I × RREF,RTD 上压降 V_RTD = I × R_RTD,代入后电流 I 抵消:
R_RTD = (Code / 0x7FFFFF) × (RREF / PGA)
不要小看这个比率测量的好处,即使 IDAC 电流漂移了 1%,RTD 电阻计算值几乎不受影响。硬件上为了这个优势,我选基准电阻时特意用低温漂类型,因为这是整个换算链路上唯一决定精度的物理量。
RTD 的阻值转温度,我用 Callendar-Van Dusen 方程。0℃ 到 850℃ 范围:
R(T) = R0 × (1 + A×T + B×T²)
-200℃ 到 0℃ 范围加一项:
R(T) = R0 × [1 + A×T + B×T² + C×(T-100)×T³]
其中 R0 = 100Ω,A = 3.9083e-3,B = -5.775e-7,C = -4.183e-12。反向求 T 不能直接解,我用的牛顿迭代法,初始值猜 25℃,迭代三次就收敛到 0.001℃ 以内。就算手写代码也就十几行。下面是我项目里使用的:
float Pt100_R2T(float R) { float T = 25.0f; for (int i = 0; i < 5; i++) { float dR = R0 * (A + B * T); float f = R0 * (1 + A*T + B*T*T) - R; if (fabsf(dR) < 1e-9f) break; T -= f / dR; } if (T < 0.0f) { float T2 = T; float f = R0*(1 + A*T2 + B*T2*T2 + C*(T2-100)*T2*T2*T2) - R; // 负温区再用一两次迭代修正 } return T; }热电偶换算是另一套逻辑。K 型热电偶输出的热电势 E(T) 是对测量端温度与冷端温度之差的非线性函数。实际操作是:先用内部温度传感器或 NTC 测冷端温度 T_cold,然后查 NIST 多项式得到 E(T_cold),再测量端热电势 E_meas,两者相加得到 E(T_hot),最后反查多项式求得 T_hot。代码实现可以用查表加线性插值,也可以直接跑 NIST 的 9 阶多项式。查表法占用 Flash 大但速度快,多项式法代码短但要小心浮点差异,我最终选了查表法,因为现场调试时可以用万用表直接核对着表头验证。
NTC 热敏电阻用 Steinhart-Hart 方程:
1/T = A + B×ln(R) + C×(ln(R))³
系数 A、B、C 可以用数据手册给定的三个阻值点反推,网上有计算器。NTC 的精度整体不如 RTD,但胜在便宜、响应快,HVAC 面板温度、风管温度够用。注意 Steinhart-Hart 公式的 T 是开尔文温度,换算回摄氏度时要减 273.15。我见过同事把这个常数漏了,整个系统读数偏了 273 度,排查半天才发现。
3.5 连续测量与滤波策略
温度信号是慢变量,但工业现场会有振铃、风扇气流、电磁干扰造成短时尖峰。我做了两级处理:第一级是硬件 RC 已经滤掉的射频干扰,第二级是软件最常用的滑动平均滤波,窗口长度取 8 到 16 个点。用 Cortex-M4F 的 DSP 指令做这个滤波很轻松,CPU 占用不足 1%。
窗口长度不是越大越好。HVAC 的风管温度响应时间本身有几十秒,窗口取 16 点没问题。但如果是测电机轴承温度并且要做保护,滤波窗口太长会导致报警滞后,反而危险。我做过一种改进方案:保留中值滤波和滑动平均两级,先用中值滤掉毛刺,再做轻量平均,效果比单纯平均好很多。工业现场偶发的静电脉冲会造成一个孤立大跳变,滑动平均会让这个尖峰缓慢影响输出,温度表会看到一条假曲线,中值滤波直接把尖峰踢掉了。
滤波之后,如果要做 PID 温控,建议把滤波后的温度作为反馈,并把滤波前原始值记录在 Ring Buffer 里,方便出故障时回溯。我在项目里就把最近 100 次转换的原始码存下来,一旦系统报超温,上位机可以拉出这段日志,很快定位是传感器问题还是控制问题。
4. 实测表现与性能调优
4.1 有效位数与噪声表现
实际测试中,在 20SPS、PGA=1 的条件下,把输入端短接,采集 1000 个数据点,峰峰值噪声大约在 5 到 6 LSB 左右,折合输入电压噪声约 1.4µV。对于 K 型热电偶,41µV/℃ 的灵敏度下,这个噪声对应约 0.03℃ 的分辨率。PGA=16 时噪声会按增益折算,等效分辨率依然能到 0.05℃ 量级,这套系统做 HVACC 控制绰绰有余,做实验室级测量也勉强够。
但 24 位不是“始终都有 24 位”,这是新手最容易误解的。有效位数取决于 PGA 增益、数据速率、参考电压噪声和 PCB 布局。数据速率越高,有效位数越低。我在 20SPS 下的 ENOB 测下来约 20 位,如果跑到 1kSPS,ENOB 会掉到 16 位左右。对温度测量,慢速率反而是优势,所以我日常固定在 20SPS 或 50SPS。
噪声表现还有一个关键因素是参考电压。如果外部基准本身噪声大,ADC 位数再高也没用。我用示波器测过 RREF 两端的纹波,纯净度直接决定了转换结果的稳定性。如果发现噪声偏大,先看参考电压,再看 MCU 数字电源有没有串扰到模拟地。
4.2 校准与误差补偿
未校准前,这套电路的绝对误差主要来自几个方面:基准电阻精度、PGA 增益误差、ADC 失调电压、传感器自身误差。其中传感器误差是最大的,比如 0.1% 精度的 Pt100 在 0℃ 处的偏差可能有 ±0.25℃,系统做得再好也绕不开这个基础误差。所以我在系统层面预留了软件校准接口。
实际操作分两步:一是零点校准,把 RTD 探头放进冰水混合物或者用标准电阻箱模拟 0℃,读取 ADC 原始码,算出失调量存进 Flash;二是满度校准,用一个高精度标准电阻(比如 300.00Ω 对应约 527℃ 的 Pt100 阻值)测出增益误差。校准系数通过上位机指令写入,不需要重新编译固件。这套两点校准做完,系统在 0℃ 到 100℃ 区间的误差控制在了 ±0.15℃ 以内。
热电偶校准更复杂,因为冷端补偿和热电偶本身的分度偏差叠加在一起。我的做法是:用恒温槽加标准铂电阻做参照,在 0℃、50℃、100℃ 三个点做补偿,软件里存一张修正表。现场工程如果只要求 ±1℃ 精度,单点零点校正其实就够,别过度设计。
4.3 工频干扰抑制实用技巧
50Hz 工频干扰在工业环境里无处不在,尤其传感器线缆和动力电缆走在一起的时候。ADS122U04 内置 SINC3 数字滤波器,不同数据速率对应的陷波频率不同。20SPS 时滤波器在 50Hz 有陷波,但 50SPS 时陷波点在 50Hz 的整数倍,实际测试下来 20SPS 对 50Hz 的抑制效果最明显。这是我把默认速率设为 20SPS 的直接原因。
软件层面再叠加一个工频同步平均法:用市电过零信号触发采样,每次都在相同相位采集,这样工频干扰在固定相位上表现为固定偏置,可以通过校准减去。我实际做过一版,在干扰强的机柜里效果立竿见影,但需要额外接线检测市电过零,成本略高。一般场景硬件 RC+软件平均后,干扰已经可以忽略,不太值得增加复杂度。
模拟前端布线也有讲究:传感器屏蔽层要在 ADC 端单点接地,不要在传感器端接地,否则形成地环路,工频感应反而更强。这是现场抗干扰屡试不爽的招。
5. 常见问题与调试实录
5.1 UART 通信异常排查
我调试中最常见的问题是 ADC 完全不响应或返回的数据错位。第一步用示波器看 UART 波形,检查 TX/RX 空闲电平、波特率误差。ADS122U04 的 UART 波特率由内部振荡器决定,MCU 这边波特率不能差太多,超过 2% 就会丢帧。所以 MCU 串口时钟源尽量用外部晶振,不要用内部 HSI 的近似值,我遇到过一次因为 CubeMX 里用的是 HSI 分频,波特率偏差达到 3%,通信时好时坏,换成 HSE 后立刻正常。
第二个坑是 TX/RX 接反。有些人习惯 MCU-TX 接 ADC-RX,就认为收发交叉了,结果把两个 RX 接在一起,数据发不出去。ADS122U04 是 UART 协议,MCU 的 TX 必须接 ADC 的 RX,MCU 的 RX 接 ADC 的 TX,这点和 SPI 的 MOSI/MISO 概念不同。
第三个问题是命令帧多余字节。读数据命令发出后,ADC 会连续发送一帧数据,如果代码里用HAL_UART_Receive只读三个字节,剩下的字节留在缓冲区,下一次读就会错位。解决方法是每次读固定帧长,数据手册里有明确长度,我直接按最长帧读,然后从帧头找数据。启动转换命令和读数据命令之间要有足够延时,有些版本需要几毫秒,我加了一个 5ms 延时保平安。
5.2 读数漂移与跳变
读数稳定但漂移,大概率是温度场的问题而不是电路问题。RTD 自热会表现为电流越大读数越高,切断激励电流后用室温对比,就能判断自热程度。HVAC 风管里风速快散热好,自热不明显,但在保温材料里或静止空气中,自热可能让读数偏高 0.2℃。我实际测试过 500µA 和 1mA 两档,在同一个探头封装里,读数差了快 0.4℃,后来统一降到 250µA,精度和稳定性都好了。
读数随机跳变,先看输入侧是不是有高频干扰。工业现场如果有变频器,高频共模干扰可以绕过 RC 滤波直接耦合进 ADC。对策是加强屏蔽和接地,或者在输入侧增加共模电感。还有一种可能性是 MCU 的 /DRDY 引脚受到 PWM 干扰,信号处理时被误触发了,导致读到不完整的转换结果,我后来在 /DRDY 引脚加了一个 10kΩ 上拉和 1nF 电容,改善明显。
5.3 冷端补偿的坑
热电偶冷端补偿是调试里最容易出问题的地方。我曾经把冷端温度传感器放在 MCU 旁边,结果 MCU 发热导致冷端读数偏高 2℃,最终热电偶显示温度整体偏低了 2℃。冷端温度传感器必须尽量贴在热电偶的接线端子或参考结上,和被测对象的发热源保持距离。
软件里的冷端补偿逻辑也要小心。内部温度传感器测的是芯片管芯温度,往往比实际冷端温度高一点,尤其是 PCB 上有功率器件时。我后来改成外部 NTC 贴在热电偶端子处,用 ADS122U04 的另一个输入通道测冷端温度,精度好很多。补偿公式里的热电偶多项式系数要注意单位,NIST 多项式输入是毫伏,计算时和 ADC 采到的电压单位要一致,否则差个 1000 倍。
5.4 发热与自热问题
ADS122U04 本身功耗不大,但电源 LDO 和 MCU 的发热会通过 PCB 传导到传感器端子,造成系统误差。PCB 布局时,传感器接线端子和 ADC 引脚尽量离 LDO 远一些,中间可以加镂空地槽做热阻隔。STM32F334 的高速运行发热不可忽略,如果它和前端采集部分做在同一块小板上,我建议把 MCU 放板边,传感器接线区放板角,保持热隔离。
还有一个小技巧是传感器检定周期里不要频繁开关激励电流,因为电流源自热会影响重复性。我在轮询多通道时,让每个通道的 IDAC 一直开着,而不是每次采集前才打开,这样热平衡稳定,读数更一致。代价是功耗略高,但对板级系统完全可以接受。
5.5 从 MCU 到上位机的数据对接
最后提一下数据对接,这往往是项目收尾时最拖时间的环节。我用 Modbus RTU 协议上报温度值,STM32F334 的另一个 UART 接 RS485 芯片,寄存器表里每个通道占两个 16 位寄存器,一个存整数部分,一个存小数部分。上位机只需要按标准的 03 功能码读保持寄存器即可。如果只是做 HVAC 本地控制,不上位机,也可以直接 PWM 输出控制阀门开度,F334 的高精度定时器干这个非常合适。
通信协议上别漏了设备地址和波特率的可配置性。现场总线总会有冲突,我把地址和波特率做成参数存在 Flash,通过串口命令行修改。正式投运前做一次 72 小时老化测试,重点观察通信错误计数和温度日志有没有毛刺,这种慢变量系统没有别的捷径,就是静下来跑数据、看趋势、找异常。
我个人在最终调试阶段最大的体会是:温度测量系统的精度不只是 ADC 性能决定的,而是传感器、激励电流、基准电阻、PCB 布局、软件滤波和校准系数共同作用的结果。把每个环节控制在合理范围内,这套 ADS122U04IPWR 加 STM32F334R8 的方案,完全能支撑从 HVAC 舒适性控制到工业过程监控的绝大多数测温需求。