
做温度采集十有八九的工程师第一反应是用单片机自带的 ADC。我在一个 HVAC 控制项目里也这么干过用 PIC18F57Q43 的 12 位内置 ADC 直接采 PT100结果读数跳得没法看精度和稳定性离温控要求差一大截。后来我把前端换成 ADS122U04IPWR 这颗 24 位 Δ-Σ ADC配合 PIC18F57Q43 做后端处理才把整个测温链路真正跑通。这篇文章就把这套组合的传感器前端、UART 通信、固件换算和现场踩坑完整讲一遍适合正在做工业温度变送器、HVAC 控制器或精密温控产品的嵌入式工程师参考。1. 这个组合解决的核心问题MCU 内置 ADC 撑不起工业测温1.1 12 位 ADC 在 0.1°C 精度面前有多尴尬工业测温的场景里0.1°C 往往只是起步要求。拿 PT100 来说0.1°C 对应阻值变化只有 0.0385Ω如果激励电流是 1mA那就只有 38.5µV 的电压变化。MCU 内置 12 位 ADC 就算把参考电压压到 2.048V一个 LSB 也相当于 0.5mV换算成温度直接就是 1.3°C 的分辨率。这还只是分辨率没算增益误差、零点漂移和参考电压温漂。批量生产时每块板子的 ADC 特性还不一致想保住 0.5°C 的系统精度就得每片做出厂校准成本完全失控。外部 24 位 Δ-Σ ADC 的价值就在这里过采样加数字滤波把噪声压下去PGA 把微伏级信号放大到合适的量程内部参考和电流源出厂校准过且有可控的温漂。ADS122U04IPWR 这类器件把完整模拟前端集成到一颗芯片里比用分立运放搭前端稳定得多也比 MCU 内置 ADC 的精度高一到两个数量级。1.2 ADS122U04IPWR 到底集成了什么ADS122U04 的型号很好拆解122 是 TI 的 24 位 Δ-Σ ADC 家族U 代表 UART 接口04 表示 4 通道输入。IPWR 后缀对应 TSSOP-16 封装温度范围 -40°C 到 125°C正好覆盖工业现场环境要求。芯片内部集成了可编程增益放大器PGA1 到 128 倍、两个激励电流源50µA 到 2mA 可配置、一个 2.048V 内部基准、一个内部温度传感器还有几个通用引脚。做温度测量需要的模拟模块全都在里面了。两个激励电流源是最容易被低估的特性。RTD 测量需要恒流激励很多方案得自己搭镜像电流源匹配度和温漂都靠手工调节。ADS122U04 把两个电流源做在同一块硅片上匹配特性天然好三线制 RTD 引线电阻补偿就是靠它们实现的。这颗芯片还支持把内部温度传感器接到测量通路里热电偶冷端补偿就可以用芯片温度做粗略参考省去一路外部传感器。1.3 为什么是 UART 而不是 SPI高精度 ADC 绝大多数用 SPI 接口ADS122U04 偏偏设计成 UART。这在工业现场反而更友好。SPI 至少需要 SCK、MOSI、MISO、CS 四根线时钟线高速翻转时容易干扰旁边的模拟信号布线超过二三十厘米就得小心处理信号完整性问题。UART 只需要 TX、RX、GND 三根线115200 波特率在测温场景绰绰有余长距离传输能力也比 SPI 强得多——想扩展成 RS-485 多点采集也简单UART 天然就是 RS-485 的物理层信号。另一个被忽略的好处是帧同步。UART 每帧有起始位和停止位数据错位马上能发现。SPI 没有帧协议CS 和时钟的时序只要稍微出问题就可能读到错位数据而且不容易察觉。在电噪声复杂的工业现场UART 的鲁棒性优势非常明显。PIC18F57Q43 刚好有两个增强型 UARTEUSART一路专供 ADC 通信另一路留给上位机 Modbus 或调试口互不干扰8 位机的性价比在这里体现得很充分。1.4 PIC18F57Q43 在系统里的角色PIC18F57Q43 是 Microchip 的 18F-Q43 系列主频最高 64MHz128KB Flash8KB SRAM带 1KB 数据 EEPROM。温度测量这种任务换算多项式、数字滤波、PID 调节算法复杂度并不高8 位机完全跑得动。这颗芯片真正的卖点是核心独立外设CIPDMA、可配置逻辑单元CLC、信号测量定时器SMT这一批不占 CPU 的外设。在我这个方案里DMA 用得最多。ADC 通过 UART 返回的转换结果由 DMA 直接搬到 RAM 缓冲区CPU 只在完整帧到达时被唤醒来做一次解析其余时间可以专心跑控制算法和通信协议栈。这让系统的响应时间变得非常可预测对温控来说是实打实的稳定性提升。2. 传感器前端PT100 比例测量和三线制补偿2.1 比例测量的原理先说为什么 RTD 测量一定要用比例测量而不是单纯测电压。如果激励电流源是 500µAPT100 在 0°C 时产生 50mV 电压这个电压直接依赖电流源的绝对值。电流源会随温度漂移比如漂 0.5%温度读数就跟着偏 0.5°C这不可接受。比例测量的思路是让同一个电流源同时流过 RTD 和一个精密参考电阻 RREF然后取 RREF 两端电压做 ADC 的参考电压。这样转换结果就变成 VIN/VREF (I×RTD)/(I×RREF) RTD/RREF电流源的绝对值在这个比值里直接约掉电流源温漂对读数几乎无影响。剩下的误差主要取决于 RREF 的稳定性选一颗低 TCR 的精密电阻就能把基准问题解决这就是工业仪表里比值测量的核心思想。换算公式很直接ADC 码值 ≈ (RTD / RREF) × 2^23已知码值和 RREF 就能反解 RTDRTD code / 8388608 × RREF。2.2 三线制怎么消掉引线电阻两线制接法最简单电流源从 ADC 输出流过引线和 RTD再从另一条引线回到地测量 RTD 两端电压。问题是每根引线本身有 0.1 到几欧姆的电阻PT100 在 0°C 时总共才 100Ω引线电阻直接叠加进去误差可能有好几摄氏度。三线制用两条引线接 RTD 的一端第三条引线接另一端。ADS122U04 的两个匹配电流源在这里发挥作用一个电流源流过一侧引线和 RTD另一个电流源流过补偿引线。两个电流源的电流相等两条引线的电阻也相等它们产生的压降在差分测量通路里互相抵消。理论上只要两条引线等长、等材质、从同一个传感点引出引线电阻误差就被消掉了实际能补偿掉九成以上。接线有几个要点两个激励引线必须从传感器根部同一点引出尽量做到阻值一致引线用屏蔽双绞线屏蔽层单端接地激励电流建议 250µA 到 500µA。电流太小信号弱、信噪比差电流太大 PT100 自热明显静止空气里 1mA 就能带来约 0.1°C 的自热温升2.3 参考电阻和增益怎么选参考电阻的取值由激励电流和目标参考电压共同决定。我的典型配置是激励电流 500µA、参考电阻 4.12kΩ这样 VREF 500µA × 4.12kΩ 2.06V接近内部基准的 2.048VADC 满量程利用率高。温度到 850°C 时 PT100 阻值约 390ΩVIN 也就 500µA × 390Ω 195mV增益选 1 就完全够用。如果只跑 -40°C 到 150°C 的 HVAC 范围PT100 阻值变化是 84.27Ω 到 157.32Ω信号电压只有几十毫伏。这时把 PGA 增益加到 4 或 8信号放大后再进 ADC能进一步压低等效噪声。经验值是不要让最大输入信号超过参考电压的 80%留出器件容差空间。参数RTD三线制热电偶K 型激励电流500µA关闭PGA 增益1~8128参考电压外部 RREF比例模式内部 2.048V数据速率400 SPS20~400 SPS输入通道差分AIN0/AIN1差分AIN0/AIN12.4 热电偶微伏级信号和冷端补偿K 型热电偶是另一种常见需求。它的灵敏度约 40µV/°C信号电平只有几毫伏必须把 PGA 增益打到 128。ADS122U04 在增益 128 时一个 LSB 对应约 1.9nV24 位、参考 2.048V虽然实际有效位数受噪声限制只有 20 位左右但分辨 0.05°C 级别的温度变化完全够用。热电偶测量最大的坑是冷端补偿CJC。热电偶输出的是测量端和冷端温差对应的电压冷端温度必须实时测出来再加回去。ADS122U04 内部温度传感器可以直接读芯片温度做粗略 CJC但芯片温度不等于接线端子处的冷端温度。我的做法是在端子排附近放一颗外部测温元件用 PIC18F57Q43 的 12 位内置 ADC 读取再在固件里做补偿这样 CJC 误差能控制在 0.5°C 以内。还有一点热电偶信号是直流微弱信号输入回路里任何接触热电势、氧化层都会变成误差。接线端子要选同种金属或热电势小的材质端子螺丝拧紧后最好点胶固定防止松动和氧化。3. UART 链路ADS122U04 和 PIC18F57Q43 的对接细节3.1 ADS122U04 的命令协议ADS122U04 的 UART 协议是典型的单主机架构MCU 永远是主机ADC 只能应答。常用命令就四类读配置、写配置、启动转换、读转换结果。每条命令由一个命令字节加若干数据字节组成具体命令字在官方 datasheet 的 UART 通信章节有完整列表这里不逐个贴十六进制避免你照抄时被版本差异坑到。协议上值得记住几个要点波特率从低速到 921600 都有档位ADS122U04 内部自带波特率发生器我常用 115200速度与稳定性平衡默认 8N1 格式可以开启校验位、地址位甚至 CRC 校验。多机 RS-485 场景用 9 位地址模式单机场景开 CRC 意义不大我一般关掉每次写配置后建议读回来验证。UART 线路上的毛刺可能导致配置写失败读回能第一时间发现读取转换结果时一次读 3 个字节高位在前我的通信时序是上电 → 延时等 ADC 内部基准稳定 → 写配置 → 读配置确认 → 发启动转换命令 → 等待数据就绪 → 读 3 字节结果。数据就绪的判断我用固定周期轮询先发读数据命令如果数据还没准备好ADC 返回的状态字段会标明忙那就等下一个周期再读。这样做代码逻辑简单不依赖外部引脚中断也少一条接线。3.2 PIC18F57Q43 的 UART 配置PIC18F57Q43 的 EUSART 配置我直接用 MPLAB Code ConfiguratorMCC生成。选 115200、8 位数据、无校验、1 个停止位接收开中断发送用查询方式。手工配寄存器也不难核心是波特率发生器BRG161、BRGH1 时SPBRG FOSC/(16×Baud) - 1。用 64MHz 时钟配 115200算出来是 33.7取 34实际波特率 114286误差 0.79%在 UART 容差范围内。如果你有条件选晶振推荐 7.3728MHz 这类整倍频SPBRG 可以整数整除误差归零。ADS122U04 那边同样有波特率容差两端误差叠加最好控制在 2% 以内否则偶发错帧会折磨你整个调试周期。我后来在项目里换成 7.3728MHz 晶振之后UART 偶发丢帧的问题就再没出现过。3.3 DMA 接管数据搬运Q43 的 DMA 可以把 UART 接收寄存器里的数据自动搬到 RAMCPU 零参与。我开了一个 8 字节的环形缓冲区DMA 收到每个字节后自动写入接收完成中断只在完整命令帧收满时触发MCU 绝大部分时间在忙其他事测温链路完全不受 CPU 调度影响。配合在固件里写一个命令发送函数和接收状态机// 发送命令帧cmd 可选 datadata_len 可为 0 void ads122u_cmd(uint8_t cmd, uint8_t *data, uint8_t data_len) { uart1_write(cmd); for (uint8_t i 0; i data_len; i) { uart1_write(data[i]); } } // 接收状态机 typedef enum { ST_IDLE, ST_DATA } rx_state_t; rx_state_t rx_state ST_IDLE; uint8_t rx_buf[8]; uint8_t rx_cnt; volatile uint8_t frame_ready 0; void uart1_rx_isr(void) { uint8_t b U1RXREG; switch (rx_state) { case ST_IDLE: rx_cnt 0; rx_buf[rx_cnt] b; // 根据 b 判断帧长度进入 ST_DATA rx_state ST_DATA; break; case ST_DATA: rx_buf[rx_cnt] b; if (rx_cnt 8) { rx_state ST_IDLE; frame_ready 1; // 置标志位主循环解析 } break; } }这是一个演示骨架实际要把帧长度解析和超时复位加进去。重点原则是中断里只搬运字节和置标志所有浮点换算、滤波、控制算法都放到主循环避免中断处理时间过长导致 UART 超载错误。4. 初始化和换算从寄存器写到温度值4.1 上电初始化序列ADS122U04 的配置寄存器有三个主要设置这几类内容PGA 增益、输入通道选择、激励电流大小和流向、参考电压来源、数据速率、单次或连续转换模式。以三线制 PT100 为例我常用的配置是差分输入 AIN0/AIN1PGA 增益 1参考电阻 4.12kΩ 时满量程利用率足够IDAC1 和 IDAC2 都开启各 500µA按三线制接法分配流向参考电压选择外部从 RREF 两端取数据速率 400SPS单次转换模式初始化流程写成文字就是复位后等待至少 10ms 让内部基准稳定写三个配置寄存器读回验证然后进入正常转换循环。如果系统对功耗敏感可以保持单次转换模式每次读完后自动进入低功耗需要时才唤醒。一个忠告配置寄存器不要照抄网上的代码。不同测量对象配置差别很大——热电偶要关电流源、增益 128RTD 要开电流源、低增益。最容易翻车的就是激励电流流向搞反结果读数直接为负或者满偏还查不出原因。4.2 从码值算到摄氏度拿到 24 位码值后先反解电阻再算温度。RTD 反解电阻很简单float rtd_resistance(uint32_t code, float rref) { return ((float)code / 8388608.0f) * rref; }这里 2^23 8388608对应 24 位 ADC 的满量程码值。如果开启了双极性模式或者 PGA 增益不为 1公式里的 rref 要除以增益。最容易出的低级错误是忽略 PGA 增益算出来的电阻差了 4 倍或 8 倍却浑然不知。电阻转温度我用 IEC 60751 的 Callendar-Van Dusen 公式。0°C 以上可以直接解二次方程// PT100 电阻 - 温度 (°C)适用 0~850°C float pt100_res_to_temp(float r) { const float R0 100.0f; const float A 3.9083e-3f; const float B -5.775e-7f; float disc A*A - 4.0f*B*(1.0f - r/R0); return (-A sqrtf(disc)) / (2.0f*B); }0°C 以下要多加一项 C×(T-100)×T³方程没法直接解我用牛顿法迭代三四次就收敛。实测这套换算在 -40°C 到 200°C 范围内误差小于 0.01°C完全够用。热电偶那边K 型电压到温度的反算要用 NIST ITS-90 多项式9 次项系数很长工程上我更推荐查表加线性插值把 0 到 500°C 的对照表存进 Flash查表加插值误差小于 0.1°C代码还干净不用担心一长串系数敲错。4.3 滤波策略24 位码值的原始噪声水平取决于数据速率。400SPS 时有效位数大概 18 位左右读数会肉眼可见地跳动降到 20SPS 有效位数能上 21 位但是响应慢。我的做法是ADC 跑 400SPS固件里做 16 点滑动平均后再输出等效更新率 25Hz噪声被压到 0.01°C 以内响应速度也不差。工业现场偶尔会出现尖峰干扰滑动平均压不住要先过一道中值滤波。取 3 个采样做中值再去滑动平均抗尖峰效果好代价只是两次采样延迟。HVAC 应用对响应速度宽容这个代价几乎可以忽略。要注意滤波窗口太大会把真实温度变化磨平温控回路反而容易震荡窗口长度要按系统时间常数来定。5. 校准精度是测出来的不是选型选出来的5.1 两点校准法ADS122U04 初始精度不错但系统级还叠加了参考电阻误差、PGA 增益误差和布线误差出厂校准省不掉。我的校准流程是用 0.02% 精度的标准电阻接在传感器端子上100Ω 模拟 0°C138.51Ω 模拟 100°C分别读取两个温度点的换算结果用两点求出增益系数和零点偏移把系数写进 PIC18F57Q43 的数据 EEPROM缺省值是 1 和 0// 校准系数应用 float cal_apply(float raw_temp) { return raw_temp * cal_gain cal_offset; }两点校准假设整条链路是线性的。24 位 Δ-Σ ADC 的非线性本来就很小PT100 的换算公式也把电阻非线性处理掉了这个假设成立。如果要求更高可以在 -40°C、0°C、100°C 三个点做二次插值把剩余误差再压一个数量级。校准系数存 EEPROM 时要考虑掉电不丢和写均衡。Q43 的数据 EEPROM 擦写寿命通常在十万次级别生产校准只在出厂写一次完全不用担心。但如果固件里设计了自校准功能注意加写次数保护别让频繁校准把 EEPROM 磨穿。5.2 冷端补偿的几个实操细节热电偶的 CJC 误差是系统精度的大头。想让冷端补偿准传感器得贴在真正的冷端上。我用外部温度传感器加导热硅脂固定在接线端子座的底部外面再用金属屏蔽壳罩住保证壳内温度均匀。经验是如果冷端传感器和热电偶端子之间隔着 5mm 以上空气层温差可能就是 0.5°C比传感器本身的误差还大。另一个很隐蔽的问题热电偶的冷端不是一个点而是一段区域。端子排上不同螺丝的温度可能存在差异多路输入时尤其明显。CJC 传感器要放在所有热电偶端子的几何中心让它测量的是平均冷端温度。我做过一个 4 路热电偶输入的采集器传感器位置偏一点各路补偿误差就不一样最后花了半天才想明白是这个原因。5.3 自检与漂移监控工业设备不能三天两头拆开校准固件里要留自检能力。ADS122U04 支持内部系统监视可以配置通道去测量 AVDD 或内部温度传感器。上电时读一下这些值确认 ADC 工作正常、电源电压在合理范围能提前发现硬件老化趋势。对关键设备我还会在板子上留一颗精密基准电阻比如 200Ω 和 100Ω 各一位配合继电器或跳线可以随时触发手动自校准。比对当前读数和出厂校准记录就能算出系统漂移了多少做到预防性维护而不是等客户报故障才跑去现场。这套机制在售后成本上省下的钱远超过那颗基准电阻的价格。6. 工业和 HVAC 现场的实战经验与踩坑记录6.1 前端滤波和布局ADS122U04 是高输入阻抗器件前端 RC 滤波不会带来明显误差。我的标准做法是每个输入引脚串 1kΩ 电阻差分线之间和每根线对地各放 100nF 电容构成截止频率约 1.6kHz 的低通。这个滤波器主要不是滤带内噪声——24 位 Δ-Σ 的数字滤波器已经处理掉了——而是滤射频干扰防止手机、变频器产生的射频信号在 ADC 输入端被整流成直流误差。这个整流效应很阴险示波器上看不到读数却能偏出零点几摄氏度。布局上注意激励电流线和差分信号线不要并行走线。500µA 的电流本身不会产生多大干扰但回流路径如果绕了大圈会在 ADC 输入端感应出差模噪声。我吃过一次亏把 IDAC 走线和 PT100 差分输入走线在 PCB 上平行了 5cm读数就跟着负载电流波动。后来把两者分到 PCB 两侧问题立刻消失。6.2 电源、地和参考电阻ADS122U04 的 AVDD 我用单独 LDO 供电3.3V输出电容按 datasheet 用 1µF 加 0.1µF。数字地和模拟地做单点连接MCU 的数字信号绝不横跨 ADC 模拟区。这个规矩看着老生常谈但很多读数漂移的案例最后都查到地回流的头上。参考电阻是比例测量的基准它的温漂直接变成温度误差。我之前手头只有 25ppm 的普通精密电阻算了一笔账环境温度变化 10°CRREF 变化 0.025%等效到 PT100 读数就是约 0.065°C 的漂移。HVAC 室内环境还能接受工业机柜冬夏温差 40°C 就完全不能忍。所以参考电阻必须选低 TCR 的至少 10ppm 以下最好用金属箔电阻。同时把它放在远离发热元件、靠近 ADC 的位置。RREF 两端的走线要加粗用开尔文接法单独引出到 ADC 参考引脚不要图省事直接连到旁边的地铜皮上。6.3 HVAC 场景的几个特殊点楼宇自控里传感器离控制器经常几十米。长线传输 24 位码值115200 波特率可能不够稳我会降到 38400 甚至 19200线缆屏蔽层单端接地信号线用双绞。温度更新率 1Hz 就足够波特率低一点完全没有影响链路可靠性优先。HVAC 还有个实际问题冷凝水。冷冻水管道旁边的传感器端子容易结露结露会把 RTD 输入短路或者让热电偶端子氧化。选型时 PCB 要涂三防漆端子选防腐蚀镀层。这些细节不影响原理但决定产品能不能在现场活过第一个雨季。另外HVAC 更常用 PT1000 而不是 PT100。同样的激励电流下 PT1000 信号大 10 倍引线电阻影响相对小自热也更低。如果项目从零开始且温区不超过 200°C我建议直接考虑 PT1000前端的滤波和校准逻辑都可以复用只是 RREF 和增益的配置要相应调整。6.4 我踩过的几个坑第一个坑是 UART 偶发丢帧。现象很随机几十个小时才丢一帧查了半天都没头绪。最后定位到是 MCU 端波特率和 ADC 端实际波特率差了 0.8%个别帧的采样点正好落在数据跳变边缘叠加电源纹波就出错。换成 7.3728MHz 晶振后波特率误差归零再没丢过。第二个坑是读数随环境温度缓慢漂移。排查到最后发现是参考电阻离一颗功率电阻太近参考电阻的温度跟着负载变化走。把参考电阻挪到 PCB 角落并用铜皮与热源物理隔开读数马上稳定。这个案例让我养成了习惯任何精密电路先画热分布图再决定敏感器件位置。第三个坑是接地环路。现场一个 RTD 传感器外壳接了设备地控制器电源也接了地地环路让 PT100 读数带上 50Hz 工频分量滤波都压不干净。最后在传感器端做了浮空处理只在控制器端单点接地问题才解决。工业现场只要长线缆就有地环路风险设计阶段就要按单点接地规划。这套 ADS122U04IPWR 加 PIC18F57Q43 的组合我前后用了一整年从实验室到电柜、从空调机组到冷冻站都跑过。最大的体会是精密测温的瓶颈从来不在 ADC 的位数而在参考、布线、校准和接地这些看不见的地方。只要把比例测量、三线制补偿、冷端处理和校准流程做扎实剩下的大多是按部就班的工程活。这些踩坑记录如果你能提前避开能省掉不少通宵排查的时间也就值了。