ADS122U04+STM32L152ZD:UART接口24位ADC的工业温度采集方案

发布时间:2026/11/5 1:03:44
ADS122U04+STM32L152ZD:UART接口24位ADC的工业温度采集方案

搞工业温度采集这块时间长了,手里总会有几套顺手又省心的组合。最近帮客户做HVAC风管和工业设备表面温度监测的样机,主控用了STM32L152ZD,前端采集选了TI的ADS122U04IPWR。这颗芯片最吸引我的地方是它作为一颗24位Δ-Σ ADC,居然直接走UART接口,不占SPI,把信号链和低功耗MCU搭配得很舒服。这篇就把这套方案从器件选型、硬件布局到固件计算和实测排障的完整过程写出来,给准备做类似温度测量的朋友一个可以直接参考的样本。

1. 方案选型:为什么是ADS122U04IPWR配STM32L152ZD

1.1 这颗UART接口的24位ADC到底特殊在哪

ADS122U04本身是一颗四通道、24位的Δ-Σ型ADC,带可编程增益放大器PGA、内部2.048V基准电压、两路可编程激励电流源(IDAC),还集成了芯片温度传感器和两个模拟多路开关。这些功能放在一颗TSSOP-16的小封装里,在工业温度采集场景里几乎没有多余的浪费。

它最特殊的一点是通信接口为UART。传统ADC基本都是SPI或I2C,SPI虽然速度快,但需要CS、SCLK、MOSI、MISO至少四根线,长线传输时时钟信号容易辐射干扰;I2C速率慢、地址冲突也麻烦。UART接口只需要TXD和RXD两根线,板级通信时布板简单,和MCU之间只要共地就行,再往上走还能用现成的隔离芯片做电气隔离。我在实际项目里往往还要把数据传给RS485总线,UART接口可以直接对接,省去一层协议转换。

同系列的ADS1220是SPI版本,ADS122U04则是把SPI换成了UART。你可能觉得多此一举,但对一些老旧产线上的设备或是对SPI时序敏感的场景,用UART简直是降维打击。而且这颗ADC的波特率可以配置,从9600bps一直支持到1.2Mbps,数据速率和通信速率分开配置,采集慢速温度信号时用低波特率反而更稳。

1.2 STM32L152ZD能打些什么

STM32L152ZD是ST超低功耗家族中的一员,Cortex-M3内核,主频32MHz,带最高384KB Flash和80KB左右的SRAM。这颗芯片虽然算力不算炸裂,但在温度采集这个场景里绰绰有余,处理热电偶线性化、RTD查表、PID控制全都够用。

它有几个点非常贴合HVAC和工业应用。第一,工作电压范围宽,2.0V到3.6V都能跑,配合内部多级低功耗模式,对电池供电的无线传感器节点很友好。第二,串口资源丰富,多个UART可以分别连接ADC、RS485收发器和调试口,彼此不打架。第三,工业级温度范围,在-40°C到85°C环境里稳定运行,这比很多消费级MCU适合做设备长期部署。选它没选STM32F系列,看重的是L系列在低功耗和引脚丰富度之间的平衡。

也有不少人问为什么不用带24位ADC的高端MCU,比如STM32G4系列内部就有高精度ADC。但工业温度测量的难点除了采样分辨率,还有传感器激励、冷端补偿、PGA增益匹配这些整链路的配合,外置ADC把模拟前端做得更干净,后端MCU专注逻辑和通信,抗干扰能力也更强。这种分立方案在维护和升级上也更灵活——传感器类型变了,换ADC配置或换前端电路就行,不用动整个主控板。

1.3 整机数据链路是怎么设计的

整套系统的数据链路分四段:传感器信号进来,经过RC滤波和IDAC激励,进入ADS122U04的模拟输入通道;ADC完成24位转换后通过UART把原始码交给STM32L152ZD;MCU负责做电压换算、线性化、校准和滤波,最终输出温度值;温度值一方面本地显示或者通过RS485上传,另一方面也能作为HVAC控制回路的反馈量。

