ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

STM32F042配ADS122U04:UART接口24位ADC打造HVAC高精度测温方案

STM32F042配ADS122U04:UART接口24位ADC打造HVAC高精度测温方案

前阵子给一套暖通空调控制柜做温度测量升级,手头的板子用的是STM32F042C6,原本测温靠NTC加上比较器,误差和一致性都让人头疼。一路查资料、做实验下来,最后落了地的是TI的ADS122U04IPWR——一颗24位Δ-Σ ADC,而且接口是UART而不是常见的SPI。这个UART接口在HVAC和工业控制里特别有用,它让我在不占用SPI总线的前提下,把一个高精度模拟前端直接搭在了MCU的串口上。这篇文章记录完整的选型、硬件、驱动、算法和实际踩坑,给做HVAC温控、工业RTD采集,或者手里有F0小芯片想扩展模拟精度的工程师一个可直接抄的参考。

1. 选型逻辑:为什么偏偏是UART接口的24位ADC配一颗F0小芯片

1.1 从HVAC温控的实际痛点说起

HVAC现场传感器的分布有个特点:风管送风/回风温度、水管供回水温度、机房环境温度,信号线经常要走三五米到几十米。传统NTC加比较器或者直接用MCU内置ADC的方案,在外墙控制柜的恶劣工况下会暴露出一堆问题。

首先是NTC的一致性差。同一型号的10k NTC,B值本身就有分散性,25℃下阻值偏差动辄±1%,换算成温度就是0.25~0.5℃的误差。批量生产时想做到±0.1℃,只能逐台标定,产线成本很高。

其次是长线压降。NTC两线制串联到控制板,线电阻从零点几欧到几欧不等,对0.1℃精度的项目是毁灭性的。哪怕用10k NTC,50米线的电阻也有好几欧,直接吃掉零点几摄氏度。

最后是内置ADC的精度天花板。STM32F042C6内置12位ADC,满量程3.3V时1 LSB约0.8mV,而Pt100在0.1℃时电阻变化只有约0.04Ω,用1mA激励时对应电压变化约0.04mV,完全量不出来。所以当HVAC或者工业项目对温度有0.1℃甚至更高要求时,外置高精度ADC几乎是必选项。24位Δ-Σ ADC配合内置PGA,可以把最小分辨率做到微伏级别,这才具备测量Pt100/Pt1000这类低阻传感器的能力。

1.2 UART接口在整机设计里的现实价值

很多人第一反应是选ADS1220,SPI接口,资料多,参考设计遍地都是。但我最终选了ADS122U04IPWR,核心原因是控制板上SPI总线已经被Flash、LCD、无线模块占了。重新分配CS引脚也能做,但布线、驱动都要改,风险不小。而STM32F042C6有USART1和USART2两个串口,用一个空闲串口接ADC,改动量最小,甚至可以直接复用现成的串口驱动框架。

UART接口相比SPI还有一些工程上的隐性优势。

长线传输更稳。SPI有SCK时钟线,时钟信号容易辐射和产生边沿抖动,走线超过10cm就开始有麻烦;UART用9600或19200波特率传输,低速串行信号抗干扰能力明显更好。

便于光电隔离。如果要在控制板和传感器面板之间做隔离,UART只需要隔离开TX/RX两根线,比SPI的SCK、MOSI、MISO、CS四根线简单很多,光耦成本也低。

软件调试直观。逻辑分析仪直接抓UART命令帧,ASCII/HEX一目了然,定位问题比扒SPI时序快得多。

代价是吞吐率不如SPI,但温度测量属于典型低速应用,ADS122U04在最高数据率下也只要求几十kbps级别的传输,UART完全能扛住。

1.3 为什么是STM32F042C6

这颗芯片库存充足、成本低,Cortex-M0核心确实弱,但温度采集不需要跑复杂算法,主要工作是UART驱动、24位数据处理和PID输出。32KB Flash装下通信协议栈和线性化查表绰绰有余,6KB SRAM足够双缓冲。LQFP48封装引脚少,layout简单,做在小控制板上非常合适。而且F0系列的低功耗模式很适合HVAC控制器长期运行在待机/轮询状态。整体看,一颗F0小芯片加一颗24位UART接口ADC,成本可控、架构干净,是这个选型组合最吸引人的地方。

2. 硬件设计:模拟前端怎么接,才能让24位不白费

2.1 供电与参考电压

