ADS122U04IPWR配PIC18F46K22的工业级高精度温度采集方案
去年给一套中央空调系统的控制柜做改造,客户要求在 -40℃ 到 120℃ 范围内把温度测准到 ±0.2℃,传感器分布最长近 30 米,现场还有变频器和接触器产生的强电干扰。试过几轮方案,最后定型下来的组合是 ADS122U04IPWR 这颗 24 位 ΔΣ ADC 配合 PIC18F46K22 单片机。这套方案不算新,但胜在稳定、成本可控,特别适合工业现场和 HVAC 这类环境复杂、传感器分散、布线受限的温度测量场景。如果你在做热电偶或 RTD 采集,正被模拟小信号长线传输折腾,或者想用更省心的 UART 接口代替 SPI,这篇文章应该能给你一个可以直接参考的工程化路径。
1. 项目背景与硬核选型思路
1.1 工业/HVAC 测量场景,难在哪
很多人觉得 HVAC 温度测量很简单,无非就是读个温度、上个 PID。可真到了工程现场,问题全冒出来了。风道里的温度探头可能装在 20 米外,水管表面温度传感器可能跟变频器动力线走同一个桥架,压缩机组启动的瞬间,空间里的工频干扰、脉冲干扰全部耦合进传感器线。这时候如果用普通单片机内置 ADC,或者用一颗凑合的外部 12 位 ADC,读取出来的数据跳得根本没法用。
温度传感器的输出信号本来就小。K 型热电偶的灵敏度大约 40μV/℃,要分辨 0.1℃ 就需要 4μV 级别的电压分辨率,再考虑漂移和噪声,至少要能在 0.1μV 到 1μV 的尺度上稳定测量。12 位 ADC 即使加了放大器,也很难做到这种精度。所以工业测温领域的核心需求,并不是“能不能测到温度”,而是“在有干扰、有长线、有温度梯度的情况下,能不能稳定测准”。
这也是我一开始就把注意力放在高分辨率 ΔΣ ADC 上的原因。ΔΣ ADC 的过采样和数字滤波特性,天然对带内噪声有压制作用,24 位分辨率又给了足够的裕量。主控端再配合软件滤波,才能真正在工况恶劣的地方跑出可用的温度曲线。
1.2 为什么我相中 ADS122U04IPWR,而不是普通 ADC
ADS122U04IPWR 是 TI 的 24 位 ΔΣ ADC,带 4 通道输入、内置可编程增益放大器和内部温度传感器。它最特别的地方是通信接口是 UART,不是传统的 SPI。多花这一层接口选择的思考,实际使用中省了很多麻烦。
先说 SPI。SPI 速度快,逻辑协议简单,但它的同步时钟线 SCK 在长线传输时特别脆弱。线一长,时钟边沿变形,MISO 数据就错位。工业现场传感器分散,如果你想把 ADC 放在主控板上,传感器线是模拟信号长距离进来,那得处理屏蔽、阻抗匹配、干扰耦合一堆事。如果你想把 ADC 放到传感器端子旁边,用数字信号传回主控,那 SPI 的时钟线距离问题又会卡住你。UART 没有时钟线,就只有 TX、RX、GND,三根线走 20 到 30 米,降到 9600 波特率,反而比 SPI 稳健得多。
另外,ADS122U04IPWR 的 24 位分辨率配合 PGA,可以把热电偶的微伏级信号直接放大。增益可以从 1 倍做到 128 倍,内置参考电压 2.048V,还带内部温度传感器,冷端补偿不用外挂专用芯片。这样整个模拟前端就很简洁,外围元件少,故障率也低。
1.3 PIC18F46K22 在这套方案里扮演什么角色
PIC18F46K22 是这个系统的“大脑”。它是一款经典的 8 位单片机,成本低、供货稳、抗干扰能力强。很多人觉得 8 位机有点过时,但做工业温度采集这种任务,它对性能要求并不极端,反倒是对外设完整度、稳定性和开发熟悉度要求高。PIC18F46K22 有多组 UART、定时器、PWM、比较器,还有内置 EEPROM,标定参数可以直接存里面,不用外挂存储芯片,这对现场调试非常友好。
具体到项目里,它用一路 UART 和 ADS122U04IPWR 通信,用另一路 UART 跟触摸屏或者上位机协议对接,定时器负责采样节拍,普通 IO 管 DRDY 和复位引脚。整个资源占用非常宽松,没压力,程序写起来也能从容不迫。
1.4 整体数据流
这套系统的数据流通路很清晰:温度传感器先进入 ADS122U04IPWR,ADC 把模拟量变成 24 位数字码,通过 UART 传到 PIC18F46K22,主控再根据传感器类型做电压换算、冷端补偿、线性化,最后得到实际温度值,再走 Modbus 或者自定协议上报给控制器或云平台。
我的做法是把 ADS122U04IPWR 直接布置在传感器接线端子附近,传感器进来最多几厘米模拟走线,之后就是数字 UART 信号长线传给主控。这样做,现场那种“模拟小信号长线传输”的噩梦直接消失,抗干扰能力提升一个量级。
2. 硬件设计:细节决定成败
2.1 供电、基准与输入滤波
ADS122U04IPWR 的模拟电源和数字电源可以共用 3.3V,但最好是模拟电源单独走线,然后在 AVDD 与 DVDD 引脚上分别放置去耦电容。我的习惯是每个电源引脚放 10μF 钽电容和 0.1μF 陶瓷电容组合,陶瓷电容必须尽量靠近引脚。不要图省事只放一个 0.1μF,因为 ADC 内部的数字逻辑开关会产生高频瞬态电流,需要小电容滤波;同时模拟部分的工作电流变化也会产生低频噪声,需要大电容做储能。
基准电压方面,热电偶测量优先用内部 2.048V 参考。因为热电偶信号放大后范围通常只有几十毫伏,内部基准的温漂已经足够,再用外部高精度基准对最终结果提升微乎其微,纯属浪费成本和 PCB 面积。如果做 RTD 比例测量,那又另说,通常需要外部基准或者用激励电流比例方案。
输入滤波是很多人容易忽略的。热偶信号从端子上来,必须经过一个 RC 低通滤波,我常用串联 1kΩ 电阻、并联 10nF 电容,构成大约 16kHz 截止频率。这个滤波器既限制射频干扰,也给 ADC 输入端提供一定的容性储能,对提高 EMC 非常有帮助。但要注意,串联电阻不是越大越好,太大会和偏置电流作用产生误差。ADS122U04 的输入偏置电流已经是 nA 量级,1kΩ 电阻只产生微伏级的电压降,可以忽略,但如果用 100kΩ,就会产生明显误差。
2.2 与 PIC18F46K22 的接口连线
硬件连接上,最重要的一点是 ADS122U04 的 TX 要接 PIC 的 RX,ADS 的 RX 要接 PIC 的 TX,不能接反。这个看起来基础,但实际调试时十有八九会翻车,尤其当你用的排线是对等直连时。
DRDY 引脚必须接一个普通 IO 口,不要省。它表示数据转换完成,拉低后主机才能读取数据。如果不用 DRDY,只靠延时去读,很容易读到不完整的转换结果,或者在一半数据更新时读到错误值。RESET 引脚也接 IO 口,程序上电时主动复位一次 ADC,排除现场上电时序导致的初始化异常。
如果现场干扰很大,比如传感器线跟动力线并行超过十米,我会在 UART 信号线上串 470Ω 电阻,并加 TVS 管。更严格的隔离方案,则用数字隔离器把主控电源和 ADC 电源完全隔开,两边只用隔离电源供电。这会增加成本,但很多工业项目值得做。HVAC 设备里,大部分情况下串电阻加共地已经够稳定了。
2.3 PCB 布线里的那些“做错才懂”的点
温度采集 PCB 设计的核心,一个是模拟输入小区干净,一个是电源去耦合理。热电偶输入走线进入 ADC 之前,底下必须铺完整的地平面,不能有数字信号横穿。我踩过很深的坑:第一次布板时图省事,把 SPI Flash 的时钟线从 ADC 底下穿过,结果 ADC 输出噪声直接大了好几倍,后来把数字线全部赶到另一层才解决。
如果你板上有继电器、蜂鸣器、DC-DC 电源,这些噪声源要尽量离 ADC 远。DC-DC 的开关节点尤其要远离模拟地,最好用一个独立的小模拟地岛,然后在 ADC 的地引脚附近单点连接到数字地。如果输入线必须走板边,可以用一圈保护环围住,配合过孔屏蔽。
另外,热电偶输入属于小信号,传感器端子直接用黄铜或端子排会有热电动势影响。要求高的场合,输入端子的金属材质和冷端等温设计都要考虑。这个在后面标定部分再展开,但布板阶段就要预留好等温块位置。
3. 寄存器配置与 UART 控制协议
3.1 ADS122U04 的 UART 协议基本认知
ADS122U04 不像 SPI 接口那样直接给寄存器地址片选,它使用 UART 半双工/全双工模式,通过命令字控制。上电后,芯片默认采用固定波特率,但具体是 9600 还是其他,要根据数据手册的设置和地址引脚状态判断。使用前务必先执行复位命令,让芯片进入已知状态。
UART 帧格式建议配置为 1 位起始位、8 位数据、1 位停止位。要不要加校验位?我的经验是,工业现场强烈建议加。UART 本身没有 ACK,数据翻转或干扰导致错误帧,校验能挡掉很大一部分。如果总线上只挂一个 ADC,可以简化命令流程;如果挂了多个,就需要利用芯片地址引脚设置不同地址,然后在命令帧里带上地址。
这段写起来很抽象,实际调试时我习惯先用 9600 波特率,逻辑分析仪抓一遍波形,确认命令帧和返回帧跟数据手册对得上,再调到目标波特率。如果一上来就调 115200,遇到问题很难分清是配置问题还是波形问题。
3.2 增益怎么选:用热电偶信号范围反推
增益选择是整个配置里最关键的一步。ADS122U04 的 PGA 增益越高,分辨率越高,但差分输入范围越小。对 K 型热电偶,温度 -40℃ 到 150℃ 对应的热电势大约 -1.5mV 到 6mV。如果设 PGA=128,内部参考 2.048V,差分输入范围是±16mV,完全覆盖。这个配置下理论 LSB 大约为 2nV,但实际电路噪声通常会到零点几微伏,已经足够把温度分辨率做到 0.01℃ 级别。
如果现场要测到 600℃ 以上,K 型热偶信号会到 25mV 甚至更高,再用 PGA=128 会满量程溢出。这时候要把增益降到 64 或者 32。所以在设计之初,要先确定测温上限,还要留出超量程的冗余,一般按信号上限只占满量程 60% 到 80% 来选增益。
采样速率也同样重要。ADS122U04 这种 ΔΣ ADC,数据速率越高,片内数字滤波器的带宽就越宽,噪声越大。工业温度本来就变化慢,没必要追高速。我通常设置为 20SPS 或 40SPS,配合数字滤波之后,现场数据相当平稳。
3.3 配置流程与读取时序
我的标准初始化流程如下:
- 复位 ADC,等待复位完成。
- 写入配置寄存器 0:选择差分输入通道,设置 PGA 增益。
- 写入配置寄存器 1:设置数据速率、转换模式(连续或单次)。
- 写入配置寄存器 2:选择内部参考,使能内部温度传感器。
- 读取设备 ID 或状态寄存器,确认通信链路正常。
- 等待 DRDY 拉低,读取 3 字节转换结果。
这里有个实用的细节:每次修改配置寄存器之后,建议丢弃随后第一次转换的数据。因为寄存器改动后内部数字滤波器需要几个周期重新收敛,直接读会拿到错误结果。很多刚上手的人漏了这一步,出现“改增益后读数不准”的问题。程序里可以做成切换通道或配置后自动丢弃两拍数据,简单有效。
4. 软件实现:PIC18F46K22 上的完整温度采集
4.1 EUSART 初始化
我用 Microchip XC8 编译器写代码。初始化 PIC18F46K22 的 UART1,按常见公式设置波特率:
#define FOSC 16000000UL #define BAUD 115200UL void UART1_Init(void) { unsigned int brg_value = (FOSC / 4UL / BAUD) - 1; SPBRGH1 = (brg_value >> 8) & 0xFF; SPBRG1 = brg_value & 0xFF; TXSTA1bits.SYNC = 0; // 异步模式 TXSTA1bits.BRGH = 1; // 高速波特率 TXSTA1bits.TXEN = 1; // 使能发送 RCSTA1bits.SPEN = 1; // 使能串口 RCSTA1bits.CREN = 1; // 使能接收 }这个初始化代码只是基础,如果你的项目还涉及接收中断或发送中断,可以再加PIE1寄存器配置。实际项目中不要让主循环等待接收,尽量用中断和环形缓冲区,否则在处理多路传感器时容易丢数据。
4.2 命令收发与数据拼接
ADS122U04 的每个命令帧按数据手册组织。我不会在这里贴死板的寄存器值,因为具体命令码需要和你的芯片版本严格核对。我用宏定义封装,看起来直观,也方便维护。
void UART1_SendByte(uint8_t d) { while(!PIR1bits.TX1IF); TXREG1 = d; } uint8_t UART1_ReceiveByte(void) { while(!PIR1bits.RC1IF); return RCREG1; } void ADS_SendCmd(uint8_t cmd_len, uint8_t *cmd) { for (uint8_t i = 0; i < cmd_len; i++) { UART1_SendByte(cmd[i]); } } int32_t ADC_ReadData(void) { uint8_t buf[3]; uint8_t cmd[3] = { READ_DATA_CMD, 0x00, 0x00 }; ADS_SendCmd(3, cmd); buf[0] = UART1_ReceiveByte(); buf[1] = UART1_ReceiveByte(); buf[2] = UART1_ReceiveByte(); int32_t raw = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | ((int32_t)buf[2]); if (raw & 0x800000) // 24 位补码转有符号 raw -= 0x1000000; return raw; }这段代码里 READ_DATA_CMD 需要根据数据手册定义成具体字节。重点在 24 位补码转换,很多新手直接拿无符号值算温度,结果 0℃ 以下全乱套。
4.3 热电偶、RTD 的换算公式
ADC 拿到的是裸码,需要转换成电压:
#define VREF 2.048 #define PGA 128.0 double ADC_To_Voltage(int32_t raw) { return (double)raw * (2.0 * VREF / (PGA * 8388608.0)); }这里的分母是 2^23,对应 24 位补码的正半范围。有人用 2^24 做分母,算出来数值偏了一倍,要注意。
得到电压后,如果是热电偶,需要先加冷端补偿。冷端补偿的思路是:假设冷端温度为 T_cold,查热电偶分度表得到冷端对应的热电势 E(T_cold)。ADC 测得的电压 V_meas 等于热端热电势减去冷端热电势。真实热电势为:
E(T_hot) = V_meas + E(T_cold)
再用 E(T_hot) 反查温度得到 T_hot。这个换算流程一定要写清楚,否则程序里经常出现“把冷端补偿加反了”的问题。
RTD 的换算相对直接,但要注意比例测量。如果使用恒流源激励 PT100,1mA 激励时,0℃ 对应 100Ω 和 100mV,100℃ 对应 138.5Ω 和 138.5mV。用 ADC 分别采集 RTD 电压和已知参考电阻电压,通过比值计算电阻,再查表得到温度。这样可以消除激励电流的漂移。
4.4 冷端补偿的真正难点
数据手册上写“利用内部温度传感器做冷端补偿”,但内部温度传感器测的是芯片附近 PCB 温度,不是真正的热电偶冷端温度。想要冷端补偿准确,必须让热电偶的冷端、接线端子、ADC 芯片处在同一个热平衡体系中。
我的做法是让 ADC 尽量靠近接线端子,PCB 在这块区域不要铺大面积铜箔去散热,也不要放置功率器件。端子材料的热阻也影响结果,质量好的接线端子温度一致性更好。如果你把 ADS122U04 放在远离端子的主板上,冷端补偿误差会随着环境温度梯度和风道气流明显变大,最终系统精度很难压进 ±0.5℃。
内部温度传感器本身也有误差,所以标定阶段要把这个偏差修正掉。比如用标准温度计实测端子温度,和 ADC 内部温度读数比较,得到一个固定的偏移量,存入 EEPROM。
5. 系统标定与误差管理
5.1 需要标定的几项误差
即使 ADS122U04IPWR 和 PIC18F46K22 都正常工作,系统仍然存在不可忽略的误差。PGA 的增益误差通常在 0.02% 左右,对一个 10mV 信号会产生 2μV 误差,约等于 0.05℃。ADC 本身的零点偏移也会带来少量误差。冷端温度传感器的绝对误差可能达到 ±0.5℃,这是热电偶系统误差的大头。还有 PCB 上的热电动势、端子接触热电动势,都是小量但不可忽视。
所以正式交付前,一定要整体标定。标定不是只写个“软件校准系数”,要区分增益误差、零点偏移、冷端偏移三部分。
5.2 冷端温度标定
冷端标定最实用的办法是用一个高精度温度计,探头紧贴热电偶端子,等热平衡后读取实际端子温度,同时通过 ADS122U04 读取内部温度传感器的值。差值就是一个固定偏移。现场没有高精度温度计时,可以用冰水混合物做 0℃ 参考,但要注意冰水状态下端子和 ADC 都必须达到热平衡,不能只把探头埋进去就算完。
热电偶本身的非线性用查表法解决。K 型热电偶的 mV-℃ 关系并不是线性,但分段线性查表在单片机里完全够用。我常把 -40℃ 到 150℃ 分成 10℃ 一档,存 20 个电压点,用线性插值算中间值,误差可以控制在 0.1℃ 以内,比多项式计算省事,也不会在低端超差。
5.3 现场精度验证
标定完成后,我是这样验证的:把整个测温系统放进恒温槽,分别设定 -40℃、0℃、50℃、120℃,读取上报温度并和标准铂电阻温度计比较。记录每个点的误差,并连续测试 24 小时观察漂移。
实测下来,这套方案在暖通空调常用区间内,进入稳态后误差基本能控在 ±0.2℃到±0.3℃。如果再把软件采样平均值取到 8 次以上,短时波动也能压得更小。这种效果在工程现场已经算很好了,毕竟现场不具备实验室的等温条件。
6. 实测:HVAC 现场常见问题与排查实录
6.1 数据跳变 / 毛刺
现场最常见的问题是温度数据偶尔跳个大值或者毛刺不断。这类问题通常不是 ADC 坏了,而是干扰从电源、地线或输入端耦合进来。变频器启动瞬间尤其明显。
我的排查顺序是:先看输入线屏蔽层是否可靠接地,再查 ADC 电源去耦是否按照要求放置,然后用示波器测量 DRDY 引脚,确认转换结果是否稳定。软件上可以在主控里加一个中值滤波和滑动平均组合。比如连续取 5 个值,先去掉最大和最小,再对剩下 3 个求平均。这个组合对付尖峰毛刺比单纯滑动平均强得多。
如果干扰出现在可控硅调压或 PWM 控温回路附近,还要注意采样时刻避开关断瞬间。把 ADC 转换开始时间固定到 PWM 周期中间,经常有奇效。
6.2 UART 收不到数据
UART 不通的现场故障也很多。先检查 RX/TX 有没有接反,这是最高频的问题。然后是共地,如果 ADC 侧和主控侧没有可靠的地连接,数字信号根本无法形成回路。逻辑分析仪看波形时,收发都要测,不能只测主机发出端。
如果波形正常但命令无响应,多半是地址或波特率配置不对。波特率误差超过 2% 就可能产生乱码,特别是用内部 RC 振荡器时。PIC18F46K22 的 UART 对波特率误差有容忍度,但建议使用外部晶振或精确校准,不然长帧数据容易尾部落错。
6.3 通道切换后读数偏慢
做多通道温度采集时,切换模拟开关后 ADC 输入端的采样电容需要时间充电,且内部数字滤波器需要重新收敛。所以切换通道后直接读,会读到上一通道的残留。我通常在切换后丢弃前两次转换结果,或者等待 10ms 再开始新一轮转换。
现场感觉就是“某一通道读数半天不更新”,其实不是转换慢,是初始化流程没做完整。把丢弃次数设置成 2 或 3 次之后,系统整体协调多了。
6.4 长线传输衰减解决小技巧
UART 走 30 米时,建议把波特率降到 9600。越高的波特率对线间电容、地线阻抗越敏感,实测 115200 在 20 米普通双绞线上就可能出现边界抖动。9600 波特率即使波形有一些畸变,接收端依然能正确采样。
布线用屏蔽双绞线,屏蔽层在控制柜单端接地。接收端可以并联一个小电容,比如 100pF,对高频噪声有抑制作用。如果是超远距离,干脆用 RS485 收发器,PIC 侧加一个 MAX485,ADC 侧也用一颗,把 TTL UART 转成差分信号,30 米变成 300 米都没问题。
7. 关于这套方案,我想多说一句
ADS122U04IPWR 配 PIC18F46K22 的组合,真正的好用之处不是某一个参数的绝对值,而是它把“模拟小信号采集”和“数字远距离传输”这两件事拆开了:ADC 贴近传感器,信号一进来就转成数字,再用 UART 长传。想通这一点,后面很多设计都顺了。如果再做一个类似项目,我会在硬件设计阶段就把 RS485 接口、隔离电源预留出来,方便现场接更多探头和更长距离。另一个小经验是,所有标定参数一定存进 EEPROM,出厂前写一次,现场只要整机更换,直接读参数,不需要重新标定,能省下大量调试时间。这套方案用完一次,你会愿意在下一个项目里继续用它。