ADS122U04与TM4C129的24位ADC温度采集系统硬件与固件设计
1. 项目概述与核心需求拆解
1.1 这个项目到底在解决什么问题
工业控制柜里的变频器一启动,PT100 采上来的温度就跳得跟心电图似的;HVAC 风柜里几十米的传感器线缆布过去,模拟信号衰减到没法看——这是做工业测温和楼宇自控现场最常见的两个噩梦。这个项目围绕的ADS122U04IPWR和TM4C129ENCPDT,本质上是在回答一个问题:能不能用一套既抗干扰、又不需要在传感器端塞一堆电路的方案,把 -40℃ 到 +150℃ 范围内的温度老老实实采回来,然后直接交给主控做闭环控制或者上报到上位机。
ADS122U04IPWR 是 TI 推出的一款带 UART 接口的 24 位 Δ-Σ ADC,它最特别的地方不是分辨率,而是把整个模拟前端——可编程增益放大器(PGA)、激励电流源(IDAC)、内部基准、冷端补偿、热电偶断路检测——全部集成进一颗芯片里,更难能可贵的是数据输出走的不是 SPI 而是 UART。对做 HVAC 和工业现场的人来说,这俩字意味着:传感器到主控之间的距离可以拉到几十米甚至上百米,线缆随便用普通双绞线就行,不用操心 SPI 时钟在长线上的完整性。
TM4C129ENCPDT 则是 TI 自家的 ARM Cortex-M4F 主控,带浮点单元,主频 120MHz,集成以太网 MAC+PHY,管脚还兼容常用的 TM4C1294 系列。选择它做主控,是因为项目里除了读 ADC,往往还要顺带处理多路数字量输入输出、RS485 通讯、以太网接入,甚至本地跑一个简易的控制算法。一颗芯片把这些活全包了,还要留足够的余量给后续扩展。
这个方案适合谁?如果你正在做:HVAC 楼宇自控的温度采集模块、工业设备的多通道温度巡检仪、冷链仓储的环境监测节点,或者想找一套比“运放+MCU 自带 ADC”更稳、比“PLC 专用模块”更灵活的低成本数据采集链路,这篇文章就是给你拆解完整设计细节用的。我会从器件选型背后的逻辑讲起,把硬件连接、UART 协议配置、固件实现、长线传输防坑这些点逐个过一遍。
1.2 两种器件在系统中各自扮演什么角色
可以这么理解这套架构:ADS122U04 是负责“感知”的耳朵,TM4C129 是负责“思考”的大脑。耳朵把传感器的微弱模拟信号——热电偶的毫伏级电压、RTD 随温度变化的毫欧级电阻——通过内部 PGA 放大、24 位 ADC 量化之后,变成一串数字流,用 UART 的帧格式吐出来。大脑则负责发号施令:让 ADC 切换到哪个通道、把增益调到多少倍、要不要打开 IDAC 恒流源、数据刷新速率设置成多少,然后把收到的原始码值换算成真实的温度值,再做滤波、线性化、协议打包,最终交给以太网或者 RS485 送出去。
两者之间只有一个 UART 连接,这在以前是难以想象的。传统的温度采集模块,ADC 和 MCU 之间要么走 SPI,要么走并口,SPI 在板内 PCB 走线上没毛病,但一旦传感器探头分散在几十米外的现场,SPI 的时钟信号早就被线缆寄生电容和串扰毁掉了。UART 的优势在于:它本质上是异步串行通信,靠的是起始位同步,收端以约定的波特率在特定时间窗口内采样,对传输线上的下降沿、上升沿畸变容忍度要高得多,而且只需要一对差分信号线或者单线+共地就能跑。ADS122U04 为了适应长线场景,甚至支持低至 0.192kbps 的波特率,速率越低,抗衰减能力越强,传输距离可以做到 1000 米级别的完全体。
这套组合的真正价值在于系统级解耦:模拟采集部分和数字控制部分可以分开布板、分开供电、分开调试。传感器板只要管信号调理和 ADC 转换,主控板只管数据处理与对外交互,中间靠 UART 对接,这非常契合工业模块化设计的思路。
2. 器件选型背后的考量逻辑
2.1 为什么偏偏是 ADS122U04 而不是 ADS122S04 或 ADS124S08
我见过不少工程师一看到 ADS122U04 就犯迷糊:TI 的 24 位 ADC 一大把,ADS122S04、ADS124S08、ADS1256 都有 SPI 接口,凭什么选一个带 UART 的冷门货?这里面的取舍值得好好掰扯。
先说 ADS122S04,它是 ADS1220 的升级版,四通道、低噪声、内部基准、IDAC 都有,出厂默认就是 SPI 接口。SPI 的好处是速率上限高(几百 kbps 到几十 Mbps),适合需要高速连续采样的场景。但问题也恰恰在这里:SPI 是主从同步通信,主控要主动拉低片选、主动送时钟,所有的时序敏感点都压在主控身上。传感器探头如果分散在柜内不同位置、布线穿过动力电缆沟槽,SPI 时钟线上的噪声耦合会直接导致采样错位,而且计算一次完整温度需要读 24 位数据加上状态字节,中间还穿插寄存器配置,代码稍不留神就会被主控其他中断打断,时序一乱,数据就错了。
ADS122U04 的 UART 接口在这方面是降维打击。它内部自动处理所有转换时序,外部主控只需要像操作串口设备一样发命令、收数据。转换结果以固定帧格式输出,带 CRC 校验位。主控哪怕正在处理以太网中断,晚个几十毫秒去读 UART 缓冲区也完全没有问题——这不叫实时性差,这叫解耦带来的鲁棒性。对于 HVAC 和工业温度采集这种本身就不要求微秒级响应、但要求数据稳定可靠的应用,这个特性比带宽重要得多。
再说 ADS124S08,它是八通道,用来做多路热电偶采集很经典。但它的封装和配置复杂度都上了一个台阶,对 PCB 面积和软件开发投入都不友好。本项目如果只是 4 通道以内,ADS122U04 的四通道单端/两通道差分配置已经足够,而且它还多了一个关键功能:传感器断路检测(Burnout Detection)。HVAC 现场最怕的就是探头线松了,系统还在瞎报警,ADS122U04 内置的上拉/下拉电流源能自动识别断线状态,结果里带一个明显标志位,这个功能在维护场景里实在太实用了。
2.2 TM4C129E 在这个项目里不可替代的三个优势
TM4C129ENCPDT 这颗芯片经常被拿来和 STM32F407 对比,同属 Cortex-M4F,带浮点,主频相当。但在工业温度采集网关这类项目里,它有三个压箱底的优势。
第一,就是它直接集成了以太网 MAC 和 PHY,而且是完整的 10/100M PHY,意味着不用外挂 LAN8710 这类物理层芯片。BOM 成本省下十几块钱倒是其次,关键是布线面积省出一大块,这对做多路温湿度采集网关这种需要堆接口的小板子来说非常解渴。TM4C129 的以太网功能本身很成熟,TI 提供的驱动库例子一跑就通,配合 lwIP 协议栈做 Modbus TCP 或者 MQTT 上报,代码量可控。
第二,它的 UART 模块数量多且配置灵活。TM4C129ENCPDT 有 8 个 UART 模块,且每个都带独立的 16 字节 FIFO。本项目用 UART0 和 ADS122U04 通信,UART1 留给 RS485 接上位机,UART2 可以接调试串口或备用传感器,互不干扰,FIFO 还能有效降低主控的响应压力。另一个细节是,TM4C129 的 UART 支持在 Sleep 模式下由接收数据唤醒,做低功耗巡检节点时,MCU 可以在两次采样之间睡大觉,ADC 一来数据就醒,功耗表现相当亮眼。
第三,它的 GPIO 基本全部支持外部中断,且大部分引脚耐 5V 输入。这意味着做 HVAC 控制器时,可以直接把无源干接点、24V 输入经过简单分压后的信号挂到 MCU 的 GPIO 上,不用额外一堆电平转换芯片。工业现场电气环境恶劣,偶尔来一根浪涌,TM4C129 的引脚鲁棒性在我实际项目中表现确实比很多同类芯片更能扛。
2.3 系统架构:从传感器到上位机的完整数据链路
我习惯先画一条完整的数据链路,再倒推每个环节怎么设计。这套系统的链路大概是这样的:
传感器探头 → ADS122U04 模拟输入引脚 → 内部 PGA/24 位 Δ-Σ ADC → 数字滤波 → UART 帧输出 → TM4C129 UART 接收中断 → 原始码值缓存 → 温度线性化换算 → 数字滤波平滑 → 协议打包(Modbus RTU / TCP / MQTT) → 上位机或云平台
这条链路上每一步都有坑。模拟前端要处理的是传感器本身的精度和噪声,PGA 增益和基准电压的配合决定了量化分辨率,UART 传输要考虑波特率与线缆长度的折中,MCU 侧要处理换算算法避免浮点运算拖慢主循环,协议层则要考虑断线报警、传感器故障怎么映射成寄存器状态。后面我会对每个环节逐个拆解。
3. 硬件设计要点与关键连接
3.1 ADS122U04 的引脚功能布局与最小系统搭建
ADS122U04 的封装是 TSSOP-16,引脚看着不多,但每个引脚的功能在系统里都不能含糊。我先把核心引脚归类说明,贴一下我实际项目里的最小连接方案。
电源相关:
- AVDD 接模拟 3.3V 电源,DVDD 也接 3.3V 但要注意两者之间加磁珠和去耦电容
- AVSS 和 DGND 分别接模拟地/数字地,在芯片下方用一个小焊盘做单点汇接
- CAP 引脚必须外接 4.7μF 电容作为内部 LDO 输出去耦,这个电容位置要尽可能靠近芯片,离远了 LDO 可能振荡
模拟输入:
- AIN0/AIN1 和 AIN2/AIN3 可以在单端/差分模式间灵活配置。实测中测 RTD 我会用差分模式接 AIN0/AIN1,热电偶冷端用内置温敏二极管参考通道,热敏电阻测环境温度则用单端模式
UART 接口:
- DOUT/DRDY(数据输出/数据就绪指示)接 TM4C129 的 UART0 RX
- DIN(数据输入,用于接收命令)接 UART0 TX
- 这两个信号线是单线双向各一条,共地传输
控制与状态:
- RESET 引脚做硬件复位,建议由 TM4C129 的一个 GPIO 控制,程序启动时先拉低再拉高确保 ADC 初始状态干净
- DRDY 除了在 DOUT/DRDY 复用引脚上做数据就绪指示,在 ADS122U04 上并没有独立的 DRDY 引脚,这块得注意——它的就绪状态是通过特殊命令读回来的,或者直接看 UART 输出帧是否有新数据,实现上我习惯用帧标志判断
最小系统搭建时有一个特别容易被忽略的点:AVDD 与 DVDD 必须同源。如果分开供电,上电顺序不一致或者纹波差异大,内部电平就会出现不确定状态。正确做法是统一从 3.3V 电源出来,先过磁珠再过 RC 滤波,分别进 AVDD 和 DVDD。
3.2 传感器接入方案:RTD、热电偶与热敏电阻的接线差异
这是整个硬件设计里对项目成败影响最大的部分。ADS122U04 支持三种最常见温度传感器,但每种传感器对输入通道的接法、IDAC 激励配置、基准电压选择都不一样,需要分别说清楚。
PT100/PT1000 RTD(三线制接法)
RTD 测量本质是测电阻,ADS122U04 内部有两个 IDAC 恒流源(IDAC1 和 IDAC2),可以配置成向传感器注入固定激励电流,然后测传感器两端的电压。三线制消除导线电阻误差的原理是:让 IDAC1 从 RTD 正端注入电流,在 RTD 负端接回 IDAC2 下拉到地,同时用同一个电流源驱动参考电阻 RREF。这样的话,参考电压 Vref = I × RREF 和传感电压 Vsig = I × R_RTD(只包含 RTD 本身的电阻,因为导线的压降在正端线上被电流源的另一个通道抵消掉了)。ADS122U04 内部有专门的参考电阻路径,接法非常讲究,我在实际接线中是这样处理的:
- AIN0 接 RTD 激励正端(同时接恒流源输出)
- AIN1 接 RTD 感应信号回线
- 参考电阻 RREF 用精密 1kΩ/0.1%/25ppm 薄膜电阻,一端接 IDAC1 的输出路径端,一端接 REFP0 和 REFN0 引脚
- 三线制的第三条补偿导线接到 RTD 的负极,和 AVSS 之间并联 0.1μF 电容
这里要特别注意:RREF 精度直接决定了最终测温的精度。IDAC 电流本身有温漂,但 ADC 的转换结果本来就是“信号电压与参考电压的比值”,如果 RREF 够准,IDAC 的温漂在很大程度上被抵消了。这就是所谓“比例式测量”的精髓,也是它比用普通 LDO 电压做基准的电路精度高一个数量级的原因。
热电偶(冷端补偿)
热电偶输出的是毫伏级电压,而且必须知道冷端温度才能算出热端温度。ADS122U04 内部内建了一个温敏二极管通道,用户可读取内部温度传感器的结果作为冷端补偿来源。热电偶正负极分别接 AIN0/AIN1 差分对,同时内部偏置电压用来检测断线。关键点是 PGA 增益要调到合适档位:K 型热电偶在 0-1000℃ 范围内输出约 0-41mV,我一般把 PGA 设为 32 倍,配合内部 2.048V 基准,等效分辨率大约在 0.02℃ 级别,完全够用。
热敏电阻(NTC)
NTC 比较简单,用单个 IDAC 电流源驱动 NTC 串联一个分压电阻。但 NTC 的温度-电阻曲线严重非线性,25℃ 时 10kΩ,到 80℃ 时可能只剩 1kΩ 出头。我的做法是用分压法:IDAC 电流流过 NTC 产生电压,ADC 测 NTC 两端电压和参考电阻两端电压的比值,然后用查表法配 Steinhart-Hart 公式做线性化。这个方案在 HVAC 风管温度、回风温度检测中用的是最多的,因为 NTC 便宜、线材要求低。
3.3 MCU 与 ADC 之间的 UART 物理层设计
ADS122U04 的 UART 是 3.3V 电平的单线双向各一条。如果主控板与传感器板之间的线缆超过 30cm,强烈建议在 MCU 侧或者传感器侧加电平转换缓冲器。我实测的经验是:
- 短距离(<30cm):直接 PCB 走线连接,3.3V 电平,走线尽量短且平行,串接 33Ω 阻尼电阻抑制振铃
- 中距离(0.3m-10m):用 SN74LVC1G17 施密特触发器缓冲输出,接收端同样加施密特缓冲整形
- 长距离(10m-100m+):改用 RS-485 收发器如 ISO3082,把 UART 转成差分信号传输,在 ADC 侧再加一组 RS-485 转回 UART。这本质上相当于把博主文章开头说到的 UART 长线优势发挥到极致,但代价是要增加两颗收发器
还有一点是 UART 共地问题。如果传感器板由独立的开关电源供电,电源地和主控板地之间有几百毫伏的电位差,UART 信号线上就会有共模干扰。最简单的解决办法是在传感器板的 DGND 与主控板 DGND 之间串一个 10Ω 电阻并联 0.1μF 电容,做成一个单点接地网络。如果现场有变频器等强谐波源,这个电阻能有效衰减地环路中的高频电流。
3.4 供电与 PCB 布局的工程经验
ADS122U04 对电源纹波的要求不算特别变态,但也要守规矩。我一般这样设计电源:
3.3V 主电源 → 磁珠(1kΩ@100MHz)→ AVDD 前再加 10Ω 串联电阻 + 10μF+0.1μF 对地电容。磁珠负责滤高频,RC 负责滤低频差模。如果系统里还有以太网 PHY 或者 RS485 收发器,它们的地和模拟地一定要严格分开。TM4C129 的以太网 PHY 是内部的,数字噪声天然会耦合到 PCB 地,所以 ADC 芯片的地要设计成星形拓扑,单独回到电源入口,不能在主控芯片附近直接扎堆打孔。
PCB 布局的黄金法则我在这个项目里总结了三条:
- ADS122U04 的 CAP 电容、去耦电容、参考电阻必须放同一面,最好控制在 3mm 以内,过孔来回穿会引入额外的寄生电感。
- 模拟输入走线严禁跨越数字信号线,尤其是 UART 数据线和以太网差分线。跨了 IC 的噪声是滤不干净的。
- UART 的 DIN/DOUT 两条线之间要挖地隔离,不用挖太大,1mm 宽度就够,防止 TX 的跳变干扰 RX 的接收窗口。
这三条任何一个做不到,结果就是高档位的 ADC 读出来的数据还不如 16 位的。很多人在 ADS122U04 上翻车,十有八九是布局问题而不是芯片问题。
4. 固件开发全过程:从寄存器配置到温度换算
4.1 配置 ADS122U04 的寄存器组
固件开发的起点是上电复位后对 ADS122U04 的寄存器做初始化,它的寄存器不像普通 SPI ADC 那样直接映射地址,而是通过 UART 命令字节进行读写。核心配置寄存器有 4 个,我把我实际工作中用的配置值列成表格:
| 寄存器 | 配置值 | 功能说明 |
|---|---|---|
| CONFIG0 | 0x04 | 开启内部温敏传感器,PGA 增益 8 倍 |
| CONFIG1 | 0x14 | 高精度模式(数据速率 20SPS),内部基准 2.048V |
| CONFIG2 | 0x00 | IDAC 电流 250μA,分配给 IDAC1/IDAC2 持续驱动 |
| CONFIG3 | 0x00 | 常规操作,关闭断路检测(需要时可配置上下拉电流) |
具体到本项目测 PT100 场景,我配置的是:CONFIG0 设为 0x04,开启温敏传感器,增益设为 8 倍。为什么是 8 倍而不是 32 倍?PT100 在常温附近的变化率约 0.385Ω/℃,250μA 激励电流下对应电压变化约 96μV/℃。8 倍增益下,ADC 在 2.048V 基准中做 24 位转换,理论上最小分辨率是 0.244μV,折合温度分辨率 0.003℃ 左右,而 32 倍增益虽然放大更猛,但噪声也会明显变大,线性范围反而受限。这里要把分辨率和有效精度区分开:标称分辨率再高,实际噪声底是个定值,过度放大只会让噪声占满低位。
寄存器配置通过 UART 发送对应的命令字节完成。每条命令由固定格式的地址字节 + 数据字节组成,命令发出后要等待 DRDY 信号返回或者至少等待 1ms 延时。如果配置后读到的状态字节看起来不对,首先怀疑的是波特率不匹配——ADS122U04 上电默认波特率是 115200,如果 MCU 端没有先切换到对应波特率,后面所有基于 9600bps 的命令都白搭。
注意:ADS122U04 的 UART 帧格式比较特殊。它不是传统的 8N1,而是8E1(8 数据位 + 偶校验 + 1 停止位),这个细节最容易踩坑。TM4C129 的 UART 完全支持 8E1,只需要在初始化时把奇偶校验位设置成偶校验(0x10 或 0x1A 取决于驱动设计)。如果沿用默认的 8N1,读出来的数据全是错位乱码,而且这种错误很难一眼看出,因为有时偶尔某几个字节能对上,误导排查方向。
4.2 TM4C129ENCPDT 的 UART 初始化与 DMA 搬运
TM4C129 的 UART 初始化在 TivaWare 驱动库下非常简单,但要把波特率精度做对,还是建议用 16MHz 的外部晶振而非内部 PIOSC。原因是内部时钟的精度只有 ±3%,可能直接导致 UART 通信在低温环境下出现位采样错误。
初始化代码如下(我实际项目中精简过的版本):
void UART0_Init(uint32_t baud) { SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); GPIOPinConfigure(GPIO_PA0_U0RX); GPIOPinConfigure(GPIO_PA1_U0TX); GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), baud, (UART_CONFIG_WLEN_8 | UART_CONFIG_PAR_EVEN | UART_CONFIG_STOP_ONE)); UARTFIFOEnable(UART0_BASE); UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT); IntEnable(INT_UART0); }这里我把偶校验位明确写出来,是因为 TivaWare 的默认配置宏经常只给 8N1 的示例,直接抄的话后面排查起来会浪费一天。FIFO 必须启用,UART0 的 16 字节 FIFO 能让 MCU 在收到一帧数据后不急着进中断,等接收超时(RT)中断触发时一次性把整包搬走,减少中断频率对主循环的影响。
对于高速率下的连续采样,我建议用 UART + DMA 的方式收到数据直接搬到内存,但 UART0 的 DMA 通道号是 UART0_TX/RX 对应的 DMA 通道,在 TM4C129E 上可以通过 uDMA 控制器配置。实际项目里如果数据速率只有 20SPS(每秒 20 次转换),每帧约 6 个字节,用普通中断就绰绰有余了,DMA 会让驱动代码复杂不少,不值得。
4.3 ADS122U04 的 UART 通信协议与读取时序
ADS122U04 的 UART 协议值得仔细讲,因为它和普通传感器的寄存器读写完全不同,更像是一个小型的命令-响应系统。协议分两类命令:配置命令(写寄存器)和操作命令(启动转换、读取数据),所有命令都由主控(TM4C129)发起,ADC 收到后执行并返回响应。
关键操作流程:
- 上电后 ADC 默认进入待命状态
- 主控发送
RDATA命令(0x01),告诉 ADC "把最近的转换结果发上来" - ADC 收到后回发一帧固定格式数据:前 3 字节是 24 位转换码值,第 4 字节是状态(包含转换是否完成、是否有断路等标志位)
- 如果是测量热电偶还需要读内部温敏传感器数据,再发一条读内部温度命令获取冷端值
实际固件里的核心循环是这样的伪代码:
uint8_t rdata_cmd = 0x01; UARTCharPut(UART0_BASE, rdata_cmd); uint8_t rx_buf[4]; for (int i = 0; i < 4; i++) { rx_buf[i] = UARTCharGet(UART0_BASE); } // 码值换算:rx_buf[0]是高字节,rx_buf[1]是中字节,rx_buf[2]是低字节 int32_t raw = (rx_buf[0] << 16) | (rx_buf[1] << 8) | rx_buf[2]; // 处理符号位有一点非常重要:ADC 每次 RDATA 都返回最近一次完成的转换结果,不会把新转换结果缓存到读完为止。因此如果你在上一次转换还未完成时发 RDATA,拿到的是上一次的旧数据。为保证数据不重复、不丢包,可以配置 CONTINUOUS 模式,让 ADC 不间断自主转换、像流水一样连续吐出数据帧。此时主控端启用 UART 的接收超时中断,每收到完整一帧就启动一次换算。这个模式最适合本项目——HVAC/工业控制系统中温度本来就是缓慢变化的连续量,保持 20SPS 的持续刷新,配合 MCU 侧的滑动平均滤波,最终拿到的温度稳定度可以做到 ±0.02℃ 以内。
4.4 温度换算算法:原始码值到摄氏度的数学推导
拿到 ADC 的 24 位码值后,关键是把它换算成真实物理温度。ADS122U04 是 24 位 Δ-Σ ADC,单极性模式下转换结果范围是 0x000000 到 0xFFFFFF,对应模拟输入从 0V 到 +VREF/PGA。换算公式如下:
Vin = (raw_code / 0xFFFFFF) × (VREF / PGA_gain) VREF = 2.048V PGA_gain = 8所以 PT100 两端的电压算出后,通过欧姆定律就得电阻值:
R_RTD = Vin / I_IDAC I_IDAC = 250μA(由寄存器配置决定)然后调用 RTD 线性化公式。PT100 的 Callendar-Van Dusen 公式是 IEC 60751 标准定义的,通用公式为:
R(t) = R0 × (1 + A×t + B×t² + C×(t-100)×t³) (0~850℃) R(t) = R0 × (1 + A×t + B×t²) (-200~0℃)标准系数 A=3.9083e-3,B=-5.775e-7,C=-4.183e-12(0℃ 以下)。实际工程里我不会在 MCU 上算三次方程,而是做一个 0.1℃ 步进的查找表,存电阻与温度的对应关系,程序里用二分查找加上线性插值。1024 个点的查找表也就占 4KB Flash,在 120MHz 的 Cortex-M4F 上查表加插值总运算时间不超过 10μs,和浮点三次方程动辄几百微秒相比,简直是花钱都买不来的加速。
如果是热电偶,换算思路是:先用 ADC 读热电势毫伏值,再加上冷端温度对应的热电势(通过冷端查表得到),然后查热电偶反向分度表得到热端温度。ADS122U04 内部温敏二极管通道输出的码值可以直接换算成芯片结温(也是热端附近 PCB 的温度),用它作为冷端补偿源,精度在 ±1℃ 左右。如果要求更严格,可以在冷端附近再贴一颗高精度 NTC 做补偿源,通过通道切换读取后换算进温度计算。
换算时的浮点中间量,我建议关掉 MCU 硬件 FPU 的默认带四舍五入模式,改用 RTOS 友好的vfp_round_mode,不然低优先级任务里连续大量浮点运算会出现上下文切换时的寄存器污染,这是 FreeRTOS + TM4C129 组合里一个比较隐蔽的 bug,新手容易忽略。
5. 常见问题与排查技巧实录
5.1 UART 通信失败的 5 个典型原因排查
这个项目里 70% 的问题集中在 UART 通信这一环。我把这几年帮人远程看问题的经验直接整理成速查表:
| 现象 | 大概率原因 | 验证与解决 |
|---|---|---|
| 读回全 0xFF 或全 0x00 | 偶校验被忽略,或者波特率不对 | 先用示波器看 ADC DOUT 引脚波形,检查帧格式是否符合 8E1;再用逻辑分析仪抓 UART 初始化后的实际波特率偏差 |
| 第一次读数据成功,之后全部乱码 | 读取时序过早,ADC 还在转换中就发 RDATA | 改为在 DRDY 有效后延时 10ms 再读;或修改为连续模式 |
| 数据偶尔丢一帧 | MCU 中断响应不及时,UART 接收 FIFO 溢出 | 检查 UART0 是否开启了 RT(接收超时)中断,把 FIFO 设置成 8 字节阈值触发 |
| 配置寄存器写不进去 | RESET 引脚没有正确拉高 | 检查 MCU GPIO 有没有初始化成输出模式,并输出高电平 |
| 长线传输后数据开始跳变 | 线缆绞合不好或者缺少终端匹配 | 用双绞线替代平行线;长于 50cm 时两个终端各加 120Ω 终端电阻 |
还有一个特别容易踩的坑是:TM4C129 的 UART 在初始化前 GPIO 默认可能是模拟模式,这在 TivaWare 里表现为GPIOPadConfigSet没设置,导致引脚内部上拉/下拉电阻状态不对。ADS122U04 的 DOUT 引脚在无数据时会保持在高阻态,主控端如果没有启用内部上拉,RX 引脚就会悬空,一有电磁干扰立刻刷新出一堆垃圾字节。正确做法是在 GPIO 初始化里显式启用内部上拉:
GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);5.2 温度读数漂移与噪声的解决实录
一个好的 24 位 ADC 方案,静态读数应在 ±0.01℃ 内稳定。如果你看到读数像随机游走一样漂移,按以下优先级排查:
一是检查基准电压。ADS122U04 用内部基准时,基准源与 AVDD 是共路的,如果 AVDD 上偶发电源毛刺,基准也会跟着抖。表现为读数呈周期性波动,周期和 PWM 控制信号或继电器切换同步。解决方法是给 AVDD 加 RC 低通截止频率设置在 10Hz 以下,或者干脆改用外部基准电压源。
二是检查 PGA 增益设置。在 8 倍增益下,RTD 的毫伏级信号已经被放大到几十毫伏,此时 PCB 上的任何跨信号走线耦合都会变成有效读数偏差。我遇到过把加热丝 PWM 控制线在 ADC 输入走线旁边平行跑了 5cm,结果读数的波动幅度直接翻倍。物理上拉开距离或者加地屏蔽是唯一解法。
三是数字滤波器。ADS122U04 内部自带数字滤波器,默认配置下等效 50Hz/60Hz 工频抑制。但如果现场有变频器,工频抑制就不够了,会有较宽的开关频率噪声落在通带内。此时需要牺牲一点数据速率,把采样率从 20SPS 降到 5SPS——ADC 内部滤波器的陷波频率也随之降低,对变频器噪声的衰减能力会明显增强。代价是温度响应的延迟变大,对于 HVAC 这种大热惯性对象完全无感,但真的有人在高速滚动的生产线上用这套方案,只能说选型时要想清楚。
5.3 多通道扩展时通道间串扰的调试技巧
如果 4 个通道都接了传感器,通道切换时 ADC 内部输入多路复用器切换后有一个短暂的建立时间。典型错误是代码里刚发完换通道命令就立刻发 RDATA,结果读到的是上一个通道残留的电荷。ADS122U04 的转换时序里专门有这个建立期的参数,虽然没有像某些 ADC 明确给出,经验值是发完配置命令后至少等 2 个 ADC 时钟周期再读数据。如果这样做了还是有串扰,可以在配置寄存器的输入多路复用器切换选项中增加一次内部短路校准,原理是把输入短路到共模电压后先测抵消值,再从后续读数里减掉。这个方法对通道间几十 μV 级别的串扰非常有效,代价是多花 20ms 的校准时间。
5.4 HVAC 现场常见的传感器断路与短路报警部署
ADS122U04 有一个很实用的断路检测功能,通过 CONFIG3 寄存器配置上下拉电流源,当传感器断路时对应模拟输入引脚被拉到 VREF 或 GND,转换结果会明显超过正常范围。我一般设置一个报警阈值:如果在连续采样 5 帧里码值 > 0xFFFFF0 或 < 0x0000F0,判断为断路或短路,然后把对应通道的寄存器标志置位,通过 Modbus 寄存器上报给上位机。注意:断路检测电流源在正常测量时是关闭的(配置为 0x00),否则它会把 RTD 的分压点抬高几毫伏,直接引入系统性偏差。所以我的策略是:平时测量用正常采样,轮询完所有通道后,在切到下一轮之前先执行一次断路检测命令,再恢复正常的 RTD 测量配置。轮询周期里每次只浪费 5ms,但整个系统的自诊断能力就补上了,后续运维成本降一大截。
6. 基于这套硬件的 HVAC 完整应用示例
6.1 HVAC 温度采集节点功能拆解
我拿一个典型空调风柜的温控模块来落地这套方案:需要采集 4 路 PT1000(回风温度、送风温度、盘管出水温度、盘管进水温度),外加 1 路 NTC 做风管环境温度参考。控制逻辑是:回风温度作为主控目标,盘管水温和送风温度作为辅助判据,实时调节水阀开度和风机频率,同时把 5 路温度值通过 Modbus TCP 送给楼宇自控系统。
ADS122U04 的 4 路模拟输入刚好全派上用场:AIN0/AIN1 差分接回风 PT1000,AIN2/AIN3 分时接另外三路传感器。ADC 固定工作在连续转换模式,每完成一个通道的转换就通过 UART 吐一帧,MCU 侧用 UART 接收中断把数据分类归档,主循环中跑一个 10Hz 的 PID 控制器,输出量通过 PWM 引脚控制水阀执行器。
这套方案对比传统的“模拟变送器 + AI 模块”的直接优势是:省掉了每个传感器探头后面的温度变送器,一个模块处理一路或几路模拟量;同时所有传感器的故障诊断(断线、短路)都集中到固件里处理,不需要 DI 模块额外检测报警干接点。BOM 成本大概能省 30%,调试工作量省一半。
6.2 冷端补偿误差对整体精度的影响与修正
HVAC 场景里热电偶不常用,但工业项目里很常见。ADS122U04 内部温敏二极管的精度规格是 ±2℃,用在冷端补偿上算下来会给最终测温带来约 ±2℃ 的误差,这显然不够。
我的修正方案是在 ADC 芯片附近再加一颗 0.1% 精度的 NTC(10kΩ),通过 AIN2 单端通道读取,用 Steinhart-Hart 方程算出更准确的冷端温度,然后作为热电偶补偿的输入。实测下来冷端补偿误差可以控制在 ±0.3℃ 以内,比芯片内部温敏二极管补偿提升一个数量级。代价仅仅是多占用一个输入通道和几十行代码,这笔买卖相当划算。
另一条更省事的路线,是利用 TM4C129 的休眠模式。ADC 连续采样时 MCU 大部分时间让 UART 中断唤醒,核心只需在每次数据到达时跑 20 行换算代码,剩余的 90% 时间进入 STANDBY 模式。120MHz 的主频对付这种负载绰绰有余,整板功耗大约 200mW,在 HVAC 机柜里根本不算负担,但如果做的是电池供电的无线测温节点,这套低功耗逻辑就得认真部署了。
6.3 Modbus RTU 主从通信的上位机对接代码思路
TM4C129 的 UART1 接一个 SP3485 转 RS485 差分信号,以 Modbus RTU 从站模式与上位机通信。我在项目里只用 3 个功能码:03(读保持寄存器)、06(写单个寄存器)、16(写多个寄存器)。寄存器地址规划如下:
| 寄存器地址 | 内容 | 数据类型 |
|---|---|---|
| 40001 | 回风温度(单位 0.01℃) | INT16 |
| 40002 | 送风温度(单位 0.01℃) | INT16 |
| 40003 | 盘管出/进水温度 | INT16 |
| 40004 | NTC 管道环境温度 | INT16 |
| 40005 | 报警状态位 | UINT16 |
Modbus 从站协议栈如果用 TI 的例程改写,核心是维护一个保持寄存器数组,然后把 UART 接收中断里的 Modbus 帧解析出来,对应地址执行读写函数。特别注意:Modbus RTU 是 3.5 字符时间间隔判定一帧结束,TM4C129 的 RT 中断正好可以用来实现这个超时判定,一个硬件中断解决帧同步问题,代码非常干净。
6.4 以太网数据上报与本地控制的协同策略
TM4C129ENCPDT 内置的以太网控制器跑 lwIP 协议栈,我把数据上报做成两种通道并行:周期上报模式(每 5 秒把 5 路温度值组成 MQTT 报文发到本地 EMQX broker),以及触发上报模式(任何一路温度超过阈值瞬间立刻上报)。本地控制不走以太网,直接由 MCU 内部 PID 完成,避免网络抖动影响控制品质。
这里有个实践心得:数据采集、控制算法、网络协议栈三件事不能全挤在同一个中断优先级。我习惯把 UART0(接 ADC)中断设为优先级 1(最高),PID 定时器中断设为优先级 2,以太网接收中断设为优先级 3。这样即使网络突然拥堵,ADC 数据读取和温控计算也不受影响。lwIP 的 TCP/IP 处理放在主循环的lwip_periodic任务里跑,配合 TM4C129 的EthernetTimerIntHandler触发调度,实测网络负载重时也不会拖慢 10Hz 的 PID 循环。
7. 实操中积累的几条关键心得
这套方案从我第一次画原理图到现在,硬件改版了三次,固件迭代了十几版。最深刻的体会是:稳定压倒一切。ADS122U04 是一颗能力非常强、但需要耐心伺候的芯片,它的 UART 协议看着简单,实际调通后你会发现这个设计非常成熟——所有配置状态都能读回校验,所有数据帧都有 CRC 保护,甚至命令帧和数据帧互相干扰的问题都被芯片内部的时序控制处理掉了。对比传统 SPI ADC 的裸寄存器操作,这套方案在可维护性和稳定性上完全值回票价。
第二点心得是关于参考电阻的选型。量级上,PT100 用 1kΩ/0.1% 即可,PT1000 则建议用 4.7kΩ/0.05%,因为 PT1000 在常温下阻抗更大,同等的导线电阻误差占比更小,对 RREF 的精度要求可以适当放松到 0.1%。但温漂指标一定要盯着,25ppm 是底线,只用 50ppm 的话,环境温度变化 10℃,测温就偏 0.1℃ 以上,这在 HVAC 的舒适度控制项目里完全不可接受。
第三点心得与 MCU 选型有关。TM4C129E 在 TivaWare 驱动库的支持下开发效率确实高,尤其是 UART 配置、以太网 lwIP 移植这些常见操作,TI 官方例程基本是拿来改改就能跑。但要注意的是,TM4C129 的 Flash 是 256KB,跑个完整 lwIP + Modbus 从站 + PID 控制 + 温度采集驱动,代码烧到 180KB 都不止,做产品前一定要规划好 Flash 的分区。如果未来还想加 OTA 升级,分区表就得提前设计,不然等固件写完再回头改 Flash 布局是灾难级的返工。