ADS122U04IPWR的数字/模拟电源都可工作在1.8~3.6V,和STM32F042C6共用3.3V很方便。但“共用3.3V”和“共用同一个LDO”是两回事。如果板上同时有继电器、风机驱动,开关噪声会通过电源串进模拟部分,24位ADC的性能就会被白白浪费。

我的做法:模拟供电单独走一个低噪声LDO,AVDD和DVDD分别加0.1µF和1µF退耦电容,DGND和AGND在芯片下方单点相连。这个细节看着小,实测对ADC噪声影响非常大。

参考电压是另一个关键点。ADS122U04有内置参考,但内置参考的漂移和噪声在0.1℃级应用里可能吃紧。做RTD比率测量时,更稳妥的做法是把精密参考电阻接在REFP/REFN差分输入端,利用同一个IDAC电流源既产生激励又产生参考电压。这样做的好处是电流源漂移可以互相抵消。如果做绝对电压测量(比如热电偶),优先选温漂≤5ppm/℃的外部基准,比如REF5025,而不是直接用AVDD当基准。

2.2 RTD的2线/3线/4线接法

RTD是低阻传感器,导线电阻是最大误差源。这里给一张对比表:

接法激励/测量方式能否消除导线电阻适用场景
2线IDAC从一根线流入,同一根线测电压否,线阻完全计入传感器和板子距离小于1米,精度要求不高
3线IDAC从AIN0流入,AIN1取差分电压,另一根线补偿基本消除,线路不平衡时剩余少量误差HVAC盘管、管道,工程上最常见
4线两根激励、两根测量完全消除实验室、工业计量级

3线接法的关键:一定要让激励电流路径和电压测量路径分离。我实际试过两种接法,效果差很多。一种是把RTD两根线直接并到AIN0/AIN1,IDAC从同一个节点流入,结果线阻变化直接进测量;另一种是严格按照“激励线走IDAC1,AIN0/AIN1只取电压”来接,长线干扰降了两个数量级。

ADS122U04有IDAC1和IDAC2两个激励源。3线方案推荐这样接:IDAC1接到RTD一端,同时通过独立的电压检测线引到AIN0;RTD另一端接AIN1,另外用IDAC2灌入一条补偿线。电压测量端的高阻特性不会拉低激励电流,线阻上产生的压降要么被差分扣除,要么根本不在测量回路里。

激励电流大小也要选。Pt100用500µA比较合适:自热功率I²R=0.025mW,引起的温升可以忽略。1mA以上在密闭探头里会明显自热,我实测能把读数抬高0.1~0.2℃。Pt1000阻值大,用100µA或250µA即可,自热更小。

2.3 热电偶冷端补偿

如果项目里要测高温,比如工业热风管道或烟道,热电偶方案成本更低。ADS122U04的24位分辨率加PGA对K型热电偶非常充裕,K型热电偶灵敏度约40µV/℃,1 LSB等效温度远小于0.01℃。

但热电偶必须做冷端补偿。冷端补偿是把热电偶冷端放在已知温度处,通常用ADC内置温度传感器或者外接NTC测量冷端温度,再按分度表或多项式补偿。这里有个很重要的经验:冷端温度传感器要放在接线端子的金属夹片附近,而不是放在MCU边上。处理器发热会带来几摄氏度的测量偏差,这个坑非常隐蔽。我第一次做的时候把NTC放在PCB角落靠近CPU的位置,结果热电偶读数差了将近两度,找了好久才发现是冷端温度不对。

2.4 PCB布局与滤波

模拟输入的滤波和布线直接决定ADC实际能到多少位有效分辨率。我的经验参数:

  • 模拟输入引脚前各加一个RC低通,100Ω串联加100nF到地,截止频率约16kHz,用来过滤射频干扰。
  • 传感器信号线用双绞线或屏蔽线,屏蔽层在控制板端单点接地,不要在传感器端也接。
  • ADC模拟输入走线远离继电器、PWM输出焊盘,模拟区下面铺完整AGND。
  • 如果传感器和控制器距离超过5米,不要直接传RTD弱信号,更稳的做法是把ADC芯片放到传感器侧,用UART数字信号回传。这是一个架构层面的大优化。

3. 让UART链路跑起来:ADS122U04的通信协议与驱动要点

3.1 通信帧结构与自检流程

ADS122U04不是简单的“发命令收数据”,它有明确的帧协议。以9600bps、8N1为例,MCU发命令帧,ADC返回应答帧。命令类型包括复位、写寄存器、读寄存器、启动/停止转换、读取数据等。帧里可以带校验字节,具体是否启用由配置寄存器决定。

