☰
24位ΔΣ ADC与PIC18单片机UART通信的温度采集系统实战
2026/11/5 1:07:18 网站建设 项目流程

做工业温度测量这些年,最让我头疼的往往不是传感器选型,而是“ADC和单片机之间的通信,以及最后的稳定性”。去年用ADS122U04IPWR搭配PIC18LF46K22做了一套能同时接热电偶、RTD和热敏电阻的温度采集板,实测下来在HVAC和工业现场都跑得很稳。这套方案的核心一句话就能说清:24位ΔΣ ADC负责把微伏级别的传感器信号变成数字,PIC18LF46K22负责跑逻辑和通信,两者之间用UART而不是SPI——就凭最后一点,帮我省掉了不少现场调试的麻烦。

这篇文章我想把整个项目的来龙去脉讲透:为什么选这两个芯片,传感器前端怎么搭,固件怎么写,以及我在现场踩过哪些坑。不管你是准备抄作业,还是想改造自己手里的老温度采集电路,应该都能从中找到有用的东西。文章偏实战,原理部分我会用通俗的方式解释,不搞教科书那一套。

1. 为什么选这套组合:方案背后的技术考量

1.1 24位ΔΣ ADC对温度测量意味着什么

温度传感器输出的电信号非常微弱,这是选型时首先要认清的事实。K型热电偶的热电动势大约只有40μV/℃,J型热电偶更小,约50μV/℃左右,而PT100在0℃附近的变化率大约0.385Ω/℃。如果用普通12位ADC去采集,参考电压按2.048V算,一个LSB约0.5mV,折算成温度就是十几摄氏度——这完全不可用。所以温度测量领域,24位ΔΣ ADC几乎是标配。

ADS122U04IPWR就是TI的一款24位低功耗ΔΣ ADC,TSSOP-16封装,工业级温度范围,内部集成了可编程增益放大器PGA、两个激励电流源、内部基准以及一个用于冷端补偿的温度传感器。PGA可以配置1到128倍增益,这一点很关键。热电偶信号只有几毫伏,经过128倍放大后,能使ADC的量化噪声远小于信号本身,配合24位的分辨率,才能把温度分辨率做到0.01℃甚至更好。

需要提醒的是,分辨率高不等于精度高。24位ADC能给的是“能分辨多小的电压变化”,而精度取决于传感器本身的误差、基准电压的温漂、PCB漏电流、校准是否到位。打个比方,24位ADC像一把刻度很细的尺子,但如果尺子本身热胀冷缩,刻度再细也量不准。所以后面校准环节我会专门展开讲。

1.2 UART接口在工业现场的长处

主流ADC的通信接口通常是SPI或I2C,ADS122U04却选择了UART。当初我拿到这颗芯片时也犹豫过,但真正在现场用起来才发现,这个设计对工业场景太友好了。

SPI是同步时钟通信,MCU要拉CS、给SCLK、走MISO和MOSI四根线。板内通信没问题,可一旦传感器通过线缆拉到几米甚至几十米外,SPI的时钟沿和数据线之间的时序对齐就很容易出问题,线缆的寄生电容和串扰会让通信变得不可靠。而UART是异步串行,没有时钟线,只需要TX和RX两根线,甚至在某些半双工模式下可以只用一根线。配合RS485驱动芯片,一对双绞线就能把距离拉到几百米。

在HVAC项目里,这个优势特别明显。楼宇控制柜里空间狭小,接线端子能少一根是一根。UART两个引脚就能搞定与ADC的通信,剩下的事情全部交给一颗MCU去处理。而且PIC18LF46K22内置EUSART硬件模块,发命令、收数据都不需要CPU死等,代码写起来跟普通串口打印一个感受。

1.3 PIC18LF46K22的角色与优势

PIC18LF46K22是Microchip的8位低电压单片机,工作电压可以低到1.8V,我直接给它供3.3V,和ADS122U04IPWR的电平无缝衔接。64KB Flash、将近4KB RAM,对温度采集来说绰绰有余,能跑传感器线性化、数字滤波,还能留出空间做通信协议栈。

我选择它的另外一个原因是它有两个EUSART串口。一个接ADC读取数据,另一个接RS485或RS232向上位机上报结果,两个串口互不干扰。做分布式温度采集节点时,这个特性特别香。MCU内部还有Data EEPROM,用来存校准系数、设备地址、通信参数,比我以前用外部Flash的方案省了不少器件。

很多人觉得8位MCU性能弱,但在这种温度采集场景里,数据速率低、算法简单,8位完全够用,反而低功耗、低成本、抗干扰能力强的优势被放大了。PIC18的IO驱动能力也足够直接驱动状态LED和数字隔离器,不需要额外的缓冲芯片。