这里要注意,UART虽然只有两根线,但通信协议还是要自己定的。我的做法是MCU作为主机,ADS122U04作为从机,所有转换由主机发命令触发。这样整个系统同步性最好,不会出现ADC自己转完但MCU还在忙别的导致数据堆积的问题。命令帧我固定用1个字节的指令加可选的寄存器地址和数据,返回数据也是固定长度的原始码字节流,方便用状态机解析。

2. 硬件设计:传感器接入与PCB布局的关键细节

2.1 热电偶、RTD、NTC三种传感器怎么接

不同温度传感器接入ADS122U04的方式差异很大,选型这一步直接决定后面电路形态。

热电偶输出的是微伏级的电压信号,K型热电偶大约40µV/°C,测1000°C也才40mV上下。这时候要用ADC内部PGA放大,增益先设到16倍或32倍比较合适。热电偶本身没有激励需求,但必须做冷端补偿,我习惯用ADS122U04内部的集成温度传感器同时测冷端温度,虽然精度比外置PT100冷端补偿略低,但胜在省事,HVAC场景里常温环境用内部传感器足够。热点偶接入时还要注意极性,正负极接反的话读数是负值。

RTD(铂电阻)是电阻型传感器,PT100在0°C时是100Ω,PT1000是1000Ω。RTD需要恒流源驱动,直接用ADS122U04内部的IDAC提供激励电流最方便。两线制接线最简单,但导线电阻会直接叠加进测量结果;三线制用两根相同规格的导线分压补偿,工业现场最常用;四线制精度最高,适合计量级场合。我的建议是HVAC设备用三线制PT1000,功耗小、导线上压降影响低,配合IDAC的1mA电流,0°C时激励电压才1V,给ADC留的输入范围很充足。

NTC热敏电阻在HVAC里最常见,成本低、灵敏度高,但线性度差,只适合-20°C到80°C的舒适度检测。NTC接入电路通常是电阻分压方式,把NTC接在上臂或下臂,另一端接参考电压,分压中点进入ADC。分压电阻最好用高精度低温漂的薄膜电阻,我吃过这方面的亏,普通贴片电阻温漂200ppm/°C,环境变个5°C就能带来不小的误差。

三种传感器的接入方式我列个表方便对比:

传感器类型输出信号是否需要激励推荐PGA增益常用接线方式典型应用场景
热电偶K/J/T型µV级电压不需要16~128倍直接差分输入工业炉温、高温管道
RTD PT100/PT1000电阻变化需要IDAC恒流1~4倍三线或四线HVAC管路、现场校准
NTC热敏电阻电阻变化需要分压参考1倍分压电路风管温度、室内温控

2.2 激励电流源和参考电压设计:这步决定精度上限

ADS122U04内部有两路可配置的IDAC激励电流源,电流范围从10µA到1.5mA可编程。用在RTD测量上,是一个很核心的精度杠杆。

选激励电流时有一个平衡:电流大了,传感器上压降大,信噪比高,但自热效应也明显,PT100在1mA下发热功率是0.1mW,长期稳定还能接受;电流小了,信号幅度小,容易被噪声淹没。我实测下来,PT100用500µA到1mA之间比较合适,PT1000用250µA到500µA。还要注意激励电流会流经参考电阻产生参考电压,这个参考电阻的温度漂移会直接进入测量链路,一定要选温漂在±5ppm/°C以下的精密电阻,最好是金属箔电阻或精密薄膜电阻。

参考电压可以选内部2.048V基准,也可以外部输入。内部基准好处是集成、少一个器件,但温漂系数一般在几十ppm/°C;要求高的场合我会用外部低温漂基准芯片,再把基准引脚接到ADC的REFP。对HVAC这种环境温度变化较大的应用,如果目标是整个温度范围内误差小于0.1°C,外部基准基本是必须的。

另外,ADC的模拟电源AVDD和数字电源DVDD建议分开走,即便都用3.3V,也要各自加磁珠和去耦电容。ADS122U04的电源抑制比虽然不错,但24位ADC对电源纹波极其敏感,电源上那点几十毫伏的毛刺,放大到24位编码上可能就是几十个LSB的跳变。