实际调试时最怕两件事:一是波特率不匹配导致整帧错位;二是发送命令后没等够响应时间,把应答帧当成下一条命令的输入。

我的经验是在上电后先发复位命令并延时10ms以上,再读回一个已知寄存器验证链路。这个自检流程能省掉一半的玄学问题。具体帧格式细节因批次和手册版本有差异,但字节序大多是“命令字+寄存器地址+数据”,读数据时用RDATA命令连续取3字节。

3.2 寄存器配置与初始化

/* 使用STM32F042C6的USART2,波特率9600,8N1 */ static void ads122u04_uart_init(void) { /* 配置PA2/PA3为USART2的TX/RX */ /* RCC、GPIO、USART初始化略 */ } static void ads122u04_write_reg(uint8_t reg, uint8_t val) { uint8_t frame[3]; frame[0] = 0x00; /* 写命令字,按手册定义 */ frame[1] = reg; /* 寄存器地址 */ frame[2] = val; /* 要写入的值 */ uart2_write_bytes(frame, 3); delay_ms(1); /* 等待ADC处理完成 */ } static void ads122u04_init(void) { ads122u04_uart_init(); ads122u04_reset(); /* RESET引脚拉低再拉高或发复位命令 */ /* 配置寄存器0:PGA增益、参考电压选择 */ ads122u04_write_reg(0x00, 0x06); /* 示例值,具体按手册bit定义 */ /* 配置寄存器1:输入MUX、单次/连续模式、IDAC相关 */ ads122u04_write_reg(0x01, 0x22); /* 配置寄存器2:数据率、滤波器 */ ads122u04_write_reg(0x02, 0x10); /* 45SPS,50/60Hz抑制 */ /* 配置寄存器3:IDAC电流大小、输出通道 */ ads122u04_write_reg(0x03, 0x6C); }

说句实在话,寄存器0到3的bit位在不同数据手册版本里画法不完全一致。我第一次调的时候就是没仔细看版本号,把某个bit写反,导致MUX一直指错通道。所以上面代码里的具体值只能当示例,务必对照你手中那颗料的datasheet来填。

3.3 读取转换值

转换模式建议用单次转换。每次需要时才触发一次,期间MCU可以做别的事,也方便多通道轮询。读取代码:

static int32_t ads122u04_read_one_sample(void) { uint8_t buf[3]; /* 启动转换 */ uart2_write_byte(CMD_START); /* 等待DRDY拉低 */ while (gpio_read_pin(DRDY_PIN) == GPIO_HIGH); /* 发送读取命令(或按配置直接接收数据) */ uart2_write_byte(CMD_RDATA); uart2_read_bytes(buf, 3); /* 24位数据,转成带符号的32位整数 */ int32_t raw = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | ((int32_t)buf[2]); if (raw & 0x800000) raw |= 0xFF000000; /* 符号扩展 */ return raw; }

DRDY引脚强烈建议接到MCU的外部中断引脚而不是轮询。轮询在测试时能用,一旦主循环里加了LCD刷新或PID计算,很容易丢数据。用外部中断就能保证每次转换完成立刻读取。

3.4 通信可靠性加固

工业现场UART会受到干扰,帧错位偶尔会发生。我的做法:

  • 每个命令帧带校验,ADC端校验失败会返回错误帧,MCU检测到就重发。
  • 每次读取数据后检查数值是否在合理范围,比如RTD对应电阻在80~300Ω之间,超范围判定为传感器故障或通信异常。
  • 连续出现三次通信错误时,对ADC做一次硬复位,拉低RESET引脚,重新初始化,而不是傻等着。

这些“脏活”看似无关紧要,但在实际项目里,正是因为有了异常恢复机制,设备才能在变频器等强干扰源附近连续跑几个月不出问题。

4. 从ADC码值到温度:RTD线性化与标定

4.1 从码值到电压

24位ADC输出的是二进制补码或偏移码,取决于配置。转换成电压:

V_in = raw × VREF / (2^23 × PGA)

假设VREF=2.048V、PGA=4,则1 LSB对应的电压为2.048 / (8388608 × 4) ≈ 61nV。这个分辨率对测温绰绰有余。

但直接按这个公式计算会引入VREF的绝对误差。如果做RTD比率测量,用下面的方式更准。

4.2 比率测量为何能省掉基准误差

把精密参考电阻Rref接在REFP/REFN之间,IDAC电流同时流过Rref和RTD。ADC测量RTD电压与参考电压的比例为:

code_rtd / code_ref = R_rtd / R_ref

所以:

R_rtd = code_rtd / code_ref × R_ref

这个公式里已经完全消掉了IDAC电流大小。即使电流源随温度漂移了1%,分子分母同步变化,比例不变。这是RTD测量的精髓。Rref本身的温漂成了主要误差源,所以Rref要选低温度系数精密电阻,建议≤10ppm/℃。

实际代码里,我会在每次读取RTD通道后紧接着读参考通道的码值,用最新一次的比例计算,避免IDAC慢漂移带来的长期误差。

4.3 RTD电阻转温度:Callendar-Van Dusen方程

Pt100在0℃以上满足:

R(t) = R0 × (1 + A×t + B×t²)

其中R0=100Ω,A=3.9083e-3,B=-5.775e-7。

0℃以下还要加一项:

R(t) = R0 × [1 + A×t + B×t² + C×(t-100)×t³],C=-4.183e-12。

0℃以上可以直接用求根公式解,省去迭代:

t = (-A + sqrt(A×A - 4×B×(1 - R/R0))) / (2×B)

代码:

float rtd_resistance_to_temp(float r) { const float R0 = 100.0f; const float A = 3.9083e-3f; const float B = -5.775e-7f; const float C = -4.183e-12f; float ratio = r / R0; if (r >= R0) { return (-A + sqrtf(A*A - 4.0f*B*(1.0f - ratio))) / (2.0f*B); } else { /* 0℃以下用迭代或查表 */ float t = -10.0f; /* 初始猜测 */ for (int i = 0; i < 10; i++) { float r_calc = R0 * (1.0f + A*t + B*t*t + C*(t-100.0f)*t*t*t); t += (r - r_calc) / (R0 * (A + 2.0f*B*t)); } return t; } }

为了防止浮点导数写错,负温区我更推荐直接做查表加线性插值。把-200~0℃按每10℃建一张电阻表,插值精度足够到0.05℃。CVD公式用于桌面校验,查表用于MCU运行,省去迭代的耗时。

4.4 校准

即使ADC精度很高,系统层面还有传感器误差、Rref误差、PCB焊接应力等。我习惯做两点校准:

  • 低温点:用精密电阻箱拨到100.00Ω,对应0℃,记录ADC计算出的温度值。
  • 高温点:拨到138.50Ω,对应100℃,记录偏差。

然后做线性修正:

t_corrected = t_raw × gain_cal + offset_cal

其中gain_cal = 100 / (t_high_raw - t_low_raw),offset_cal = -gain_cal × t_low_raw。

这种做法能把系统级误差压到0.05℃以内。如果现场没有电阻箱,至少也要用冰水混合物做一次零点校准。很多时候焊板造成的初始偏差比想象的大,千万别跳过这个步骤。

4.5 精度预算参考

误差来源典型影响(Pt100 @ 0~100℃)对策
RTD自身±0.1℃(Class A)选型时确认精度等级
Rref温漂约0.02℃(10ppm)选低温漂精密电阻
IDAC电流比率测量下几乎抵消不要做绝对电压测法
PGA失调约0.005℃单点校准抵消
ADC噪声约0.01℃ RMS(45SPS)软件取平均/滑动滤波

综合下来,系统做到±0.1℃不是难事,关键投入在传感器等级和参考电阻上。

5. HVAC与工业场景:分场景处理与工程细节

5.1 HVAC:NTC与Pt1000怎么选

大多数HVAC项目对成本敏感,NTC依然是主流。ADS122U04的24位精度拿来测NTC有点“大材小用”,但换来的是不需要逐点校准的一致性。10k NTC在25℃附近灵敏度约-4%/℃,也就是-400µV/℃(1µA激励时),用PGA=16后分辨率远超需求。在AHU和风机盘管的进出水温度、送回风温度测量上,用NTC加本方案的ADC读值,省去传统“电位器调零”的人工标定,批量生产一致性会好非常多。

HVAC环境具体选型时,有几点经验:

  • 送风/回风温度:探头要伸到气流里,避免贴近外壳导致热惯性,用护套型Pt1000响应更快。
  • 盘管供回水温度:水管内温度波动大,数据率建议45~90SPS,软件再做16次滑动平均,能明显压住水流脉动带来的读数波动。
  • 冷凝风险:盘管表面可能在低温工况结露,模拟前端布线要避开冷凝水滴落路径,PCB刷三防漆,传感器端子用防水型。
  • 抗干扰:变频风机、水泵在HVAC系统里到处都是,ADC模拟输入端远离变频器输出线,屏蔽层单端接地,这些在施工图上就要提前标好。

