基于PJ85718DM与PIC32MX的双通道温度监测节点设计
温度监测这件事听上去是嵌入式里最简单的一类活但真放到 HVAC 现场能把人折腾到崩溃。你不仅要管好采集板自己那块温度还要拿到几十米外风道里的真实温度并且保证数据不被变频器、继电器、压缩机干扰成一个乱跳的野值。我前阵子做了一套本地/远程温度监测节点核心就两个器件PJ85718DM 这颗双通道数字温度传感器和 PIC32MX664F064L 这款 32 位 MCU。前者在片内完成了本地和远端两路温度采集后者负责读数据、滤波、跑 Modbus 协议再通过 RS-485 把结果送到楼宇自控系统。这篇文章与其说是方案介绍不如说是我从选型、画板、写固件到现场调试的一段流水账里面踩过的坑我会尽量说清楚。适合正在做嵌入式温度采集、暖通空调环境监测、机房温控这类项目的朋友参考如果你现在还在纠结到底用 8 位机还是 32 位机、传感器选模拟还是数字后面几段应该也能帮你把思路理清楚。1. 项目整体设计与器件选型思路1.1 为什么要把本地温度和远程温度分开看先问自己一个问题要测的到底是哪个温度控制柜里 MCU 旁边的“本地温度”和风管深处的“远程温度”本质上就是两个完全不同的物理量。本地温度受板子自身发热影响大电源、MCU、电机驱动都会给传感器加热温度变化往往滞后远程温度才是真正要控制的工艺参数随着负荷和季节变化范围可能从零下二十几℃ 到 60℃ 以上。如果用一个传感器硬扛两种需求要么把探头装在外面但做不到真正远端要么用长线把传感器拉出去结果线阻和噪声全进来了。PJ85718DM 这类双通道传感器的思路就高明在这里一个通道测芯片附近的环境另一个通道通过一根细线去接外部二极管探头用同一个 ADC 和校准体系读出两路温度。本地通道专门评估板卡热状态远程通道专心测风道或水管温度两边互不拖累也方便在软件里分别设置不同的告警阈值和滤波参数。1.2 为什么是 PJ85718DM 而不是 NTC 加 ADC早期我做过的很多方案都是 NTC 热敏电阻分压后进 MCU 的 ADC。成本确实低但有几个问题很现实一是 NTC 的 B 值离散性大批量生产时几乎每台都要单独校准不然同一温度可能差 2℃ 以上二是分压参考电压如果直接用 VCC电源一波动折算出来的温度就会跟着漂三是长线场景下线缆电阻直接串进分压回路读数会偏高或偏低而且很不好补偿。PJ85718DM 这类芯片把传感器、ADC、参考电压都做到了一起输出直接是数字量外部不再需要手工匹配电阻也不用担心参考电压漂移。尤其是它的远程测温通道靠三极管/二极管 PN 结电压随温度变化的特性工作只要探头线用屏蔽双绞线并合理处理线阻几十米距离一样能稳住。相比之下热电偶要冷端补偿和放大电路PT100 要恒流源和调理电路成本和复杂度都高出一截。对 HVAC 这种追求长期稳定、维护简单的场景数字传感器确实更合适。1.3 PIC32MX664F064L 的价值不只是“主频高”单看温度采集一颗 8 位 MCU 也能完成。但我的项目还要跑 Modbus 从站协议、处理 RS-485 收发、记录报警状态、偶尔扩展显示和按键。用 8 位机不是不行而是代码会写得非常局促中断、定时器、串口资源都要精打细算后期加功能很痛苦。PIC32MX664F064L 是 64 引脚的 32 位 MCU给我的第一感觉是外设资源宽裕多路 UART 可以同时留一个调试口和一个 RS-485 通信口I2C 直连 PJ85718DM剩下还有定时器、外部中断、ADC 用于监测板卡供电电压。主频比我常用的 8 位机高出不少Modbus CRC 这类计算几乎不占时间RAM 也够我给收发缓冲和滤波算法使用。更重要的是如果后续想把协议栈换成现场总线或者加一个小型 RTOS这颗芯片仍有余量不用推翻重来。所以这套方案的选型逻辑很简单传感器负责“温度变数字”MCU 负责“剩下所有事”两边各司其职不让任何一方成为短板。2. 硬件连接与关键电路解析2.1 PJ85718DM 最小系统别把电源和 I2C 当小事硬件设计第一步就是把 PJ85718DM 的电源、I2C 和远程探头接口弄对。电源我用 3.3V芯片电源引脚旁边放了一个 0.1uF 陶瓷电容尽量靠近引脚另外在板级再放一个 4.7uF 钽电容吸收低频波动。数字温度传感器的内部 ADC 对电源纹波其实很敏感如果供电不稳内部基准也会跟着晃表现出来就是温度在安静的环境里还会无规律跳变。I2C 部分SDA 和 SCL 都接了上拉电阻阻值我最初用的 4.7k后来因为总线长度和干扰问题改成 2.2k后面调试部分再细说。上拉电阻的选择不是拍脑袋总线电容越大、通信速率越高上拉电阻就得越小但太小会把低电平拉不干净影响从机识别。4.7k 是常见的起步值有示波器的话可以直接看上升沿如果沿太缓就换小。PJ85718DM 的地址引脚 A0、A1 我接成高电平让 I2C 地址避开板上另一个器件。芯片的 ALERT 引脚是开漏输出也接了一个上拉到 3.3V然后连到 MCU 的 INT 引脚。有人觉得告警用轮询就行但 HVAC 现场一旦真的超温最好让 MCU 立刻知道中断比轮询可靠得多而且主循环不会被频繁打断。2.2 远程探头的接线温度和噪声是一场拔河远程测温的原理是利用外部二极管正向压降随温度变化PJ85718DM 内部有一个电流源给二极管供电然后测量电压。这个信号本身比较微弱所以探头线一定要用屏蔽双绞线屏蔽层在采集板这一端单点接地不能两端都接地否则会形成地环路反而把共模干扰引进来。实际布线时我曾经拿普通排线走过 5 米读数在 0.1℃ 到 0.5℃ 之间来回摆。换上屏蔽双绞线之后立刻稳定。远程线上不要随便并联大电容有人想当然加个 100uF 滤波结果温度响应慢得像蜗牛而且二极管电压建立时间变长读数反而偏了。如果探头线超过 10 米建议在探头端加一个低阻值串联电阻比如 4.7Ω配合传感器内部的电流源做阻尼同时注意线缆自身的电阻会产生偏移。24AWG 线大概每米 0.08Ω 左右20 米回路多出约 3Ω算下来可能会引入 0.5℃ 到 1℃ 的偏差。对这种偏差我后面会讲怎么在软件里做补偿但前提是你得知道线长和线径。2.3 MCU 外围与 RS-485 接口现场通信的地环路陷阱PIC32MX664F064L 的 3.3V 供电我用了 DC-DC 从 24V 电源降下来。HVAC 控制柜里常见 24V AC/DC但纹波和浪涌都不小电源模块输入侧要有极性保护和共模电感输出侧至少要保证 50mV 以内的纹波否则 MCU 本身可能工作不稳I2C 和 UART 都会受影响。RS-485 是这套系统最主要的对外出口Modbus RTU 报文都靠它送出去。A/B 差分线末端要放 120Ω 终端电阻具体加不加取决于总线上设备和线长短距离一对一也可以不加。最容易被忽略的是隔离如果采集节点和上位机不共地RS-485 收发器的地线会形成环路轻则通信丢包重则烧芯片。我这次因为成本和空间限制没有上完整隔离只在电源输入端做了隔离如果下次布新板我一定会把数字隔离器加进去尤其是多个节点跨设备柜时。调试串口我在设计初期就留了一个 UART直接引到板边的三线插座。有人觉得调试口没啥用实际干活时你才知道它多救命。我后面很多问题定位都靠这个口打印原始寄存器值而不是只看最终温度。3. 固件架构与温度采样实现3.1 裸机状态机就够别急着上 RTOS这套系统的任务列表其实不复杂每 1 秒读一次 PJ85718DM 的本地和远程温度做滤波更新告警状态响应 Modbus 请求定时喂看门狗。我最后用了裸机状态机加一个 1ms 时基没有上 RTOS。主循环大概是这样一个形状示意代码不是完整工程但思路可以直接用int main(void) { system_init(); // 时钟、GPIO、UART、I2C、看门狗 sensor_init(); // 配置 PJ85718DM 分辨率、告警阈值 while (1) { if (timer_flag_1s) { timer_flag_1s 0; uint16_t local read_sensor_temp(TEMP_LOCAL); uint16_t remote read_sensor_temp(TEMP_REMOTE); filtered_local median_filter(local, 5); filtered_remote median_filter(remote, 5); update_alarm(filtered_local, filtered_remote); } modbus_poll(); // 处理串口收发的 Modbus 帧 wdt_clear(); // 喂狗 } }为什么不用 RTOS因为任务之间没有复杂的优先级抢占需求1 秒读一次传感器不可能把 CPU 占用到需要调度才能解决的程度。裸机状态机的好处是代码直观、不会出现优先级反转这种问题出 bug 也好复现。如果你后续要同时跑以太网协议栈和文件系统那再考虑 RTOS。我见过不少团队在小系统里硬塞 RTOS结果大半时间都在调任务优先级反而把最简单的温度采集搞得复杂。3.2 I2C 读写寄存器地址、字节序和等待时间PJ85718DM 的 I2C 操作不复杂但寄存器地址必须看芯片手册不同批次甚至不同版本的芯片可能会有差异。我这里用的是样片手册上的映射配置寄存器设置转换分辨率和告警阈值温度寄存器分本地和远程两个通道各占两字节。读取顺序一般是先写寄存器地址再连续读两个字节。读取温度时我踩过一个很典型的坑高字节和低字节的顺序。有的传感器是高位在前有的低位在前而且符号位扩展方式不同。所以我在代码里把读取函数统一封装高低字节合并后按 int16_t 处理后面做滤波和比较就省心很多。具体换算以 12 位分辨率为例原始值乘以约 0.0625 得到摄氏度但我不会在代码里用浮点到处算而是换算成 0.1℃ 精度的整数方便 Modbus 上报。例如 25.6℃ 就存成 256既避开浮点开销也不丢精度。一个重要的节奏问题PJ85718DM 的转换并不是瞬间完成的转换周期和配置的分辨率有关分辨率越高转换时间越长。如果你读得太快读到的可能是上一次转换的数据或者转换还没结束的中间值。我一开始没太在意把 I2C 时钟调到 400kHz 后疯狂读结果温度值偶尔出野值。后来老老实实在读取前查询状态位或者干脆在两次读取之间隔一个转换周期数据就干净了。3.3 本地/远程温度的滤波与告警逻辑从传感器读回来的原始值我一般先做 5 次采集的中值滤波把偶发毛刺干掉然后再做一阶低通平滑掉缓慢的噪声。中值滤波的窗口取 5 比较合适窗口再大响应就慢了。低通滤波我用整数实现避免浮点库int16_t lowpass(int16_t cur, int16_t prev, uint8_t alpha) { // alpha 范围 0~100越大跟随越快 return (cur * alpha prev * (100 - alpha)) / 100; }alpha 我通常取 20 左右对应 1 秒采样周期时还算跟手也不会把噪声完全消除到温度变化都变迟钝。HVAC 的温度变化本来就是分钟级的所以 1 秒采样、几秒滤波完全够用。告警逻辑我用滞回比较高温报警阈值 60℃恢复阈值 55℃中间留 5℃ 滞回避免温度在阈值附近抖动时报警信号反复翻转上位机那边被刷屏。ALERT 引脚的中断也要做软件消抖我一般靠一个 200ms 定时器确认状态防止瞬间毛刺误触发。3.4 Modbus RTU 从站不要小看帧间隔Modbus RTU 的协议本身不算难但“帧与帧之间的时间间隔”这个细节经常坑人。RTU 规定一帧报文内部字节间隔不能超过 3.5 个字符时间超过就算断帧。如果你的串口中断处理不及时或者主程序在别处做了耗时操作帧就可能被拆散上位机读到一半就丢包。我的做法是串口接收用中断加环形缓冲区每收到一个字节记录时间戳主循环里用定时器检查当前时间戳和最新字节之间的间隔一旦超过 3.5 字符时间就认为一帧结束交给 Modbus 解析函数。这样即便主循环忙了 2ms帧也不容易丢。CRC16 校验我用查表法多项式 0xA001初始值 0xFFFF按照 Modbus 的标准实现别搞成大端小端颠倒。寄存器规划我做成一张表这样上位机联调省事寄存器地址内容格式40001本地温度放大 10 倍如 256 表示 25.6℃40002远程温度放大 10 倍如 248 表示 24.8℃40003告警状态位 0本地高温位 1远程高温我用的是保持寄存器功能码 0x03 读取0x06 写单个刚好满足现场修改告警阈值的需求。4. 本地/远程温度处理的工程细节4.1 误差来源一颗 0.5℃ 的传感器最后可能偏出 2℃温度传感器标称精度正负 0.5℃但整机实际误差往往是多因素叠加传感器自身误差、远程二极管探头和被测目标热接触不好、线缆电阻引入偏移、采集板自热、电源纹波引起 ADC 基准波动。每一项看着不大加在一起就能让显示值偏出 2℃。HVAC 现场虽然不像实验室那样严格要求到 0.1℃但如果偏差太大上位机的联动控制就会误动作。所以我在项目里加了一个两级校准流程第一级在冰水混合物和恒温箱里做两点校准记录每个通道的偏移和增益修正系数第二级是现场安装后用经过校准的参考温度计放在探头旁边比对修正安装方式造成的偏差。校准参数我存在 MCU 的片内 Flash 模拟 EEPROM 区域掉电不丢。这里要反复提醒一句别想着靠软件把一个硬件极限只有 0.5℃ 的传感器“算”成 0.01℃ 精度。显示位数多不代表测得准反而会让维护的人误判系统状态。4.2 HVAC 现场冷凝、凝露和风道的热接触HVAC 场景比普通桌面设备多了一个“湿”的问题。远程探头如果放在风道或者冷水管表面当表面温度低于空气露点时探头外壳会结露时间长了水汽渗进接头处测温精度和绝缘都会出问题。所以探头要做好密封接线端子最好用灌胶或者热缩管保护并且定期检查。另一个容易被忽略的是热接触。你把探头用扎带绑在风管壁上中间隔了一层保温棉测到的可能不是风道温度而是保温层温度。正确做法是让探头和被测表面直接接触中间涂导热硅脂外面再裹保温棉隔绝环境温度。这个细节在调试时特别捉弄人我曾经在现场对着一个远程温度看了两个小时最后发现是探头没贴紧管道。本地温度通道也有特殊问题。MCU、电源、RS-485 收发器都在发热如果传感器离这些发热源太近本地温度会偏高甚至高到触发误报警。要测柜内环境温度得让传感器位置避开主要发热器件的风口并保证外壳有进气和出气通道。如果只是监控板卡热状态那本地温度偏高反而是有用的信号关键是得想清楚你想测什么。4.3 掉电存储与低功耗扩展HVAC 控制柜的供电通常持续存在但也要考虑断电情况。我这套节点用 ADC 监测 24V 输入电压一旦低于阈值就在电压彻底掉没前把当前温度、告警状态、运行时长写进 Flash下次上电后把状态恢复。这个功能一开始没做后来碰到一次意外断电现场不知道之前发生了什么排查起来特别被动。加上掉电保存后至少有个日志可以看。低功耗方面如果节点要用电池或者太阳能供电PJ85718DM 和 PIC32MX664F064L 都有低功耗模式。实际做法是让传感器大部分时间睡眠每 10 秒醒来一次完成转换MCU 也进入睡眠靠定时器唤醒读取。1 秒一次轮询功耗是毫安级10 秒一次采样可以把平均电流压得很低配合电池能撑很久。但 HVAC 节点通常不会这样限制功耗所以我把采样周期设为 1 秒保证响应及时代价是功耗高一些反正现场有 24V 供电无所谓。5. 常见问题与调试排查实录5.1 I2C 总线挂死从机不回 ACK我在项目中期遇到过一个问题系统跑了一天多温度读数变成 0xFFFF复位后又能恢复但过几小时又犯。用示波器一看SDA 线被拉低SCL 还在正常翻转这是典型的 I2C 从机挂死。排查思路分三步先确认不是上拉电阻太小导致低电平拉不下去再用 GPIO 手动模拟 I2C 时钟连续给 9 个脉冲把从机释放最后查现场总线走线有没有可能被干扰。我做了个软件“总线恢复”函数在每次读取失败后自动执行先释放 SDA再发 STOP。当然这只是补救根本原因是上拉电阻 4.7k 在总线电容接近 100pF 时上升沿太缓加上现场变频器偶发噪声从机状态机就乱了。后来上拉改成 2.2kI2C 时钟从 400kHz 降到 100kHz问题再也没出现过。5.2 远程温度读数漂移像在跳迪斯科有一段时间远程温度显示值在 22℃ 和 24℃ 之间来回跳用万用表量探头两端电压又看不出明显问题。我怀疑是接触不良端子压接得不够紧氧化层导致接触电阻不断变化。重新压接后有所好转但依然有小幅抖动。接着排查到线缆上去原来远程线跟一路 220V 动力线绑在同一个线槽里没做屏蔽。换屏蔽双绞线、屏蔽层单端接地后抖动基本消失再加上 5 次中值滤波读数就稳了。这类问题非常典型数字温度传感器能抗一部分干扰但远程二极管信号本质上还是模拟量物理层的屏蔽和走线比任何软件滤波都重要。想靠算法硬扛现场干扰通常都是给自己挖坑。5.3 本地温度越测越高甚至报警设备装进密封外壳后本地温度从室温一路爬到 45℃远程温度却正常。检查版图发现 PJ85718DM 离一颗 LDO 太近LDO 本身功耗不小散热全往传感器方向走而且外壳密封热量散不出去等于给传感器烤了个小温室。解决方法有两个层面硬件上把传感器挪到板边避开 CPU 和电源的热通道外壳开通风孔软件上把本地通道做了一点偏移校正让显示值更贴近真实环境温度。如果你想用本地通道测机柜环境温度这个教训值得记住本地温度通道测的是“芯片周围”的温度不一定是“机柜空气”的温度。PCB 布局和结构散热对测温点的影响往往比传感器精度本身还大。5.4 快速定位问题的调试手法折腾完这些坑之后我总结了一套调试顺序对类似项目很有用。第一步先把 PJ85718DM 和 MCU 用杜邦线连起来单独跑读温度的程序不接 Modbus、不接 RS-485确认传感器本身能读数第二步用逻辑分析仪抓 I2C 波形确认地址、寄存器、ACK 都对第三步加上串口调试口打印原始寄存器和换算后的温度反复对比最后才把所有功能集成在一起。我特别推荐在固件里留一个“原始值打印”开关。出问题的时候只看最终温度往往不够必须看寄存器原始值、转换状态位、I2C 错误计数。有了这些信息才能判断到底是传感器坏了、线路干扰还是软件算错了。现场调试时能多拿到一个信息源就能少花一个下午。问题现象可能原因处理办法I2C 读取超时上拉不足、总线干扰、从机挂死降低 I2C 时钟、换小上拉、软件恢复总线远程温度跳动线缆屏蔽差、接触不良换屏蔽双绞线、重新压接端子本地温度偏高传感器靠近发热源、散热差调整版图、加通风、软件偏移校正Modbus 偶发丢帧帧间隔判断不对、地环路用时间戳断帧、做好 RS-485 接地6. 写给想复刻这套方案的人6.1 先把传感器读通再写协议栈我见过不少方案一上来就把 Modbus、看门狗、掉电存储、显示全部堆上结果温度都没读准就开始联调出了 bug 根本分不清是哪一层的问题。我的建议是先跑最小系统一颗 MCU一颗 PJ85718DM一个调试串口先实现“每秒打印一次本地和远程温度”。这一步通了等于把最核心的采集链路摸清了后面加什么都是增量。协议栈只是锦上添花温度源都不稳协议再标准也白搭。6.2 现场布线决定了这套方案的长期稳定性软件写得好只能保证上限现场布线才决定下限。HVAC 环境里远程探头线和动力线一定要分开走线能穿管就穿管接线端子要压紧并做防水处理屏蔽层单端接地这件事现场工人很容易习惯性两端都接你要在图纸和说明里特别强调。板子拿回来后我先做了 72 小时连续运行测试日志每隔五分钟记录一次本地和远程温度确认没有一只野值才敢往现场发。之后又在恒温箱里做了一次 -20℃ 到 70℃ 的循环测试观察滤波后的读数跟随速度确认没有明显滞后。温度监测这活稳定比任何花哨功能都重要。这套 PJ85718DM 加 PIC32MX664F064L 的组合在我这里算是经受住了考验至少现场运行到现在我再没半夜接过报修电话。