2. 硬件架构与传感器前端设计

2.1 系统整体框图与电源分配

整个系统的硬件结构并不复杂,但是每一部分都有讲究。MCU通过UART_TX和UART_RX两根线与ADS122U04IPWR相连,ADC的模拟输入AIN0~AIN3接各路传感器,激励电流源IDAC1和IDAC2用于驱动RTD,电源部分给MCU和ADC提供3.3V。

电源分配是第一个坑点。ADS122U04的模拟部分对电源纹波非常敏感,特别是在PGA高增益模式下,电源上几十毫伏的纹波会直接进入测量结果。我实测过,如果直接用普通的LM2596开关电源给ADC供电,热电偶通道的读数会周期性波动。后来我把供电分成两级:前级用开关电源降到5V,后级用低压差线性稳压器(LDO)降到3.3V,再在LDO输出端加10μF钽电容和100nF陶瓷电容并联去耦,才把纹波压下去。

MCU的数字部分和ADC的模拟部分虽然共用同一个3.3V,但PCB上要分开走线,最后在LDO输出端一点汇合。ADS122U04的电源引脚附近,我习惯放一个100nF的陶瓷电容,紧贴引脚放置,走线尽量短。如果板上同时有继电器或接触器,电源入口一定要加TVS管,否则继电器吸合的瞬间反电动势很容易把ADC打死。

2.2 热电偶、RTD、热敏电阻三路前端

这套板子我设计了三个常用的输入类别,对应工业现场最常见的三种传感器:

热电偶输入最需要注意共模偏置问题。热电偶是一个浮地电压源,如果输入端没有偏置路径,共模电压会漂移到ADC输入范围之外。我的做法是在热电偶的负极和AVDD之间接一个10MΩ的大电阻,给共模电压一个参考点,同时不影响差分测量。信号进入ADC之前,我还加了一级RC低通滤波器,1kΩ电阻加100nF电容,截止频率约1.6kHz,主要用来滤除空间耦合进来的射频干扰。

RTD输入我用了比例测量法。ADS122U04内部有两个激励电流源,配置一个IDAC输出500μA电流,先流过PT100,再流过一只精密参考电阻RREF(我选了2500Ω,1%低温漂)。电流在RREF上产生1.25V的电压,这个电压同时作为ADC的参考电压。这样,ADC测量的结果直接就是RTD电阻与RREF的比值,与激励电流的绝对值无关——电流源本身有温漂也没关系,这是比例测量的精髓。

热敏电阻输入我用的是标准分压法。一只10kΩ NTC热敏电阻和一个10kΩ精密电阻串联,从分压点接入ADC输入。关键点是分压的电源必须和ADC基准同源,否则电源抖动会直接变成测量误差。我直接把分压电路的顶端接到ADC的内部基准输出,这样分压比例和ADC量化用的基准完全一致,电源波动被抵消掉。

2.3 引脚分配与PCB布局避坑要点

引脚分配我在第一版布线时吃了点亏,后来重新整理过。我的建议是ADC的模拟输入引脚布局尽量紧凑,AIN0和AIN1作为一组差分输入,AIN2和AIN3作为另一组,中间不要穿插数字信号线。UART的TX和RX远离模拟输入引脚至少3mm以上,不得已要交叉时,尽量垂直走线而不是平行走。

PIC18LF46K22这边,我用了RC7/RC6作为UART1的TX/RX,接ADC;RC3/RC2作为UART2的TX/RX,接RS485。两个UART都用了中断方式处理,MCU主循环只做数据换算和状态管理。

PCB布局有一个特别容易被忽视的点:传感器接线端子附近的地线。

工业现场传感器线缆经常从很远的设备端拉过来,如果PCB上的模拟地与数字地没有规划好,共模噪声会通过地线耦合进ADC输入。我的经验是模拟地AGND和数字地DGND在PCB上不要大面积分割,而是保持完整地平面,只在ADC芯片下方用0Ω电阻或磁珠单点连接。大面积分割反而会切断回流路径,形成更大的环路,这是很多人布线时容易犯的方向性错误。

3. 固件实现:从寄存器配置到温度换算

3.1 PIC18LF EUSART初始化与波特率校验

PIC18LF46K22内部虽然有时钟源,但做UART通信我不建议直接用内部RC振荡器。内部RC即使在出厂校准后也可能有1%到2%的频率误差,而ADS122U04的UART帧格式对波特率误差通常要求在2%以内,一旦超了就会出现偶发乱码、命令不响应这类恶心问题。所以我直接用了外部16MHz晶振,配两个22pF负载电容。

