ARTICLE DETAIL

资讯详情

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

UART接口24位ADC搭配RS485,解决远距离温度监控难题

UART接口24位ADC搭配RS485,解决远距离温度监控难题

去年接了一个循环水温度监控项目,控制柜到传感器节点直线距离不到三十米,结果第一版方案差点翻车。当时我按习惯选了SPI接口的24位ADC,PCB打样回来短距离调试一切正常,线一拉到现场就开始丢数据,示波器上时钟线的振铃看得人头皮发麻。后来换成了带UART接口的ADS122U04IPWR,配合手头现成的STM32F100ZE做主控,用一对双绞线加RS485收发器把数据传回来,三十米距离稳如老狗。这篇文章就把这套方案的选型逻辑、电路细节、代码框架和调测经验完整整理一遍,尤其适合做工业设备温度监控和HVAC暖通控制器开发的同行参考。

1. 为什么 UART 接口的 24 位 ADC 能同时解决"信号弱"和"距离远"两个痛点

1.1 温度信号到底有多弱

先说清楚一个容易被忽略的事实:测温信号是典型的"微伏级"信号。以工业里最常见的Pt100铂电阻为例,0°C附近它的灵敏度大约是0.385Ω/°C。如果用1mA的恒流源激励,那么温度每变化1°C,产生的电压变化只有0.385mV;目标精度如果是0.1°C,那就是38.5µV;想做0.01°C的分辨率,就得处理3.85µV的信号。

这个量级靠普通12位或16位ADC根本没法看。即便ADS122U04IPWR这类24位ADC,在满量程±2.048V下理论LSB也才244nV左右,听起来绰绰有余,但ADC本身有噪声、参考有漂移、前端有干扰,实际有效分辨率通常会打不少折扣。所以这颗芯片内部集成了可编程增益放大器(PGA),先把几十微伏的信号放大到伏级,再由24位ADC数字化,这才是真正的"杀鸡也要用牛刀"——不是性能过剩,而是信号本身就这么苛刻。

1.2 SPI和I2C在长线场景为什么容易翻车

最初我选SPI,是因为大多数高精度ADC都是SPI接口,可选的型号多、资料也全。但SPI是同步串行总线,主机要主动输出SCK时钟,数据线和时钟线必须严格对齐。控制器到传感器之间走线一长,线的分布电容、反射、串扰都会让沿变脏,时钟和数据的相对时序偏移,误码率直线上升。更麻烦的是隔离,工业现场往往要加数字隔离器,SPI至少得隔离SCK、MOSI、MISO、CS四根线,成本高不说,每一根线都是潜在的干扰入口。

I2C也指望不上。它是开漏输出,靠上拉电阻驱动总线,总线电容一大,上升沿就变得非常平缓,传输距离基本被限制在一米以内。再加上I2C地址有限,多节点扩展也要费一番功夫。在HVAC现场,传感器散落在风管、水管、机房各个角落,动不动就是十几米几十米的走线,这两种总线都不合适。

1.3 UART方案的本质优势

UART是异步串行,收发双方各走各的时钟,只要波特率一致,靠帧起始位就能把数据对齐,对线缆的要求天然比SPI低。配合RS485收发器改成差分传输后,几十米、几百米都很正常,抗共模干扰能力也强。最赚的一点是隔离成本:UART只需要隔离TX和RX两根线,如果做半双工RS485,一个光耦或数字隔离器就够用,省下来的物料和PCB面积非常可观。

ADS122U04IPWR这颗芯片比较特殊的地方在于,它把模拟前端(PGA、基准、IDAC电流源、内部温度传感器)和UART通信做到了同一颗IC里,主机端不再需要处理微伏级模拟信号,只负责按命令帧读写寄存器、收24位转换结果。配合STM32F100ZE这种低成本、多路USART的Cortex-M3单片机,一个HVAC控制器主板上留几个USART口,就能挂好几个温度采集节点。下面这张表格应该能把方案优势说得更直白:

总线类型典型传输距离抗干扰能力隔离成本多节点能力远距离测温实用性
SPI30cm~1m一般,SCK沿线质量敏感高,需隔离4路信号靠CS扩展,节点受限基本不可用
I2C1m以内一般,开漏易受噪声需隔离SCL/SDA,仍受电容限制地址有限不可用
UART+RS485几十米~几百米好,差分信号抗共模干扰低,1~2路隔离可组多从机总线推荐

