ADS122U04 + STM32F437ZG 工业级温度采集方案详解 二线制还是四线制ADS122U04 STM32F437ZG 把工业级温度测量一次讲透做工业仪表和暖通空调控制的工程师十有八九都被温度采集折磨过。热电偶的毫伏级信号、PT100 的微小阻变、长线传输带来的干扰、还有那绕不开的冷端补偿——每一项单独拎出来都能让人调上三天三夜。我最近帮一个做组合式空调机组的客户做控制系统升级核心需求就是把分布在风管、水管、回风口的几十路温度信号统一采回来精度要求到 ±0.5℃ 以内还得抗得住变频器启动时的强干扰。最终定型的方案就是ADS122U04IPWR 加 STM32F437ZG一个负责信号采集一个负责逻辑控制中间只用一条 UART 线配合得相当干净。这篇文章会把整个方案从头到尾拆开来讲包括为什么选这套组合、硬件上怎么接线、STM32 端怎么写驱动、温度怎么从原始 ADC 码值换算成真实温度以及我实际调试中踩过的一堆坑。文章适合正在做温度采集方案选型的嵌入式工程师也适合想用 UART 接口 ADC 简化系统设计的开发者参考。1. 方案设计思路为什么是这颗 ADC 配这颗 MCU1.1 需求倒推出来的选型结论先说项目背景。工业现场和 HVAC 系统里温度传感器型号往往五花八门一次侧用 PT100 的居多风管里 K 型热电偶也不少还有大量 NTC 用在盘管和风机盘管上。客户要求一套硬件能兼容全部类型而且传感器离控制器距离从两米到三十米不等。这就把方案选择逼到了几个硬性条件上分辨率要够温度分辨率至少要 0.01℃ 级别折算到电压上就是微伏级别输入通道要能复用最好四通道以上要能直接接热电偶内部带 PGA 放大和冷端补偿参考通信接口要抗干扰长线传输不能用 I2C 这种对时序敏感的接口。ADS122U04 完全覆盖这些要求。这颗芯片是 TI 推出的 24 位 Δ-Σ ADC四通道差分输入内置可编程增益放大器PGA增益从 1 倍到 128 倍可调还集成了一个用于冷端补偿的温度传感器。最特殊的是它的通信接口——支持 UART 协议三根线TX、RX、GND就能搞定比 SPI 少了时钟信号的约束长线传输稳定度反而更高。MCU 选了 STM32F437ZG。这颗料是我手头经常备着的型号Cortex-M4F 内核主频 180MHz带浮点运算单元做温度换算和滤波算法时可以直接算浮点不用像 M0 内核那样做整型近似。另外它有 2MB Flash 和 256KB RAM后面如果要加 Modbus 协议栈、LCD 屏驱动、曲线记录功能资源都撑得住。1.2 工业场景和 HVAC 场景的差异化需求同一个硬件平台在工业和 HVAC 两个场景下需求其实差异很大。工业环境往往要求宽温区、高防护等级、24V 供电、强电磁干扰下不能丢数据HVAC 场景则更看重性价比和安装便利性传感器数量多、布线距离远、还要能容忍空调机组启停瞬间的电源波动。ADS122U04 在这些方面还算从容。它的模拟电源和数字电源分开供电内部有低噪声的 LDO 给 ADC 核心供电输入引脚带 EMI 滤波功能抗工业现场的射频干扰能力比普通 ADC 强一截。整套方案在实验室实测时把 24V 电源线跟动力线绑在一起跑满载电流测量数据纹波依然能控制在 0.3℃ 以内这个表现对 HVAC 现场来说是绰绰有余的。2. 硬件电路设计接线、供电、传感器接口2.1 ADS122U04 的供电与引脚分配ADS122U04 的模拟电源 AVDD 建议接 3.3V 或 5V数字电源 DVDD 可以直接跟 MCU 侧的 3.3V 共用注意两个电源都要各自并联 0.1μF 和 10μF 的旁路电容尽量靠近芯片引脚放置。电源顺序上要求 AVDD 先上电或者同时上电硬件上如果 MCU 和 ADC 共用一个电源芯片这个条件天然满足不用加额外的上电时序控制。芯片有四组差分输入通道AIN0/AIN1、AIN2/AIN3、AIN4/AIN5、AIN6/AIN7同时每个引脚也可以配置成单端模式。我实际项目中是把前两路接热电偶中间一路接 PT100三线制最后一组接 NTC 热敏电阻。这样分配的好处是每组输入都能独立配置 PGA 增益和偏置电流源不需要在外部做模拟开关切换减少漏电流带来的误差。REFOUT/REFIN 引脚是参考电压的输入输出。ADS122U04 内置了一个低温漂参考源输出 2.048V内部已经连接到 ADC 的参考输入默认情况下不用外接参考芯片。如果外部干扰严重REFIN 引脚也可以直接接地强制使用内部参考。2.2 热电偶、PT100、NTC 三种传感器的接入方式热电偶接入时传感器直接接到差分输入端即可。K 型热电偶的热电势大约 41μV/℃在 1000℃ 时输出约 41mV因此 PGA 增益选择 64 倍比较合适此时满量程对应约 64mV正好覆盖常用温区。冷端补偿需要在热电偶的冷端也就是接插件位置放一个测温元件ADS122U04 内部集成的温度传感器可以直接用来做冷端温度的测量但需要注意它测量的是芯片自身温度实际使用时要保证芯片和冷端接插件之间热耦合良好我用了一块铜箔把接插件引脚和芯片底部连起来实测冷端补偿误差能控制在 0.2℃ 以内。PT100 的接法推荐三线制。所谓三线制就是传感器的两根引线分别从电桥两端接入第三根引线用于补偿导线电阻。接法上用 ADS122U04 内部的可编程电流源 IDAC1 输出 500μA 恒流给 PT100电流流经 RTD 和一路参考电阻常见做法是加一个精密 1kΩ 电阻或者直接用参考电阻网络然后把 RTD 各端点按差分方式接入 ADC。这样做的核心思想是比例测量——输入的电压和参考电压均源于同一个电流源电源波动理论上可以完全抵消。PT100 在 0℃ 时电阻 100Ω500μA 恒流下压降约 50mVPGA 选 32 倍就能获得足够的电压分辨率。NTC 的接入最简单采用分压结构。NTC 串联一个精密电阻节点接 ADC 的差分输入一端另一端接模拟地。值得注意的是 NTC 的温度特性是高度非线性的一般认为 25℃ 时的阻值变化率约为标称值的 5%/℃因此分压电阻要选合适阻值我习惯选和 NTC 标称值同一量级例如 100k NTC 配 100k 电阻这样在 25℃ 附近分压点处于电桥中心灵敏度最高。2.3 PCB 布局与信号完整性这类微伏级信号采集PCB 布局决定了大半的调试工作量。核心注意事项有这几条模拟地和数字地分开铺设在电源入口处单点汇接ADS122U04 的 AGND 和 DGND 引脚各自连到对应的地平面不能混在一起处理输入信号线尽量走差分对保持等长等间距从接插件到芯片引脚之间不要穿层避免地平面断裂恒流源驱动 PT100 时驱动线走内层避免和数字信号线平行走线。我第一版 PCB 就是偷懒把 485 通信线的走向和模拟输入线挨着走了几个厘米结果串口收发数据时 ADC 读值跳了十几个码。后来把模拟输入线改走底层、485 线改走上层并用地孔隔离问题才消失。3. 通信协议与寄存器配置3.1 UART 通信机制比 SPI 更省心的选择ADS122U04 的 UART 接口是它区别于普通 ADC 的最大卖点。它采用标准的 8-N-1 格式可选波特率有 9600、19200、38400、57600 和 115200。协议层面MCU 作为主机所有通信都由 MCU 主动发起ADC 不会主动上传数据这一点和 Modbus RTU 的问答机制很像理解成本很低。通信帧格式为命令字节 数据。命令字节的 MSB 规定传输方向0 表示主机发送1 表示主机接收。具体命令包括写寄存器0x4D方向位写入后跟寄存器地址和数据读寄存器0x6D方向位读取后跟寄存器地址读转换数据0x60ADC 返回 24 位转换结果。每条命令前都要加一个同步周期也就是拉低 RX 线 8 个波特率周期以上然后发送 0x00 字节让 ADC 重新检测到一个完整的起始位确保内部时序重新同步。这个同步机制在实际调试时非常重要特别是 MCU 复位后波特率尚未稳定的情况下首次通信前强制同步能避免“卡死在收到半个字节”的尴尬局面。3.2 寄存器的关键位域与配置分组ADS122U04 有 4 个 8 位配置寄存器地址从 0x00 到 0x03每个寄存器的作用和关键位我列个表方便查阅寄存器地址位域功能说明建议配置0x00PGA增益选择热电偶 64、PT100 32、NTC 10x00MUX输入通道选择按实际接入的通道切换0x01VREF参考电压源选择默认内部 2.048V0x01IDAC电流源输出设置PT100 用 500μA0x02DRATE数据率20 SPS低速高精度0x02MODE连续转换/单次连续转换模式为主0x03TCB热电偶开路检测开启接电流源到输入写配置的时序我提一句发送 0x4D 之后紧跟寄存器地址再按顺序发送要写入的数据字节。例如写 0x00 寄存器把 PGA 设为 64 倍、通道 0 选上写入值就是 0x1A对应 PGA64、MUXAIN0/AIN1发送序列为0x4D 0x00 0x1A。读转换结果时MCU 发送 0x60 命令后ADC 返回 3 个字节高字节在前数据格式是 24 位二进制补码。例如读回0xFF 0xF3 0x80对应的十进制码值是(-1 * 2^23) 805376 -795648再除以2^23 - 1得到比例值后续换算成电压。3.3 STM32F437ZG 的 UART 驱动实现要点STM32 端的驱动代码我拆成三个函数模块初始化、发送命令、接收数据。初始化时需要注意UART 的波特率寄存器配置和 ADC 侧保持严格一致我这里统一用 115200。STM32F437 的 USART2 因为我挂在了 DMA 上直接让 DMA 把从 ADC 读回的 3 字节搬到 RAM 缓冲区可以不打扰主循环的实时控制。关键序段是发送命令的函数。它需要在发送命令字节前先在 RX 线上输出一段空闲电平时钟周期。STM32 的做法是先把 RX 对应的 GPIO 脚复用为普通输出口拉低 10 个毫秒远大于 8 个波特率周期再拉高 1 个毫秒然后切回复用功能。这样硬拉出一个低电平窗口刚好触发 ADC 的同步检测。以下是我精简过的初始化代码框架供参考void ADS122U04_Init(void) { // 1. GPIO 配置: PA2TX(USART2), PA3RX(USART2) // 2. USART2: 115200, 8N1, 使能收发和 DMA // 3. 等待 ADC 上电稳定(延时至少 10ms) Delay_ms(50); // 4. 发送同步序列 ADS122U04_Sync(); // 5. 写寄存器: PGA1, 单次模式 uint8_t cmd[] {0x4D, 0x00, 0x00}; ADS122U04_Send(cmd, sizeof(cmd)); // 6. 读回校验(略) }数据接收采用查询加超时的方式可能更稳定。这有个坑要提醒一下如果 MCU 端用了 RTOS要注意在任务切换期间不能让 UART 空闲超过 10 个字符时间否则 ADC 可能因为长时间没有通信而进入低功耗待机下次唤醒需要重新同步。我在 FreeRTOS 任务里专门给通信加了一个互斥锁确保整个读过程原子化。4. 温度换算算法从 ADC 码值到真实温度4.1 ADC 原始值的电压换算读到的 24 位码值需要先换算成电压公式为V_in (ADC_Code / (2^23 - 1)) × V_REF / PGA举个例子热电偶通道配置 PGA64V_REF2.048V读回 ADC_Code 323955十进制那么 V_in 323955 / 8388607 × 2.048 / 64 ≈ 0.0612V即 61.2mV。K 型热电偶在这个热电势下对应的温度大约 760℃可以先粗算验证数据在合理范围内避免后面查找表时偏差太大。公式中每一处细节都可能被误导。比如2^23 - 1而不是2^23是因为 24 位补码最大正值是2^23 - 1满量程对应的就是这个值。如果直接把码值除以2^23在满量程附近会引入大约 0.00001% 的误差换算成温度约 0.00004℃虽然一般工况可忽略但在高精度校验时还是得用标准值。4.2 热电偶的冷端补偿与查表热电偶测量最大的陷阱是冷端补偿。假设直接将热电偶两根线绕到接插件那么热端和冷端都有温度ADC 测量到的是两者的热电势之差。ADS122U04 能测量自己芯片附近的温度也就是冷端温度 Tref可我们需要的是绝对温度 T_hot因此必须做如下补偿T_hot T_measured T_ref其中T_measured是根据 ADC 电压查热电偶分度表得到的表观温度T_ref是冷端温度。问题是T_ref不仅依赖芯片内部的温度传感器还依赖芯片引脚和实际冷端之间的热阻。实际操作时我会在设备外壳上接近热电偶接线端子处加一颗 TMP117 或 MCP9808 来直接测冷端温度然后把值写入软件补偿流程。这颗外部传感器的温度精度直接影响最终测量实测使用 TMP117 时温补误差降到 0.1℃ 以下。查表部分我选用多项式拟合法。查 IEC 60584 的标准 K 型热电偶分度表在 0~1000℃ 温区内用 9 次多项式拟合拟合误差可以做到 0.1℃ 以内。关键点是多项式的系数要选用反温反算版本。我在代码中直接内插一个查找表表的步长是 1℃用线性内插完成内存开销不大且精度可接受。4.3 RTD、NTC 的温度解算与线性化PT100 用比例法采集的话不需要独立的参考电压直接测 RTD 两端的电压 U_rtd 和参考电阻两端的电压 U_ref电阻值就是R_t R_ref × U_rtd / U_ref得到电阻后按 PT100 分度表查温度。0~100℃ 区间内常用二次多项式 R_t R0 × (1 A×T B×T²)其中 A3.9083×10⁻³B-5.775×10⁻⁷。用这个公式反解温度即可误差在 0.1℃ 量级。NTC 的非线性比 RTD 严重得多我用的是 Steinhart-Hart 方程1/T A B×ln(R) C×(ln(R))³三个系数 A、B、C 从 NTC 厂家数据手册拿到或者用三个已知温度点实测标定。对 100k NTC 在 0~50℃ 区间这个方程拟合误差通常小于 0.05℃。需要注意方程里 T 用的是开尔文温标输出要减去 273.15 换算成摄氏度。4.4 数字滤波策略一阶滑窗和中值滤波的取舍工业现场的噪声不会只靠硬件去扛软件滤波是最后一道防线。我试验过几种方案最推荐的组合是连续采样 16 次先做中值滤波去掉粗大误差再对中值滤波的输出做一阶滑动平均。中值滤波的窗口选 5滑动平均的长度选 4整体延迟约 1 秒左右这在 HVAC 机组控制中是完全可以接受的——温度本来就是慢变量。滑动平均的系数可以这样理解每次新值进来后当前值 alpha × 新值 (1 - alpha) × 旧值。alpha 取 0.2 时响应时间约 1.5 秒取 0.1 时约 3 秒。对于空调机组 DDC 控制alpha 取 0.2 既能滤掉冷水阀动作产生的阶跃干扰又不至于让 PID 调节器觉得“温度半天不变化”两者之间需要平衡。5. 实测数据与问题排查5.1 系统搭建与实测精度记录硬件的完整架构是传感器通过屏蔽双绞线接入 ADS122U04 的端子板ADC 输出 UART 信号经过 100Ω 电阻串联后接到 STM32F437ZG 的 USART2MCU 侧以 DMA 方式读取数据然后跑温度换算和滤波算法最终结果通过 RS485 上传到上位机组态软件。实验室用 Fluke 1523 标准温度计做比对对手头的 K 型热电偶通道在 30℃、100℃、200℃ 三个校验点做了记录标准温度ADC 电压未补偿温度冷端补偿后误差30.0℃1.203mV29.2℃30.1℃0.1℃100.0℃4.096mV99.4℃100.2℃0.2℃200.0℃8.138mV199.2℃200.1℃0.1℃整体误差稳定在 ±0.2℃ 以内满足项目要求的 ±0.5℃。PT100 通道通过四线制接法并联一个精密电阻做了比对误差在 0.05℃ 上下。NTC 通道因为本身精度只有 1%换算后误差约 0.3℃在 HVAC 场景下可以接受。5.2 通信失败和读数跳变怎么定位我调试过程中遇到过三个典型问题这里一并列出并说明我如何排查问题一UART 通信偶发失败。现象是 MCU 发命令后 ADC 长时间不响应或返回错误数据。排查后发现是 MCU 上电时 GPIO 默认状态和 UART 初始化之间存在毛刺ADC 误以为收到了部分指令状态机卡死。解决办法是 MCU 先保持 RX 线为高电平完成 GPIO 切换后再初始化 UART。此时主机主动发一帧同步指令即可恢复正常。问题二读数跳变几十个码值。用示波器观察 ADC 的 DOUT/DRDY 引脚严格说是 UART 的 TX 线发现信号并不干净有高频毛刺叠加在跳变沿上。搭配 PCB 检查最终锁定在给 ADC 供电的 3.3V 电源纹波上。电源纹波明明白白测出 70mV 的 60kHz 噪声来自旁边 DC-DC 模块。处理办法是在 DC-DC 输出端增加一级 LC 滤波器将纹波降到 10mV 以下读数立刻稳定。问题三热电偶开路时读数乱跳。如果传感器断线ADC 输入悬空此时测量值没有物理意义。我把 ADS122U04 的偏置电流源打开给输入引脚串一个 10μA 的偏置同时利用芯片的开路检测标志位寄存器 0x03 的 TCB 位判断故障一旦发现开路立即在协议层上传 0x7FFF 标记为故障状态上位机显示“传感器异常”而不是一个虚假的温度。5.3 校准技巧和量产指导批量生产时每块板子都存在 ADC 的失调和增益误差需要做校准。我的校准流程是把模拟输入端短接到模拟地采样 100 次取平均作为失调值然后输入一个标准 2.048V、1.024V 参考电压测出增益误差把这两个参数写入 Flash 保存。校准后用 0℃ 和 100℃ 两个温度点做线性度验证误差超标的产品即剔除。这里多说一句坚持在量产前做两温校准远比依赖芯片出厂参数更可靠。ADS122U04 内部虽然有自校准功能但它只能校准 ADC 本身的失调和增益无法校准前端传感器的误差。两条校准路径不能搞混。6. 一些个人经验和建议这个项目从立项到稳定运行花了大约六周如果让我重新做一遍我会在一开始就做三件更省事的事第一把 ADC 的配置寄存器做成一个结构体在代码中通过位域操作单个字段而不是整字节赋值。这样改增益或通道时只需要一条config.mux CH_PT100; ADS122U04_WriteConfig(config);就搞定本质上减少错误。第二前期就为每个通道建立独立的滤波缓冲区和滤波参数结构体而不是用一个全局数组混着存。不同传感器的时间常数差异很大——热电偶响应快NTC 响应慢PT100 介于两者之间——统一滤波参数会在多通道切换时出现诡异的温度滞后现象。第三尽早定义错误码规范。通信超时、开路检测、校准失败、溢出检查每类错误都有固定的错误码方便后续故障定位。我在项目后期深有体会排查一个偶发的 0x1F 错误码花了两天如果从一开始就文档化错误码定义这个时间能省一半。说到最后ADS122U04 带给我的最大感受是“省心”——UART 接口让布线简化不少内置的 PGA 和基准电压源让外围电路变得特别干净。但任何省心背后都需要对传感器类型、信号调理、通信时序、故障处理这四件事有足够清晰的理解否则出问题时反而容易模糊定位。希望这篇文字能帮你少踩几个我踩过的坑把项目更快地推进下去。