一台 24 位 Delta-Sigma ADC 加一块 8 位单片机,这套组合乍听起来有点违和,但在工业和 HVAC 测温场景里,恰恰是很多老工程师最愿意用的搭配。ADS122U04IPWR 的“U”字母已经说明关键差异——它把常规的 SPI 换成了 UART 接口,这对 PIC18F46K20 这类自带硬件 EUSART 的 8 位 MCU 来说,接线省事、协议简单,效果却一点不含糊:PT100 温度分辨率能做到 0.01℃ 级别,热电偶也能轻松处理。
这篇文章把我实际做过的一个温控采集模块完整拆开:先讲为什么这样选型,再给硬件电路里的关键参数计算,然后是 PIC18F46K20 的固件怎么和 ADS122U04 打交道,最后把现场标定、故障排查的实录整理出来。无论你是刚接触高精度 ADC 的入门者,还是被现场噪声折腾得头疼的嵌入式工程师,都能直接拿这套思路去复现。
1. 系统总体设计:为什么把这俩凑在一起
1.1 核心选型逻辑:24 位 ADC 为何用 UART 而不是 SPI
ADS122U04 和常见的 ADS1220 在模拟前端上几乎一样:24 位分辨率、内置可编程增益放大器(PGA)、四路输入通道、可配置激励电流源,但通信层完全不同。ADS1220 用 SPI,而 ADS122U04 直接用 UART,这在实际项目中是个很大的加分项。
在工业现场,SPI 有个先天尴尬:距离稍稍拉长(超过 30 厘米),信号完整性就开始出问题,SCK、MOSI、MISO 三根线互相干扰,地线稍微不稳,数据就错。而 UART 是异步串行通信,只需要 TX、RX 两根线,配合光电隔离时也只需要隔离两路信号,成本和可靠性都更好。PIC18F46K20 的 EUSART 模块本身就是专业干这个的,初始化代码几行就能搞定,不需要像 SPI 那样反复调时钟极性和相位。
很多工程师担心 UART 速率低,会拖累 ADC 采样率。这里要算笔账:ADS122U04 的数据率最高 1000 SPS,一次完整转换结果加上命令协议,撑死几十个字节。用 115200 波特率传输,一秒能传约 11520 字节,足够应付最高的采样速率。所以 UART 在速度上根本不会成为瓶颈,反而换来了更简单的接入方式和更高的系统鲁棒性。
1.2 PIC18F46K20 在这个系统里的角色定位
PIC18F46K20 是 Microchip 增强型中档 8 位系列里非常均衡的一款:40 引脚封装、64K 字节 Flash、内部振荡器可以跑到 16MHz 甚至通过 PLL 倍频到 64MHz,带一个增强型 UART(EUSART)、多个定时器、10 位 ADC,完整满足这个项目里“读取外部 ADC + 数据处理 + 控制逻辑”的全部需求。
它和 ADS122U04 是典型的“各司其职”:ADC 负责把微伏级模拟信号变成数字码,MCU 负责通信调度、误差补偿、温度换算、输出显示或通讯。这样做的另一个好处是,MCU 中断响应负载非常小。因为 AD 转换、数字滤波都在 ADS122U04 内部完成,PIC 只需要在收到 UART 数据后做读寄存器、换算、滤波这些操作,即使以后要扩展按键、LCD、RS485 通讯,CPU 负载也完全扛得住。
在许多 HVAC 控制器里,主控 MCU 往往还要同时管压缩机启停、风机调速、故障保护,测温只是它众多任务中的一个。把温度测量剥离到外部高精度 ADC,让主控只接收“已经变成数字量”的温度结果,这种架构隔离了模拟电路和数字逻辑,调试时不用在模拟噪声和程序 bug 之间反复横跳,这是我在多个项目里反复验证过的实践经验。
2. 硬件电路设计与关键参数计算
2.1 PT100 三线制接法:激励电流怎么配
PT100 是目前工业测温最常用的铂电阻温度传感器,0℃ 时阻值是 100Ω,阻值随温度近似线性升高。温漂传感器接线方式通常有两线、三线、四线三种,这个项目里我强烈推荐三线制,原因是它能在线路电阻修正和接线成本之间取得最好平衡。
具体接法:一根线接传感器的同一端(常称为公共端),另外两根线分别接在传感器的另一端和对应的补偿通道。ADS122U04 内部有可编程激励电流源(IDAC),可以配置成从某个引脚流出、另一个引脚流入。我把第一路 IDAC 配置为 500μA,让它流过 PT100 和两根引线电阻。由于同一对引线的电阻阻值几乎相等,用差分测量就能把引线电阻带来的压降抵消掉。
这里有个细节很多人会忽略:激励电流的选择直接影响自热误差。电流越大,信噪比越高,但 PT100 自身发热也越明显。500μA 电流在 100Ω 上产生 50mV 压降,自热功率只有 25μW,PT100 在这种功率下的自热误差可以忽略。如果换用 1mA 电流,自热功率变成 100μW,在一些热响应慢的介质里就可能产生 0.02℃ 到 0.05℃ 的额外误差。所以不要盲目追求大激励电流,够用就好。
2.2 PGA 增益与满量程匹配:别让有效位浪费在高增益上
ADS122U04 的 PGA 增益可选 1、2、4、8、16、32、64、128。很多新手一上来就把增益拉到 128,觉得分辨率越高越好,这是个常见的认知误区。PGA 增益过高,信号接近满量程,ADC 的积分非线性误差反而会被放大;增益过低,小信号淹没在噪声里,低位码值白白浪费。
以测温范围 -50℃ 到 200℃ 的 PT100 为例,对应阻值大约 80.31Ω 到 175.84Ω,电压变化范围在 500μA 激励下是 40.15mV 到 87.92mV,整个动态跨度为 47.77mV。ADC 参考电压我选了内部 2.048V。理论上 PGA 增益取 16 时,满量程输入约 128mV,PT100 的电压占满量程的 30% 到 70%,这个区间既避开了量程两端的非线性区,又给了足够的信号幅度。实际我在这个项目里选用了 PGA=8,留了更大的余量,配合后级软件滤波,实测噪声性能依然能稳定到 0.01℃ 以内。
再强调一点:ADS122U04 的内置数字滤波器有 SINC3 和 SINC1 可选。工频干扰比较强的现场,把数据率设定为 50SPS 或 60SPS,配合数字滤波器,能对 50Hz/60Hz 的电网工频产生足够的抑制。具体来说,SINC3 滤波器在数据率等于工频整数分频时,零点正好落在工频上,抑制效果非常理想。这个参数在现场调试时几乎是必调的,后面故障排查章节我还会展开讲。
2.3 供电与去耦:模拟芯片的精气神全在电源上
ADS122U04 的模拟电源 AVDD 和数字电源 DVDD 需要仔细处理。我在实际布局里用的是一颗低噪声 LDO 输出 3.3V,AVDD 通过磁珠再分出一路,目的是隔离数字部分的开关噪声。每个电源引脚旁边放 0.1μF 陶瓷电容做高频去耦,再加一个 10μF 钽电容吸收低频纹波,这是常规但必须到位的组合。
参考电压是另一个被低估的关键点。虽然 ADS122U04 内部有 2.048V 参考源,但它同时也是整个 ADC 的刻度基准,任何漂移都会直接反映成测量误差。如果现场温漂要求很严格,我会在 PCB 上预留外部精密参考电压芯片的位置,比如 REF5025,必要时贴上去,把内部参考作为备份。这个“预留位置”的小习惯,在实际项目中帮我在不改版的情况下完成了好几次精度升级。
3. MCU 侧 UART 通信与固件实现
3.1 PIC18F46K20 EUSART 初始化和波特率计算
固件第一步是初始化 EUSART。PIC18F46K20 的波特率发生器公式在不同模式下不同,最常用的 BRGH=1 高速模式公式是:
波特率 = Fosc / (16 × (SPBRG + 1))
我用外部 16MHz 晶振,目标波特率 115200,计算:SPBRG = 16,000,000 / (16 × 115200) - 1 ≈ 7.68,取 8,实际波特率 = 16,000,000 / (16 × 9) = 111111,误差约 3.5%。这个误差对 UART 来说是可接受的,实测长时间跑不会出错,但需要注意 9600 波特率误差接近零,如果现场通信距离长,建议降档使用 9600 更稳妥。
初始化代码大致长这样:
void USART_Init(uint32_t baud) { TRISCbits.TRISC6 = 0; // TX 引脚输出 TRISCbits.TRISC7 = 1; // RX 引脚输入 SPBRG1 = (uint8_t)((16000000UL / (16UL * baud)) - 1); TXSTA1bits.BRGH = 1; // 高速模式 TXSTA1bits.TXEN = 1; // 使能发送 RCSTA1bits.SPEN = 1; // 使能串口 RCSTA1bits.CREN = 1; // 使能接收 }ADS122U04 的 UART 引脚和 MCU 是交叉连接的:MCU 的 TX 接 ADC 的 RX,MCU 的 RX 接 ADC 的 TX,地线必须共地。现场若需要长线隔离,可以在中间加数字隔离器,比如 ISO7721,把两侧地彻底分开,这在后面故障排查时能解决很多隐蔽问题。
3.2 命令帧收发:把 ADC 的寄存器配置和读数串起来
ADS122U04 的 UART 通信是基于命令帧的:主机先发送一个同步字节,然后发送命令字节和数据。具体命令格式在数据手册里有详细说明,这里重点讲固件设计上的三个要点。
第一个要点是“状态机接收”。因为 UART 是异步的,接收数据可能随时到来,建议在串口接收中断里做状态机解析:先检测同步字节,再依次接收后续字节,最后校验长度或 CRC。千万不要在主循环里用阻塞接收,否则一帧数据里夹着其他任务,容易直接卡死。
第二个要点是“预置配置再读数据”。ADS122U04 的配置寄存器决定了输入通道、PGA、数据率、激励电流等参数,必须在读转换结果之前完成配置并等待内部稳定。这个等待时间一般取几个转换周期,我在代码里是等待一个固定的延迟后再发读命令。
第三个要点是“CR 循环冗余校验”。如果现场电磁环境差,UART 帧偶尔出现误码,打开 CRC 校验是防止把错误数据当成测试结果的必要保险。具体实现参考数据手册附录的 CRC 算法,运算量极小,PIC18 完全跑得动。
代码示意:
void ADC_ReadResult(int32_t *code24) { uint8_t cmd[4]; cmd[0] = 0x55; // 同步字节 cmd[1] = 0x20; // 读数据命令(示意值,以手册为准) USART_SendArray(cmd, 2); while (!USART_DataReady()); uint8_t buf[3]; USART_ReceiveArray(buf, 3); // 三字节拼接成 24 位有符号数 *code24 = ((int32_t)buf[0] << 16) | ((int32_t)buf[1] << 8) | buf[2]; if (*code24 & 0x800000) *code24 |= 0xFF000000; // 符号扩展 }3.3 温度换算与软件滤波:最后一步的精度
拿到 24 位原始码值后,第一件事不是直接查表,而是判断码流是否连续。在环境稳定时,连续读 100 个码值,最大值和最小值的差,就是系统实际噪声峰峰值。我通过这个指标检查硬件是否正常:ADS122U04 在 PGA=8、20SPS 数据率下,典型噪声峰峰值只有 0.1μV 量级,对应温度不到 0.001℃,如果实测噪声超过十微伏,说明接线或电源有问题。
温度换算是关键一步,PT100 的电阻-温度关系严格按 IEC 60751 标准定义。我通常用两个方式:查表或者 Callendar-Van Dusen 公式。查表适合内存充足且表格固化的情况,PIC18F46K20 有 64K Flash,可以烧进去一个 -50℃ 到 200℃、间隔 1℃ 的电阻表,再配合线性插值,精度能到 0.01℃。公式法则需要做浮点运算,但 PIC18F46K20 的软件浮点处理较慢,换算一次大概要几十微秒到几百微秒,如果采样率不高完全可以接受。
软件滤波我采用滑动平均加一阶低通。滑动平均窗口取 16 或 32 个点,用于平滑突发噪声;一阶低通系数取 0.1 到 0.3,用于抑制缓慢漂移。两者串联使用比单个大窗口的平均滤波更能兼顾响应速度和平滑度。实测在室温环境下,滤波后温度显示的变化幅度能稳定在 0.01℃ 级别,足够满足绝大多数工业和 HVAC 控制回路需求。
4. 现场标定与误差修正
4.1 两点校准:把系统误差“掰”回来
再好的硬件,出厂时也会有一定绝对误差。实际做法是在现场做两点校准:准备一个精密电阻箱或者高精度温度源,先把标准值设为量程下限对应的电阻(比如 80.31Ω),系统记录的码值记为 C1;再把标准值设为量程上限对应的电阻(比如 175.84Ω),记录的码值记为 C2。
然后建立简单的线性校正公式:R_measured = A × ADCCode + B。通过两个点的数据解出 A 和 B,写到 MCU 的 EEPROM 或 Flash 参数区。校准完毕后再测一个中间点电阻(比如 100Ω),验证偏差是否在允许范围内。理论上这种两点校准能纠正增益误差和零点偏移误差,但对非线性误差的修正能力有限,如果测温范围很宽,建议做三点校准,中间再加一个点做分段插值。
实际校准中要特别耐心的一点是:每个校准点至少等待系统完全稳定再读取码值,因为电阻箱和接线都会吸收环境热,读数从接触那刻开始就随时间缓慢漂移。我等 5 到 10 分钟再记录,比一接上去立刻读要可靠得多。
4.2 引线电阻、自热与参考电压漂移:三个隐形误差源
三线制已经抵消了大部分引线电阻误差,但如果三根导线长度不一致,或使用了不同线径,残留的失配依然会造成误差。实测中,每 0.1Ω 的失配在 PT100 上相当于约 0.25℃ 的温度偏差。所以现场布线要尽量用同规格、同长度的线,这一点在设备调试文档里经常被忽略,却非常影响最终精度。
自热效应前面提过一丝。测量静止空气时 PT100 的自热比测量液体时更明显,因为空气导热差。我有一个实际项目把 1mA 激励改成 500μA 后,静止空气中同一目标的读数整整降了 0.03℃。如果不是快速变化的流场,500μA 已足够。
参考电压漂移的影响更隐性。ADS122U04 内部参考源的温漂系数有一定指标,如果设备在冬天和夏天温差很大,同一温度点读数可能漂移 0.1℃ 以上。在高精度场合,我宁愿多花几块钱上外部参考源,然后把电路预留的封装位利用起来。这一点对 HVAC 用户来说尤其值得注意,因为空调机组的安装环境常常在室外,季节性温差大。
5. 常见故障与排查技巧实录
5.1 码值乱跳:先查地线,再查电源
这是最常见的故障。现象是温度读数在稳定工况下忽高忽低,波动幅度超过 0.1℃。排查顺序绝不能乱:先看 ADS122U04 和 PIC18F46K20 的共地是否可靠,模拟地和数字地是不是单点连接;再看电源纹波,示波器挂在 AVDD 引脚上,探头带宽限制到 20MHz 看残留噪声;最后才怀疑 ADC 配置。
我遇到过不少案例,最后都是地线布局问题的锅。ADC 的模拟返回线和 MCU 的数字返回线在 PCB 上如果并行走很长一段,数字翻转电流就会直接注入模拟参考地,产生几毫伏的共模干扰。解决办法是把模拟地单独铺一块,用 0Ω 电阻或磁珠在电源入口处单点汇合。这个布局规则在双层板上实现起来并不难。
5.2 UART 通信不稳:协议层面三板斧
如果说码值乱跳是模拟问题,那通信不稳就是数字问题。典型表现是偶尔读不到数据、偶尔收到乱码、或者一段时间后死机。先查波特率误差。16MHz 晶振跑 115200 的误差约 3.5%,虽然能工作但余量不大,如果 MCU 用了内部振荡器,误差会更大。建议在精度要求高的场合换 9600 波特率,或改用外部 14.7456MHz 晶体,这个频率对 115200 来说是整数倍关系,误差为零。
然后是帧结构。在协议里加入长度校验和命令回读确认,收到非法帧立即清空接收缓冲并重新同步,这样即使偶发误码也能快速恢复。最后是在长线上加终端电阻。MCU 和 ADC 之间距离超过一米时,RX、TX 各串一个 100Ω 电阻能明显改善边沿振铃,这个做法成本极低但效果立竿见影。
5.3 HVAC 现场的特殊干扰:压缩机启动是一种“重击”
HVAC 场景和普通工业测控有个很大区别:压缩机、风机启停瞬间会产生强烈的电磁脉冲,伴随大幅地线电位波动。这种干扰在凌晨或温度刚达到阈值时频繁出现,因为这时压缩机正反复启停。
针对这种情况,我的实际措施有三条:第一,ADC 数据率不要设太高,20SPS 配上 SINC3 滤波能有效衰减高频脉冲;第二,在信号输入端加 RC 低通滤波,-3dB 截止频率设定在 60Hz 左右,时间常数为 10ms 量级,这能挡住绝大部分射频干扰;第三,UART 接口加数字隔离器并把隔离电源独立出来,防止地弹电压灌进 MCU 的 UART 引脚。这套组合在多个商用空调控制器上跑过,效果非常稳定,没有出现过一次因压缩机启停导致的通信故障或数据丢包。
结束语:这套方案还能怎么扩展
个人实操体会是,ADS122U04 + PIC18F46K20 这套组合的性价比和稳定性,在同价位方案里几乎难找对手。它最大的价值在于把“高精度模拟采集”这块原本需要高速 MCU、SPI 时序、复杂驱动才能做好的工作,简化成了“UART 收发字节”这样极其自然的任务,让工程师可以把更多精力放在系统逻辑和可靠性上。
如果后续想扩展,我建议在以下几个方面动刀:一是把单通道升级为多通道循环采集,利用 ADS122U04 的多路输入选择器,配合 PGA 增益切换,实现 PT100 和热电偶混合测量;二是在 MCU 侧加入 PID 温控算法,把温度采集模块直接升级成一个完整的恒温控制器;三是把 UART 输出改成 RS485 总线协议,挂到上位机或楼宇自控系统里,这样整个系统就能融入标准工业物联网架构,实现远程监控和数据记录。
最后再分享一个小技巧:ADS122U04 的寄存器配置不要写死在代码里,把配置值做成一个数组存 Flash,调试时通过 UART 指令动态修改,能免去反复烧录程序的麻烦。这个习惯我用了很久,省下的时间足够多做两个项目了。