2. ADS122U04IPWR 外围电路设计:照着搭不返工

2.1 供电、基准和去耦

工业设备里通常没有干净的3.3V,控制器板上可能是24V转5V的开关电源,纹波不小。我的做法是先让24V经过一级DC-DC降到5V左右,再用低压差LDO(比如LM1117-3.3或更安静的型号)给ADS122U04的模拟供电。开关电源的纹波哪怕只有几十毫伏,经过ADC内部电路后都会直接变成读数跳动,省这一步后面调试会非常痛苦。

去耦电容要贴近电源引脚放,常规组合是10µF钽电容加0.1µF陶瓷电容并联,数字电源和模拟电源之间加一个磁珠隔开更好。基准源方面,ADS122U04内部集成基准,一般应用够用;但如果项目指标是长期0.1°C级精度,建议外部基准供电,选择低温漂的精密基准芯片(常见2.5V或2.048V规格)。这里有个设计平衡:参考电压越高,ADC满量程越大,对应每个LSB代表的电压也越大,分辨率会变粗;参考电压太低,前端PGA输出容易饱和。要结合传感器输出范围算好再定。

2.2 UART电气接口与远传设计

芯片的UART接口默认支持短距离TTL电平直连,调试阶段和主控在同一块板上时,直接连PA10/PA9这种USART引脚就好。如果要拉到现场几十米,必须加RS485收发器,比如MAX3485、ISL3170这类3.3V半双工芯片。接线时注意A/B端子不要接反,总线两端各并一个120Ω终端电阻,环评大的地方还要加TVS管。

波特率建议从9600起步完成通信验证,稳定后再切换到115200。调试初期我遇到过用115200连不上、发命令没响应的情况,后来发现是收发器方向切换时序没处理好——半双工RS485在发送完命令后要马上把驱动器关闭、切换到接收模式,这个切换如果太急,最后一个字节会被吞掉。一个小技巧是发送完成后延时2~3个字节时间再切接收,简单可靠。

2.3 模拟输入滤波与传感器保护

每个模拟输入(AIN0~AIN3)建议都串一个100Ω电阻并加10nF对地电容,构成一阶RC低通。截止频率大概在159kHz左右,能滤掉大部分射频干扰和高频噪声,对RTD这类低阻传感器也不会引入明显误差。RC滤波好处是成本几乎为零,但一定要放在靠近ADC引脚的位置,走线长了电容本身就成了天线。

如果输入接的是热电偶,建议在AIN正负输入端各加一个偏置电阻到GND(比如1MΩ左右)。热电偶内阻很低,但开路时输入会悬空,芯片内部没有强下拉,输入电位可能漂到中间某个随机值,导致读数乱跳。加上偏置电阻后,开路时输入被拉到GND,程序就能根据超量程判断出"传感器断线"而不是报一个几百度的假温度。

2.4 PCB布局里最值得注意的两件事

第一件是模拟地和数字地要分区,然后单点汇接。刚开始我画的板子地平面是一整块,RS485收发器的数字噪声直接耦合到了模拟输入,读数在±0.3°C左右来回跳。后来把模拟区域和数字区域分开,只在电源输入处用一个0Ω电阻连接,跳变立刻收敛到±0.02°C级别。

第二件是IDAC电流走线要远离UART数据线。IDAC输出的是直流激励电流,本身不产生噪声,但它走的路径如果和数字信号线平行,数字跳变产生的容性耦合会影响激励回路稳定性,进而影响测量结果。这类细节在原理图上完全看不出来,只能靠布线阶段提前规划,所以画PCB之前先想想模拟信号是从哪一路进的、数字信号又从哪一路出的。

3. 传感器链路:Pt100 三线制与热电偶冷端补偿

3.1 为什么三线制比两线制准这么多

两线制接线最简单,拿两根线把RTD接到ADC就行,但引线电阻全都会算进测量结果里。假设导线是0.5mm²铜线,来回走20米,铜的电阻率约0.0175Ω·mm²/m,这20米导线的电阻就有0.7Ω左右。对Pt100来说,0.7Ω意味着接近1.8°C的误差,这在工业测温里根本没法接受。