2.3 PCB布局和长线走线的几个细节

PCB布局这块,我踩过不少坑,总结几条实操经验。

第一,模拟输入走线要短而粗,远离数字走线和开关电源。ADS122U04的模拟输入引脚是高阻抗输入,走线稍微长一点就容易拾取噪声,我一般把RC滤波电容尽量靠近ADC引脚放,让高频干扰在进入ADC之前就被滤掉。

第二,ADC下方的地平面要完整,模拟地和数字地在ADC芯片下方单点连接,不要让数字电流穿过模拟区域。如果板子上还有继电器或可控硅,必须把它们和模拟区用开槽隔离,这在HVAC控制板里特别重要,因为空调压缩机的启停会产生很强的电磁干扰。

第三,UART通信线虽然只有两根,但也要注意它们和模拟输入线的间距。RXD和TXD上的开关噪声会通过空间耦合到模拟输入端,我给UART线串了33Ω电阻,并把它们走在远离模拟输入的另一层。

第四,如果传感器线从板外接入,长度超过1米,我建议输入端加共模电感和TVS管,并把线缆做成双绞屏蔽线。屏蔽层只在传感器端或采集板端单点接地,两端都接地会形成地环路,反而引入工频干扰。前阵子客户现场就是温度波动像心跳一样规律,后来查到是PLC控制柜和采集板之间地电位差叠加进了信号线。

3. 固件实现:UART通信与温度换算核心代码

3.1 初始化ADC和UART的代码骨架

ADS122U04通过UART接收命令,MCU侧只要把UART波特率配成和目标一致就可以通信。我先给一个STM32L152ZD的HAL库初始化骨架,重点不在库函数,而在配置思路。

/* UART1 for ADS122U04 */ UART_HandleTypeDef huart1; UART_HandleTypeDef huart2; void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; /* PA9: TX1, PA10: RX1 */ GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF1_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 9600; 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; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } }

UART波特率我最初用115200,后来实际项目中因为线缆较长和隔离器延迟,降到9600反而更稳定。温度信号本身变化慢,9600bps每秒也能传几十次完整转换结果,完全够用。

ADC初始化部分的要点是配置寄存器而不是传输大量数据。ADS122U04内部有数个配置寄存器,我用宏定义把命令封装成以下形式,具体命令码和寄存器位定义要以你手里的数据手册为准:

/* 复位ADC,重新加载默认寄存器 */ void ADS122U04_Reset(void) { uint8_t cmd = CMD_RESET; HAL_UART_Transmit(&huart1, &cmd, 1, 10); HAL_Delay(2); } /* 向指定寄存器写入配置 */ void ADS122U04_WriteReg(uint8_t reg_addr, uint8_t reg_val) { uint8_t buf[3]; buf[0] = CMD_WREG | (reg_addr & 0x07); buf[1] = 0x00; buf[2] = reg_val; HAL_UART_Transmit(&huart1, buf, 3, 10); } /* 触发一次转换并读取24位原始数据 */ uint32_t ADS122U04_ReadTemp(void) { uint8_t cmd = CMD_START; uint8_t raw[3] = {0}; HAL_UART_Transmit(&huart1, &cmd, 1, 10); HAL_UART_Receive(&huart1, raw, 3, 100); return ((uint32_t)raw[0] << 16) | ((uint32_t)raw[1] << 8) | raw[2]; }

配置的关键参数有四个:输入多路开关选择哪一路通道、PGA增益设多少、数据速率多少、是否开启IDAC电流源。调试时我习惯先用内部温度传感器验证ADC本身是否正常,读到片上温度大约25°C,再切到外部传感器通道,这样能把问题快速分隔到ADC端还是传感器端。

3.2 从原始码到物理温度的换算公式

ADS122U04返回的是24位二进制补码数据,看起来是一串无符号整数,实际上正负温度都要正确处理。我先把原始码转成有符号数,再换算成电压:

int32_t raw_signed = (int32_t)raw_uint; if (raw_signed & 0x800000) { raw_signed |= 0xFF000000; /* 扩展到32位有符号 */ } double vref = 2.048; /* 实际使用的基准电压 */ double gain = 32.0; /* PGA增益 */ double voltage = (double)raw_signed * vref / 8388608.0 / gain;

这里的8388608就是2的23次方,对应24位数据去掉符号位后的满量程。K型热电偶的电压-温度关系近似线性,但工程上要用NIST多项式或分段线性表才能做到0.1°C级别。我做了一个简化版,在0°C到500°C区间用查表加线性插值,表点间隔25°C,每两个点之间线性化,实测误差在0.15°C以内。查表法比NIST多项式省算力,对STM32L152ZD这种主频不高的MCU更友好。

热电偶测量还有一个必须处理的问题:冷端补偿。ADS122U04采集的是热端和冷端的电势差,如果冷端在25°C,K型热电偶测300°C时输出约11.4mV,但此时ADC实际看到的电压还差一个25°C对应的补偿电势约1.0mV,得把这个值加上才能得到真实热端温度。具体流程是:先读ADC内部温度传感器得到冷端温度,查表得到冷端等效电压,把ADC测得的电压加上冷端电压,再查总电压对应的温度。很多新手漏掉这一步,结果温度怎么都对不上。

RTD的换算简单一些,用比例法。定义Rref是0°C时的标准电阻,Vrtd是RTD两端电压,Vref是基准电阻两端电压,则Rt = Rref * Vrtd / Vref。PT100的电阻-温度关系虽然有Callendar-Van Dusen公式,但0°C到100°C区间直接用线性系数0.385Ω/°C也够HVAC用,我在0°C到50°C区间实测误差小于0.1°C。

NTC的换算我用Steinhart-Hart公式:

1/T = A + Bln(R) + Cln(R)^3

三个系数从NTC厂商数据手册拿,计算量稍大但对主频32MHz完全没压力。如果用查表法,B常数10K的NTC在25°C附近斜率大约是-4.4%/°C,非常高,也就是温度变0.1°C会引起电阻千分之几的变化,ADC一个LSB对应的温度分辨率能做到0.002°C级别,前提是参考电压足够稳。

3.3 校准、滤波和故障保护

24位ADC的原始精度很高,但系统级误差往往来自传感器本身和信号链路的系统性偏差,所以校准环节不能省。

我做了两级校准。第一级是零点校准,在传感器探头放在0°C冰水混合物里时记录ADC原始码,把它作为偏移量存进Flash,后续每次测量都减掉这个偏移。第二级是增益校准,用一个高精度温度源或精密电阻箱模拟已知温度,测出实际值和理论值的比例系数并存入。校准完以后,正常测量的误差基本能压到设备标称精度以内。

滤波方面,温度信号属于缓变信号,我推荐滑动平均加限幅的组合。滑动平均窗口取8到16点,在0.5Hz采样率下也就带来1到2秒的延迟,对HVAC系统完全可以接受。限幅滤波是防止传感器断线或接触不良时出现离谱值:相邻两次温度采样变化超过5°C就判定为异常,直接丢弃并计数,连续多次异常就报传感器故障。这个方法简单但非常有效,现场出现线缆松动时不会把假数据送去控制回路。

固件里还要处理UART通信超时。ADC偶尔会因为干扰没有响应,MCU侧用HAL_UART_Receive带超时的接收函数,超时后重发命令。连续重发超过3次就把这条通道标记为通信故障,接着去查硬件,不能无限等下去。

4. 实测问题与排查速查实录

4.1 现场踩过的几个坑

第一个坑是UART电平不匹配。ADS122U04的IO电平取决于DVDD,如果DVDD接了5V而STM32是3.3V,TXD直接对接会把MCU的引脚钳位到不安全状态。我第一次搭测试板时忽略了这点,结果STM32的UART引脚发热、通信时好时坏。后来改成RXD上加一个2K串联电阻加钳位二极管的方式,或者直接用双向电平转换芯片才解决。这个必须在原理图阶段就确认好,不能靠运气。

