做工业或HVAC温度测量的人,多半有过这种经历:控制逻辑、通信协议都调得差不多了,最后卡在温度读数上。我最初在一个变频器密度很高的暖通项目里,用PIC18F66K40自带的10位ADC去读NTC,静调风的时候数据还像样,压缩机一启动,读数能跳好几度;后来换成PT100,10位ADC更是直接没戏——1℃的变化对应不到0.2mV电信号,而5V参考下的一个LSB就有4.88mV。最后把ADS122U04IPWR这颗24位Δ-Σ ADC挂上去,测量链路才算真正立住。这篇文章把ADS122U04IPWR与PIC18F66K40的完整搭配讲透:芯片选型逻辑、传感器电路、UART通信配置、温度算法和现场抗干扰经验,都是可以直接抄作业的内容,适合正在做HVAC控制器、工业数据采集板或想给8位MCU系统补上高精度模拟前端的工程师。
1. 为什么拿24位ADC配8位MCU:一个精度鸿沟的账本
先说结论:温度测量这个事儿,MCU的CPU主频再高也没用,精度几乎全看ADC这条链路。PIC18F66K40本身是一颗很成熟的8位MCU,64KB Flash、4KB RAM、两个EUSART、PPS外设重映射,做控制逻辑和通信绰绰有余。但它内部那颗10位ADC,在多数的温度测量场景里就是短板。
1.1 10位ADC在PT100面前的无力
拿PT100举例。PT100在0℃时电阻是100Ω,灵敏度大约0.39Ω/℃。如果用500µA的恒流源激励,温度每变化1℃,PT100两端的电压只变化0.195mV。
PIC18F66K40的内部ADC参考电压如果取5V,10位分辨率对应的LSB是5V/1024=4.88mV。用4.88mV除以每摄氏度0.195mV,算下来一个码字对应大约25℃。也就是说,哪怕ADC完全无噪声,你的温度分辨率也只有25℃一级。这还没把参考电压温漂、PCB漏电、电源纹波算进去,实际读数跳个十几度非常正常。
这不是PIC一家的问题,而是几乎所有MCU内置ADC的通病:为了控制成本,内部参考源、采样保持电路和输入开关的串扰都做得比较一般。MCU的强项是逻辑和通信,不是模拟前端。所以在工业和HVAC项目里,成熟的架构永远是“MCU做控制+外置高精度ADC做采集”,两部分各司其职。
1.2 24位Δ-Σ ADC到底做了什么
ADS122U04IPWR是一颗24位、4通道的Δ-Σ ADC。注意“Δ-Σ”这个词,它跟传统的逐次逼近型ADC走的是完全不同的路线。逐次逼近型ADC像一把皮尺,一次性把电压切成1024份;Δ-Σ ADC则像一位反复称重的计量员,通过过采样、噪声整形和数字抽取滤波,用速度换精度,把量化噪声推到高频段再滤掉。
对温度这种变化很慢的物理量来说,这套策略非常合适。温度信号本身变化慢,采样率不需要高,20SPS就够,但分辨率要求高、抗干扰要求高,Δ-Σ恰好全占。以内部2.048V参考为例,24位补码的满量程是2^23=8388608,一个LSB对应0.244µV。对比PT100 500µA激励下每摄氏度0.195mV的灵敏度,理论上温度分辨率能到0.001℃级别。实际有效位数受噪声限制,20SPS下通常也有21位以上,温度分辨率到0.01℃级毫无压力。
更重要的是,这颗料把模拟前端常用的东西都集成进去了:可编程增益放大器PGA、两路匹配的激励电流源IDAC、内部温度传感器、可选的外部参考。以前这些得用一堆分立元件搭,现在一颗TSSOP-16就搞定,这对PCB面积和生产一致性都是好事。
1.3 为什么选UART版本的ADS122U04
ADS122U04IPWR后缀里的“U”代表UART接口,这也是我当初选它而不是ADS1220(SPI接口)的核心原因。SPI通信至少要SCLK、MISO、MOSI、CS四根线,在工业现场,时钟线既是干扰源也是敏感线,布线稍不注意就会把变频器的高频噪声耦合进去。
UART接口只需要两根线:PIC的TX接ADC的DIN,ADC的DOUT/DRDY接PIC的RX。9600波特率下,几米的板内走线非常从容,抗电磁干扰能力比SPI强不少。ADS122U04的数据速率最高到330SPS,温度应用通常只用到20~90SPS,9600波特率的带宽完全够用。
再一个原因是PIC18F66K40本身有双EUSART。一路固定给ADS122U04,另一路可以接RS-485收发器跑Modbus RTU,或者接人机界面屏,互不干扰。PIC18F66K40还支持PPS引脚重映射,UART的TX/RX能映射到任意普通IO上,PCB布局非常灵活,这在后面硬件设计部分会详细说。
另外提一句,“IPWR”这串后缀不是功能差异,PW代表TSSOP-16封装,R代表卷带包装。ADS112U04是这颗料的16位版本,如果只做NTC这种低成本传感器,用16位版能省一点成本;但考虑到PT100、热电偶甚至以后要扩展更高精度的测量,我建议直接上24位版,省得以后重新设计。
2. 传感器到MCU的硬件链路:热电偶、RTD和NTC分别怎么接
ADS122U04IPWR的四个模拟输入AIN0~AIN3可以配置成2路差分或4路单端,具体选哪种取决于传感器类型。温度传感器里最常见的三种:热电偶、RTD铂电阻、NTC热敏电阻,正好对应三个典型接法。我建议把差分通道留给热电偶和RTD,单端通道留给NTC。
2.1 热电偶:毫伏级小信号与冷端补偿电路
热电偶输出的热电势很小。K型热电偶的灵敏度大约是41µV/℃,0~1000℃的输出范围是0~41.276mV。这类毫伏级信号必须经过PGA放大后才能充分用足ADC的量程。
ADS122U04的PGA增益从1到128可调,选多少需要算一下。内部参考2.048V,PGA=128时满量程输入是2.048V/128=16mV,K型热电偶在1000℃输出41mV,直接超量程。所以K型热电偶我实际用的是PGA=32,满量程64mV,覆盖0~1000℃还有余量;如果测量范围只到500℃,PGA=64也够。J型热电偶灵敏度约55µV/℃,PGA=32同样合适。
热电偶自身是浮地器件,两端没有固定共模电位,所以要在AIN0和AIN1各接一个几百kΩ到1MΩ的偏置电阻,把输入共模电压拉到ADC允许的范围。这个细节很多人会漏,导致读数漂移或者跳变。
还有一个所有热电偶方案都绕不开的点:冷端补偿。热电偶输出的电压是热端与冷端的温差电压,必须知道冷端温度,才能换算出热端绝对温度。冷端温度传感器要尽可能靠近热电偶接线端子,而不是贴在ADC旁边。如果你用ADS122U04的内置温度传感器做冷端补偿,它测的是芯片结温,只适合粗略估算;真要满足工业验收,我建议在端子排附近放一颗0.1%精度的NTC或者专用的冷端补偿芯片,让探头去感受真正的冷端温度。
2.2 RTD:三线制PT100与比例式测量
RTD铂电阻的测量核心是“比例式测量”,这也是ADS122U04这类带IDAC电流源的ADC最大的价值。比例式测量的思路是:让同一个IDAC电流同时流过PT100和一颗精密参考电阻Rref,ADC把Rref上的电压当作参考电压,实际测量的就是PT100电阻与Rref的比值。这样一来,IDAC电流的绝对值精度和温漂在计算中被抵消,测量结果只取决于Rref的精度。Rref选0.1%或更高精度的金属箔电阻,温度漂移做到5ppm/℃以内。
具体取值要算一笔账。假设IDAC设500µA,PT100在0℃时是100Ω,两端电压50mV;到400℃时电阻约247Ω,电压变成123.5mV。外部参考Rref选3.9kΩ,500µA流过它产生1.95V参考电压,接近内部2.048V参考,又不超限。PGA增益选8,此时满量程是1.95V/8=243.75mV,覆盖0~400℃的123.5mV信号绰绰有余。如果选PGA=16,满量程变成121.9mV,接近超量程,风险太大。
接法上,两线制是最不建议的:导线电阻直接串进测量回路,20米的铜线几十欧姆,比PT100本身还金贵。工业上最少要用三线制:IDAC电流从AIN0经一根导线到PT100,从PT100另一端经第二根导线回到公共端,第三根导线作为电压检测线接入差分输入的负端。这样两根导线上的压降被差分测量抵消,剩下的误差只剩检测线上的微小电流,可以忽略。如果精度要求更高,可以做四线制,但HVAC领域三线制已经足够。
PT100的自热效应也要留意。500µA在100Ω上产生的功率只有25µW,几乎可以忽略;如果用1mA激励,功率变成100µW,在无风密闭套管里可能带来0.1℃级别的误差。能选500µA就不要上1mA。
2.3 NTC分压电路:HVAC的低成本选项
HVAC里大量的回风温度、送风温度、盘管温度用的是10kΩ NTC,B值通常3950。NTC的接法比PT100简单得多:用一颗精密电阻做分压,NTC下端接地,分压点接ADC的单端输入AIN2即可。分压电阻选择与NTC标称值同阻值的10kΩ,在25℃时分压点恰好在中间,灵敏度最高。
NTC的优点是便宜、响应快、灵敏度高——在25℃附近,10k NTC的温度系数大约-4.4%/℃,折算成电压变化非常明显;缺点是B值离散度较大,批次间一致性不如PT100,标定工作量会上来。所以我的经验是:HVAC的舒适性控制用NTC完全够,但如果是工艺冷却水这种要参与费用结算或者工艺联锁的测点,老老实实上PT100。
还有一个操作细节:NTC分压电路的参考电压最好直接取ADC的内部参考2.048V,而不是用系统3.3V电源。因为ADS122U04内部参考是稳定的基准源,而电源电压会随负载波动,直接决定分压比换算电阻的精度。这一点在后续固件标定里会体现出来。
2.4 ADC与PIC18F66K40的UART接线和PPS重映射
ADS122U04IPWR与PIC18F66K40的通信只有三根线真正关键:PIC的EUSART1_TX接到ADS的DIN,ADS的DOUT/DRDY接到PIC的EUSART1_RX,ADI的RESET引脚接一个GPIO用于上电复位控制。我这个配置里把RESET也接到了GPIO,而不是简单用RC延时电路,因为软件可控的复位对调试和异常恢复很重要。
PIC18F66K40的PPS功能在这里非常加分。PPS允许把UART的TX和RX重映射到几乎任意普通IO引脚,这意味着你在画PCB时可以先把模拟信号走线规划好,再把UART信号安排到不穿越模拟区域的位置。用MPLAB Code Configurator(MCC)配置时,选择EUSART1模块,点两下TX和RX的引脚映射就生成了,比自己手工翻寄存器安全得多。
硬件走线方面,UART的两根线要尽量短、尽量远离功率管、变压器和继电器。ADS122U04的DIN和DOUT都属于数字信号,但离模拟输入太近时,翻转沿还是可能串扰到微弱的热电偶信号上,所以在布局时保持至少5~10mm的间距比较稳妥。
2.5 电源与去耦:容易被拖后腿的环节
ADS122U04IPWR是模拟混合器件,AVDD和DVDD最好分开处理。我常用的做法是:系统5V经过磁珠或者小电感后给AVDD供电,DVDD与MCU共用3.3V,两个电源域在PCB上做单点连接,避免数字电流回流穿过模拟区域。
每个电源引脚旁边放0.1µF陶瓷电容,再在电源入口放一颗10µF钽电容或者大尺寸MLCC做低频储能。ADS122U04的参考电压如果使用内部2.048V,VREF引脚的去耦电容不能省,一颗1µF以上、ESR低的X7R电容直接贴近引脚放,别走太多过孔。
很多人忽视的是模拟地的回流路径。ADC的AGND引脚必须单独走线回到电源端子,不能与MCU的数字地共享一小段铜皮。曾经有个项目,模拟地走线太细,继电器吸合瞬间温度读数跳了1℃多,查来查去就是地线上几百毫伏的脉冲压降。把模拟地加粗、加宽、缩短回流路径之后,干扰立刻消失。
3. 固件落地的关键动作:EUSART初始化、寄存器配置与数据解析
硬件链路通完之后,固件是决定项目成败的另一半。PIC18F66K40的固件其实不复杂,但有几个关键动作容易被理解偏差:波特率计算、上电时序、寄存器写入意图、24位数据符号扩展。一个一个过。
3.1 EUSART1初始化与波特率误差
ADS122U04的UART默认匹配标准8数据位、无校验、1停止位(8N1)。PIC18F66K40使用内部16MHz振荡器时,9600波特率的SPBRG值计算如下:
SPBRG = Fosc / (16 × Baud) - 1 = 16000000 / (16 × 9600) - 1 ≈ 103.17,取103。
实际波特率是16000000 / (16 × 104) = 9615.38,误差约0.16%,在UART容差范围内,很稳。初始化代码如下:
// PIC18F66K40,内部16MHz振荡器,9600波特率 void UART1_Init(void) { SPBRGH1 = 0x00; SPBRG1 = 103; // 16MHz/(16*9600)-1 BAUDCON1bits.BRG16 = 1; // 16位波特率发生器 TXSTA1bits.BRGH = 1; // 高速模式 TXSTA1bits.TXEN = 1; // 使能发送 RCSTA1bits.SPEN = 1; // 串口使能 RCSTA1bits.CREN = 1; // 使能接收 // 清掉上电时可能残留的接收标志 RCSTA1bits.CREN = 0; RCSTA1bits.CREN = 1; }发送和接收函数用最标准的轮询方式即可。接收这边我建议开中断,因为ADS122U04在连续转换模式下会自主把数据推给MCU,主循环去轮询RCIF很容易丢帧或者被别的逻辑卡住时序。
void UART1_WriteByte(uint8_t byte) { while (!PIR1bits.TXIF); TXREG1 = byte; } uint8_t UART1_ReadByte(void) { while (!PIR1bits.RCIF); return RCREG1; }void __interrupt() ISR(void) { if (PIR1bits.RCIF) { rxBuf[rxIndex++] = RCREG1; // 收进环形缓冲区/状态机 PIR1bits.RCIF = 0; } }3.2 ADS122U04的上电时序与命令帧结构
ADS122U04不是一上电就能通信的,它需要一个复位过程。我的启动序列是:MCU复位后先等待100ms,让ADC电源稳定;然后拉低RESET引脚至少10µs再释放,等待DRDY指示就绪;接着发送启动转换命令进入工作模式。
它的命令帧结构遵循“命令字节 + 地址/参数 + 数据”的模式。以写配置寄存器为例,主机依次发送写命令码、寄存器起始地址、要写入的寄存器数量、随后是寄存器数据。读数据的时候先发读数据命令,然后从DOUT上接收对应字节。这里特别说明一下:不同批次数据手册上的具体命令码可能有差异,我在示例代码里用宏定义统一管理,烧录前务必对照TI官方数据手册的Command Definitions章节核对。
// 命令码以数据手册为准,这里给出框架 #define ADS_CMD_RESET 0x06 #define ADS_CMD_WRITE_REG 0x40 #define ADS_CMD_READ_DATA 0x60 #define ADS_CMD_START 0x103.3 写寄存器:按配置意图而不是背地址
我见过不少新手死记寄存器地址值,换一颗料就抓瞎。正确的做法是先明确配置意图,再去数据手册找对应位域。下面这个表格是我在PT100三线制项目里的实际配置意图,你可以对照自己的传感器改:
| 配置项 | 选值 | 目的 |
|---|---|---|
| 输入MUX | AIN0-AIN1差分 | 接入三线制PT100 |
| PGA增益 | 8 | 匹配123.5mV满量程信号 |
| 数据速率 | 20SPS | 兼顾噪声抑制和响应时间 |
| 转换模式 | 连续转换 | 简化主循环时序 |
| 参考电压 | 外部Rref(3.9kΩ) | 比例式测量抵消IDAC漂移 |
| IDAC电流 | 500µA | PT100激励,自热可忽略 |
| IDAC路由 | IDAC1输出到AIN0 | 驱动PT100 |
写寄存器流程的代码框架:
uint8_t adsConfig[4]; // adsConfig[0] 对应REG0,按数据手册的MUX和PGA位域填充 // adsConfig[1] 对应REG1,按数据速率和模式填充 // adsConfig[2] 对应REG2,按参考和IDAC档位填充 // adsConfig[3] 对应REG3,按IDAC路由引脚填充 UART1_WriteByte(ADS_CMD_WRITE_REG); UART1_WriteByte(0x00); // 从REG0开始 UART1_WriteByte(0x04); // 连续写4个寄存器 for (uint8_t i = 0; i < 4; i++) UART1_WriteByte(adsConfig[i]);写完之后,我会读一遍配置寄存器回读验证。别嫌麻烦,这套“写后读”在排错时能帮你快速区分是寄存器没写进去还是数据换算错误。
3.4 读取24位结果并正确做符号扩展
ADS122U04是24位ADC,转换结果用二进制补码表示,读出三个字节后需要正确合并和符号扩展。很多人栽在这里:三个无符号字节直接拼起来,结果一个最简单的负数就变成几百万的诡异数字。
正确做法是先把最高字节强制转为有符号8位,再左移16位,这样符号位能自然扩展:
// 假设buf[0]是MSB, buf[1]是中间, buf[2]是LSB int32_t raw = ((int32_t)(int8_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | (int32_t)buf[2];如果编译器对int8_t的符号扩展行为不放心,可以手动判断:
int32_t raw = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | buf[2]; if (raw & 0x800000UL) raw |= 0xFF000000UL;电压转换公式也很关键。带符号24位补码的满量程是2^23=8388608,所以:
float voltage = ((float)raw) / 8388608.0f * (vref / pga);以外部参考1.95V、PGA=8为例,raw=4194304时,电压=4194304/8388608×(1.95/8)=0.121875V,正好对应PT100在390Ω附近的压降,计算链条是闭合的。
3.5 连续模式还是单次模式:现场判断
ADS122U04支持连续转换和单次触发两种模式。连续模式下,ADC转换完自动把数据推给MCU,主循环只要在收到数据帧时处理就行,时序最简单,适合绝大多数工业和HVAC应用。缺点是MCU始终得挂着接收中断,功耗略高。
单次模式适合电池供电或者多通道轮询的场景:每次发启动命令,等DRDY变低后再读数据,读完可以立刻让ADC进入低功耗状态。代价是时序控制复杂度上升,而且如果DRDY处理不及时,容易读到陈旧数据。
我的建议是:有市电的HVAC设备直接连续模式;便携式仪表或者需要严格控制待机功耗的场景才用单次模式。另外,如果数据速率选20SPS,一个数据周期是50ms,MCU只要确保50ms内能响应一次接收中断就行,PIC18F66K40的16MHz主频完全没问题。
4. 从ADC原始码到温度值:线性化、滤波与现场标定
ADC原始码只是电压或者电阻的镜像,距离“温度读数”还差三步:传感器非线性校正、滤波、系统标定。这一步处理得好,传感器精度才能被24位ADC真正发挥出来;处理不好,再贵的ADC也白搭。
4.1 RTD温度反算用查表还是迭代
PT100的电阻-温度关系使用IEC 60751标准,公式就是Callendar-Van Dusen方程。0℃以上时可以简化成:
R(T) = R0 × (1 + A×T + B×T²)
其中A=3.9083×10⁻³,B=-5.775×10⁻⁷。反算温度就是解一元二次方程,直接在MCU上用求根公式:
float RTD_OhmToTemp(float R, float R0) { float ratio = R / R0 - 1.0f; float disc = A * A - 4.0f * B * ratio; if (disc < 0.0f) return -999.0f; return (-A + sqrtf(disc)) / (2.0f * B); }这个公式在0~200℃范围内精度可到0.1℃以内,对HVAC和大多数工业现场完全够用。如果测量范围要延伸到0℃以下,方程里会多一个C×(T-100)×T³项,没法直接求根,这时用查表加线性插值更省心。PIC18F66K40的64KB Flash可以轻松放一张0.1℃步进的PT100对照表,查表插值复杂度低,代码也更可控。
4.2 K型热电偶的冷端补偿与线性化
热电偶的难点不在ADC读数,而在冷端补偿。K型热电偶在冷端0℃时直接输出热端毫伏值,但实际上冷端不可能一直待在0℃,所以必须把冷端温度换算成等效毫伏,加到测量值上再反查表。
过程分三步:
- 读取冷端温度。用紧贴接线端子的NTC或专用冷端传感器,实测冷端25℃。
- 查K型热电偶表,得到25℃对应的热电势,大约1.000mV。
- ADC测到的热端电压加1.000mV,得到“以0℃为冷端的等效热电势”,再反查表得到热端温度。
在MCU里实现就是查两张表:一张是从温度查毫伏(冷端补偿时用),一张是从毫伏查温度(最终转换时用),两张表间隔1℃,相邻点线性插值,K型整个0~1000℃范围也就1001个点,Flash完全放得下。
这里有个容易忽略的点:热电偶表的基准是ITS-90,查表前要确认ADS122U04测得的电压是经过PGA放大后的值,先除以PGA还原成真实毫伏,再做补偿和查表。否则放大倍数一旦带入查表过程,结果错得离谱。
4.3 两层滤波:中值去尖峰、滑动平均去抖动
ADS122U04本身在20SPS下已经有内置数字滤波器对工频50Hz/60Hz有抑制,但工业现场还有变频器、继电器、接触器产生的随机尖峰干扰。我习惯在MCU里再套两层滤波:先做N=5的中值滤波把明显的脉冲毛刺剔除,再做N=8的滑动平均平滑输出。
中值滤波的实现就是把最近5个采样点放进数组排序取中间值,抗尖峰能力极强,代价是延后两个采样周期。滑动平均本质上是一个低通滤波器,N越大输出越平滑但滞后越大。温度控制回路对滞后的容忍度相对较高,20SPS下N=8对应0.4s延后,HVAC完全够用;如果是工业温控PID,建议N取4,避免影响控制稳定性。
两层滤波顺序不能反:先中值后滑动平均。如果先滑动平均,一个尖峰会被平均到后续好几个点里,相当于污染范围扩大,处理起来更棘手。
4.4 两点标定和三点标定的实操
24位ADC给系统带来的好处就是标定过程变得非常“干净”。两点标定的思路是:测出零点偏移和增益误差,然后用线性校正修正。
实际操作中,我用精密电阻箱模拟PT100的电阻值,比用水浴锅、干井炉更方便。把电阻箱设到100Ω,记录ADC换算出的温度值,记为T1;再把电阻箱设到200Ω,记录T2。假设电阻箱准确,那么校正后的温度就是:
T_corrected = T_raw - offset / gain,其中gain = (T2 - T1) / (R箱2对应温度 - R箱1对应温度),offset = T1 - 标准值。
如果你有干井炉或者冰水浴,温度点的校正更直接:0℃用冰水混合物(注意要等冰水充分平衡),100℃用沸水(要考虑当地海拔修正沸点),两个点之间做线性校正即可。要求更高就做三点标定,比如0℃、50℃、100℃三个点,分别计算每一段的增益,非线性能被修正得更干净。
标定完记住把修正系数写到EEPROM或Flash里,还要在设备上电时做一次自检——读内部温度传感器,确认芯片工作正常,再进入正常测量流程。这个自检步骤在工业验收时很加分,能避免现场装完发现整批读数偏移才发现是标定丢失。
5. 现场实测踩过的坑:通信时序、布线和干扰的对抗记录
硬件和固件都调通之后,真正的考验才刚开始。现场环境和实验室最大的差异就是干扰来源多、随机性强。这节记录的是我实际踩过并且花费不少时间才解决的几个问题,全是常规文档里不会写的细节。
5.1 DRDY时序不对导致的数据错位
第一次上电,连续模式下读数偶尔出现“飞点”,一个几千欧姆的电阻突然跳成负数,让排查了半天。用逻辑分析仪看UART波形才发现:ADS122U04在转换完成后会自主把数据帧发出来,而MCU主循环里负责读取的代码执行时机不确定,数据流没有被帧边界对齐,收到的三个字节错位了。
解决办法有两个方向:
- 方向一,利用DRDY信号。ADS122U04的DOUT/DRDY引脚在数据准备好时会拉低,MCU可以把这脚接外部中断,中断触发后再读取UART数据,从根上保证不会错位。
- 方向二,在接收中断里做帧状态机。约定帧头,MCU不断接收三个字节,按命令号校验,无效帧丢弃。
我最终选择的是接收中断加状态机,因为DRDY引脚一旦接到外部中断,后续想复用这个IO做输出就麻烦了。状态机的核心是:收到命令帧首字节后,后续两个字节强制归位到同一帧,任何超时或者命令不匹配都重启状态机。
5.2 长线屏蔽层处理与输入RC滤波
现场有几路热电偶线从二楼桥架拉下来,长度超过20米,读数在变频器启动时会有规律性跳动。起初以为是屏蔽层没接,把所有屏蔽层两端都接地,结果干扰反而更严重——这是典型的地环路问题。
正确的做法是屏蔽层单端接地。我把它改成在控制器端子处单点接地,传感器端悬空,地环路电流立刻消失,读数跳变幅度下降了90%。如果现场条件不允许单端接地,至少保证屏蔽层与信号大地之间只有一个连接点。
另外,模拟输入前端要加RC低通滤波。我在AIN0和AIN1各串了一个1kΩ电阻,对地接0.1µF电容,截止频率约1.6kHz,既能抑制射频干扰,又不会影响20SPS的数据速率。注意RC滤波的电阻值不能太大,否则会与传感器阻抗分压产生增益误差;1kΩ对于PT100和热电偶都够安全。
5.3 上电顺序、复位延时和首字节丢失
有个现象很诡异:设备冷启动时,第一帧温度数据永远是垃圾值,后面就正常了。排查到最后是MCU和ADC上电速度不一致导致的。ADS122U04的电源还没稳定,MCU已经把启动命令发过去了,ADC要么没收到,要么收错了。
解决方法是三层保险:
- MCU上电后延时100ms,再拉RESET引脚做一次软件复位;
- 复位后发送一个命令读取版本或者状态寄存器,等ADC确认回复;
- UART初始化后立刻做一次“假读”,把上电瞬间误触发接收缓冲区里的残留字符清掉。
首字节丢失的问题同样常见。MCU使能EUSART接收的瞬间,线上噪声可能造成一个假起始位,RCREG里出现一个0x00,后续数据全部错位。解决办法就是初始化完成后,把RCREG读一次丢弃,同时检查并及时清零OERR上溢错误标志。
5.4 一组实测稳定性的参考数据
最后给一组实验室环境下的实测数据,供大家心里有个底。所有数据都是ADC在连续模式、20SPS、两层滤波开启后的表现:
| 传感器 | 配置 | 连续采样100次的最大波动 | 备注 |
|---|---|---|---|
| PT100三线制 | IDAC=500µA, PGA=8, 外部参考3.9kΩ | ±0.03℃ | 对应电阻波动约±0.012Ω |
| K型热电偶 | PGA=32, 冷端NTC补偿 | ±0.2℃ | 主要受冷端温度和表精度影响 |
| 10kΩ NTC | 分压到AIN2, 内部参考 | ±0.05℃ | 常温HVAC场景 |
可以看到,PT100通道在24位ADC下的稳定性确实对得起这颗料,热电偶的波动主要来自冷端补偿和热电偶本身的噪声,NTC的波动则受制于它的非线性。如果PT100通道标定后仍然有整体偏移,先检查Rref的实际阻值,再确认PGA设置是否和数据手册一致,这两个点是所有“差一度”问题的第一嫌疑。
实际接入变频器环境后,干扰主要体现在热电偶通道上,这是由热电偶输出阻抗高、信号电平低的天性决定的。这时的应对就是前面说的:屏蔽层单端接地、输入RC滤波、中值滤波去掉尖峰,三步全做下来,热电偶的动态波动可以压在±0.5℃以内,作为HVAC回风温度或工业管道温度的监测已经是可靠的水平。
最后分享一点个人体会:高精度ADC只是精度链路的起点,传感器本身的精度、参考源的稳定性、布线规范、滤波算法,任何一个环节拉胯,最终误差都不会小。ADS122U04IPWR这颗料的24位分辨率和UART接口确实省心,但真正决定你能不能在HVAC验收里拿到漂亮数据的,往往是冷端补偿的位置、屏蔽层接地的那一头、以及上电时序里那100ms的耐心。把这些细节当回事,温度测量这块基本就稳了。