☰
UART接口ADC+STM32F072RB实现高抗干扰温度采集方案
2026/11/5 6:26:37 网站建设 项目流程

去年做一个HVAC冷站改造项目,让我对“温度测量”这四个字彻底改观。现场温度传感器分散在空调箱、水管和风道里,离主控柜最远的走线超过30米,我一开始沿用老做法——PT100模拟信号直接进控制器,结果调试那几天快崩溃:变频器一启动,温度读数就跳±2°C,怎么滤波都压不住。后来我换了个思路,把ADC从控制器端挪到传感器端,用数字接口传回主控,干扰问题基本消失。那颗ADC就是 ADS122U04IPWR,主控则是 STM32F072RB。这篇文章就围绕这个组合,记录我在工业与HVAC场景下做温度采集的完整过程:信号链设计、硬件布局、固件实现、线性化算法,以及踩过的那些坑。

1. 为什么是“UART接口ADC + M0内核MCU”这个组合

1.1 传统模拟传输方案的三个痛点

在HVAC系统里,温度传感器最大的特点不是精度要求高,而是距离远、数量多、环境杂。空调箱内部的传感器距离控制器动辄十几米,冷水管上的传感器还要穿过强电桥架。传统方案是传感器直接接模拟量输入模块,PT100经电桥或恒流源变成电压,长线传到控制器端再进ADC。

这个方案有三个绕不开的问题。

第一是压降与线阻误差。两线制PT100连几十米线,线阻本身就能带来好几欧姆的误差,换算成温度就是几度。即使用三线制补偿,现场接线不规范也白搭。

第二是共模干扰。变频器、接触器、大功率水泵启动的时候,长线就像天线,把共模噪声全都带进来。普通差分放大器在高共模环境下很容易饱和,ADC输入端直接扛不住。

第三是布线成本。每个传感器都要拉到控制器,30个点就是30根电缆,穿管、桥架、编号,施工量很大。

所以那段时间我一直在想:能不能把ADC放在传感器那一端,把模拟量就地数字化,然后用数字总线传回来?这正是 ADS122U04IPWR 这种带UART接口ADC出现的最佳场景。

1.2 为什么 ADS122U04IPWR 适合做“就地数字化”

ADS122U04IPWR 是TI的一颗24位ΔΣ ADC,最明显的特点是集成UART接口,而不是常见的SPI/I2C。它内部包含一个4通道输入多路复用器、可编程增益放大器(PGA)、两个可编程激励电流源(IDAC)、内部2.048V参考电压,以及一个内部温度传感器。

单独说任何一个特性都算不上惊艳,但这个组合非常适合HVAC现场:

  • 24位分辨率:温度传感器输出电压信号通常只有几毫伏到几十毫伏,特别是热电偶,信号级别在微伏到毫伏之间。24位ΔΣ ADC加PGA放大后,能把微小信号从强干扰背景里“抠”出来。
  • 内置IDAC激励源:PT100/PT1000这类电阻型传感器,必须有恒流源激励才能测量。内置双IDAC意味着不需要外部恒流源,而且可以做比例测量,消除激励电流自身漂移带来的误差。这个下面会详细展开。
  • 内部参考电压:省掉外部基准芯片,降低BOM成本。配合IDAC,还能用外部精密电阻做比例基准,比内部参考更稳。
  • UART接口:在工程上,UART是嵌入式系统里最直白的接口。它不像SPI需要时钟线、片选线,也不像I2C有从机地址和上拉电阻的麻烦,只要两根线就能通信。更关键的是,UART可以方便地转成RS485,实现几十米甚至上百米的可靠传输。

从产品设计角度看,这种结构特别适合做成一个小型采集模块:传感器插在模块上,模块里跑一个STM32F072RB,把测量结果打包成协议,通过RS485或CAN发给中央控制器。ADC靠近传感器,信号路径最短,干扰也最小。

1.3 STM32F072RB 在这个项目里的角色