波特率我选的是9600bps。ADS122U04不是高速器件,温度数据本身更新速率也就每秒几十次,9600bps完全够用,而且波特率低一点,现场抗干扰能力更强。PIC18LF的UART波特率寄存器计算公式是:当BRG16置1且BRGH置1时,SPBRG = Fosc / (16 × Baud) - 1。16MHz下,9600bps的SPBRG值算出来是104.17,四舍五入取104,实际波特率误差约0.16%,完全在允许范围内。

初始化代码我习惯写成这样,实测没有出过问题:

void uart1_init(void) { TRISCbits.TRISC7 = 1; // RX输入 TRISCbits.TRISC6 = 0; // TX输出 TXSTA1 = 0x24; // 8位模式,TX使能,BRGH=1 RCSTA1 = 0x90; // 串口使能,接收使能 BAUDCON1 = 0x08; // BRG16=1 SPBRGH1 = 0x00; SPBRG1 = 104; // 16MHz, 9600bps RCONbits.IPEN = 0; // 关优先级中断 PIE1bits.RC1IE = 1; // 接收中断使能 INTCONbits.PEIE = 1; INTCONbits.GIE = 1; }

发送一字节就用最普通的阻塞方式,因为命令发送频率很低,没必要在这个环节纠结效率。接收用中断方式,把收到的字节放进环形缓冲区,主循环里再解析,这样不会丢数据。

3.2 ADS122U04寄存器配置与启动流程

ADS122U04的配置核心就是写配置寄存器,这一点和大多数TI ADC类似。上电后的推荐流程是:先让MCU的UART稳定至少100ms,然后发复位命令或拉低复位引脚,等待芯片内部上电稳定,再写寄存器,最后启动转换。

配置寄存器的内容主要决定四件事:输入多路选择、PGA增益、数据速率、激励电流源设置。以热电偶测量为例,我的配置思路是这样的:输入通道选择AIN0和AIN1差分输入,PGA增益设为128,数据速率设为20SPS,内部基准使能。20SPS看起来不高,但ΔΣ ADC在低数据速率下对50Hz和60Hz工频干扰的抑制能力最强,这是故意选低速率的理由。

写寄存器时序上有一个容易犯的错:写完配置之后不能立刻去读数据。ADC需要时间完成内部校准和第一次转换,我实测至少要等300ms以上,否则读回来的数据是随机值。稳妥的做法是连续丢弃前三次读取结果,从第四次开始才当作有效数据。

命令收发我封装成了三个函数,核心逻辑是这样:

void adc_write_reg(uint8_t addr, uint8_t count, uint8_t *data) { uart1_send_byte(0x40 | (addr << 2)); // WREG命令 uart1_send_byte(count - 1); // 寄存器数量-1 for (uint8_t i = 0; i < count; i++) { uart1_send_byte(data[i]); } } int32_t adc_read_data(void) { uint8_t buf[3]; uart1_send_byte(0x20); // RDATA命令 for (uint8_t i = 0; i < 3; i++) { buf[i] = uart1_receive_byte(); } int32_t code = (buf[0] << 16) | (buf[1] << 8) | buf[2]; if (code & 0x800000) { code |= 0xFF000000; // 24位有符号扩展 } return code; }

命令字节的具体值以你手上的ADS122U04数据手册为准,不同批次固件库可能略有差异,但流程都是这个流程。注意返回的24位数据是有符号数,不做符号扩展的话,负温度会被解释成一个很大的正数。

3.3 温度计算的三种典型算法

拿到ADC码值后,计算温度的算法是这套系统里“最不该偷懒”的部分。三种传感器我用了三种不同的换算逻辑。

热电偶的计算核心是冷端补偿。ADC测到的毫伏电压是热端和冷端的温差电势,要得到真实温度,必须先知道冷端温度。我的做法是使用ADS122U04内置温度传感器测量PCB板温度作为冷端温度,然后查K型热电偶的分度表,把冷端温度对应的毫伏值加到ADC测量值上,再反查分度表得到热端温度。查表方式用线性插值就够了,表格可以预先生成好存在Flash里,程序里只跑插值算法。

RTD的计算用比例法。我采集两个通道数据:一个通道测PT100上的电压,另一个通道测2500Ω参考电阻上的电压。两个通道共用一个激励电流,因此电阻比值就等于电压比值:

R_rtd = (code_rtd / code_ref) × 2500

得到RTD阻值后,如果测量范围在0℃以上,我直接用Callendar-Van Dusen方程反解,精度足够工业使用:

T = (-A + sqrt(A² - 4·B·(1 - R/100))) / (2·B)

其中A=3.9083e-3,B=-5.775e-7。这个公式在0到850℃范围内误差小于0.1℃。负温段需要引入三次项修正,我一般直接查表处理,省去复杂公式。

NTC热敏电阻用B值公式比较方便,但只适合精度要求不高的场合。10kΩ NTC配3435的B值,公式是:

1/T = 1/298.15 + (1/3435) × ln(R / 10000)

注意这里的T是开尔文温度,算完要减273.15。如果要求更高的精度,用Steinhart-Hart方程,三个系数需要厂商提供或自己在恒温槽里标定。

4. 校准方法与工业现场精度验证

4.1 为什么24位分辨率不等于高精度

我在前面已经提了一句,这里要展开讲,因为这是整个项目最容易让人误解的地方。24位ADC的分辨率意味着它能分辨极微小的电压变化,但这不代表着测量的绝对温度值就准确。ADC自身的增益误差、基准电压的温漂、PGA的偏置电压、传感器的个体离散性,都会让最终温度偏离真实值。

举一个实际例子:我最初用K型热电偶通道测室温,ADC读数换算成毫伏后明显偏高了0.12mV,折算成温度差不多3℃。这个偏差来自PGA的输入偏置电压及布线产生的微小热电势差。0.12mV的失调对24位ADC来说算很大了,如果不校准,直接输出的温度值没有任何实用价值。校准不是可选项,而是必选项。

校准的思路也很直白:记录传感器在不同标准温度下的ADC码与理论码之间的偏差,用线性方程去修正。工业现场最常用的就是两点校准,一条直线的偏移和斜率两个参数就够用了。

4.2 两点校准实操步骤

我在校准热电偶通道时,用干体炉提供0℃和100℃两个标准温度点。先把热电偶探头放进干体炉,等到温度稳定后读取ADC码,计算偏差。然后改到100℃再读一次,得到另一个偏差点。两点确定一条直线,校准公式就是:

修正值 = 斜率 × ADC码 + 偏移

这两个参数算出后存入PIC18LF46K22内部的Data EEPROM,以后每次上电时读出来,在温度换算之前先套用修正逻辑。

RTD通道校准更讲究一点。因为比例测量的关系,RTD通道的增益误差主要来自参考电阻的精度和ADC通道间的失配。我用精密电阻箱替代PT100,分别设置500Ω和1000Ω两个标准值,读取码值后同样做两点校准。参考电阻的温漂在冰点附近的影响也要留意,我选的是25ppm低温漂的金属膜电阻。

校准之后还有一步验证,很多人会跳过去:把传感器放回室温环境,持续记录8小时,观察最大漂移量。工业现场白天和夜间的温度变化,会让未充分老化的电路板产生微伏级的热电势漂移,8小时稳定性测试能帮你提前发现这类问题。

4.3 HVAC和工业场景的精度预期

校准完成后,不同应用场景对精度的要求差别很大,理解这点有助于你合理设置校准投入。

HVAC场景里,风管温度传感器通常用NTC,控制精度要求并不苛刻,±1℃完全够用,因为暖通空调本来就是大滞后系统,温度波动一两度对舒适度影响不大。冷冻水系统的PT100温度测量,要求会高一些,±0.2℃是比较合理的预期,这个水平通过两点校准加低温漂参考电阻可以达到。

工业场景就麻烦一些。锅炉排烟温度、注塑机料筒温度这类测点,温度范围大、环境恶劣,但控制精度要求反而不高,±2℃是常见标准。真正要求高精度的是制药、半导体等精密行业,那种场合就必须用标准铂电阻温度计做多点校准,并且把校准温度点选在传感器实际工作温度的附近,外推越远误差越大。

我自己在这套配置下实测过:校准后的RTD通道在0到100℃范围内的最大误差约0.15℃,热电偶通道在100到400℃范围内误差约±1.5℃,NTC通道在室温范围内约±0.3℃。对于标题里提到的那两种场景,这个精度已经绰绰有余。

5. 现场问题排查与避坑实录

5.1 通信与配置类问题

现场调试过程中,最常碰到的第一类问题就是通信异常。我遇到过MCU发命令后ADC毫无反应,排查半天发现是PIC18LF的TX引脚配置成了模拟输入。PIC的引脚功能复用很灵活,默认状态不一定是数字IO,芯片手册里的引脚说明必须逐条核对,尤其是ADC和比较器功能默认开启时,会把引脚占住。

另一个高频问题是波特率不匹配。自己用逻辑分析仪看波形,发现MCU发送的数据和ADC期望的帧格式差了一个字节位。原因是我最初用了内部RC振荡器,晶振焊上后问题就消失了。这里再强调一次:UART通信对时钟精度有要求,温度采集不是高速场景,不要为了省一个晶振钱去冒险。

还有一类问题看起来像通信故障,实际上是电源问题。ADC在欠压状态下会表现为“发命令不回”、“回的数据全是0xFF”或“偶尔回一帧正常的”。我的经验是用示波器同时抓电源和TX引脚波形,如果电源在发送命令瞬间出现明显跌落,说明供电余量不足或去耦电容摆放太远。

5.2 测量噪声与漂移类问题

测量噪声是最容易让人怀疑ADC质量问题的大类。我先说一个反直觉的经验:很多“ADC读数跳动”实际上不是ADC造成的,而是前端电路本身的热噪声和外部干扰。

热电偶通道出现读数大幅抖动时,我第一步不是改软件滤波,而是检查热电偶线是否屏蔽、屏蔽层是否单端接地。有一次现场读数波动达到5℃以上,最终发现是热电偶延长线穿过了一个大功率变频器的电缆桥架,感应噪声直接把微弱的热电偶信号淹没了。把传感器线重新布线,远离变频器电缆后,波动立刻降到0.2℃以内。

RTD通道出现漂移则要重点检查激励电流源。如果ADC内部电流源的设置寄存器没有正确配置,激励电流会随温度明显变化。比例测量虽然理论上抵消了电流源的绝对误差,但如果RTD和RREF不在同一个电流回路上,比例关系就不成立,漂移就会暴露出来。三线制RTD连接时,必须保证激励电流先流经RTD再流经RREF,顺序错了测量结果会乱。

NTC通道的漂移则更多来自分压电阻。普通贴片电阻温漂可以达到100ppm/℃甚至更高,如果分压用的是这种电阻,环境温度变化10℃就能造成0.1℃以上的测量漂移。换成低温漂电阻后问题立刻缓解。

5.3 工业控制柜里的“隐藏杀手”

最后分享几个只会在工业现场才会暴露的问题。第一个是接地环路。传感器探头和控制器被安装在不同的金属设备上,两边都接了保护地,这就在传感器信号回路里形成了一个接地环路。地环路电流会在热电偶的测量回路里产生额外的直流偏差,而且这种偏差随风量、设备运行状态变化,非常难排查。处理方式是把控制器侧的传感器接线端子与机壳地隔离,保持单点接地。

第二个问题是继电器和接触器开关时的瞬态干扰。HVAC控制箱里密集安装了各种接触器,动作瞬间会在母线上产生几百伏的尖峰。我的一版板子在压缩机启动时温度值会瞬间跳变,排查后确认是PCB上的模拟输入走线恰好经过继电器驱动电路下方,瞬态干扰通过空间耦合进了ADC输入。修改走线并在输入RC滤波器中加大电容后问题解决。

第三个问题是冷端补偿温度测量点不准。热电偶的冷端补偿依赖ADS122U04内部温度传感器,但这个传感器测量的是芯片封装内部温度。如果PCB局部有发热元件,比如MCU或RS485芯片紧挨着ADC,内部温度传感器读到的温度会比实际连接器的温度高好几度,冷端补偿就会出现偏差。我的补救措施是把ADC尽量远离发热源,同时在校准环节把冷端补偿误差一起修正掉。

6. 回头再看这套设计,几个我特别想提醒的点

这套ADS122U04IPWR加PIC18LF46K22的方案,我最满意的不是某个单一性能指标,而是它的通用性。一块板子同时兼容三路传感器类型,硬件不用改,固件里切换配置就能适配不同测点,在项目前期传感器选型不明确的时候特别实用。

如果让我重新做一遍,我会在系统设计阶段就把校准接口做进去,而不是等硬件定型后再补。在PIC18的固件里预留一个虚拟串口命令用于在线校准,可以省去后续打开机箱拆板调试的麻烦。校准系数也不要只存在EEPROM里,最好在上位机软件里留一份备份,万一现场误操作清空了参数,还能远程恢复。

另一个建议是保留一个独立的DRDY信号线。虽然UART方式可以不依赖它,但调试时有一个明确的数据就绪指示,能大大缩短查找问题时的时间。当初省略这个信号导致我排查数据时序多花了两天。

最后,如果传感器距离控制器超过50米,强烈建议在UART后面加RS485转换,而不是直接用TTL电平拉长线。TTL电平在长线上的衰减和反射会让你怀疑人生,RS485差分信号才是工业现场的正确打开方式。这套方案里PIC18LF46K22的第二个EUSART可以正好用来接RS485芯片,MCU内部把两路串口数据转发的代码只需要十几行,性价比极高。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询