1. 工业温度测量方案的整体设计思路
工业现场和HVAC系统里的温度测量,看起来是个再普通不过的需求,但真正做过项目的人都知道,这里面的坑一点都不少。我接触过不少暖通空调、工业过程控制的案子,客户张口就是“测个温度而已,随便搞个传感器不就行了”,结果一到现场就出问题:读数跳变、精度不够、长线传输干扰、多点采集不同步,各种毛病全冒出来。所以这次我拿ADS122U04IPWR这颗24位ΔΣ ADC配合PIC18F87J50单片机,做一套针对工业和HVAC场景的温度采集方案,把从传感器选型到ADC配置再到软件滤波的完整链路捋一遍。
先说这套组合能干什么。ADS122U04IPWR是TI的一款24位、4通道、带PGA的低功耗ΔΣ模数转换器,内置两个匹配的激励电流源,专门为RTD、热电偶、热敏电阻这类温度传感器做了优化。PIC18F87J50是Microchip的一款8位MCU,自带全速USB 2.0控制器,64KB Flash,3936字节RAM,跑温度采集这种任务绰绰有余。两者通过SPI或者UART通信,ADS122U04支持这两种接口,我一般选SPI,速度快、时序可控。
这套方案解决的核心问题是:在工业电磁环境复杂、传感器离主控可能有好几米远的条件下,稳定地拿到±0.1℃级别的温度读数。适合谁看?做HVAC控制器的嵌入式工程师、搞工业数据采集的硬件开发者、以及正在选型温度测量方案的产品经理。哪怕你之前没碰过ΔΣ ADC,只要懂基本的SPI通信和C语言,跟着走一遍就能落地。
为什么不用MCU自带的12位ADC直接测?这是很多人第一个会问的问题。PIC18F87J50内部ADC是10位或12位(取决于配置),在测量PT100这种变化量很小的信号时,分辨率完全不够。PT100在0℃时是100Ω,每升高1℃大约增加0.385Ω。如果用1mA激励电流,1℃对应的电压变化只有385μV。12位ADC在3.3V参考下,1个LSB就是0.8mV,根本分辨不出0.1℃的变化。而ADS122U04在PGA增益为8、使用内部2.048V参考时,有效分辨率能到20位以上,1个LSB对应不到2μV,轻松覆盖0.01℃的分辨需求。这就是为什么工业级温度测量几乎都绕不开高精度外置ADC。
2. 核心器件选型与关键参数拆解
2.1 ADS122U04IPWR凭什么适合RTD测温
ADS122U04IPWR的核心优势在于它把RTD测量需要的几个关键模块都集成进去了。它内部有两个可编程激励电流源,可以输出10μA到1.5mA的电流,用来给RTD供电。为什么这个很重要?因为RTD测量通常采用比率法,用同一个电流源同时激励RTD和参考电阻,这样电流的温漂和长期漂移会被抵消掉,测量精度只取决于参考电阻的精度。如果外部分立搭建电流源,不仅占板面积,匹配和温漂也是大麻烦。
它的PGA支持1到128的增益,对于PT100在低温段输出信号很小的情况,可以把增益设高一点,充分利用ADC的满量程。输入多路复用器支持4个差分通道或者2个差分加2个单端,做多点温度采集时不用外接多路开关。内部参考电压可选2.048V或2.4V,温漂典型值5ppm/℃,这个指标对工业环境来说够用了。
数据输出速率从5SPS到2000SPS可调。这里有个取舍:速率越低,数字滤波器抑制工频干扰的能力越强,噪声也越低。HVAC场景里温度变化本来就慢,我通常设20SPS,正好把50Hz和60Hz工频干扰压得很死。如果做快速响应的工业探头测试,可以设到200SPS以上,但这时候就要靠外部RC滤波来补救了。
2.2 PIC18F87J50在系统中的角色定位
PIC18F87J50在这套方案里干三件事:配置ADS122U04的寄存器、读取转换结果、做二次滤波和温度换算。它自带SPI模块,最高支持10Mbps,跟ADS122U04通信完全不是瓶颈。64KB Flash存温度换算表、滤波算法、通信协议栈都够用。3936字节RAM对于缓冲采样数据、跑滑动平均或者中值滤波也绰绰有余。
选它还有一个实际考虑:它支持2.0V到3.6V宽电压供电,可以直接和ADS122U04的DVDD共用一个3.3V轨,省掉电平转换。工业现场很多设备还是5V系统,PIC18F87J50的I/O口耐5V,跟老式PLC接口时不用加电平转换芯片,这一点在改造项目里特别省事。
它的USB功能在这个方案里不是必须的,但如果你要做桌面校准工具或者数据记录仪,直接用它内置的USB跟PC通信,省掉一颗USB转串口芯片,BOM成本能降一点。我有个客户就是拿它做便携式温度校准器,USB供电加通信,一根线搞定。
2.3 传感器选型:PT100、PT1000还是热电偶
工业和HVAC场景里,PT100和PT1000是最常见的选择。PT100在0℃时100Ω,PT1000是1000Ω。同样的激励电流下,PT1000的输出电压是PT100的10倍,信噪比更好,但自热效应也更明显。所谓自热效应,就是激励电流流过RTD时会产生焦耳热,让传感器本身温度略高于环境温度。PT100用1mA激励时自热大约0.1℃,PT1000用0.1mA激励时自热差不多,但输出信号只有PT100用1mA时的水平。所以选哪个要看你的精度要求和传感器封装。
我的经验是:HVAC风管温度测量,PT1000更合适,因为风管里传感器封装小,自热影响小,而且PT1000的引线电阻影响相对小。工业管道或者高温炉,PT100更常见,因为标准铂电阻温度计都是PT100,校准和互换性更好。热电偶适合测高温,但冷端补偿和信号调理复杂得多,ADS122U04虽然能接,但需要额外的冷端传感器,这个方案里先不展开。
3. 硬件电路设计与实操要点
3.1 RTD接口电路:三线制还是四线制
RTD接线方式直接决定测量精度。两线制最简单,但引线电阻直接加到测量结果里,每米铜线大约0.02Ω,100米就是2Ω,对应PT100大约5℃误差,完全不能用。三线制是工业标配,用一根补偿线抵消引线电阻,前提是三根线材质长度一致。四线制精度最高,用两根线通电流、两根线测电压,完全消除引线电阻影响,但布线成本高。
ADS122U04支持三线制和四线制。三线制接法是把RTD一端接两个输入通道,另一端接激励电流源,通过两次测量或者内部多路复用切换来消除引线电阻。具体操作是:第一次测量RTD电压加引线1的压降,第二次测量引线2的压降,两者相减。ADS122U04的内部多路复用器可以自动完成这个切换,但需要软件配合。
四线制就简单粗暴:激励电流从RTD两端流入流出,测量电压从另外两端取,引线电阻上没电流所以没压降。我一般建议客户:如果传感器离主控超过3米,直接上四线制,省得后面调半天发现是引线电阻问题。三线制适合传感器和电路板在同一个机柜里的场景。
3.2 参考电阻的选择与计算
比率法测量里,参考电阻的精度和温漂直接决定系统精度。ADS122U04的参考输入可以接外部参考电阻,用同一个激励电流源驱动。假设用PT100,激励电流1mA,参考电阻选1.65kΩ,那么参考电压就是1.65V。PT100在0℃时电压是100mV,在100℃时是138.5mV。ADC的满量程是±VREF/PGA,如果PGA=1,满量程就是±1.65V,100mV只用了满量程的6%,浪费了很多分辨率。
所以要把PGA设高。PGA=8时,满量程变成±206mV,138.5mV对应满量程的67%,利用率好多了。但要注意PGA的输入范围限制:ADS122U04在PGA=8时,输入共模电压要满足AVSS+0.2V到AVDD-0.2V之间,差分输入不能超过±VREF/PGA。算一下:138.5mV差分,共模电压设在1.65V/2=0.825V左右,满足要求。
参考电阻的选型:1.65kΩ用0.1%精度、10ppm/℃温漂的金属膜电阻,比如Vishay的PTF系列。这个电阻的温漂会直接乘到测量结果上,10ppm/℃在0到50℃变化范围内引入500ppm误差,对应PT100大约0.13℃。如果要求更高,可以用0.05%精度、5ppm/℃的电阻,成本翻倍但误差减半。
3.3 电源与去耦:别小看这几个电容
ADS122U04有AVDD和DVDD两组电源。AVDD给模拟部分供电,DVDD给数字接口供电。虽然它支持2.3V到5.5V宽电压,但为了跟PIC18F87J50的3.3V系统匹配,两组都接3.3V。关键点是AVDD必须干净,任何纹波都会直接调制到ADC输出上。
我的做法是:AVDD用一颗低压差线性稳压器单独供电,比如TPS7A4700,噪声只有4μVrms。DVDD可以跟MCU共用数字3.3V,但要在ADS122U04的DVDD引脚旁边放0.1μF和1μF电容各一颗,0.1μF要尽量靠近引脚,走线短而粗。AVDD的去耦更讲究:10μF钽电容加0.1μF陶瓷电容,再并一颗1nF的C0G电容滤高频。别用X7R或者Y5V的电容做模拟去耦,它们的压电效应会引入噪声。
参考电压引脚REFP和REFN之间也要放0.1μF电容,这个电容影响参考电压的稳定速度。如果设了50SPS以上的速率,电容可以小一点,响应快;如果设20SPS以下,电容可以大到1μF,噪声更低。
3.4 SPI接口连接与PCB布局
ADS122U04的SPI接口有四根线:CS、SCLK、DIN、DOUT/DRDY。DRDY是数据就绪信号,也可以复用成DOUT。我一般把DRDY单独接到PIC18F87J50的一个外部中断引脚上,这样MCU不用轮询,数据准备好了直接进中断读,效率高。
SPI时钟极性要设对:ADS122U04在SCLK下降沿采样DIN,上升沿输出DOUT,对应SPI模式1(CPOL=0,CPHA=1)。PIC18F87J50的SSP模块支持四种模式,配置成模式1就行。时钟频率别超过4MHz,虽然手册标称支持到10MHz,但长走线或者高噪声环境下降频更稳。
PCB布局上,模拟部分和数字部分要分开。ADS122U04放在板子中间,左边是模拟输入和参考电阻,右边是SPI数字线。模拟输入走线要远离SCLK和任何开关信号,最好用地线包起来。参考电阻和RTD的走线要对称,差分对走等长线,减少共模干扰转化成差模噪声。如果板子空间允许,在模拟输入前面加一个RC低通,截止频率设在1kHz左右,用1kΩ电阻加100nF电容,能滤掉大部分高频干扰。
4. 软件配置与温度换算实操
4.1 ADS122U04寄存器配置流程
ADS122U04有四个配置寄存器,上电后需要按顺序写。我一般用下面这个配置流程:
// 假设SPI接口已经初始化,CS控制函数为ADS_CS_LOW()和ADS_CS_HIGH() // 写寄存器函数:先发0x40|(reg<<2)|(num-1),再发数据 void ADS122U04_Init(void) { ADS_CS_LOW(); // 配置寄存器0:PGA使能,增益8,20SPS,连续转换模式 // MUX[3:0]=0000 差分通道0,GAIN[2:0]=011 增益8 // DR[2:0]=010 20SPS,CM=1 连续转换,TS=0 禁用温度传感器 ADS_WriteReg(0, 0x0A); // 0000 1010 // 配置寄存器1:50/60Hz抑制,低侧参考,IDAC关 // 具体位定义参考手册,这里设50Hz抑制 ADS_WriteReg(1, 0x00); // 配置寄存器2:外部参考,IDAC电流1mA // VREF[1:0]=00 外部参考,IDAC[2:0]=100 1mA ADS_WriteReg(2, 0x20); // 0010 0000 // 配置寄存器3:IDAC1路由到AIN0,IDAC2关 ADS_WriteReg(3, 0x00); ADS_CS_HIGH(); }这里解释几个关键位。MUX设成0000表示选差分通道0,也就是AIN0和AIN1之间的电压。GAIN设成011对应增益8。DR设成010对应20SPS,这个速率下50Hz和60Hz抑制都能做到-100dB以上。CM设成1是连续转换模式,ADC自己按速率转换,DRDY引脚会周期性拉低通知MCU。如果设成单次转换模式,每次都要发命令启动,软件开销大。
IDAC配置在寄存器2和3里。IDAC[2:0]=100对应1mA,IDAC1_ROUTE设成000表示从AIN0输出。这样电流从AIN0流出,经过RTD,回到AIN3或者外部地。具体路由要看你的硬件接法。
4.2 读取转换结果与数据格式处理
ADS122U04输出24位二进制补码。正满量程是0x7FFFFF,负满量程是0x800000。读取时先发0x10命令(读数据),然后连续读3个字节。注意SPI是MSB先行,第一个字节是最高8位。
int32_t ADS122U04_ReadData(void) { uint8_t buf[3]; int32_t raw; ADS_CS_LOW(); SPI_Transfer(0x10); // 读数据命令 buf[0] = SPI_Transfer(0x00); buf[1] = SPI_Transfer(0x00); buf[2] = SPI_Transfer(0x00); ADS_CS_HIGH(); raw = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | buf[2]; // 符号扩展:如果bit23是1,高8位补1 if (raw & 0x800000) { raw |= 0xFF000000; } return raw; }这里有个坑:很多新手忘了符号扩展,结果负温度读出来变成很大的正数。24位补码的负数在32位里要手动补高8位,不然0xFFFFFF会被当成16777215而不是-1。
4.3 RTD温度换算:从ADC码到摄氏度
拿到raw值后,先算RTD电阻。比率法公式:
R_RTD = R_REF × (Code / 2^23) / PGA
其中Code是ADC码,2^23是满量程码值(8388608),PGA是增益。假设R_REF=1650Ω,PGA=8,Code=1000000,那么:
R_RTD = 1650 × (1000000 / 8388608) / 8 = 1650 × 0.1192 / 8 = 24.59Ω
这个值明显不对,因为PT100在0℃时应该是100Ω。问题出在公式上。比率法里,参考电压VREF = I_EXC × R_REF,RTD电压V_RTD = I_EXC × R_RTD。ADC码 = (V_RTD × PGA / VREF) × 2^23。代入:
Code = (I_EXC × R_RTD × PGA) / (I_EXC × R_REF) × 2^23 = (R_RTD × PGA / R_REF) × 2^23
所以:
R_RTD = R_REF × Code / (PGA × 2^23)
重新算:R_RTD = 1650 × 1000000 / (8 × 8388608) = 1650 × 1000000 / 67108864 = 24.59Ω
还是不对。等等,我检查一下。如果R_RTD=100Ω,PGA=8,R_REF=1650Ω,那么Code = (100 × 8 / 1650) × 8388608 = 0.4848 × 8388608 = 4067040。反过来,Code=4067040时,R_RTD = 1650 × 4067040 / (8 × 8388608) = 1650 × 4067040 / 67108864 = 100Ω。对了。所以之前Code=1000000算出来24.59Ω是对的,因为1000000对应的RTD电阻就是24.59Ω,不是100Ω。我举的例子数值不匹配,但公式是对的。
实际代码里,为了效率,可以先把R_REF / (PGA × 2^23)算成一个常数:
#define RREF 1650.0f #define PGA 8.0f #define ADC_FS 8388608.0f #define RREF_SCALE (RREF / (PGA * ADC_FS)) float GetRTDResistance(int32_t code) { return (float)code * RREF_SCALE; }然后从电阻算温度。PT100的电阻-温度关系在-200℃到850℃范围内可以用Callendar-Van Dusen方程:
R(T) = R0 × (1 + A×T + B×T² + C×(T-100)×T³) (T<0℃时C项才有效)
对于T≥0℃:
R(T) = R0 × (1 + A×T + B×T²)
其中R0=100Ω,A=3.9083e-3,B=-5.775e-7。反解T:
T = (-A + sqrt(A² - 4B(1 - R/R0))) / (2B)
这个公式在0到850℃精度很高,误差小于0.01℃。负温度段要用C项,C=-4.183e-12,但反解没有解析式,一般用查表加插值。
float RTD_ResistanceToTemp(float r) { float A = 3.9083e-3f; float B = -5.775e-7f; float R0 = 100.0f; float ratio = r / R0 - 1.0f; float disc = A*A - 4.0f*B*ratio; if (disc < 0) return -999.0f; // 错误 float t = (-A + sqrtf(disc)) / (2.0f*B); return t; }注意sqrtf要包含math.h,PIC18F87J50的编译器支持单精度浮点,但速度不快。如果对实时性要求高,可以预先算好电阻-温度表,用线性插值查表,速度快很多。
4.4 软件滤波:滑动平均加中值
工业现场噪声大,单次采样值可能跳变。我一般用滑动平均加中值滤波的组合。先连续采5个点,去掉最大最小,剩下3个取平均。这样既能抑制脉冲噪声,又能平滑随机噪声。
#define FILTER_SIZE 5 int32_t filter_buf[FILTER_SIZE]; uint8_t filter_idx = 0; int32_t Filter_AddSample(int32_t new_sample) { filter_buf[filter_idx] = new_sample; filter_idx = (filter_idx + 1) % FILTER_SIZE; // 复制到临时数组排序 int32_t temp[FILTER_SIZE]; for (int i = 0; i < FILTER_SIZE; i++) temp[i] = filter_buf[i]; // 冒泡排序 for (int i = 0; i < FILTER_SIZE-1; i++) { for (int j = 0; j < FILTER_SIZE-1-i; j++) { if (temp[j] > temp[j+1]) { int32_t t = temp[j]; temp[j] = temp[j+1]; temp[j+1] = t; } } } // 去掉最大最小,取中间三个平均 return (temp[1] + temp[2] + temp[3]) / 3; }这个滤波器的延迟是5个采样周期,20SPS下就是250ms,对于温度这种慢变量完全可以接受。如果要求更快响应,可以把FILTER_SIZE降到3,但噪声抑制会差一些。
5. 常见问题与排查技巧实录
5.1 读数跳变严重怎么办
这是最常见的抱怨。先分清楚是随机跳变还是有规律的周期性跳变。随机跳变一般是噪声,周期性跳变可能是工频干扰或者ADC配置问题。
排查步骤:先把ADS122U04设成单次转换模式,用示波器看DRDY信号和SPI时钟,确认时序没问题。然后短接模拟输入,看ADC输出码的峰峰值。如果短接时噪声就很大,说明是ADC本身或者电源问题。检查AVDD纹波,用示波器AC耦合看,峰峰值应该在100μV以下。如果电源没问题,检查参考电压,REFP和REFN之间的电容是不是焊好了。
如果短接时噪声正常,接上RTD才跳,那就是传感器或者引线引入的干扰。检查RTD引线是不是跟动力线走在一起了,如果是,分开走或者用屏蔽线。屏蔽层单端接地,接在电路板的地上,不要两端都接,否则形成地环路。
还有一个容易被忽略的点:ADS122U04的输入多路复用器在切换通道时会有电荷注入,如果信号源内阻高,恢复时间不够,读数就会跳。解决办法是在模拟输入前面加RC滤波,电阻100Ω到1kΩ,电容100nF,给电荷注入提供低阻泄放路径。
5.2 温度读数整体偏移怎么校准
如果所有读数都偏同一个方向,比如总是高2℃,那是系统误差,可以校准掉。校准方法:把RTD放到冰水混合物里(0℃),读ADC码,算出实际电阻,跟理论值100Ω比较,得到一个偏移量。然后在软件里减去这个偏移。
但要注意,偏移可能来自多个地方:参考电阻精度、PGA增益误差、RTD本身精度。如果偏移随温度变化,那就是温漂问题,单点校准解决不了。这时候要做两点校准:0℃和100℃各校一次,算出一个增益误差和一个偏移误差,软件里做线性修正。
我一般建议客户用0.01%精度的参考电阻,RTD选A级(±0.15℃@0℃),这样不校准也能做到±0.3℃以内。如果要±0.1℃,必须校准,而且校准用的温度源精度要至少高一个数量级。
5.3 SPI通信失败怎么查
SPI通信失败的表现是读回来的数据全是0或者全是0xFF。先检查硬件:CS、SCLK、DIN、DOUT四根线有没有接反,特别是DIN和DOUT,很多人会搞混。ADS122U04的DIN是MCU输出、ADC输入,DOUT是ADC输出、MCU输入。
然后用示波器看SCLK有没有波形,频率对不对。如果SCLK正常但DOUT没反应,检查CS是不是一直拉低。ADS122U04要求每次读写操作CS都要拉低再拉高,如果CS一直低,ADC可能不响应。
还有一个坑:ADS122U04上电后需要至少一个SPI时钟周期来初始化内部状态,如果MCU上电后立刻发命令,可能第一个命令被忽略。我一般在初始化SPI后延时10ms再配置ADC。
如果时序都对但数据还是不对,检查SPI模式。ADS122U04要求CPOL=0、CPHA=1,也就是模式1。PIC18F87J50的SSPSTAT寄存器里CKP和CKE位要设对。CKP=0对应空闲低电平,CKE=1对应下降沿发送、上升沿接收。设错了数据会移一位,读出来全是错位的数据。
5.4 常见问题速查表
| 现象 | 可能原因 | 排查方法 | 解决措施 |
|---|---|---|---|
| 读数跳变±5℃以上 | 电源纹波大 | 示波器AC耦合测AVDD | 加LDO,增加去耦电容 |
| 读数整体偏高2℃ | 参考电阻精度差 | 万用表测参考电阻实际值 | 换0.1%精度电阻,软件校准 |
| 负温度读成正值 | 符号扩展遗漏 | 检查代码是否补高8位 | 加符号扩展逻辑 |
| SPI读回全0 | CS未拉低或时序错 | 示波器看CS和SCLK | 检查CS控制,确认SPI模式1 |
| 温度响应迟钝 | 滤波太强或速率太低 | 检查DR和滤波参数 | 提高速率,减小滤波窗口 |
| 多点采集互相干扰 | 多路复用切换太快 | 切换后延时再采样 | 增加通道切换后的稳定时间 |
| 高温段误差变大 | RTD非线性或自热 | 对比标准温度计 | 用Callendar-Van Dusen全公式,减小激励电流 |
5.5 实操心得:几个文档里不会写的细节
第一个,ADS122U04的DRDY引脚在连续转换模式下会周期性拉低,但如果你在DRDY拉低后没有及时读数据,下一个转换周期开始时DRDY会再次拉低,旧数据就丢了。所以DRDY中断服务程序里要尽快读数据,别在里面做浮点运算。我的做法是中断里只读raw值存到缓冲区,主循环里再做滤波和温度换算。
第二个,PIC18F87J50的SPI模块在高速时钟下,如果SSPIF标志没及时清除,会阻塞下一次传输。我一般在SPI_Transfer函数里等SSPIF置位后立刻清除,再返回数据。别用延时等待,不同主频下延时不准。
第三个,RTD引线如果很长,比如超过10米,引线电容会跟ADS122U04的输入电容形成低通,影响建立时间。这时候要降低SPI速率,或者增加通道切换后的延时。我有个项目引线15米,通道切换后延时2ms才采样,数据才稳定。
第四个,校准的时候别只校一个温度点。我见过一个客户在25℃室温下校准,结果用到80℃时误差1.5℃。后来发现是参考电阻的温漂导致的,换5ppm/℃的电阻后误差降到0.2℃。所以校准至少要在工作温度范围的两端各取一个点。
6. 系统集成与现场调试经验
6.1 从实验室到现场:环境差异带来的挑战
实验室里跑通不代表现场能用。我印象最深的一个HVAC项目,实验室里精度做到±0.05℃,装到楼顶空调机组上,读数每隔几秒跳一次,幅度有1℃。排查了半天,发现是机组里的变频器干扰。变频器开关频率8kHz,谐波丰富,通过空间辐射耦合到RTD引线上。
解决办法分三步:第一步,RTD引线换成双绞屏蔽线,屏蔽层接机柜地。第二步,在ADS122U04模拟输入前加共模扼流圈,抑制共模干扰。第三步,把ADC的转换速率从20SPS降到5SPS,数字滤波器对低频干扰抑制更强。三步做完,跳变降到0.1℃以内。
这个经验告诉我,工业现场的EMC问题,光靠电路设计不够,布线、屏蔽、接地都要考虑。特别是RTD这种高阻抗小信号传感器,引线就是天线,不屏蔽等于把干扰直接引到ADC输入端。
6.2 多点温度采集的通道切换策略
HVAC系统经常要测多个点的温度,比如回风、送风、新风、盘管表面。ADS122U04有4个通道,可以接4路RTD。但通道切换时有个问题:多路复用器切换后,输入电容需要充电到新的电压,如果信号源内阻高,充电时间不够,读数会偏低或偏高。
我的做法是:切换通道后,先丢弃第一次转换结果,从第二次开始读。因为ADS122U04在连续转换模式下,通道切换后的第一次转换可能不准确。具体操作是:写配置寄存器切换MUX,等DRDY拉低,读一次数据但不使用,再等DRDY拉低,读第二次数据才用。
如果对速度要求高,可以在每个通道的输入前面加一个缓冲运放,比如OPA333,输入偏置电流只有10pA,不会影响RTD测量,但输出阻抗低,多路复用器切换后能快速建立。这样每次切换后第一次转换就能用,吞吐率翻倍。
6.3 低功耗设计:电池供电场景的取舍
有些HVAC无线传感器节点用电池供电,功耗很关键。ADS122U04在20SPS连续转换模式下功耗大约300μA,PIC18F87J50跑8MHz时大约5mA,加起来对电池来说还是太大。这时候要改成单次转换模式,MCU平时休眠,定时器唤醒后启动ADC,转换完读数据,再休眠。
单次转换模式下,ADS122U04从休眠到转换完成大约需要1ms(20SPS时)。MCU唤醒后发启动命令,等DRDY拉低,读数据,然后发关机命令。整个周期大约5ms,如果每分钟测一次,平均电流可以降到10μA以下。用2000mAh的电池,理论能跑好几年。
但要注意,ADS122U04从关机状态唤醒后,内部参考和PGA需要建立时间。手册里写的是大约100μs,但实际测试下来,如果要求高精度,最好等1ms再启动转换。我一般设成唤醒后延时2ms再发启动命令,确保内部电路稳定。
6.4 温度数据的线性化与上报
从ADC码到温度值,中间要经过电阻计算、线性化、滤波、单位换算。如果MCU还要跑通信协议,计算量不小。PIC18F87J50没有硬件浮点,单精度浮点运算靠软件模拟,一次sqrtf大约要几百个周期。如果每秒采10次,每次都要算sqrtf,CPU占用率会很高。
优化方法:用查表加线性插值代替浮点运算。预先在Flash里存一张电阻-温度表,比如每10℃一个点,从-50℃到150℃共21个点。查表时先找到电阻落在哪个区间,然后线性插值。这样只需要整数运算和一次除法,速度快很多。
// 简化的查表插值示例 const uint16_t r_table[] = {8031, 8427, 8822, 9216, 9610, 10000, 10390, 10779, 11167, 11554, 11940, 12324, 12707, 13089, 13470, 13850, 14229, 14606, 14982, 15357, 15731}; // 对应-50℃到150℃,每10℃一个点,单位0.01Ω int16_t ResistanceToTemp(uint16_t r_centiohm) { if (r_centiohm <= r_table[0]) return -500; if (r_centiohm >= r_table[20]) return 1500; for (int i = 0; i < 20; i++) { if (r_centiohm < r_table[i+1]) { uint16_t r_lo = r_table[i]; uint16_t r_hi = r_table[i+1]; int16_t t_lo = -500 + i * 100; int16_t t_hi = t_lo + 100; return t_lo + (int16_t)((int32_t)(r_centiohm - r_lo) * 100 / (r_hi - r_lo)); } } return 1500; }这个函数返回的温度单位是0.01℃,用int16_t表示,范围-5000到15000,对应-50℃到150℃。整数运算,速度快,精度在0.1℃以内,对HVAC应用足够了。
6.5 现场调试工具的准备
去现场调试,别只带个万用表。我一般带这几样:一台带SPI解码功能的示波器(比如带MSO的),一个USB逻辑分析仪(便宜的那种就行),一个高精度温度计(作为参考),还有几个不同阻值的精密电阻(用来模拟RTD)。
到了现场先别急着改代码,先用精密电阻代替RTD,看读数对不对。如果电阻模拟时读数准,接上RTD不准,那就是传感器或者引线问题。如果电阻模拟时就不准,那是电路或者软件问题。这一步能快速定位问题方向。
逻辑分析仪抓SPI波形,看命令和数据对不对。有时候是MCU发命令时CS拉低太晚,或者SCLK太快导致ADC没响应。逻辑分析仪能直观看到时序问题,比示波器方便。
高精度温度计用来做现场校准。如果现场没有冰水混合物,可以用温度计的读数作为参考,在软件里做单点偏移校准。虽然精度不如实验室校准,但能消除大部分系统误差。
7. 方案扩展与变体思路
7.1 从PT100扩展到热电偶
如果应用场景温度超过500℃,PT100就不合适了,得用热电偶。ADS122U04也能接热电偶,但需要冷端补偿。冷端补偿可以用ADS122U04的第四个通道接一个PT1000或者LM35,测电路板温度作为冷端温度。软件里把热电偶的热电动势加上冷端对应的热电动势,再查表得到实际温度。
热电偶的信号比RTD小得多,K型热电偶在100℃时输出大约4mV,需要PGA=128才能充分利用ADC量程。但PGA=128时,ADS122U04的输入共模范围很窄,要仔细设计偏置电路。我一般用两个等值电阻分压,把热电偶的一端偏置到VREF/2,另一端接ADC负输入。
7.2 多片ADS122U04级联做高密度采集
如果通道数超过4个,可以用多片ADS122U04,每片用一个独立的CS引脚,共用SPI时钟和数据线。PIC18F87J50有多个I/O口,可以控制8片甚至16片。每片的DRDY可以接到不同的中断引脚,或者用一个二极管或门合并成一个中断,然后在中断里轮询各片的DRDY状态。
级联时要注意电源去耦,每片ADS122U04的AVDD都要单独去耦,不能共用一颗电容。SPI时钟线要加缓冲器,因为多片并联时容性负载大,时钟边沿会变缓。我一般用74LVC244做缓冲,每4片一组。
7.3 加入隔离:工业现场的安全与抗扰
工业现场有时候要求传感器和主控之间电气隔离,防止地环路或者高压串扰。ADS122U04的SPI接口可以加数字隔离器,比如ADuM1401,把MCU和ADC隔开。但隔离后ADC的电源也要隔离,用一个小型DC-DC模块,比如B0505S,给隔离侧的ADS122U04供电。
隔离会引入额外的噪声和延迟,SPI速率要降到1MHz以下。隔离侧的电源纹波也要处理好,DC-DC后面加LDO和LC滤波。我做过一个项目,隔离后噪声反而比不隔离大,后来发现是DC-DC的开关频率耦合到模拟电源上了,换了低噪声的DC-DC模块才解决。
7.4 用PIC18F87J50的USB做数据记录
PIC18F87J50自带USB,可以做一个简单的数据记录仪。温度数据存到外部EEPROM或者SD卡里,通过USB导出到PC。Microchip的USB协议栈有现成的CDC类驱动,PC端识别成串口,用串口助手就能看数据。
USB供电时,整个系统可以从USB取电,不需要外部电源。但USB的5V要降到3.3V给MCU和ADC,用一颗LDO就行。注意USB的地和模拟地要单点连接,避免数字噪声串到模拟部分。
8. 写在最后的一些个人体会
这套ADS122U04IPWR加PIC18F87J50的温度测量方案,我从2019年第一次用在某个洁净室空调控制项目上,到现在陆陆续续改了十几版。最大的感受是:高精度测量是个系统工程,ADC再好,电源不干净、布局不合理、软件滤波不到位,照样出不来好结果。
新手最容易犯的错是只盯着ADC的分辨率,觉得24位就一定比12位准。实际上,如果参考电阻温漂大、电源纹波高、PCB布局差,24位ADC的有效位数可能只有14位,跟12位比也好不到哪去。我一般建议先把电源和参考做好,再考虑ADC选型。
另一个体会是,校准比选型更重要。再好的器件也有误差,工业现场的温度测量,不校准很难做到±0.5℃以内。校准不丢人,关键是要有可追溯的校准方法和定期校准的计划。
最后说一个实用技巧:如果现场调试时发现温度读数有规律地缓慢漂移,比如每小时漂0.5℃,先别怀疑ADC,去看看参考电阻周围有没有发热元件。我有一次把参考电阻放在LDO旁边,LDO发热导致电阻温漂,读数跟着漂。把电阻挪到板子边缘,远离热源,问题就解决了。这种问题,数据手册上不会写,只有踩过坑才知道。