STM32F072RB 是ST的一款Cortex-M0+内核MCU,主频48MHz,128KB Flash,16KB SRAM。单独看性能参数,它在这个组合里显得相当低调,但它有几个点正好匹配这类采集场景:

  • 多个UART外设:一个UART接ADS122U04IPWR,另一个UART接RS485收发器,资源完全不冲突。F072最多有4个USART,做多路采集模块也够用。
  • 带CAN 2.0B控制器:HVAC和工业项目里,CAN总线比RS485更皮实、实时性更好,而且F072本身就有CAN外设,不需要外加CAN控制器芯片。
  • 低功耗与成本:M0+内核功耗低,价格便宜,在每块板子省几块钱的批量项目里,这个优势很实在。

我最终确定的硬件拓扑是:ADS122U04IPWR 作为传感器前端,通过UART连接 STM32F072RB;STM32F072RB 负责配置ADC、读取原始码、做线性化计算,然后通过RS485/Modbus或CAN上传给上位机。这套结构可以覆盖绝大多数HVAC温度采集需求。

2. 信号链设计:传感器激励、PGA增益和参考电压

2.1 传感器选型:PT100、PT1000还是NTC

工业与HVAC温度测量,传感器类型往往比ADC本身更影响最终精度。按我的经验,HVAC项目里90%的场景用这三类:

传感器类型典型温度范围灵敏度成本适用场景
PT100-200°C ~ 850°C0.385 Ω/°C中等水管温度、风道温度、冷站控制
PT1000-50°C ~ 300°C3.85 Ω/°C中等与PT100类似,长线时线阻影响小
NTC 10K-40°C ~ 150°C约 -4%/°C(非线性强)低室内温度、回风温度、舒适性控制
热电偶 K型-200°C ~ 1300°C约 41 µV/°C低工业管道高温、烟气温度

HVAC系统里最常用的还是PT100和PT1000。PT100的精度高但信号微弱,PT1000的信号是PT100的10倍,导线电阻引起的误差比例小,但传感器本身响应略慢。如果是长距离布线且没有三线制条件,我会优先选PT1000。

NTC虽然便宜,但B值一致性差、长期稳定性也不如铂电阻,只用在舒适性控制这种不追求精度的场合。真要在0°C~100°C范围内做到0.2°C以内的偏差,铂电阻是更靠谱的选择。

2.2 RTD比例测量:两个IDAC的价值

ADS122U04IPWR测量RTD的原理值得仔细讲一遍,因为它直接决定了误差到底被消除到什么程度。

RTD本质上是一个随温度变化的电阻。测量思路是给它加一个已知电流,然后测它两端的电压。但激励电流本身会随温度漂移,如果用固定的电流源去做计算,电流漂1%可能对应温度误差好几度。比例测量就是为了解决这个问题。

做法是这样的:用IDAC1产生一个激励电流,让它流过外部精密基准电阻R_REF,同时流过RTD。ADC用R_REF两端的电压作为参考电压,测RTD两端的电压。

假设激励电流为I,那么:

  • V_REF = I × R_REF
  • V_RTD = I × R_RTD

ADC输出的数字量正比于V_RTD / V_REF,也就是:

R_RTD = (V_RTD / V_REF) × R_REF

关键在于,I同时在分子和分母里,最终被约掉了。所以激励电流的绝对值漂移、温漂、纹波,都不影响最终测量结果。ADC的比例测量特性把电流源精度要求从“绝对精度”降到了“短期稳定性”,这是工业温度测量里非常经典也非常实用的一招。

三线制RTD的接法,是把RTD的一端分别引出两条线到ADC的同一输入通道,另一端点接另一输入通道。两个IDAC分别配置到两个激励通道,使得流过两条引线的电流相等,引线电阻上的压降在差分测量里被互相抵消。

我这里用的配置是:

  • IDAC电流设为1mA(PT100在1mA下自热很小,约几毫瓦)
  • R_REF选1.8kΩ低温漂电阻(25ppm/°C或更好),参考电压 = 1mA × 1.8kΩ = 1.8V
  • PGA增益设为4,因为PT100在100°C时电阻约138.5Ω,两端电压约0.138V,增益4之后约0.55V,远低于参考电压1.8V,留有充分裕量
  • 数据速率设置在20SPS,这是为了把工频干扰和噪声压到最低

2.3 热电偶测量与冷端补偿

如果用ADS122U04IPWR测K型热电偶,信号链又是另一套玩法。热电偶输出电压随温度变化,灵敏度约41µV/°C,信号特别小。PGA需要放到64甚至128倍,参考电压改用内部2.048V,输入范围要匹配热电偶的电压范围。

