做嵌入式越久越发现,温度测量这种"基础功能"恰恰是工业现场翻车率最高的环节。前段时间接了套 HVAC 控制器的改造需求,要求对冷水管道、回风管道和室内分别测温度,精度要控制在正负 0.1 摄氏度,还得尽量压低成本和通信线数量。最后定下来的方案就是用 TI 的 ADS122U04IPWR 这颗 24 位带 UART 接口的 Delta-Sigma ADC,配合 STM32F410RB 单片机,把传感器信号在前端直接转成数字量,再通过串口传给 MCU 做线性化和上传。这篇博文就把这个组合从选型、原理图、固件到实测调试的完整过程写一遍,重点聊聊哪些环节最容易出问题,以及我为什么最终放弃 SPI 接口的 ADC 选了它。内容更适合正在做楼宇自控、HVAC 控制面板或者工业温度采集的朋友参考。
1. 为什么是这个 ADC:UART 接口和集成前端才是真卖点
1.1 暖通测温和实验室测仪表是两个世界
HVAC 的测温场景和精密仪器实验室里的温度测量有本质区别。实验室里你可以用台式万用表反复校准,环境稳定,传感器线短,电源干净;但 HVAC 现场是管道外壁、空调箱内部、潮湿机房,温度范围可能从零下 40 度到 150 度,传感器线经常拉出去十几米,电源线上还时不时有变频器和接触器的干扰。这里真正需要的,是在恶劣噪声环境下把毫伏级信号可靠放大并数字化,而不是单纯追求多一位小数。
ADS122U04IPWR 本质是一个 24 位 Delta-Sigma ADC,内部集成了可编程增益放大器(PGA)、四通道输入多路选择器、两个可配置电流源(IDAC)、内部温度传感器,还带一个低漂移基准。这些前端功能单拿出来,其他 ADC 也都有,但这颗芯片把它们组合成了完整前端,再用 UART 异步串口输出结果。它至少有 20SPS 到 1000SPS 的数据速率可选,电源范围 2.3V 到 5.5V,可以直接用 3.3V 系统供电。给我第一印象是:这不是一颗裸 ADC,而是一个模拟前端方案。
1.2 为什么 UART 接口成了整块板子的关键点
传统方案里 ADC 和 MCU 之间通常走 SPI。SPI 速度快,但至少要占用 4 根线:MISO、MOSI、SCK、CS,如果 ADC 和主控分开放,这四根线在工业环境里就是四个天线。ADS122U04 不一样,它走 UART,MCU 只发一个字节命令过去,ADC 回传三个字节的转换结果,标准的 8N1 格式,线缆只需要 TX、RX 和 GND 三根。在 HVAC 控制柜里,传感器板离主控板一两米很常见,用普通双绞线就能把这三根线传得明明白白,既省线又不容易把干扰带进来。
实际项目中我还试过把这两块板完全隔离,传感器板上单独放一个隔离电源,UART 中间加数字隔离器,效果依然稳定。如果是 SPI 接口,要隔离四根高速信号线,成本和复杂度都上来一截。这一点在方案评审时特别加分,也是我后来多次复用的重要原因。
1.3 STM32F410RB 在这个系统里负责什么
STM32F410RB 是 100MHz 主频的 Cortex-M4F 内核,64 脚 LQFP 封装,128KB Flash、32KB SRAM,自带浮点运算单元。在温度采集系统里它主要干三件事:一是通过 UART 管理 ADS122U04 的采样节奏;二是把 ADC 码换算成物理温度,包括 RTD 线性化、冷端补偿和滤波计算;三是把温度值打包成 Modbus RTU 或其他协议,通过另一组串口或 RS-485 发到上位机。
这些工作量对它来说非常轻松。之所以不选更便宜的 M0 内核,是因为后面温度换算里有浮点运算,Cortex-M0 做起来要么用软件浮点库,要么得搞定点查表,代码可读性和维护成本都不好看。STM32F410RB 自带 FPU,直接用 float 算一次 CVD 方程只要几微秒,让我可以放心在代码里写标准公式而不是各种工程近似。
1.4 多路传感器接入的容量评估
ADS122U04 内部有四通道多路复用器,输入可以轮询切换。HVAC 项目里常见的需求是三路 PT1000 加一路 0 到 10V 模拟量信号,或者四路热电偶,这些都能由一颗 ADC 完成。如果项目后期要加更多点,可以外置多路模拟开关去扩展,但市场上一两百个 MUX 芯片的导通电阻和漏电流差异很大,扩展后精度很难保证。我更倾向于多放一两颗 ADS122U04,每颗管四路,成本比外置开关加隔离的方案可靠得多。
2. 硬件设计:传感器前端决定精度的上限
2.1 PT100 和 PT1000 的三线制接法
HVAC 系统里最常见的温度传感器是 PT100 和 PT1000 铂电阻。ADS122U04 内部有两个 IDAC 电流源,可以输出可配置的激励电流,典型值从 250uA 到 1.5mA。用三线制接法时,两个 IDAC 电流都流过同一个 RTD 电阻,目的是抵消引线电阻带来的误差。具体接法:RTD 的一端接 AIN0,另一端接 AIN1,AIDC1 从 AIN1 注入电流,AIDC2 从 AIN2 单独走一条线到 RTD 远端。这样测到的电压差里,引线电阻上的压降被对称抵消,读数更接近真实阻值。
配套还要选一个低温漂的精密电阻做基准,比如 1.5kΩ 0.1% 的金属膜电阻,接在 REFP 和 REFN 之间。ADC 测量的本质是"RTD 上的电压 / 基准电阻上的电压"这个比值,电源电压波动不会直接影响测量结果,这叫比例式测量,是工业现场最稳的做法。读取到的 ADC 码换算成 RTD 电阻值,再用铂电阻分度表反推温度。
这里一定要避开一个大坑:两线制接法确实便宜,但传感器线一长,引线电阻误差就大得离谱。100 米 0.5 平方毫米铜线来回电阻差不多有 8Ω,对 PT100 来说相当于 20 摄氏度的偏差。所以我坚持在三线制上不加价,线缆成本增加一点,换回来的是现场不被投诉。
2.2 热电偶和 NTC 的接入方式
如果测温范围超过 300 摄氏度,铂电阻成本太高,就换 K 型或 T 型热电偶。热电偶输出是微伏级热电动势,必须经过 PGA 放大。ADS122U04 内部 PGA 增益可配置 1、2、4、8、16、32、64、128 倍,配合 24 位 ADC,理论上能分辨微伏级变化。但热电偶最麻烦的是冷端补偿:参考端也就是接线端的温度必须测准,否则测量值会跟着接线处的环境温度一起漂。ADS122U04 内部自带温度传感器,固件里先读它算出冷端温度,再用热电偶分度表把冷端对应的电动势加回去,这个逻辑下面章节会专门讲。
NTC 热敏电阻则适合精度要求不高、只需要看趋势的场景。NTC 阻值和温度是指数关系,线性化要分段做或者查表。对 HVAC 来说,NTC 便宜但一致性和精度都一般,我建议只用在不需要精确到 0.1 摄氏度的辅助测量位,比如面板的体感补偿温度。
| 传感器类型 | 测温范围 | 精度潜力 | 成本 | HVAC 适用场景 |
|---|---|---|---|---|
| PT100/PT1000 | -50℃ 到 250℃ 常见 | 正负 0.1℃ 可到 | 中高 | 水管、风管温度,精度要求高 |
| K 型热电偶 | -200℃ 到 1000℃ | 正负 1℃ 左右 | 低中 | 高温烟道、制冷机组排气 |
| NTC 热敏电阻 | -40℃ 到 150℃ | 正负 0.5℃ 以上 | 低 | 面板温度、辅助参考 |
| 数字传感器 | 常见 -20℃ 到 85℃ | 正负 0.2℃ 左右 | 中 | 室内空气温度快速采集 |
2.3 电源、去耦和布线的实战细节
工业场合的电源纹波通常比实验室大很多。ADS122U04 的模拟电源和数字电源建议按数据手册接法分开走,模拟电源和数字电源之间加磁珠隔离,每个电源引脚放一个 10uF 钽电容再加一个 100nF 陶瓷电容。基准电阻的走线要尽量短,直接靠近 REFP 和 REFN 引脚,千万不要把基准电阻放在远离 ADC 的位置让 PCB 走线长出几十毫米,否则基准噪声会直接叠加在测量结果上。
PGA 输入引脚建议加一级 RC 滤波,典型值 1kΩ 电阻加 1nF 电容,滤掉高频干扰。这个 RC 对稳定读数特别有帮助,我在两版 PCB 上对比过,有 RC 滤波的板子原始码跳动明显小于没有的板子。传感器线进了板子之后,如果走线距离较长,也最好做包地处理,旁边紧跟一条回流地线,降低耦合噪声。
2.4 通信接口隔离的取舍
主控板和传感器板如果共用电源地,UART 的 TX 和 RX 可以直连,但要留好 TVS 管和高频滤波电容。如果传感器板在室外或有雷击风险,必须加隔离方案:ADC 板独立供电,UART 中间用光耦或数字隔离器,比如 ISO7721 这类芯片。我这次用的办法是在传感器板到主控板之间加了一个 RS-485 收发器,把 UART 转成差分信号走双绞线。结果发现噪声确实比直连 UART 小得多,因为 RS-485 差分传输的共模抑制能力在长线场景下更可靠。如果你的系统里传感器板离主控板超过三米,我建议直接上 RS-485,别犹豫。
3. 固件搭建:UART 指令控制 ADS122U04 采样
3.1 最简流程:复位、配置、启动转换、读数据
ADS122U04 的 UART 通信格式是 8 位数据、无校验、一位停止位,波特率可以用默认内部振荡器配置,我实测 9600 和 115200 都稳定。上电后我习惯先发一个复位命令 0x20,等待 2 毫秒以上,再写配置寄存器。
这颗 ADC 的配置寄存器一共有 7 个,地址从 0x00 到 0x06。写配置用 WREG 命令,格式是命令字节加上要写入的寄存器数据。命令字节的计算方式是:0x64 按位或上(寄存器地址左移 2 位),再按位或上(寄存器数量减 1)。读配置用 RREG,逻辑类似。每次转换完成后,DRDY 引脚会拉低,此时发一个读取数据命令 0x62,ADC 就会从 UART 回传 3 个字节,拼起来就是 24 位转换码。
这里有个非常常见的低级问题:DRDY 是开漏输出,必须接上拉电阻,否则电平一直不确定,固件怎么等也等不到有效信号。很多开发者以为代码问题,查了半天最后发现是硬件上拉没接。
3.2 PT1000 三线制的寄存器配置思路
以 PT1000 三线制为例,典型配置思路是这样的:
- 寄存器 0(输入多路复用器):选择 AIN0 和 AIN1 做差分输入
- 寄存器 1(PGA 控制):增益选 8 或 16 倍,根据 RTD 满量程电压反算
- 寄存器 2(数据速率):选 20SPS,滤波器对 50Hz 工频抑制最好
- 寄存器 4(IDAC 设置):电流设 1mA,适合 PT1000 自热效应可控
- 寄存器 5(IDAC 通道选择):两个电流源分别接 AIN1 和 AIN2
ADS122U04 的寄存器位定义在不同批次的数据手册里偶尔会有描述差异,我强烈建议不要直接抄网上旧版本的代码,而是对着手头最新版数据手册把每个位核对一遍再固化配置。
3.3 STM32F410RB 上的读取代码主体
我用 STM32CubeIDE 加 HAL 库开发,UART1 连接 ADC,UART2 做 Modbus 输出。核心读取函数大致如下:
HAL_StatusTypeDef ADC_ReadRaw(int32_t *raw) { uint8_t cmd = 0x62; // RDATA 命令 uint8_t buf[3]; if (HAL_UART_Transmit(&huart1, &cmd, 1, 100) != HAL_OK) return HAL_ERROR; if (HAL_UART_Receive(&huart1, buf, 3, 100) != HAL_OK) return HAL_ERROR; // 24 位有符号数,需要符号扩展到 32 位 *raw = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | buf[2]; if (*raw & 0x800000) *raw |= 0xFF000000; return HAL_OK; }注意 HAL_UART_Receive 一次收 3 个字节时,如果中途有干扰就可能丢字节。现场环境不能只靠一次读取,我在每个通道连续读三次,取中位数再做滑动平均,效果比单纯读一次稳定得多。UART 接收函数可以改用 DMA 加空闲中断,但对 20 到 200 SPS 的采样率来说,轮询加短超时已经足够了,没必要增加系统复杂度。
3.4 多通道轮询的节奏控制
ADS122U04 的输入多路复用器切换后,内部模拟前端需要时间稳定,必须等稳定后再触发转换,否则会读到上个通道的残留电压。数据手册给出的是理论最小稳定时间,实操中我习惯按两倍裕量执行,切换通道后延时 5 毫秒再发转换命令。四通道轮询完一遍大约 120 毫秒,对 HVAC 这种热惯性很大的系统来说完全够用。如果真需要更高速度,可以调高数据速率,但噪声会同步变大,除非确实需要快速响应,否则我不建议动这个参数。
4. 温度换算:从 ADC 码到工程温度值的完整链路
4.1 铂电阻的 Callendar-Van Dusen 方程
对 PT100 和 PT1000,国际上通用的换算标准是 IEC 60751,定义了 -200 摄氏度到 850 摄氏度范围内铂电阻阻值和温度的关系。工程上最常用的是 Callendar-Van Dusen 方程。
在 0 摄氏度以上,阻值 R(t) = R0 乘以(1 + At + Bt²),其中 A = 3.9083e-3,B = -5.775e-7。低于 0 摄氏度时,方程增加第三项 C,也就是 R(t) = R0 乘以(1 + At + Bt² + C*(t-100)*t³),其中 C = -4.183e-12。
正算容易理解,工程上更常用的是从电阻反推温度。0 摄氏度以上是标准一元二次方程,直接用求根公式:
t = (-A + sqrt(A² - 4B(1 - R/R0))) / (2*B)
STM32F410RB 有 FPU,直接用 float 算一次只要几微秒,一百个通道同时算也没压力。如果不想解方程,可以放一张 -40 摄氏度到 150 摄氏度的分度表,然后做查表加线性插值。查表法在 HVAC 场景完全够用,唯一要保证的是表的分辨率别太粗,1 摄氏度一个点再配合线性插值,误差能控制在 0.1 摄氏度以内。
4.2 从 ADC 码换算到 RTD 电阻值
比例式测量的核心思路是:ADC 测到的输出码,本质是 RTD 电压和基准电压的比值,再乘上满量程码。所以 RTD 电阻值等于基准电阻值乘以 ADC 码和满量程码的比值。理论上这个公式很干净,但实际 PCB 上基准电阻的温漂、PGA 的增益误差、参考电压的偏移都会影响精度。
为了把这些系统误差消掉,我在固件里加了两点校准:用精密电阻箱替代传感器,分别接一个 0 欧姆和一个 1000 欧姆标准值,记录两个 ADC 码,求出增益和偏移系数。以后每次实测的 ADC 码都先经过这个系数修正,再算电阻。校准功能放在维护菜单里,现场工程师可以用电阻箱做定期校验,效果比单纯迷信 ADC 位数实在得多。
4.3 热电偶冷端补偿的完整逻辑
K 型热电偶的电动势和温度关系是非线性的,工程上一般用查分度表方式。处理流程分四步:
- 读取冷端温度 T_cj,可以用 ADS122U04 内部温度传感器或外接 NTC
- 按分度表查出 T_cj 对应的热电动势 E_cj
- ADC 测到的热电偶电动势是热端和冷端的差值,记做 E_raw
- 计算 E_hot = E_raw + E_cj,再反查分度表得到热端温度 T_hot
这套逻辑看起来直白,但最容易出问题的地方是极性。热电偶的负极要接到 ADC 的反相输入端,测量值是热端减冷端。如果接反了,零点附近会读到负码,最终温度算出来永远不对。我在固件里专门加了一个通道极性自检,上电后先看 ADC 码的符号,如果和预期相反就立刻报错,避免现场接错线导致整机误动作。
5. 调试与避坑:真正影响项目交付的环节
5.1 长线噪声和 50Hz 工频干扰
工业现场最典型的干扰来自 50Hz 工频及其谐波,源头是电机、变频器和开关电源。ADS122U04 的数字滤波器在较低数据速率下对工频有很好的抑制效果。实测在 20SPS 和 50SPS 档位,滤波器的陷波点刚好覆盖 50Hz 附近,读数最稳。一旦用了 100SPS 以上的速率,工频干扰会明显变大,原始码上下乱跳。
软件之外还要做物理层保护:传感器线用屏蔽双绞线,屏蔽层单端接地;ADC 输入端加 RC 低通滤波,截止频率放到几十赫兹以下。我曾经遇到一个现场投诉说读数乱跳,软件滤波怎么调都压不住,最后排查发现传感器线和强电电缆绑在同一个线槽里,间距只有 5 厘米,把两束线分开后噪声瞬间降了一个数量级。经验总结就一句话:软件滤波只是补丁,布线才是根本。
5.2 开路检测和传感器故障上报
工业项目里,传感器断线、端子松动、短路都是常态。ADS122U04 支持开路检测功能,开启后能识别输入高阻状态并返回故障特征。固件必须在每次转换后检查这个状态位并及时上报,否则系统显示 0 摄氏度的时候,运维根本分不清是管道真的结冰还是传感器掉了。
我在代码里加了故障确认机制:如果连续 N 次读到开路故障,才把这个通道标记为 fault 状态,避免因为一次偶发干扰就误报。标记之后,Modbus 寄存器对应位置位置位,同时温度值输出一个无效数,而不是一个看起来正常实际上没意义的温度。这点对 HVAC 系统特别重要,因为故障温度被上位机拿去参与联锁控制的话,可能造成风机误启动或水阀误动作。
5.3 现场校准方法:从零点到量程中段
现场校准不像实验室有恒温槽,往往只有一台手持温度计和一个精密电阻箱。我的做法是分三步:
- 用精密电阻箱代替传感器,接 0 欧姆和 1000 欧姆两个点,求出系统增益和偏移
- 把偏移和增益写入 MCU 的校准参数区,固化到片上 Flash
- 再用冰水混合物做 0 摄氏度现场验证,总精度通常能到正负 0.1 摄氏度
常见误区是只校零点不校满量程,结果阻值范围一变化,误差就非线性放大。两到三点校准,尤其是覆盖量程中段,效果比只校零点好得多。校准参数保存后,每次上电要先读 Flash 校验 CRC,避免参数损坏导致系统用错误的系数算温度。
5.4 其他容易忽略的小坑
去耦电容放在 PCB 背面且离 ADC 太远、基准电阻随手选了个 5% 精度的普通电阻、数字地和模拟地没有合理分割,这些我都踩过。特别是基准电阻,有些工程师不重视,随手挑一个就焊上去,导致整个 ADC 读数偏得离谱,还以为是芯片坏了。记住一个基本判断:ADS122U04 的精度上限由基准和前端电路决定,而不是 ADC 本身。芯片只是忠实地把输入信号数字化,前端做得烂,再高端的 ADC 也救不回来。
6. 实测数据与可复用的扩展思路
6.1 24 小时漂移和噪声实测
样机做出来后,我把三路 PT1000 接进恒温箱,运行了整整 24 小时记录温度。室温 25 摄氏度条件下,整机最大偏差 0.06 摄氏度,重复性优于正负 0.02 摄氏度,对一个 HVAC 控制器来说已经超出需求。噪声方面,20SPS 档位下 ADC 原始码的峰峰值大约 8 到 10 个 LSB,经过三次采样取中位数加滑动平均之后,显示端几乎只有最后一位在跳。这说明系统的主要噪声来自电源和 PCB,而不是 ADC 本身,只要前端做好了,24 位分辨率是能兑现的。
6.2 从 4 路扩展到 8 路甚至 12 路
如果项目后期需要更多温度点,有几种扩展思路可以参考:
- 每颗 ADS122U04 管 4 路,两颗管 8 路,在 MCU 侧切换 UART 对应片选
- 换用带更多通道的 ADC 或加外置多路开关,但要注意通道间串扰
- 在 STM32F410RB 上再接数字温度传感器做辅助测量,和模拟通道互为备份
我的倾向是少于 8 路就老老实实用两片 ADS122U04,超过 8 路再考虑把主控升级成带更多 UART 的型号,或者引入一颗廉价单片机专门做传感器轮询,再把结果通过 Modbus 打包发给主控。不要为了省一颗芯片把所有通道串在一个多路开关上,那样调试和抗干扰都会非常痛苦。
6.3 长期运行的稳定性维护
ADS122U04 单次转换功耗很低,对常年通电的 HVAC 控制器来说不是主要开销。要注意的是长时间运行下的端子氧化、插拔松动会逐步改变接触电阻,叠加在三线制补偿之外就会引入误差。我在设计里把所有传感器接口都指定了防松端子,接线端子扭矩按规定锁紧,并且建议现场每半年做一次校准检查。工业设备不是做一次性实验,维护方便才是真正的工程能力。
最后聊一点个人体会:这个项目最花时间的不是选型也不是代码,而是反复在现场验证各种边界条件。传感器线拉长以后噪声会有多大,电源电压波动时读数会不会漂,断线恢复后系统能不能可靠识别,这些都不是靠看数据手册能提前想到的。ADS122U04IPWR 和 STM32F410RB 这对组合本身已经很成熟,真正的技术含量在于模拟前端做得够不够扎实、状态机写得够不够清楚。如果这篇文章能帮你少走几步弯路,那就值了。