三线制的核心思想是让电流回路和电压测量的路径分开。具体接线是:RTD的一端引出两根规格完全相同的线,分别接到ADC的差分输入端高端和激励电流源;另一端引出一根线接到差分输入端低端和公共回路。由于三根线的长度、材质一致,导线电阻相等,电流在回路和测量路径上产生的压降会在差分测量中相互抵消,引线电阻带来的误差被压到很低。四线制更准,但要多拉一根线,实际成本和施工复杂度的提升不小,工业/HVAC场景三线制是性价比最高的。

3.2 IDAC激励电流的大小怎么选

ADS122U04内部有IDAC恒流源,可以直接给RTD提供激励。电流选得太大会产生自热效应:电流流过RTD本身会发热,把铂电阻的温度抬起来,测出来的温度就偏高。1mA电流在100Ω的Pt100上功耗是0.1mW,普通封装探头温升大概零点零几度;如果改成2mA,功耗直接变4倍,自热误差可能到0.1°C以上,这就不能忍了。所以我的默认选择是1mA,除非传感器封装导热特别差,再考虑降到0.5mA。

IDAC还有个很实用的玩法:让激励电流同时流过RTD和一个精密基准电阻,分别测量两路的电压比值。这样IDAC本身的温漂在比值中会相互抵消,相当于做了一次比例测量,对长期稳定性和温漂指标提升非常明显。

3.3 PGA增益和参考电压怎么搭配

输入范围和增益的选择要一起算。假设系统要测的温度范围是-50°C到150°C,Pt100在这个区间对应电阻大约80.31Ω到157.33Ω(以0°C时100Ω为基准)。用1mA激励,信号电压就是80.31mV到157.33mV,选PGA增益8后,ADC输入端的电压范围是642mV到1259mV,在2.048V参考下余量充足,还能留出一定过冲空间。

如果测量范围收窄到0°C到100°C,信号电压是100mV到138.5mV,此时选PGA=8后最大只有1.108V,依然合适;但要是贪心选PGA=16,100°C时放大后达到2.216V,已经超过2.048V参考电压,ADC会饱和,读数直接废掉。所以先算信号范围,再倒推增益和参考值,顺序千万别反。

3.4 热电偶接入的要点

热电偶输出的是毫伏级热电动势,比如K型热电偶灵敏度大约是41µV/°C,测量几百摄氏度的信号,满量程也就几十毫伏。这时PGA要选64或128,输入范围才能匹配。热电偶本身不接IDAC激励,它的信号是自发电的,接反了极性会把温度符号反过来,现场很容易踩坑。

另外一个绕不开的问题是冷端补偿。热电偶测的是热端和冷端的温差,要得到真实温度必须知道冷端(也就是接线端子处)的温度。最省事的办法是直接用ADS122U04内部集成的温度传感器读冷端温度,或者外接一个NTC/DS18B20放在接线端子附近,把这路温度读数加上去。实际操作中还有个隐蔽坑:接线端子如果用了不同材质的金属,接点本身会产生附加热电动势。所以冷端位置要尽量远离热源,端子材质尽量统一,避免人为制造第二个"热电偶"。

4. STM32F100ZE 驱动与温度换算代码

4.1 软件整体流程

STM32F100ZE的主频虽然是24MHz,但对温度采集这种慢速应用完全够用。软件流程可以归纳成四条:上电延时等待电源稳定、发送NOP命令和ADC建链、写配置寄存器设定测量参数、周期轮询读取24位转换结果。ADS122U04的命令码和寄存器映射以最新版数据手册为准,下面代码里的宏定义是示意用的框架,读者务必替换成手册里的实际数值。

先看USART初始化和命令发送的基础框架:

/* STM32F100ZE 使用 USART2,CubeMX 配置为异步 115200 8N1 */ /* 命令码宏:实际值请对照 ADS122U04 数据手册更新 */ #define ADS122U04_CMD_NOP 0x00U #define ADS122U04_CMD_RREG 0x20U #define ADS122U04_CMD_WREG 0x40U #define ADS122U04_CMD_RDATA 0x10U /* 向 ADC 发送配置帧:命令 + 寄存器数量 + 寄存器值 */ uint8_t cfg_buf[5] = { ADS122U04_CMD_WREG, 0x02, /* 连续配置2个寄存器 */ config_reg0, /* 多路开关/输入选择 */ config_reg1 /* PGA增益/参考源/数据速率 */ }; HAL_UART_Transmit(&huart2, cfg_buf, 5, 100); /* 等待一小段,让 ADC 完成配置 */ HAL_Delay(5); /* 读取24位转换结果 */ uint8_t resp[3]; HAL_UART_Receive(&huart2, resp, 3, 20);

4.2 24位数据的拼接与电压换算

ADC返回的24位数据通常按二进制补码格式组织,高位在前。把三个字节拼成一个32位整数后要先做符号扩展,再用满量程去换电压。代码大概是这个意思:

int32_t code = ((int32_t)resp[0] << 16) | ((int32_t)resp[1] << 8) | (int32_t)resp[2]; if (code & 0x800000) { code |= 0xFF000000; /* 符号扩展为32位有符号数 */ } double vref = 2.048; /* 实际参考电压,按硬件填入 */ double gain = 8.0; /* PGA增益 */ double voltage = code * vref / 8388608.0 / gain;

这里容易出两个问题:一是字节顺序搞反,拼出来的数据乱跳;二是忽略符号扩展,负温度时读出的是巨大正数。调试时建议先把ADC输入端短接,看码值是否接近0,再用一个已知电压灌入做验证,这样能快速排除拼接错误。

4.3 电阻转温度计算

对于Pt100,0°C以上时电阻和温度的关系可以用Callendar-Van Dusen公式描述:

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

其中R0=100Ω,A=3.9083e-3,B=-5.775e-7。实际程序里经常做的是反问题:测得R,反解T。这个方程是二次的,直接用求根公式能解,但我更推荐牛顿迭代,代码写起来直观,扩展成更复杂的分度表也不费劲:

double rtd_to_temp(double r_rtd) { double r0 = 100.0; double a = 3.9083e-3; double b = -5.775e-7; double t = (r_rtd / r0 - 1.0) / a; /* 线性近似作为初值 */ for (int i = 0; i < 5; i++) { double f = r0 * (1.0 + a * t + b * t * t) - r_rtd; double df = r0 * (a + 2.0 * b * t); t -= f / df; } return t; }

如果测温范围覆盖负温,-200°C到0°C区间公式里要加入C×(T-100)×T³项,但工程上更省事的做法是直接预置一张分度表,用线性插值查表,计算量小且不怕公式边界搞错。

4.4 通信异常恢复机制

UART虽然比SPI皮实,但现场电磁干扰强的时候也会出现帧错位或响应超时。我的经验是一定要设计重同步机制:检测到接收超时或数据非法时,连续发送几个NOP指令让ADC回到已知状态,然后再重新发起读取;如果连续三次都不成功,就拉高复位相关引脚或重新初始化寄存器。程序里还要给每次UART收发加超时,绝不能阻塞在HAL_UART_Receive里死等,否则一旦ADC不响应,整个MCU就卡死了。

5. 精度、标定与实测排查

5.1 误差源先分清是谁的锅

温度测不准,往往不是ADC芯片不行,而是误差源太多且互相叠加。我把常见的几类整理成了一张表:

误差源典型影响抑制手段
ADC增益误差读数整体偏大或偏小软件增益校准
参考电压漂移随温度缓慢变化选低温漂基准,恒温
IDAC电流温漂激励电流变化导致电阻计算偏差比例测量法,消掉IDAC影响
引线电阻两线制最明显,可达1°C以上三线制/四线制接线
自热效应读数持续偏高减小IDAC至1mA以下
电源纹波和数字噪声码值随机跳动LDO供电、去耦、模拟数字分地
工频干扰(50Hz)读数周期性波动RC滤波、整周期平均

5.2 标定流程怎么做

如果项目只要求±0.5°C,直接用芯片默认参数可能就够了。但要做0.1°C级别精度,标定绕不开。我的习惯是分两步:第一步做失调校准,把输入端短接或用精密电阻(比如精确100.00Ω)作为已知零点,读到的码值作为offset存下来;第二步做增益校准,用一只精密电阻(比如138.50Ω对应100°C左右)作为标准,算出一个校准斜率。