热电偶的本质是产生“热端与冷端温度差对应的热电势”。比如K型热电偶,热端在100°C、冷端在25°C时,输出约3.1mV。如果冷端温度变化,读数就会跟着漂。冷端补偿的核心思路是:用另一支温度传感器测出冷端实际温度,再把这个温度对应的热电势补偿回去。

ADS122U04IPWR内部集成了温度传感器,精度虽然比不上专用的冷端补偿芯片,但在HVAC这种场景下够用了。我在固件里是这样处理的:

  1. 先读内部温度传感器,得到冷端温度T_cold
  2. 用K型热电偶的NIST多项式,算出冷端对应的热电势E_cold
  3. 读ADC获得热电偶输出电压E_measured
  4. 计算E_hot = E_measured + E_cold
  5. 用反查多项式的办法,由E_hot求出热端温度T_hot

这里有个工程细节:内部温度传感器读数本身也有噪声,直接把T_cold塞进查表流程,会把噪声引入最终温度。我的做法是先做32次平均,再参与冷端补偿计算。实测下来,冷端噪声对最终读数的影响可以控制在0.05°C以内。

2.4 模拟滤波与保护电路

ADC之前的一小段模拟电路,对最终精度的影响可能超过ADC本身。我在这块板子上做的处理是:

  • 差模RC滤波:在每个AIN输入引脚上串联22Ω电阻,并在差分输入之间跨接一颗100nF的C0G电容。这个组合的截止频率在72kHz左右,主要用来抑制高频干扰,同时给ΔΣ ADC内部的采样电容提供电荷。
  • 共模滤波:每个AIN引脚对地再接100nF电容,进一步降低共模射频干扰。注意这里差分电容和共模电容的比例要控制,否则输入共模电压会因为充放电不平衡而畸变。
  • TVS管保护:传感器线缆在工业现场容易碰到浪涌和静电,我用了5V的双向TVS并联在输入端。ADS122U04IPWR允许的绝对最大输入电压是AVDD+0.3V,TVS必须把钳位电压控制在安全范围之内。
  • 限流电阻:在TVS后面串1kΩ电阻。如果出现异常高压,这个电阻能限制流入ADC引脚的电流,避免内部ESD二极管过流损坏。

HVAC现场还有一类常见干扰源:24V电磁阀和变频器共箱布线。传感器电缆虽然屏蔽,但屏蔽层如果两端都接地,反而会形成地环路。我的经验是屏蔽层只在传感器端单点接地,控制器端悬空,实测噪声下降非常明显。

3. 硬件布局:24位ADC对PCB设计的要求

3.1 电源、参考电压与去耦

ADS122U04IPWR的供电是单电源2.3V~5.5V,我用的是3.3V,和STM32F072RB共用一路电源。但这不意味着可以随便共电——24位ADC对电源上的纹波非常敏感,特别是PGA增益放大的时候,电源纹波会直接耦合到模拟输入端。

我在这块板子上做了三层处理。

第一,模拟电源与数字电源之间串一颗磁珠。磁珠在高频下呈现高阻,能把STM32跑起来的高频噪声堵在数字区域。

第二,AVDD引脚用两颗电容去耦:1µF的X7R和0.1µF的C0G并联,都尽量靠近引脚。X7R负责低频储能,C0G负责高频旁路,两种材质互补。

第三,参考电压虽然没有单独的REFP/REFN引脚(RTD比例模式下参考电压来自外部R_REF),但R_REF两端的电压直接送到ADC的参考输入端,所以必须配一个0.1µF的C0G电容,紧贴参考输入引脚放置。如果此处的电容用了X7R或Y5V,温漂会让参考电压跟着漂,最终温度读数就会呈现肉眼可见的漂移。

3.2 地线处理:模拟地、数字地、传感器地

我见过太多温度采集板,ADC精度本来够,PCB布局一塌糊涂,出来的数据还不如16位ADC。ADS122U04IPWR这类ΔΣ ADC对地线最敏感的地方是输入信号的单点接地。

