
去年在帮着做一套工业现场温度监控系统同时要给楼宇自控的 HVAC 机组做温度采集手边最常用的组合就是 ADS122U04IPWR 和 STM32F767BI。ADS122U04IPWR 是一颗 24 位四通道 Δ-Σ ADC带 UART 接口、内部 PGA 和激励电流源非常适合把 PT100、热电偶、NTC 这些微弱信号直接变成数字量STM32F767BI 则是主频 216MHz 的 Cortex-M7 单片机负责跑通信协议、滤波算法、显示和联动控制。整套系统一路调试下来把温度测量从“能测”做到了“测得准、测得稳”这里把完整的设计思路和踩过的坑都记录下来给后面做类似温度采集板的朋友一个参考。不同场景对温度测量的需求其实很不一样。HVAC 里要测冷冻水供回水温度、冷却水温、风管回风温度、压缩机吸气排气温度工业现场可能还要测轴承、电机绕组、加热炉炉膛。信号范围从 PT100 几十毫伏的变化量到 K 型热电偶几十微伏级别的热电势差距非常大。ADS122U04IPWR 的高位数、可配置 PGA 和多通道 MUX加上 STM32F767BI 的算力正好能把这些信号统一处理不用再为每一种传感器单独做一套模拟前端。1. 项目是怎么落地需求拆解与选型思路1.1 温度测量在工业和 HVAC 场景中的真实需求做工业采集的人都知道真正难的不是把传感器接到 ADC 上而是把误差控制住。以 PT100 为例0℃ 时阻值 100Ω温度系数大约 0.385Ω/℃如果导线电阻有 0.5Ω两块表显示的温度就有 1.3℃ 左右的差别。这在 HVAC 的舒适性控制里还能接受但在工业工艺监控里可能就直接意味着批次报废。所以选型时首先要明确系统需要多高的绝对精度、多好的长期稳定性、要不要满足防爆/电磁兼容认证。HVAC 系统里温度变化速度不快风管温度一般几十秒才稳定压缩机排气温度变化的惯性也比压力慢很多因此采样率不需要很高20SPS 到 100SPS 足够。但 HVAC 对可靠性和成本敏感传感器常常分布在几十米长的管道上走线会经过变频器、接触器这些干扰源所以 ADC 必须有足够的抗工频干扰能力最好能直接带 50Hz/60Hz 抑制滤波器。工业现场则更看重宽量程和灵活性一台设备可能要兼容 PT100、各种热电偶、4-20mA 变送器如果每换一种传感器就换一块采集板维护成本会成倍增加。把需求拆开之后适合的 ADC 大概要有这么几个特征24 位或以上分辨率、内置 PGA、内置激励电流源、多路输入、可配置数据速率。ADS122U04IPWR 基本踩在这些点上而且它通过 UART 输出结果而不是传统的 SPI这在远距离和分布式布线上反而有优势。STM32F767BI 则是因为项目里不只做温度采集还要跑 Modbus、控制继电器、带一块液晶屏甚至做简单的数据记录M7 内核的资源和外设数量都比较充裕。1.2 为什么是 ADS122U04IPWR STM32F767BI这个组合不是随便定的。市面上一堆 24 位 ADC比如 I2C 接口的 ADS122C04、SPI 接口的 ADS124S08、ADS1261还有各种国产高精度 ADC单独拿出来都能测温度。但 ADS122U04IPWR 的特殊点在 UART 物理层主控只需要两根线就能完成配置和数据读取而且支持多设备地址访问适合一个主机带多个从机测量模块。对 HVAC 这种分散式系统来说每台空调机组放一块带 UART 的采集小板用一条总线连回主控布线比 SPI 的“一主多从片选线”更简单。STM32F767BI 的选型看中的是资源和算力。它内部有硬件浮点单元跑温度查表和滤波算法非常轻松多路 UART 可以同时接数据采集板、调试串口、Modbus 网关内置以太网 MAC 和 LCD 控制器允许后续直接做触摸屏或联网监控。之前我也考虑过 STM32F103 之类更便宜的芯片后来发现要在 F1 上用软件实现浮点滤波、还要同时处理多路 UART 和显示代码优化成本很高不如直接用 F7 把时间花在算法和控制逻辑上。当然这套组合也有代价。ADS122U04 的寄存器配置比普通温变芯片复杂第一次上手时容易因为几个位没配对导致输出数据乱跳。STM32F767BI 的电源设计和 PCB 布局也比小单片机苛刻一些特别是 216MHz 主频下如果用劣质 LDO模拟采集部分很容易受到数字噪声干扰。后面章节会把这些问题逐一展开。1.3 系统整体框图与数据流整个系统的数据链路可以分成四段传感器、模拟前端、数字转换、主控处理。温度传感器首先经过保护滤波电路进入 ADS122U04 的输入通道内部的 MUX、PGA 和 Δ-Σ 调制器把模拟电压转成 24 位数字码接着 UART 以帧形式把结果发给 STM32F767BI最后在 MCU 里做电阻/温度换算、冷端补偿、滤波、越限判断再把数据送到显示、通信或执行机构。这里最需要注意的是信号链上的每一个环节都可能引入误差但效果完全不同。传感器本身决定物理精度上限比如 PT100 在 0℃ 精度可能是 ±0.3℃而 K 型热电偶常温附近精度只有 ±1.5℃ 左右。模拟前端的激励电流源、参考电阻和输入滤波决定了噪声底和温漂。ADC 的高位数只在前面都做得好的时候才有意义如果外部参考电阻温漂 100ppm/℃那么即便 ADC 有 24 位分辨率整机精度也会被参考电阻拉低。因此在设计时我把更多精力放在模拟链路的“一致性”和“长期稳定”上而不是只看 ADC 位数。2. 硬件设计核心细节传感器输入到 ADC 再到 MCU2.1 传感器类型与接口PT100/PT1000、热电偶、NTC 怎么接PT100 和 PT1000 最常用的是三线制和四线制接法。四线制是把激励电流从一对导线注入用另一对导线把 RTD 两端的电压单独引回来彻底消除导线电阻影响适合实验室级测量。但工业现场为了省线通常用三线制一条导线接激励电流源一条导线接参考电阻第三条导线接公共地或者作为电压检测补偿这样导线电阻在测量回路里相互抵消实际误差可以控制在 0.1℃ 以内。ADS122U04 内部有可配置的激励电流源这给三线制接线提供了很大便利。典型做法是用内部 IDAC1 给 PT100 串联路径提供恒流同时让这股电流也流过一颗低温漂参考电阻 RREF以 RREF 上的压降作为 ADC 的参考电压。这样 RTD 电压和参考电压由同一个电流源建立ADC 码值直接等于 RTD 电阻和 RREF 的比值激励电流自身的漂移就被完全抵消了。这也是后面软件里为什么能用“码值乘以 RREF 再除以最大码值”直接算出电阻的原因。热电偶输出的是微伏级热电势通常接到 AIN2/AIN3 这样的独立通道配置 PGA 增益为 32、64 或 128。由于热电偶本身没有激励电流冷端补偿必须在靠近热电偶接线端子的位置放一颗温度传感器可以是板载 NTC也可以直接用 ADS122U04 内部温度传感器。NTC 则相对简单常与固定电阻构成分压电路激励源可以选固定电流源也可以直接由 ADC 参考电压驱动只要满足输入共模范围和量程即可。2.2 激励电流、低通滤波和输入保护电路激励电流的选取要平衡信噪比和自热效应。PT100 在 100Ω 时用 1mA 电流电阻上压降才 100mVADC 输入信号太小PGA 需要开较高增益如果加到 2mA在 PT100 变为 1000Ω 时压降就有 2V可能超过 PGA 输入范围同时电流在传感器内部产生的热量会影响测量结果。按经验PT100 用 0.5mA 到 1mA 比较合适PT1000 因为在更高阻值段工作0.5mA 也很稳妥。RC 低通滤波是每个模拟输入通道必备的。工业现场经常有变频器、继电器拉弧产生的几百 kHz 高频干扰如果不滤掉会在 Δ-Σ 调制器输入端混叠成低频噪声。通常选择电阻 1kΩ、电容 0.1μF 的组合截止频率约 1.6kHz既能滤掉大部分射频干扰又不会把传感器信号压掉。电容要用 C0G/NPO 材质普通 X5R 电容在直流偏置下容值会下降且温飘较大。如果传感器线很长我还会在入口处加共模电感或者磁珠。输入保护也要做但不建议用压敏电阻直接并联在 ADC 输入上因为漏电流在高温下会恶化测量精度。比较稳妥的做法是串联 10kΩ 到 100kΩ 的限流电阻再用低漏电 TVS 管接到电源和地轨。这样 24V 电源误碰、静电放电、雷击浪涌都能被限制在 ADC 可承受范围内而且不影响正常测量。做多用表温度输入时还会加一个二极管钳位到 AVDD/AVSS防止断线瞬间产生过压。2.3 ADS122U04 与 STM32F767BI 的 UART 电气连接ADS122U04 的 UART 是异步串行数据线和时钟线就是 TX/RX 两根直接接 STM32F767BI 的任意一组 USART。STM32F767BI 的 I/O 工作在 3.3V而 ADS122U04 也支持 3.3V 数字电源因此这里可以直连。为保证调试时不因杜邦线插拔打坏引脚我在 UART 线上各串了一个 100Ω 电阻必要时再连到 MCU 的 USART RX/TX 引脚。通信波特率建议先用 9600 或 19200 起步确认帧格式和 CRC 校验没问题后再提到 115200。UART 本身是异步的如果两端波特率偏差超过 2%长帧传输就可能出现误码。STM32F767BI 内部使用 16MHz 到 25MHz 晶振通常误差不大但 ADS122U04 内部的时钟精度有限因此不要让波特率太高尤其是用内部振荡器做多板通讯时115200 以下更稳妥。如果温度采集板和主控板要分开放比如一个装在机柜里一个装在传感器附近UART 之间可以加数字隔离器比如 ISO7721。隔离器放在传感器侧而不是主控侧好处是模拟部分和数字部分彻底断开地环路干扰问题和共模电压问题一次解决不影响 UART 信号速度。2.4 电源与基准电压设计要点模拟电源 AVDD 和数字电源 DVDD 建议都由低噪声 LDO 供电不要直接从开关电源纹波大的 12V 取。ADC 的电源抑制比在高频段并没有想象中好一个 30mV 的开关纹波就可能通过内部比较器耦合到测量结果里。我常用 TPS7A 系列或 LP5907 这类超低噪声 LDO把 5V 降到 3.3V再用 10μF0.1μF 去耦。STM32F767BI 的 VDD 可以用同一条 3.3V 电源但模拟部分的 AVDD 建议单独去耦。基准电压的设计是温度测量精度的核心。ADS122U04 使用外部参考电阻做比例测量时实际上并不需要一个绝对精确的 2.048V 基准带隙而是把 RREF 的电压当作参考。因此 RREF 的品质直接决定了整机精度我选择 0.1% 精度、温漂 10ppm/℃ 的精密电阻阻值根据量程选 1kΩ 或 2kΩ。如果使用内部基准则要确保 VREF 引脚滤波电容采用高质量 X7R并根据温漂定期校准。模拟地、数字地在 ADC 芯片下方用一颗 0Ω 电阻或者磁珠单点连接不要把大面积地直接连成一片否则数字噪声会沿着地平面串进模拟前端。STM32F767BI 的高速数字引脚和 ADC 模拟输入要尽量拉开距离至少保证 3mm 以上的间距这在四层板上效果最明显。3. 软件驱动与温度计算把原始码变成可用温度3.1 ADS122U04 寄存器配置与 UART 通信协议第一次用这颗 ADC 的人容易被 UART 命令模式绕晕。它不像 SPI 那样直接拉低片选读数据而是要先发读写寄存器命令再发数据读取命令并且每一帧都可能有 CRC 校验。我的建议是把配置过程封装成独立的驱动函数只暴露初始化、通道切换、读取温度三个接口后面应用层不直接碰寄存器位。下面是一段示意性的初始化代码寄存器地址和状态位以 ADS122U04 数据手册为准这里重点展示整个配置流程static void adc122u04_write_reg(uint8_t addr, uint8_t value) { uint8_t frame[3]; frame[0] 0x20 | (addr 1); // 写寄存器命令格式 frame[1] value; frame[2] crc8(frame, 2); // 开启CRC时追加校验 uart_send(frame, 3); } void adc122u04_init(void) { adc122u04_send_cmd(0x11); // STOP先停掉连续转换 delay_ms(5); // 选择AIN0/AIN1差分通道内部PGA跟随输入 adc122u04_write_reg(REG_CONFIG0, 0x02); // PGA增益设为16适合PT100满量程信号 adc122u04_write_reg(REG_CONFIG1, 0x04); // 数据速率设为20SPS并启用50Hz/60Hz抑制 adc122u04_write_reg(REG_CONFIG2, 0x03); // 参考电压选择外部RREF比例方式 adc122u04_write_reg(REG_CONFIG3, 0x01); // 激励电流源0.5mA分配到IDAC1 adc122u04_write_reg(REG_CONFIG4, 0x05); // 启动连续转换 adc122u04_send_cmd(0x08); }需要注意寄存器配置完成后最好回读一遍确认写入成功因为在某些异常电压下 UART 命令可能被噪声破坏。如果配置值和读回值不一致软件应主动报警而不是继续用错误参数跑数据否则测出来的温度可能整体偏移好几度。读取数据时可以设置成连续转换模式主控周期性地从 UART 收帧解析。ADS122U04 输出的 24 位数据需要拼成有符号整数再除以最大码值得到电压比例。如果开启了 CRC每帧末尾会有校验字节接收端不通过就丢弃这一帧。我在实际项目中把 CRC 开启宁可在现场看到少数几条丢弃告警也不希望一次干扰直接导致温度跳变 10℃。3.2 STM32F767BI 端 UART 收发与 DMA 实现STM32F767BI 端用 HAL 库配置 UART 接收会比较简单但要注意别在主循环里用阻塞方式等数据。温度采集本身不需要极高实时性可一旦加入显示、控制、通信主循环很容易被卡住。我一般用 DMA 接收固定长度帧接收完成后在 DMA 完成中断里解析数据这样 ADC 的数据更新不会阻塞其他任务。DMA 接收的关键是要知道一帧有多长。如果设成 6 字节一帧就配置 HAL_UART_Receive_DMA(huart1, rx_buf, 6)每收满 6 字节触发一次中断。ADS122U04 连续转换模式下会持续发帧主控只要不断接收即可。收到后先判断帧头或状态字节再检查 CRC最后把 3 字节 ADC 数位提取出来。uint8_t adc_rx_buf[8]; volatile uint8_t adc_data_ready 0; int32_t adc_last_raw 0; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart-Instance USART1) { if (check_frame_crc(adc_rx_buf)) { adc_last_raw extract_signed_24(adc_rx_buf 2); adc_data_ready 1; } HAL_UART_Receive_DMA(huart, adc_rx_buf, 8); } }这段代码演示了整个收发框架。工程上还要注意 DMA 缓冲区在中断里被访问的原子性最好关中断取数或者用双缓冲。另一个容易踩的坑是 STM32F767BI 的 USART 时钟源和波特率配置如果用内部低速时钟误差会大建议把 USART 时钟源设置为 PLL 分频后的高频时钟并且用逻辑分析仪实测一帧的位宽确认没有多或少 1μs。3.3 RTD 电阻计算、线性化与热电偶冷端补偿硬件采用比例测量时ADC 的码值可以直接换算成 RTD 电阻值。假设 ADS122U04 使用的是二进制补码24 位有符号数满量程对应 2^23那么电阻的计算就是R_rtd code × RREF / 2^23只要 RREF 足够稳定这个公式对激励电流源的绝对值不敏感。对应代码可以这样写float ratio_to_resistance(int32_t code, float rref) { return ((float)code / 8388608.0f) * rref; }算出电阻之后还要把电阻换算成温度。PT100 在 0 到 850℃ 范围内可以用 Callendar-Van Dusen 公式但直接解方程比较麻烦工程上更快的办法是查表和二分法。我预生成一张 1℃ 间隔的电阻-温度表固件里用二分查找加线性插值计算一次不到 1μs精度可以做到 0.1℃ 以内。热电偶的软件处理比 RTD 多一个冷端补偿步骤。先把冷端温度查成对应的热电动势 e_cold再把它加在实际测得的热电势 e_hot 上得到修正后的热电势 e_real最后按热电偶分度表把 e_real 换算成被测温度。由于热电偶的非线性非常明显直接用线性公式会差出几度必须查表或多项式拟合。冷端温度可以从 ADS122U04 内部温度传感器读取也可以外接 NTC但 NTC 要贴在热电偶冷端接线上而不是贴到主控芯片附近这个位置错误很常见。3.4 滤波与抗干扰滑动平均限幅IIRADC 原始数据即使在高分辨率下也还会有低频噪声和偶发尖峰。我是按“限幅-平均-低通”三级来处理先把明显超过物理极限的尖峰点剔除再滑动平均抑制高斯噪声最后用一阶 IIR 平滑输出避免曲线过于生硬。滑动平均的程序很简单关键在窗口大小。窗口太大会导致温度变化响应慢HVAC 里也许还能接受但工业保护联锁要求快速反应所以窗口长度取 8 比较合适。一阶 IIR 的系数则要按采样周期和期望响应时间计算比如 20SPS 采样alpha 取 0.3 时响应时间约 15 个采样周期也就是 0.75 秒对大多数温度控制够用。#define FILTER_WIN 8 float filter_sum 0; float filter_win[FILTER_WIN]; uint8_t filter_idx 0; float temp_filter(float new_temp) { filter_sum new_temp - filter_win[filter_idx]; filter_win[filter_idx] new_temp; filter_idx (filter_idx 1) % FILTER_WIN; return filter_sum / FILTER_WIN; }要注意滤波不能替代硬件屏蔽。如果现场干扰严重把滤波系数调得很深温度显示是稳定了但真实温度突变时系统反应会迟滞极端情况下会导致保护逻辑误判。所以我开发时习惯在界面上保留一个“原始值”页面专门用于调试时对比滤波前后数据干扰排查全靠它。4. HVAC 与工业场景的实测问题与排查实录4.1 现场常见的错误接线和传感器故障判断用这套方案跑了两个项目后我发现大多数“不可理喻”的问题其实发生在接线端。PT100 的开路故障会读出接近正满量程或负满量程的乱码因为输入悬空时 PGA 输入端没有电流回路电压漂到上限附近热电偶接反则表现为冷端补偿后温度反而下降正常加热时读数越来越低。想要快速分辨故障类型可以在固件里加一个简单的合理性检查PT100 电阻在 -50℃ 到 300℃ 之间对应多少欧姆如果 ADC 换算出的电阻值明显超过这个范围就置一个“传感器异常”标志。热电偶可以检查热电势的变化率和极性如果几分钟内温度变化速率超过物理极限也应直接告警而不是把异常数据送到控制环里。我印象最深的是某次 HVAC 风管温度传感器显示 -55℃换了新传感器也一样。后来查出来是传感器线缆内部断芯断点处的氧化层产生了类似热电偶的接触电势而 ADC 通道又恰好配置成热电偶模式把这个寄生电势当成了真实信号。从那以后我在硬件额定范围外做了软上限和断线检查不再盲信 ADC 数据。4.2 电磁干扰导致的跳码问题工业现场最大的敌手是变频器和接触器。它们产生的干扰频带非常宽轻则让 ADC 最后 2-3 位乱跳重则整帧数据 CRC 错误。第一次遇到时我以为是供电问题后来用示波器量 ADC 输入引脚才看到几百毫伏的高频毛刺。这些毛刺在 24 位 ADC 面前会被放大得非常明显。处理电磁干扰要分两步走。硬件上传感器线要换成屏蔽双绞线屏蔽层只能一端接地ADC 输入走线远离大电流走线并且加大 RC 滤波电容如果干扰来自地环路就加数字隔离器或者把模拟地与机箱地隔离。软件上把数据速率降到 20SPS启用 50Hz 工频抑制滤波器然后再加上前面说的滑动平均。这两步做完大部分跳码问题都能消失。还有一个容易忽略的点STM32F767BI 的高速数字信号本身也是噪声源。有一次我在调试时发现 ADC 读数在 LCD 刷新瞬间会跳一下单独测模拟部分又没问题。后来把 ADC 的 AVDD 用磁珠和 DVDD 分开并把 SPI/LCD 走线移到另一面现象就消失了。所以不能只怪外部干扰内部布板和供电耦合往往才是幕后黑手。4.3 漂移问题ADC 自校准与零点修正长期漂移比随机干扰更隐蔽。开机前几个小时内温度读数缓慢变化可能是 ADC 或运放刚开始工作时的热漂移几个月内发生漂移则往往是参考电阻老化、PCB 受潮漏电或者传感器本身劣化。对于工业应用我会在每次上电时做一个自校准输入通道短接记录零点偏移再通过内部校准命令修正失调。ADS122U04 配置里可以启用内部失调校准和增益校准但要注意校准命令执行期间不要切换通道并且要在稳定的电源环境下进行。如果现场供电波动大校准结果反而会引入新误差。实践经验是凌晨低负载时段执行一次校准保存校准系数到 STM32F767BI 内部 Flash 的备份区重启后自动叠加到计算结果上。参考电阻的漂移问题最好在设计阶段就规避。选用 10ppm/℃ 以下的精密电阻并且把 RREF 尽量靠近 ADC 的 REF 引脚远离发热元件。PCB 上预留两颗校准电阻的焊盘量产时用自动化设备做两点校准把增益系数写入每台设备的 MAC 地址区。这种做法的成本增加很小但能保证不同批次设备的温度读数一致尤其适合批量出 HVAC 控制器和工业采集器的场景。4.4 长距离传输与隔离问题当传感器离主机超过 10 米时直接模拟走线不是好选择。我曾经试过用普通屏蔽线从 20 米外接 PT100 到 ADC 板虽然三线制补偿了大部分线阻但现场的变频器噪声和共模电压仍然让读数不稳定。后来改为在现场放置一块小的采集板通过隔离 UART 传给主机信号质量立刻改善。具体做法是每台设备上用一个 ADS122U04 做模拟前端就近采集传感器信号然后通过 UART 驱动隔离器再走 RS-485 总线回传。STM32F767BI 作为总线主站接收各从站数据统一做记录和控制。这样每个采集点只处理自己的模拟信号总线传输的是已经数字化的温度值抗干扰能力与直接传模拟电压完全不同。虽然单板成本高了一点但调试和后期维护的复杂度大幅下降。再补充一个我踩过的坑隔离器两侧的电源必须独立不能共地。如果隔离器输出侧和 MCU 还是共用一个 3.3V那么隔离实际上只增加了延时没有斩断地环路。至少要保证模拟侧电源和数字侧电源分别用两颗 DC-DC 或 LDO否则现场雷击浪涌时照样会烧毁主控板。这个细节在很多方案文档里都不会写恰恰是长期可靠性的关键。在我自己的项目上我坚持把隔离放在传感器侧而不是总线侧这样后续排查问题会非常清晰传感器板只负责模拟采集总线板只负责通信哪边异常直接换哪块。这套 ADS122U04IPWR 加 STM32F767BI 的思路从原型到量产迭代了三轮目前已经稳定跑了大半年至少在温度测量这条赛道上是我用过性价比最合适的组合。