5.2 工业:长线传输、断线检测与EMC

工业场景和HVAC最大的区别在距离和电磁环境。如果传感器离控制器20米,直接传RTD弱信号一定会被干扰。这时候把ADS122U04IPWR做成传感器侧模块,UART走RS485或隔离UART回传主机,是更稳的架构。UART的低速特性也让光电隔离成本更低。

断线检测方面,RTD开路时测量电压会异常拉高,ADC很容易识别;短路时读数接近0。利用IDAC的特性可以做自动诊断:正常Pt100在-50~150℃对应约80~157Ω,如果换算出来的电阻值超出范围,就报故障并选择安全输出。在工业现场,这些诊断逻辑比精度还要重要——宁可显示“传感器故障”,也不要错误数据触发连锁反应。

另外,工业现场经常和变频器、接触器共用电气柜。安装时注意模拟信号线不要和动力电缆平行走线,穿越不同区域时尽量垂直交叉。实在避免不了的长距离布线,优先选择电流环或者数字总线传输。

5.3 多通道轮询与电源策略

ADS122U04有AIN0到AIN3四通道。做典型HVAC控制箱时,我会这样分配:

通道用途传感器
AIN0/AIN1RTD差分Pt100供水温度
AIN2单端NTC回风温度
AIN3单端NTC送风温度或冷端补偿

轮询时每通道用单次转换,每路取4次平均后再切换到下一路。45SPS数据率下,4路完整轮询大约90ms,对HVAC的温控周期(通常1s)毫无压力。

供电上,如果现场有24V电源,用DC-DC降到3.3V时注意纹波。实测发现DC-DC开关纹波直接落在模拟电源上时,ADC噪声能明显多出几个码;加了π型滤波后安静很多。这也是一个花钱很少但效果非常大的细节。

6. 实测数据与踩坑记录

6.1 坑一:激励电流太大,把读数“烤”高了

刚开始为了追求信号幅度,把Pt100的IDAC设成1mA。密闭式探头在空调水管上装了一晚,第二天看数据比参考温度计高0.19℃。起初以为是传感器装偏了,后来单独做自热实验:同一探头在静止空气中,1mA下读数持续爬升十几分钟才稳定;改成500µA后这个爬升基本消失。这就是自热误差。选激励电流时不要贪信号强度,信号差一点可以靠PGA补,自热误差却是实打实的物理偏差。

6.2 坑二:基准电压直接接AVDD,读数跟着开关电源一起跳舞

有一版样板为了省料,把REFP接AVDD、REFN接GND。结果只要压缩机继电器一吸合,ADC读数就跳十几码。查到最后发现AVDD上叠加了几十mV的开关毛刺,基准不干净,转换结果自然全脏。改成外部基准加RC滤波后,同样工况下噪声降了一个数量级。经验:模拟基准和数字电源必须分开,至少也要在基准引脚前加二级LC滤波。

6.3 坑三:UART中断被LCD刷新打断,导致错帧

最初用轮询方式读UART,结果在LCD刷新期间把RX字节丢了,校验直接不过,隔三差五出一帧坏数。后来把UART接收改成中断加FIFO,LCD刷新等任务优先级调低,丢帧率降到零。另外请务必给每条命令帧加超时重发机制:发送后20ms内无响应就重发,连续失败才复位芯片。这个机制看着简单,在现场调试时是救命稻草。

6.4 实测结果

一个在恒温槽里做的对比(45SPS,PGA=4,3线Pt100):

参考温度(℃)本方案读数(℃)最大偏差(℃)
0.000.010.01
25.0024.980.02
50.0050.020.02
100.0099.960.04

32小时连续运行,管温监测通道读数波动在±0.02℃以内(滑动平均16次后)。这水平对HVAC的能效控制和工业的温度监测完全够用。

6.5 最后的体会

这套方案用下来,最大的感受是“有时候换个接口,比换一颗更强的MCU还管用”。ADS122U04IPWR的UART接口解决的是整机架构的现实问题,STM32F042C6虽然只是一颗Cortex-M0小芯片,但配合24位ADC后能力边界一下子大了很多。后续如果要做多路扩展,可以在前端加模拟开关扩展通道数;如果做分布式采集,直接让每块传感器板挂一颗ADS122U04,UART汇总到主控,架构非常干净。希望这篇实操笔记能给正在做HVAC温控或工业测温和的朋友少走点弯路。

返回列表