之后每次测量都按"校正温度 = 原始温度 × gain_cal + offset_cal"处理。有条件的话再用恒温槽或干井炉配合二等标准铂电阻做三点验证,25°C、60°C、100°C各测一轮,确认线性度。如果没有恒温槽,至少也要用多只精密电阻覆盖目标温度范围,把整个链路校准一遍。

5.3 数字滤波怎么选

工业测温不像示波器那样追求响应速度,HVAC场景温度变化周期都是秒级甚至分钟级,所以数字滤波可以大胆一点。最简单的做法是连续读8次取平均,代价是吞吐率降8倍;如果现场有偶发干扰,再加一级中值滤波把最大最小值剔掉。我现在这个项目用的是滑动平均窗口16,效果是读数稳定度从±0.05°C降到±0.01°C量级,而且控制环也不会觉得温度反应变慢。

还有个细节:滤波窗口最好是10ms或20ms的整数倍,这样50Hz工频干扰能在统计意义上被压掉,比单纯靠RC滤波效果更明显。

5.4 现场常见异常排查

调试期间我把可能碰到的怪现象和原因整理成了一个对照表,直接按表排查能省不少时间:

现象可能原因处理方法
读回数据全是0xFFUART帧不同步、波特率错误发NOP重同步,检查双方波特率
数据来回跳,幅度很大电源纹波、模拟地未分检查LDO纹波,调整地线
数值整体偏高增益误差、基准偏大做增益校准
数值缓慢向一个方向飘IDAC温漂、探头自热比例测量法,降低激励电流
读数周期性波动50Hz工频串入屏蔽层单端接地、整周期平均

6. HVAC 项目里的部署要点和个人体会

6.1 多节点总线拓扑

HVAC系统里典型的温度点包括风管送风温度、回风温度、水管供回水温度、室外补偿温度等,分布范围广但每个点的数据量不大。用STM32F100ZE做总控,通过RS485总线上挂多个ADS122U04节点,每个节点负责本地一个或两个测温点,主站轮询,是非常经典的架构。节点和主站之间唯一的纽带就是那对A/B双绞线,敷设方便,检修也容易定位。

6.2 隔离供电与探头防护

现场有水泵、变频器,强电干扰躲不掉,所以节点供电我建议用隔离DC-DC模块,485通信再用ADM2483这类隔离收发器,做到电和信号双重隔离。传感器探头的金属外壳接地要看情况,通常接仪表地而不是动力地,否则会形成地环路,反而把变频器噪声灌进来。露在室外的传感器还要加防雷措施,TVS管和气体放电管成本不高,关键时刻能救命。

6.3 采样周期与超量程保护

HVAC温度采集周期设置在0.5秒到10秒都很常见,完全不需要让ADS122U04跑在最高数据速率。反而是把数据速率调低一点(比如几十SPS),配合数字滤波,能得到更稳定的读数。程序里一定要做超量程判断:温度超出传感器范围或ADC码值接近满量程时,直接上报故障,而不是把异常数值送进控制逻辑。这个保护逻辑看着简单,真省过事——探头被老鼠咬断线时,如果没有判断,控制器可能会按"高温报警"去关设备,实际只是断线了。

6.4 最后分享几个实际项目里的土办法

凡是碰到UART通信不稳,先把波特率降回9600试一轮,稳定了再往上加,别迷信115200一定更好。凡是碰到读数跳变,先去摸电源芯片烫不烫、纹波大不大,大概率是电源而不是ADC软件的问题。凡是碰到温度偏高但很稳定,先怀疑自热和引线电阻,三线制接法和IDAC电流值优先检查。

这套方案我从前年做到现在,从实验室跑到现场,已经稳定跑过了两个夏天和一个冬天。ADS122U04IPWR加STM32F100ZE的组合,说不上多高端,但在工业/HVAC这种温度和距离都"较真"的场景里,恰好把每一分成本都花在了刀刃上。如果你也在做类似的东西,希望这篇笔记能帮你少走几步弯路。

返回列表