我的布局原则是:

  • 模拟地与数字地物理分割,在ADC芯片下方的星点位置单点连接。
  • STM32F072RB的数字地、晶振地、去耦电容地都走数字地平面,绝不穿过模拟输入电路。
  • 传感器输入插座的地引脚,直接接到模拟地,信号地与大地之间用1MΩ电阻并联0.1µF电容连接,避免静电积累又阻断地环路。
  • ADC芯片下面的模拟地和数字地引脚,不需要割开,直接连到各自平面,然后靠中间的桥接点短接。

在四层板上,我通常把第二层作为完整地平面,第三层作为电源平面,顶层和底层走信号。完整的地平面比分割的地平面在高频抗干扰上要好得多,尤其在传感器长线输入的情况下。

3.3 UART电平与长线传输的边界

ADS122U04IPWR的UART接口是标准3.3V逻辑电平,STM32F072RB的UART引脚也工作在3.3V,两者短距离直连没问题。但工程上很容易踩一个认知误区:UART不是拿来长距离传输的,3.3V单端信号走超过 0.5 米就开始有风险。

在这个项目里,我在同一个PCB板上让两芯片直连,距离不超过5厘米。如果需要把ADC模块放到百米之外,我是坚决不用单端UART的,而是用MAX3485把UART转成RS485,双绞线传输,120Ω终端电阻匹配,实测在工业现场跑100米完全没问题。

还有一个经常被忽略的点:UART通信的参考地。ADC和MCU虽然都是3.3V逻辑,但如果两块板子各自用独立电源,地电位差会使逻辑电平失真,甚至烧毁引脚。跨板通信时,我建议要么用共地线,要么加数字隔离芯片。ADuM1201这类双通道数字隔离器成本不高,能一次性解决电平适配和地环路两个问题。

4. STM32F072RB端的固件:UART协议与转换数据读取

4.1 初始化流程与寄存器配置

ADS122U04IPWR上电后不会自动开始转换,需要主机通过UART先配置相关寄存器,再发送启动转换命令。我在STM32F072RB上做的初始化流程是:

  1. 复位ADC(如果硬件上有RESET引脚则拉一下,没有的话通过命令复位)
  2. 等待片内参考电压稳定,至少10ms
  3. 逐字节写入配置寄存器的目标值
  4. 发送开始转换命令
  5. 等待DRDY引脚拉低,表示新数据就绪
  6. 发送读数据命令,接收4字节原始码

为了便于维护,我把寄存器配置封装成了一个表驱动的函数,结构大致是这样的:

static const uint8_t ads_config[4] = { 0x00, // CONFIG0: PGA=1, 数据速率低档 0x10, // CONFIG1: 连续转换模式,IDAC配置中间档 0x80, // CONFIG2: 内部参考使能,R_REF外部参考选择 0x00 // CONFIG3: 禁用温度传感器,输入接RTD }; uint8_t ads_write_config(const uint8_t *cfg, uint8_t len) { for (uint8_t i = 0; i < len; i++) { // 写寄存器命令 + 寄存器地址 uart_write_cmd(ADS_CMD_WREG | (i << 2)); uart_write_byte(cfg[i]); } return 0; }

注意每个芯片的命令编码不是固定不变的,具体要用数据手册里的命令表核对。这里的关键思路是:写寄存器命令是一条字节指令,后面跟数据;读数据命令是另一条字节指令,执行后ADC通过UART把转换结果发回来。

4.2 UART帧协议与状态机设计

用UART接ADC,最容易犯的错误是“发了读数据命令就立刻读串口”。UART是异步传输,ADC收到命令后需要时间准备数据,直接读串口往往会读到上次的数据,或者读到不完整的数据帧。

我在工程上一直用状态机来管理这条UART链路,核心节点是等待DRDY信号。DRDY引脚每完成一次转换就拉低一次,这个信号对于保证“读到的数据一定是最新一次转换结果”至关重要。

状态机大致是:

typedef enum { ST_IDLE, ST_WAIT_DRDY, ST_SEND_RDATA, ST_RECEIVE_DATA, ST_PARSE } ads_state_t; ads_state_t ads_state = ST_WAIT_DRDY; void ads_process(void) { switch (ads_state) { case ST_WAIT_DRDY: if (HAL_GPIO_ReadPin(DRDY_GPIO_Port, DRDY_Pin) == GPIO_PIN_RESET) { ads_state = ST_SEND_RDATA; } break; case ST_SEND_RDATA: uart_write_cmd(ADS_CMD_RDATA); ads_state = ST_RECEIVE_DATA; break; case ST_RECEIVE_DATA: if (uart_rx_len >= 4) { ads_state = ST_PARSE; } break; case ST_PARSE: parse_adc_data(uart_rx_buf); uart_rx_len = 0; ads_state = ST_WAIT_DRDY; break; default: ads_state = ST_WAIT_DRDY; break; } }

实际工程里,我还会加超时判断。如果长时间没等到DRDY或者UART接收超时,就强制复位ADC重新初始化,防止意外卡死。

4.3 DMA接收与中断配合,确保不丢数据

STM32F072RB的UART有DMA功能,使用DMA接收ADC返回的数据是最省心的方式。我配置了一个长度为4字节的固定缓冲区,开启UART空闲中断,收满4字节后DMA完成中断触发解析。

关键点在于:发送读数据命令之前,必须先把DMA缓冲区和接收计数器清零。否则上一次残留的数据会和本次数据混在一起,解析出现错位。

我踩过一次很隐蔽的坑:DMA配置成循环模式,ADC返回的不是4字节,而是因为配置错误返回了8字节甚至更多。解析函数读到缓冲区边界附近时,数据错位导致温度偶尔跳变到几百摄氏度。后来我在DMA完成中断里增加长度校验,只有收满4字节才进入解析,只要不是4字节,一律视为通信异常并复位DMA。

4.4 从原始码到工程值

ADS122U04IPWR返回的转换结果是24位有符号数,读取的4字节里,前三个字节是24位数据,最后一个字节是状态字节。解析方式是把前三个字节拼接成有符号24位整数,然后根据PGA增益和参考电压换算成电压。

我的换算代码大致是这样:

typedef struct { float voltage; float resistance; int32_t raw; } ads_sample_t; ads_sample_t ads_parse(uint8_t *buf) { ads_sample_t s; int32_t raw; raw = ((int32_t)buf[0] << 16) & 0xFF0000; raw |= ((int32_t)buf[1] << 8) & 0x00FF00; raw |= ((int32_t)buf[2]) & 0x0000FF; // 转换为有符号24位 if (raw & 0x800000) { raw |= (int32_t)0xFF000000; } s.raw = raw; // 电压换算,VREF=1.8V,PGA=4, 24位满量程对应2*VREF/PGA s.voltage = (float)raw * 1.8f / 8388608.0f / 4.0f; // RTD:R = V / I,I = 1mA s.resistance = s.voltage / 0.001f; return s; }

换算过程忽略了一个微小误差:1.8V参考电压由IDAC电流和RREF共同决定,RREF实际阻值有误差,所以计算出来的电阻值还需要在固件里做一次增益校准。具体见下一章的校准部分。

5. 从原始码到温度值:线性化、冷端补偿与校准

5.1 PT100的Callendar-Van Dusen公式

PT100的阻值与温度不是线性关系,0°C以上和0°C以下的曲线表达式不同。0°C以上用三阶公式,-200°C到0°C之间还要加一个四次项修正:

  • 0°C ~ 850°C:R(T) = R0 × (1 + A·T + B·T²)
  • -200°C ~ 0°C:R(T) = R0 × [1 + A·T + B·T² + C·(T-100)·T³]

其中:

  • R0 = 100 Ω
  • A = 3.9083 × 10⁻³
  • B = -5.775 × 10⁻⁷
  • C = -4.183 × 10⁻¹²

反向求解时,我不用封闭式求根公式(0°C以下那个四次项非常麻烦,公式又长又容易写错),直接用牛顿迭代法。这个方法通用性强,热电偶反查多项式也能复用同一套逻辑。

static double pt100_temp_from_resistance(double R) { const double R0 = 100.0; const double A = 3.9083e-3; const double B = -5.775e-7; const double C = -4.183e-12; // 初始猜测:用线性近似 double T = (R - R0) / (R0 * A); for (int i = 0; i < 10; i++) { double R_calc; double dR_dT; if (T >= 0.0) { R_calc = R0 * (1.0 + A * T + B * T * T); dR_dT = R0 * (A + 2.0 * B * T); } else { R_calc = R0 * (1.0 + A * T + B * T * T + C * (T - 100.0) * T * T * T); dR_dT = R0 * (A + 2.0 * B * T + C * (4.0 * T * T * T - 300.0 * T * T)); } double delta = (R_calc - R) / dR_dT; T -= delta; if (fabs(delta) < 1e-6) break; } return T; }

这个函数在-50°C到+150°C范围内的误差远小于0.01°C,完全够用。

5.2 热电偶查表与冷端补偿实现

热电偶的NIST多项式是高阶拟合,直接塞进M0+上跑不划算。我的做法是在工程里放一张稀疏的查表,每10°C一个点,用线性插值补齐中间值。表本身用Python生成,嵌入到C数组里。

冷端补偿的完整叠加需要两步查表。第一步,由冷端温度查表得到冷端热电势;第二步,把冷端热电势加到实测电压上,再由总热电势反查温度。反查表时由于多项式单调递增,直接用二分查找即可。

float tc_get_temp_from_voltage(float voltage) { // 二分查找索引 int low = 0, high = table_size - 1; while (high - low > 1) { int mid = (low + high) / 2; if (tc_table[mid].voltage > voltage) { high = mid; } else { low = mid; } } float frac = (voltage - tc_table[low].voltage) / (tc_table[high].voltage - tc_table[low].voltage); return tc_table[low].temp + frac * (tc_table[high].temp - tc_table[low].temp); }

查表精度取决于表的密度。10°C间距的K型热电偶表,线性插值误差约0.05°C,可以接受。如果要求更高,可以改成5°C间距,Flash容量多花几个KB而已。

5.3 校准流程:用万分之一电阻箱还不够

ADS122U04IPWR加上外围电路之后,系统级误差主要来自三处:R_REF的绝对值误差、PGA的增益误差、以及ADC本身失调。

R_REF误差是比例测量的核心误差源。我用的1.8kΩ电阻标称0.1%,对应温度误差约0.25°C,这在HVAC场景下勉强可以,但要做高精度就必须校准。

实战校准流程,我一般分三步:

  1. 失调校准:把ADC输入端短路,读取原始码作为失调值,在换算公式里减掉。这一步能把零点漂移消除。
  2. 增益校准:在输入端接入一个已知精度的电阻(比如100Ω),用校准好的万用表实测其阻值,然后计算修正系数K = R_actual / R_computed。
  3. 线性验证:再接入几个不同阻值(如90Ω、110Ω、120Ω),检查校准后读数与实测阻值之间的偏差。

校准系数存到STM32F072RB的Flash特定扇区里。如果对批量生产有要求,还可以把校准流程做成出厂测试脚本,通过UART自动写入。注意STM32F072RB的Flash扇区写次数有限,不要每次上电都擦写,只在校准模式下写。

这里有个很容易被忽视的点:万用表的四线测电阻精度很高,但校准夹具的接触电阻一样会引入误差。我建议校准夹具用镀金弹片,不要用杜邦线,否则你的校准标准本身就是错的。

5.4 滤波策略:平滑与响应速度的取舍

ADC原始数据的噪声来源很复杂,有芯片自身的量化噪声,也有工业现场的电磁干扰。HVAC系统对温度响应的实时性要求不高,几秒级的滞后完全可接受,所以滤波参数可以拉得比较重。

我用的组合是:中值滤波 + 滑动平均。

  • 中值滤波窗口取5个点,专门去除偶发的尖峰毛刺。
  • 滑动平均窗口取16个点,进一步降低随机噪声。
  • 最终输出频率控制在1Hz左右。

如果现场有变频器干扰,我还会加一个50Hz陷波思路的软件处理。不过要注意,数据速率如果选了50SPS以上,混叠效应可能把工频噪声折回到信号频带内,这属于ADC采样率选择问题,不是滤波能解决的。我的建议是先把采样率降到20SPS,利用ΔΣ ADC内部的数字滤波器,对工频干扰的抑制效果比任何后级软件滤波都好。

6. 实测性能、异常排查与工程化改进

6.1 噪声实测:20SPS下的底线在哪里

我拿这套方案做过长时间带记录仪的测试。传感器用PT100三线制,室温25°C稳定态,记录24小时。

在20SPS数据速率下,ADS122U04IPWR配合PGA=4、外部R_REF比例参考,实际测得的峰值噪声大约是±0.15Ω的读数(对应的峰峰值噪声折算到24位码约几千个LSB)。由于PT100在0°C附近是0.385Ω/°C,这个噪声水平对应温度波动约±0.04°C。再经过中值滤波加16点滑动平均,最终输出波动控制在±0.02°C以内。这个指标对HVAC项目来说是绰绰有余的。

如果切换到640SPS高速模式,噪声会明显增大,峰值噪声折算到温度大约±0.3°C。所以在我的项目里,永远是20SPS跑到底。高速模式只用于上电自检时快速判断传感器是否断路,不用于正常温度计算。

6.2 温度精度验证

我用Fluke 754过程校验仪作为标准温度源,设定了0°C、25°C、50°C、75°C、100°C五个点,校准后实测误差如下(供参考):

设定温度ADC测得温度偏差
0°C0.03°C+0.03°C
25°C25.01°C+0.01°C
50°C49.98°C-0.02°C
75°C75.04°C+0.04°C
100°C100.02°C+0.02°C

这个结果是在做完失调校准和增益校准之后得到的。未校准时,偏差会明显偏大,大约在±0.2°C~0.3°C,主要来自R_REF误差和PGA增益误差。所以别指望芯片本身的24位精度能直接变成系统精度,校准这一步省不了。

6.3 踩坑记录:五个影响数据质量的问题

第一,基准电阻用了普通厚膜电阻。最开始为了省成本,用了一颗普通的0805厚膜电阻,温漂大约±100ppm/°C。到了夏天现场温度升高,读数跟着飘了将近0.5°C。换成25ppm/°C的精密薄膜电阻之后,问题消失。RREF的温漂会直接叠加到温度示值上,而且无法通过软件校准消除。

第二,等待DRDY不够就发RDATA命令。早期固件靠定时器估算转换周期,定时器早了就发读数据命令,结果偶尔拿到旧数据。后来改成真正读取DRDY引脚电平,一次都没错过。

第三,IDAC电流设置过大。最开始PT100激励电流设2mA,虽然信号更大了,但自热效应导致读数持续性偏高约0.08°C。RTD的自热功率和电流平方成正比,1mA下的自热是2mA下的四分之一。只要PGA增益足够,1mA甚至0.5mA是更好的选择。

第四,UART地电位不对齐。有一版采集模块用了独立的24V转3.3V隔离电源,ADC和MCU的参考地电位差有几百毫伏,读出来的数据周期性跳变。我查了很久才发现是UART共地问题,后来用了数字隔离器解决。记住,隔离电源不是免死金牌,必须配上隔离通信才算完整隔离方案。

第五,传感器屏蔽层两端接地。工程队把所有屏蔽线两端都接了大地的地排,结果形成了一个巨大的地环路,变频器启停时测量值剧烈波动。改成传感器端单点接地后,测量值立刻稳定下来。现场接地的教训是:屏蔽层要接,但只能接一头。

6.4 下一版迭代方向:从单点测量到多点网络

这个方案跑通之后,我基于同样的硬件思路做了扩展:把STM32F072RB上的另一个UART口接RS485收发器,用Modbus RTU协议把温度数据上传给中央控制器。一块F072可以接多颗ADS122U04IPWR,每颗负责4个通道,相当于一个模块能覆盖十几路温度点。

STM32F072RB自身还带了CAN控制器,这对工业场景更有吸引力。CAN总线在抗干扰、实时性和布线简化上比RS485更省心,下一版我准备把上传接口换成CAN,中央控制器通过CAN逐一询问各采集模块的数据。对于HVAC这种传感器分散、数量多、距离远但实时性要求不高的场景,CAN总线还真挺合适。

如果你手头正在做类似的工业或HVAC温度采集方案,我的建议是:别在最开始就陷入AD芯片选型对比的纠结里,先把信号链想清楚,再把“ADC怎么靠近传感器”这件事解决掉,后面很多麻烦就自然消失了。ADS122U04IPWR和STM32F072RB这个组合,至少在成本和精度之间找到了一个让我满意的平衡点。

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

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

立即咨询