1. 一颗24位ADC和一块M4为什么凑在一起ADS122U04IPWR、TM4C129XKCZAD这两个型号凑在一起主角不是MCU而是ADS122U04IPWR这颗带UART接口的24位ΔΣADC。TM4C129XKCZAD负责调度、通信和干活ADS122U04负责把毫伏级、微伏级的温度信号变成靠谱的数字。温度和ADC的关系就像体重计和弹簧之间的关系。先把这个项目解决的痛点讲清楚。工业现场和HVAC暖通空调里的温度测量看起来是“测个温度”实际上是个精度与抗干扰的博弈。HVAC里测水管温度通常希望误差控制在±0.2℃以内工业现场如果测的是风机盘管、冷水机组或压缩机排气管传感器可能离控制器好几米导线电阻、工频干扰、自热效应全都来了。普通MCU内置12位ADC在这个场景下非常吃力分辨率不够、噪声偏大、输入范围不合适还不带可编程增益放大器和恒流源。ADS122U04IPWR这类专用ADC就是专门来解决这些问题的。ADS122U04IPWR和TM4C129XKCZAD的组合还有一个容易被忽视的价值通信协议是UART。相比SPIUART在长线传输和抗干扰上更皮实而且TM4C129XKCZAD本身就是带着以太网MACPHY的控制器在楼宇自控的场景里采集板可以直接把温度数据整理成BACnet或Modbus TCP报文上传到上位机。这就是整块板子的分工前端模拟链路交给24位ADC后端数据处理和网络通信交给Cortex-M4F。这套方案适合谁参考做工业数据采集、HVAC控制器、环境监测设备的工程师以及想把“传感器MCU”链路做扎实的嵌入式开发者。接下来我按实际开发顺序把硬件接线、寄存器配置、UART通信、温度换算和现场踩坑记录都过一遍。2. ADS122U04的寄存器与硬件接线细节2.1 硬件连接管脚怎么安排ADS122U04IPWR的封装是TSSOP-16通道少但每个通道干的事很明确。以最常见的PT100三线制RTD和K型热电偶两路输入为例我把管脚规划成下面这样管脚连接目标说明AVDD/DVDD3.3V或5VADS122U04支持2.3V到5.5VTM4C129XKCZAD是3.3V系统我直接统一用3.3V供电AIN0/AIN1PT100差分输入接RTD两端三线制时第三根线接AIN3作为激励电流返回AIN2/AIN3热电偶/备用通道K型热电偶接AIN2/AIN3AIN3同时可做IDAC返回脚REFP0/REFN0外部基准电阻两端RTD比率测量时外部基准电阻必须是高精度低温漂电阻/DRDYTM4C129 GPIO数据就绪下降沿中断用来触发UART读取UART_TX/RXTM4C129 UART接MCU的RX/TX注意交叉连接/CSGPIOUART帧同步锁存脚防止误帧这里有一个设计上容易被忽略的点REF。ADS122U04内置基准但RTD测量要拿到高精度最稳的方式是比率测量。外部基准电阻串在激励电流回路里PT100的电阻变化和基准电阻的电压变化用同一个电流源驱动电流源的波动就被抵消了。基准电阻我选了一个25ppm/℃的精密电阻阻值按激励电流大小而定目标是让REF电压落在1.8V到2.1V之间。这样做的好处是即便电流源有温度漂移ADC读到的比例值也是准的因为分子分母同时变化。供电和滤波方面AVDD和DVDD各放了一个10μF钽电容加0.1μF陶瓷电容模拟电源尽量远离板上的继电器和开关电源。TM4C129XKCZAD的数字地通过0Ω电阻和模拟地单点相连避免数字噪声串进模拟回路。这些细节在样板阶段可能看不出差别上到EMC测试就完全是两回事。2.2 配置寄存器的关键位ADS122U04的寄存器配置不多核心是四个寄存器Config0、Config1、Config2、Config3。我按测量需求走一遍Config0要处理的是PGA增益、输入多路复用器和输入缓冲。PT100在250μA激励下的满量程电压以0到100℃为例电阻从100Ω变到138.5Ω电压从25mV变到34.6mV。这信号太弱12位ADC肯定不行24位ADC也得加增益。我把PGA设为8倍34.6mV乘8等于277mV离2.048V的参考电压还有很大余量但已经足够把温度分辨率推到远小于0.1℃。对K型热电偶热电势更小0到100℃大约4mV我单独用PGA64档。输入缓冲我默认打开这样外部滤波电阻的阻值可以选大一些不用太担心ADC输入阻抗对信号的分流。Config1是数据速率和转换模式。工业现场最大的干扰源是50Hz工频ADS122U04的滤波器在20SPS采样速率下能对50Hz和60Hz同时提供抑制。这个一定要优先保证而不是一味追求采样速度。温度变化是慢变量20SPS对99%的HVAC和工业场景都够用。Config2里最关键是两个匹配电流源IDAC的配置。我把IDAC配置为250μA方向从AIN2输出流过PT100后从AIN3返回。注意不是从AIN0方向走而是把激励电流和测量通道分开规划。这样做的意义在于后续如果要多路扩展可以顺着同一路电流串接多个传感器做分布式测温。两个IDAC还可以配置成两个不同的电流值用于热电偶的冷端补偿检测不过我用的是内置温度传感器方案IDAC只用于RTD激励。Config3是内置温度传感器和高低温报警。热电偶冷端补偿需要知道接线端子附近的温度我把内置温度传感器使能打开转换结果会周期性输出芯片温度值。芯片温度不能完全代表端子温度但把传感器尽量靠近端子区摆放误差可以控制在可接受范围内。高低温报警我暂时没用阈值寄存器保持默认关闭状态。2.3 UART命令帧的注意事项ADS122U04的UART协议和普通传感器不太一样它本质上是一个命令-响应协议。帧的第一步是同步上电后MCU必须持续发送0xFF直到/DRDY出现下降沿表示ADC锁定了波特率。这个步骤如果省略后续所有命令都会石沉大海。我调试时遇到的第一块板子就是卡在这里波形上看TX有输出但ADC就是不回应。同步之后写寄存器、发起转换、读数据都按数据手册的帧格式进行。有一点必须强调ADS122U04的寄存器写入不是简单的UART发送一个字节而是要把命令前缀、寄存器地址、寄存器数据拼成完整的帧且/CS脚的电平变化要配合好。我把这层封装成了ADS122U04_WriteReg和ADS122U04_ReadData两个函数而不是直接在应用代码里裸发UART字节。原因很现实协议帧一旦出错排查成本非常高封装成独立模块后即使换芯片型号也方便改。读数据时24位结果是二进制补码格式也就是带符号数。从UART收到的三个字节必须先拼成32位整数再加符号扩展否则负温度会变成一个很大的正数。这个坑后面实测部分还会详细说。3. TM4C129XKCZAD端的通信工程实现3.1 TivaWare初始化TM4C129XKCZAD是120MHz的Cortex-M4FTivaWare驱动库开发效率很高。UART初始化这一块直接用TivaWare的标准接口。我选UART7因为它的引脚正好落在角落布线时离模拟前端最近。初始化代码大致是#include inc/hw_memmap.h #include inc/hw_types.h #include driverlib/sysctl.h #include driverlib/gpio.h #include driverlib/uart.h #include driverlib/pin_map.h void uart7_init(void) { SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); SysCtlPeripheralEnable(SYSCTL_PERIPH_UART7); GPIOPinConfigure(GPIO_PB0_U7RX); GPIOPinConfigure(GPIO_PB1_U7TX); GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1); UARTConfigSetExpClk(UART7_BASE, SysCtlClockGet(), 1000000, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE)); UARTEnable(UART7_BASE); }波特率我选了1Mbps。ADS122U04支持的最高UART波特率远高于这个1Mbps在1米左右的排线传输下非常稳定而且比低速率的帧周期短能更快把24位数据搬回来。UART中断使能后把接收FIFO设为8字节触发这样一帧数据3字节有时带命令前缀可以一次性进入中断服务函数。3.2 读取状态机与中断设计ADS122U04的读取过程是一个典型的生产者-消费者模型ADC是生产者TM4C129是消费者。我不建议在MCU主循环里轮询等数据那样会浪费CPU而且容易漏掉/DRDY的下降沿。正确做法是把/DRDY接到TM4C129的GPIO外部中断上。void DRDY_ISQ_Handler(void) { // 清中断标志 GPIOIntClear(GPIO_PORTC_BASE, GPIO_PIN_5); if (ads_state ADS_STATE_WAIT_DATA) { // 发起读取数据帧 UARTCharPut(UART7_BASE, 0x00); // 读数据命令 ads_state ADS_STATE_WAIT_RX; } }这里的状态机设计有一个点值得展开读数据命令发出后ADC返回的三字节结果什么时候到并不完全可控。我在初始化时关闭了FIFO中断产生条件改为在RX中断里判断是否收满3字节。收满后立刻拼接原始码并换算温度同时释放一个信号量给主控层。主循环里如果还有RTOS就POST到采集任务如果裸机就置一个标志位。整体流程不阻塞数据也不会积压。UART接收中断要处理两个错误场景一个是超时一个是帧错误。如果连续5ms没有收到后续字节状态机回滚到WAIT_DATA重新拉一次/DRDY读取。工业现场电磁干扰严重时UART帧偶尔会坏这种超时重试机制比死等要可靠得多。3.3 同步与错误恢复上电同步是ADC初始化里最不能省的一步。TM4C129这边我写了单独的函数int32_t ads122u04_sync(void) { uint32_t timeout 100000; while (timeout--) { UARTCharPut(UART7_BASE, 0xFF); if (GPIORead(GPIO_PORTC_BASE, GPIO_PIN_5) 0) { // 检测到DRDY下降沿同步成功 return 0; } } return -1; }同步失败后不要立刻继续跑先把UART外设软复位一次再重新同步。ADS122U04对UART信号线的毛刺很敏感如果同步时刚好碰到一个干扰脉冲就可能错误识别波特率。软复位重来比反复尝试发数据更省时间。还有一个小细节/CS脚在每次读帧之前要拉低再拉高。虽然在UART模式下它不像SPI的片选那样每一字节都必须操作但配合帧同步它能有效防止UART起始位被噪声误触发。实测下来不拉/CS也能跑但EMI测试时数据丢帧率明显上升加上以后就稳定了。4. 从ADC原始码到真实温度RTD与热电偶换算4.1 RTD比例测量与Callendar-Van Dusen方程拿到ADS122U04的24位原始码第一步不是急着查表而是先搞清楚它代表什么。比率测量模式下ADC输出的是测量电阻端电压与基准电阻端电压的比例。对于PT100三线制接法实际计算公式是R_rtd R_ref × (ADC_code / 0x7FFFFF)这里有个隐含前提ADC输出满量程对应±Vref而比率测量中Vref就是基准电阻的端电压。也就是说ADC数字直接等于R_rtd和R_ref的比例电流源的绝对电流值从公式里消掉了。这个设计是RTD测量精度的重要来源。电流源我配成250μA基准电阻我用8.2kΩ精密电阻端电压约2.05V靠近Vref上限。PT100在0℃时输出100ΩADC比例约100/82000.0122100℃时138.5Ω比例约0.0169。除以满量程后原始码在0x1F400到0x2A000左右。这区间覆盖得很好。得到R_rtd之后要换成温度。IEC 60751标准里的Callendar-Van Dusen方程是这样的0℃以上R(T) R0 × (1 A×T B×T²)0℃以下R(T) R0 × (1 A×T B×T² C×(T-100)×T³)其中A3.9083×10⁻³B-5.775×10⁻⁷C-4.183×10⁻¹²。这个方程的正问题是已知温度求电阻工程里我们通常是已知电阻求温度所以需要数值求解。常见的做法是用二分法在-200℃到850℃区间迭代或者直接做分段多项式拟合。我在TM4C129上没用标准库里的数学函数浮点开FPU之后反而简单。直接启用硬件浮点单元用二分法迭代10次就收敛到0.01℃。实测一个100.00Ω的基准电阻对应标准PT100 0℃换算结果在0.02℃以内完全满足HVAC控制需求。4.2 热电偶冷端补偿与查表K型热电偶和RTD完全不同它输出的是热电势而且是相对冷端的电势差。冷端在哪就是接线端子那里。所以热电偶测量的完整链路是用ADS122U04测量热电偶的热电势E_measured。读取内置温度传感器得到冷端温度T_cold。根据T_cold查K型热电偶分度表得到冷端对应的热电势E_cold。真实热端热电势E_hot E_measured E_cold。再查分度表由E_hot反查热端温度T_hot。这里最容易出错的是正负号。K型热电偶在0℃以上热端温度越高输出越大冷端补偿加的是E_cold不是减。我当时调试时犯过一次反符号的错200℃的管道测出来只有160℃排查半天才发现是符号问题。ADS122U04内置温度传感器的输出是芯片结温不是端子温度。要让这个数值尽量接近冷端实际温度布局上要把ADS122U04放在接线端子附近同时避免大功率器件贴近ADC。我后来在端子和芯片之间加了一条细的铜走线没有散热实测内置温度传感器读数和外部精密温度计差不到0.3℃对K型热电偶冷端补偿来说这已经足够。反查分度表我直接用NIST多项式。K型热电偶的0到1370℃范围用9阶多项式拟合误差可以做到0.05℃以内。查表程序先按10℃间隔二分查索引再用拉格朗日插值计算量很小。TM4C129跑到120MHz一轮完整换算下来不到20μs20SPS的刷新率毫无压力。4.3 校准和实测数据温度测量光靠芯片精度不够系统级校准是必须的。RTD链路我用一个0.01℃精度的恒温槽分别在0℃、25℃、50℃三个点做校准。设定温度ADC原始比例换算温度误差0.00℃0X1F3F80.03℃0.03℃25.00℃0X1F8C225.06℃0.06℃50.00℃0X1FCA049.94℃-0.06℃这个数据是在未做软件校准时得到的实际上已经满足绝大多数HVAC项目±0.2℃的精度要求。如果项目要求更高可以在三个点做最小二乘线性校正将误差压到±0.02℃以内。校准表的存储我放在TM4C129内部的Flash里用一段独立的结构体保存斜率K和截距B。每台设备出厂前跑一次单点校准把25℃的偏差写进去。这样批次间电阻和基准的误差也能纠正。需要注意的是校准值必须是flash中单独的扇区避免程序升级时被擦除。5. 我踩过的一些坑5.1 50Hz工频干扰导致跳数第一批样板拿回来后RTD读数在20SPS下还有±0.5℃的跳变。示波器看AIN0对地波形叠加了一个50Hz正弦波纹幅度大约20μV。原因是样板电源用的是220V转5V适配器适配器初级和次级之间的耦合电容把工频共模干扰耦合进了模拟地。解决方法是三层配置里把数据速率改成20SPS它的数字滤波器在50Hz处有极深的陷波模拟地到机壳之间加一个高压电容泄放共模电流最后在ADC输入端各串一个1kΩ电阻加100pF电容做低通。三步做完跳变降到±0.02℃。这里有个细节PGA开启时输入滤波电容不能太大否则放大器的相裕度变差会自激振荡。我最初用10310nF电容结果PGA输出电压明显抖动换成100pF后立即正常。模拟滤波和PGA稳定性要综合考虑。5.2 负温度换算出来是6553524位无符号拼装错误。ADS122U04输出的是二进制补码三位字节拼完后如果最高位是1表示这是一个负数。必须做符号扩展int32_t raw (buffer[0] 16) | (buffer[1] 8) | buffer[2]; if (raw 0x800000) { raw - 0x1000000; // 符号扩展 }这个坑很多人会踩。0℃以下的PT100电阻小于100ΩADC输出接近满量程负端不做符号扩展温度直接变成几万摄氏度。HSI逻辑上很好理解但写代码时很容易漏。5.3 UART失步MCU里UART如果只收不发波特率本身不需要太精确。但ADS122U04需要MCU发命令双向通信如果TM4C129的时钟配置有问题UART波特率误差超过2%同步就时好时坏。TM4C129XKCZAD上电后必须先调用SysCtlClockFreqSet确保系统时钟是精确的120MHz再配置UART。我试过用内部振荡器跑同步成功率只有一半换外部25MHz晶振后一百次同步全部成功。5.4 冷端温度迟迟不准热电偶通道测出来的温度比实际低而且开机后前几分钟漂移很大。后来发现是板子上电源芯片离ADS122U04太近芯片自热稳定需要时间。开机前30秒内置温度传感器读数从32℃一路涨到38℃然后稳定。冷端补偿值的漂移直接导致测得的管道温度偏低。解决方法是把ADS122U04挪到板子边缘电源芯片换到另一侧两者间隔超过15mm同时在两者之间铺了一条地隔离带。这么改完后开机3分钟温度读数就稳定了冷端补偿误差从0.8℃降到0.2℃。如果结构空间不允许也可以软件上做开机延时前30秒显示“预热中”等ADC自热稳定后再显示最终温度。6. HVAC与工业场景落地的差异点HVAC项目里的温差控制通常不追求绝对精度而追求一致性。比如同一个项目里装了几十块采集板每块板子测同一个恒温槽显示值如果相差0.5℃控制逻辑会很难受。所以批量生产时要做两点一是基准电阻选低漂移型号二是出厂校准流程统一。ADS122U04的增益误差本身很小但外部基准的分化是误差主要来源所以基准电阻的精度和温漂直接决定了产品一致性。工业场景则更关注可靠性和长线传输。传感器到采集板可能相距几十米RTD三线制能抵消大部分导线电阻但更长距离时要考虑线阻对电流源电压裕量的影响。250μA电流在50米0.5平方毫米铜线上的压降大约0.9Ω×0.25mA×2≈0.45mV折算成PT100温度误差约1.2℃。如果线很长就要改成四线制或者用PGA增益来补偿压降损耗。这个计算不能拍脑袋得按实际线长和线径来算。防雷和浪涌方面工业现场建议在传感器端子和ADC输入之间加TVS管和串联限流电阻。我在一版工业设计里加了一个8.2V的TVS用于雷击浪涌防护HVAC版本则省掉了成本差出来可靠性对于各自的场景也够用。TM4C129XKCZAD的以太网能力在这里是加分项。工业现场的数据采集板用Modbus TCP或者EtherNet/IPHVAC项目用BACnet/IP。TivaWare自带的以太网驱动库成熟MACPHY集成在芯片内部省掉了一颗PHY芯片BOM成本降了一些布线也简单。这个组合真正有意思的地方是模拟前端做到了工业级数字后端又具备联网能力一套硬件可以同时打两个场景。最后分享一个小经验ADS122U04的UART调试用逻辑分析仪比示波器好用十倍。UART空闲时是高电平一旦出现一个低电平毛刺示波器很难抓逻辑分析仪设好触发后能看到完整帧。我调试时把TX、RX、/DRDY三路信号同时接到逻辑分析仪上状态机里每一个状态跳变对应的是什么帧一目了然。工欲善其事必先利其器这套调试思路拿到其他UART传感器上也一样通用。
阅读完成 · 觉得有帮助?