第二个坑是参考电压被IDAC拖垮。我最初参考电阻用了普通0805贴片电阻,温漂大概100ppm/°C,实验室环境里看不出来,拿到客户厂房后环境从20°C到35°C变化,温度读数跟着漂了将近0.8°C。换成精密电阻后立竿见影。这个问题在HVAC现场特别容易碰到,因为设备经常在室外机或机房这种温度波动大的地方。

第三个坑是传感器线缆太长导致的共模干扰。有一次现场安装距离大约30米,走线经过变频器附近,温度读数跳得厉害。我在ADC输入端加了共模电感,并在软件里把数据速率降到20SPS,Δ-Σ ADC的数字滤波特性把高频干扰滤掉了不少,跳变幅度骤降。如果还压不住,就得考虑在传感器端加变送器把信号先转成4-20mA电流环,再用采样电阻还原,抗干扰能力完全不同级别。

4.2 问题排查速查表

把这次调试过程中遇到的现象、原因和解决思路整理成表格,方便现场直接对照。

现象可能原因排查方法与解决措施
UART完全无响应波特率不匹配/电平不匹配/接线错误示波器抓RXD引脚波形,确认电平幅值和波特率;先用USB转TTL直连ADC验证通信
读数固定为满量程传感器断线/输入悬空检查传感器接线,断开ADC输入量转换引脚电压;热电偶断线时ADC会读到上拉电压
读数波动大电源噪声/参考电压不稳/干扰耦合增大RC滤波,检查AVDD去耦电容,降低数据速率,改用屏蔽线
温度整体偏移冷端补偿未做/校准偏移丢失检查冷端补偿代码,重新做零点校准;确认Flash里的校准系数是否被意外覆盖
低温和高温段偏差不一致传感器非线性/增益校准不准换用查表插值或专业拟合公式;重新做两点或多点校准
上电后一段时间读数才稳环境温度冲击/自热效应给传感器足够稳定时间,软件做上电后10分钟平滑过渡;检查IDAC电流是否偏大导致自热
偶尔出现跳变到离谱值偶发干扰/通信字节错位软件增加限幅滤波;UART加帧头帧尾校验,防止误码直接进解析

4.3 关于精度等级的量化参考

很多朋友关心这套方案到底能做到多高的精度,我用K型热电偶和PT100分别测过一组对比数据,这里给出一个参考范围。

用内部2.048V基准、PGA增益32倍、数据速率20SPS时,ADS122U04的实测噪声折算到温度大概是K型热电偶0.05°C峰峰值左右,这是ADC本身的贡献。但加上冷端补偿误差、热电偶精度等级和非线性校正误差之后,系统级误差通常在±0.5°C到±1°C,其中热电偶本身的允差就是大头。换成PT100三线制、外部低温漂基准后,0°C到100°C范围内系统误差能做到±0.15°C以内,这已经能满足绝大多数HVAC和工业过程控制的需求。如果目标比这更高,就得换更高精度的基准和更严格的四线制传感器了。

另外要提功耗,STM32L152ZD在停止模式下电流可以掉到微安级别,唤醒后采集一次温度再睡,整套板子用电池供电的话续航可以做得很长。ADS122U04在低功耗模式下电流也才几十微安,两个器件搭配起来非常适合无线温度节点,这是这类方案比PLC加变送器方案更有竞争力的地方。

说回我个人的实际体会,这套方案最花时间的并不是读写ADC那点UART代码,而是把精度从“看起来对”做到“长期稳定可靠”。ADS122U04的UART模式有个非常大的调试优势,就是你可以不先写STM32代码,直接用USB转TTL模块接电脑和ADC通信,把原始码读出来验证硬件链路,等传感器和前端都确认正常了再回头写MCU代码。这种逐级验证的思路能省掉不少排查时间。再分享一个我习惯的做法:产品定型前一定把传感器线缆按现场实际长度和走向测试一遍,别只信实验室里那30厘米杜邦线测出来的结果,长线状态下的抗干扰表现才是这套方案真正的试金石。