拿到这个项目的时候,我心里第一反应是:又要跟“温度”打交道了。做嵌入式的人都知道,温度采集看着简单——无非一个探头、一支 ADC、一个滤波,但真把场景拉到 HVAC 或者工业现场,问题就完全不是一回事了。本地温度、远程温度、探头布局、总线干扰、校准误差、掉电重连,随便哪个没处理好,现场就会给你脸色看。这个项目的核心组合是 PJ85718DM 这个前端采集模块,加上 Microchip 的 PIC18F96J94 做主控,目标很明确:一套方案同时覆盖本地和远程温度监测,应用场景锁定在嵌入式设备与 HVAC 系统。
先说清楚这个项目适合谁看:如果你正在做楼宇自控、暖通机组、冷库监测、或者设备内部的温度监控,手里有一个类似的多通道采集前端,又在纠结主控怎么选、软件怎么写、现场怎么调试,那这篇文章就是给你准备的。我会从器件选型的底层逻辑讲起,接着拆硬件接口、固件实现、通信方案,最后把调试现场踩过的坑也一并交代。整个项目我做下来最大的体会是:温度监测的难点从来不在“读温度”,而在“把这个数读稳、传准、用对”。
1. 项目背景与整体设计思路
1.1 为什么“本地+远程”双路温度监测是刚需
先聊聊场景。HVAC 系统里有一个很典型的矛盾:控制逻辑需要知道回风温度、送风温度、盘管温度这些“本地”参数,同时又要知道室外温度、其他区域的温度等“远程”参数,才能做焓差控制、新风补偿、联动启停。嵌入式设备内部也一样,电路板上的热点监测和机柜外部的环境温度往往需要同时掌握。如果分开做两套系统,成本和维护量都会翻倍,而且两套数据之间没有统一的时间基准,数据分析时很容易出现错位。
所以这个项目在设计上一开始就走“双路采集、单主控汇聚”的路子:PJ85718DM 负责在靠近传感器的位置完成信号调理和数字化,把多路温度信号统一成数字量,PIC18F96J94 只需要通过数字接口去读,既能拿到现场探头的实时温度,也能把数据汇总之后通过远程接口上报。这种架构最大的优点,是主控不需要处理模拟信号的小信号放大、偏置补偿这些脏活,前面已经有一个“专业前台”帮你干完了。
1.2 器件选型:PJ85718DM 和 PIC18F96J94 各干各的活
先说 PJ85718DM。我拿到这块模块的时候,第一感觉是它的接口很干净,跟主控之间是标准的数字通信协议,不需要自己做放大电路。模块内部集成了多路温度采集通道,支持常见的 PT 传感器和 NTC 类型探头,而且还带通道隔离和滤波处理,直接把模拟域的麻烦挡在外面。在 HVAC 现场,探头经常要拉很长的线,如果自己用运放搭采集电路,线缆上的工频干扰会让人怀疑人生,PJ85718DM 这种“前端数字化”的方式可以大幅减少长线传输带来的误差。
PIC18F96J94 这颗芯片选择它,主要从三个角度考虑。第一是外设配置灵活,它有多路 UART、I2C/SPI 和丰富 GPIO,接 PJ85718DM 和远程通信模块都不用做太多桥接。第二是自带比较充足的 Flash 和 RAM,温度采集的协议栈、滤波算法、远程报文解析完全放得下,不用整天抠空间。第三是工业级温度范围和稳定供货,这类芯片在 HVAC 控制器里已经很常见,后续做认证和备料都方便。简单说,PJ85718DM 解决“数据好不好”,PIC18F96J94 解决“数据怎么用、怎么传”。
我在设计初期也考虑过用更高端的 ARM 平台来做,但评估之后发现性能和功耗都没有明显优势,反而是 8 位机的开发周期和调试成本都低不少。温度监测这种应用,核心诉求是稳定和实时,而不是算力,PIC18 这条线完全够用。
2. 硬件架构与接口设计
2.1 PJ85718DM 的连接方式与引脚分配
硬件设计的第一步是确认 PJ85718DM 怎么跟主控接。我手上的模块提供的是数字接口,常见接法就是把它的时钟线、数据线、中断输出和地线引到 PIC18F96J94 的对应引脚上。具体接哪个引脚,不能凭心情,得先看数据手册里的外设引脚选择配置,PIC18F96J94 这种带有可重映射 PPS 功能的芯片,可以把 UART 或 I2C 信号映射到不同的引脚上,布局时就能绕开走线冲突,这是它一个很大的优势。
我实际设计时,把 PJ85718DM 的 I2C 接到主控的 SCL1 和 SDA1,同时模块的 ALERT 中断脚接了一个普通 GPIO。这个 ALERT 脚非常有用,模块检测到某通道温度越限时会主动拉低中断,主控不需要轮询所有通道,大大降低了软件负担。有一点要特别注意,I2C 总线的上拉电阻不能省,好多新手直接接上就发现通信时好时坏,其实就是上拉没接或者阻值不对。模块在长距离接线下,I2C 速率不宜拉满 400k,我守规矩用了 100k 模式,距离上加一些余量,实际跑下来很稳定。
除此之外,模块这边还需要供 3.3V 电源,我单独用了一路来自 LDO 的输出,没有跟任何电机驱动电路共用电源,避免电源噪声串进温度采集。PIC18F96J94 本身也工作在同一 3.3V 域,整个数字侧就是个干净的小系统。
2.2 本地探头与远程探头的硬件接法
这个项目里我对“本地”和“远程”的定义很明确:本地温度指的是和控制设备处于同一环境或者同一柜内的探头,线缆比较短,几十厘米到两三米;远程温度则是需要布置到几十米甚至上百米外的测点,比如室外新风温度、远端风管温度。针对这两种情况,PJ85718DM 的通道分配和接线方式是有讲究的。
对于本地探头,我直接接到 PJ85718DM 的差分/单端输入通道,线缆用了屏蔽双绞线,屏蔽层在模块端单点接地,避免形成地环路。对于远程探头,我单独划分了两个通道,并且在线缆选型上下了功夫,不是随便拿普通的延长线接上去,而是用了带屏蔽的低阻抗线,接头处用防水的航空插头,毕竟 HVAC 现场可能安装在管道井里,冷凝水和灰尘都很常见。
接口分配的表格可以这样整理:
| 通道 | 测点类型 | 位置 | 线缆预估长度 | 探头类型 |
|---|---|---|---|---|
| CH0 | 本地温度 | 控制柜内 | 约 0.5 米 | NTC |
| CH1 | 本地备用 | 回风管道 | 约 2 米 | NTC |
| CH2 | 远程温度 | 室外新风 | 约 60 米 | PT100 |
| CH3 | 远程备用 | 远端风管 | 约 40 米 | PT100 |
这样分开做的好处是调试时可以单独验证每一路,哪一路出现漂移或者干扰,立刻能根据通道位置缩小排查范围。
2.3 电源、复位与看门狗:不要在这些基础环节省钱
温度监测系统看起来“无脑”,实际上它对稳定性的要求很高。HVAC 项目一旦装到现场,通常是不允许频繁人工干预的,设备一跑就是几个月。所以我在硬件上加了三道保险:第一是电源入口做了 TVS 和防反接,第二是复位电路用带手动复位的专用复位芯片,第三是 PIC18F96J94 的内部看门狗使能,并且喂狗逻辑放在主循环之外的中断里,以防止程序跑飞后主循环还在“假死状态”里定时喂狗。
另外一个很多人忽略的问题是晶振。PIC18F96J94 可以工作在内部振荡器,但涉及到 UART 通信时,波特率误差最好控制在 2% 以内。我建议使用外部晶振,并且晶振旁边两个负载电容的值按照数据手册给出参数配置,不要随意加大。实测下来,用内部振荡器做 9600 波特率短时间没问题,长期运行或者温度变化大的场合,误差会变得明显,所以宁可多一颗物料也换成外部晶振。
3. 固件框架与关键实现
3.1 初始化流程:先把本地模块“伺候好”
固件设计的第一步是初始化系统,但我说的不仅仅是对 PIC18F96J94 做一轮寄存器配置,而是整个系统从上电到稳定跑数需要经历一个有顺序、有等待过程的状态机。我习惯把上电流程设计成四个阶段:时钟与外设初始化、PJ85718DM 模块复位与握手、远程通信模块初始化、主循环运行。
PJ85718DM 模块上电后,内部完成自检需要几百毫秒,如果主控立刻发起通信,很可能拿到一个无效响应。所以我的代码里在发起第一次握手之前会做一个延时,并且连续读取模块的状态寄存器,确认模块已经进入准备就绪状态才继续往下走。这一段虽然不复杂,但很能说明“读温度为什么会读不到数”的一个典型原因——上电时序没匹配上。
下面是初始化流程的伪代码思路,用 C 语言表达:
void system_init(void) { // 配置系统时钟为外部晶振 + PLL,确保外设总线频率稳定 configure_clock(); // 初始化 I2C1 主模式,速率 100k i2c1_init(100000); // 复位 PJ85718DM 模块 gpio_set(MODULE_RESET_PIN, LOW); delay_ms(50); gpio_set(MODULE_RESET_PIN, HIGH); // 等待模块自检完成,连续读取状态寄存器 while (read_module_status() != MODULE_READY) { delay_ms(10); } // 初始化远程通信 UART uart1_init(9600); // 使能看门狗和全局中断 wdt_enable(); interrupt_global_enable(); }这个初始化顺序是我的基准模板,后面做任何基于 PJ85718DM 的项目,都是在这个基础上改的。很多现场问题回头看,都是初始化太仓促,导致模块没有进入正常工作模式。
3.2 温度采样与滤波:为什么不直接拿 ADC 值就用
模块虽然把模拟信号变成数字量了,但数字量不等于可以直接上报的温度值。我收到 PJ85718DM 的原始数据时,一般还要做三件事:单位转换、异常剔除、滑动滤波。单位转换好说,主要是根据模块协议把原始计数换算成摄氏度。异常剔除则是把明显超出合理量程的点(比如负 50 度或者正 150 度以上的数据)直接丢弃,这种数据多半是通信瞬断或者传感器断线时的产物。滑动滤波我选了一个长度为 8 的窗口,每次新数据进来就更新平均值,这样既不会像中值滤波那样带来明显滞后,也不会让个别毛刺直接穿透到控制逻辑。
在 HVAC 应用里,控制逻辑最怕的是温度值来回跳。比如设定阈值是 25 度回差 2 度,如果温度在 24.9 到 25.1 之间反复跳变,压缩机的启停就会变得非常频繁,设备寿命会明显下降。所以软件滤波不是可有可无的“精品优化”,而是必需品。我实测下来,加了滑动滤波之后,温度显示的稳定性提升非常明显,控制输出的抖动也基本消除了。
举一个直观的例子:室外新风探头在自然环境下,由于风的影响,单次采样值可能在 12.5 到 13.8 度之间波动,但 8 点滑动平均之后,输出基本稳定在 13.1 度加减 0.2 度,这样的数据用来做焓差控制才有意义。
3.3 校准与标定:我的补偿表经验
任何温度采集系统,都存在传感器个体差异和模块通道差异。PJ85718DM 虽然出厂做了校准,但换上不同品牌、不同批次的探头之后,读数未必和标准温度计一致。我个人的做法是:在初次装机时,用一台经过计量标准校验的参考温度计,和被测探头放在同一个恒温环境中,在 0 度、25 度、50 度、75 度四个温度点做比对,记录每个点的偏差,然后生成一个简单的分段线性补偿表,烧录到 PIC18F96J94 的 Flash 存储区里。
不要觉得这一步多余。HVAC 系统如果两个温度测点相差 1 度,控制逻辑可能就会做出完全不同的判断,比如把新风阀从 30% 开度调成 50%,而如果某个通道没有校正,偏差 1-2 度非常正常。我的补偿表算法很简单:在两段温度区间内做线性插值,也就是查表加比例修正。温度点之间的偏差基本是单调的,不需要复杂的高阶拟合。
需要特别提醒一个问题:校准时的恒温环境要保证探头已经完全热平衡,有人为了图快,把探头塞进温水里马上就读数,数值还在飘就说“有偏差”,这是错误的校准方法。通常每个温度点要等探头读数稳定至少五分钟,才能记录参考数据。
4. 本地与远程温度监测的实现
4.1 本地温度监测:轮询、报警与联动逻辑
本地温度的用途主要有三个:一是作为设备内部的过热保护依据,二是作为控制逻辑的输入,三是用于本地显示屏或面板上的直观展示。我在这套系统里,用本地温度通道 CH0 做柜内温度监测,如果超过 85 度,立即触发报警,同时切断大功率负载,防止设备进一步升温。回风管道的 CH1 温度则参与 PID 调节,作为暖通控制的重要反馈变量。
报警逻辑的设计值得单独说一说。常见的错误做法是只在超过阈值的那一刻发送一次报警,然后温度降下来了就不再处理,结果现场巡检人员看到的永远只是一个“曾经超温”的记录。我建议设计成三级状态:正常、预警、报警,预警设一个接近阈值的提前量,比如报警阈值 85 度,预警阈值 80 度。进入预警状态之后开始计时,如果持续超过 10 分钟没有改善,再升级为报警。这种设计可以减少误报,又不会放过真实的持续超温情况。
本地数据展示方面,如果系统需要接一个数码管或者 LCD 面板,PIC18F96J94 提供的驱动能力可以直接带小型显示,不需要额外的显示驱动芯片,当然前提是电流消耗算好,不能超引脚最大驱动电流。我这次带了一块小尺寸 LCD,轮询频率是每秒更新一次显示,肉眼看起来数值很顺滑,没有闪烁感。
4.2 远程温度监测:通信链路与数据上报
远程温度的实现,核心在通信链路。我当时有两种选择,一种是用 RS-485 走 Modbus 协议,把温度数据汇聚到上位机或者触摸屏;另一种是通过无线模块转以太网,把数据推送到远程服务器。考虑到项目现场已经布好了 RS-485 总线,最终采用了 Modbus RTU 方案,主控作为从机,响应上位机的保持寄存器读取请求。
这里要提一个整洁的做法:PIC18F96J94 的 UART 配合 RS-485 收发器,需要控制 DE/RE 方向引脚。Modbus 主机发送请求时,从机处于接收状态;等到主机停止发送,从机经过一个短延时,把方向切换成发送模式,再回复报文。这个方向切换的时序很讲究,如果切早了,可能会把主机的最后一个字节吞掉;如果切晚了,回答报文就会超时。我用定时器做了一个 3.5 字符的帧间隔判断,主机停止发送后,等待这段时间才拉高 DE,实测下来,很多上位机软件都能正常响应。
远程温度的通道映射,我用 Modbus 寄存器统一定义:
| 寄存器地址 | 内容 | 类型 |
|---|---|---|
| 0x0001 | 本地柜内温度 | 只读 |
| 0x0002 | 回风管道温度 | 只读 |
| 0x0003 | 室外新风温度 | 只读 |
| 0x0004 | 远端风管温度 | 只读 |
| 0x0010 | 本地温度报警状态位 | 只读 |
| 0x0011 | 模块通道故障位 | 只读 |
路过 PLC 或者组态软件读这些寄存器,直接把温度值拿去画曲线、报警显示都可以。有一点经验得分享:寄存器里的温度值,我建议放大 10 倍传输,也就是 23.45 度表示成 2345,这样可以保留一位小数而不引入浮点数传输的麻烦。Modbus 报文是整数世界,浮点转成 IEEE 754 虽然也能传,但会增加上位机解析的复杂度,放大十倍是暖通行业很常用的做法。
4.3 通信异常与重连机制
远程通信不是永远稳定的。RS-485 线缆穿过强电区域,或者施工时被其他信号线干扰,都会导致通信丢包。我在固件里专门加了一个通信健康状态检测:主控维护一个“最近成功通信时间”变量,每次收到上位机的有效读请求就更新。如果超过 10 秒没有收到任何请求,就认为链路异常,本地指示灯闪烁告警,但温度采集和本地控制逻辑继续运行。
这个设计很重要,因为它保证了通信断了也不影响本地功能。很多项目里,远程通信只是为了数据集中监控,真正关键的设备保护逻辑全部在本地完成。如果通信一旦断了就连本地逻辑也停止,那现场会出大问题。所以我把“通信层”和“控制层”在代码里做了明显的模块隔离,通信任务卡住或者重连时,控制任务不受干扰。
另外,重连机制也要考虑模块自身的问题。PJ85718DM 如果长时间运行,偶尔也可能出现通信无响应的情况,我建议定时对模块做一次软重置,比如每 24 小时主动复位一次模块,避免某些底层状态卡死。这种做法不会影响温度数据的连续性,因为重新握手之后,模块能在几百毫秒内恢复数据输出。
5. 调试实战与问题排查
5.1 调试时读不到传感器数据怎么办
这个项目做原型测试时,我最先遇到的坑,是在 PJ85718DM 上电之后怎么都读不到数据。我用逻辑分析仪看 I2C 波形,发现主机发出地址之后根本没有 ACK,说明模块没有应答。排查过程是这样的:先查供电,模块供电从 LDO 出来后测量电压,3.3V 很稳,排除电源;再查上电复位,手动拉低复位脚之后再重新上电,依然没有 ACK;最后查波形,发现 SCL 和 SDA 都被外部上拉了,但我自己在板上又加了一组上拉,等于两个网络上的上拉电阻并联重叠了,虽然没有直接出问题,但电平被拉得过弱。
其实真正的原因是模块的地址在出厂配置里不是默认值,需要先读取 EEPROM 里的地址配置。我后来翻资料确认,PJ85718DM 模块的 I2C 地址在出厂时可能设过非默认值。解决方法是先用广播地址扫描一遍总线,把模块实际地址找出来,再把固件里的地址改成实际值。这个方法比逐个猜地址快得多。
排查这类问题的最佳路径,我给一个表:
| 异常现象 | 优先排查项 | 常见原因 |
|---|---|---|
| 无 ACK 应答 | 供电、地址配置 | 模块地址非默认、上拉缺失 |
| 有 ACK 但数据全 0 | 通道配置寄存器 | 通道未使能、传感器断线 |
| 数据跳变剧烈 | 滤波、干扰 | 长线未屏蔽、电源地噪声 |
| 数据稳定但偏差大 | 校准系数 | 探头未补偿、参考点漂移 |
5.2 温度跳变与毛刺:一次典型的现场干扰事故
安装到模拟机房环境测试时,有一路远程温度数据在压缩机启动瞬间会出现明显跳变,幅度有 3-4 度,然后几秒后才恢复正常。我开始以为是软件滤波不够,把滤波窗口加大到 16 点,结果跳变幅度变小了,但恢复变慢了。后来排查硬件才找到真正原因:远程探头线缆在走线时和压缩机的电源线绑在了同一个线槽里,压缩机启动瞬间的大电流在信号线上感应出了共模干扰。
解决方法是重新规划走线,让信号线和动力线分开,至少保持 30 厘米以上距离,如果必须交叉,交叉角度做成 90 度垂直。同时,我在探头线缆的末端增加了共模电感,把高频干扰滤掉一部分。这一轮整改之后,同样的测试工况下,温度数据纹波明显减小,系统稳定了。这里我的结论是:软件滤波能掩盖一部分硬件问题,但彻底解决问题必须回到源头,别指望 Rx 算法搞定所有电磁兼容问题。
5.3 HVAC 场景下的工程化细节
HVAC 系统跟普通消费电子产品最大的不同,是工作环境相对恶劣,而且故障影响面大。一个温度传感器失效,轻则显示异常,重则整个控制策略错误,可能让压缩机长时间高频运行,导致设备损坏。所以我在代码里对传感器故障做了很多保护:比如持续一段时间检测到温度值超出合理范围,就把该通道标记为“故障”,此时控制逻辑会使用安全默认值,而不是拿一个离谱的数据去计算。
另外,探头线缆在 HVAC 现场不应该做成活接头随意拔插,我见过很多现场因为接头进水导致信号短路。我自己的习惯是:所有室外探头进入设备之前,先做一个滴水弯,防止冷凝水顺着线缆流进设备内部。这一个小的安装细节,后期省掉了无数售后问题。
调试时还有一个容易被忽略的点:PIC18F96J94 的 ADC 模块如果没有使用,要记得把对应引脚配置成数字输入,避免意外消耗模拟输入通道。这个芯片外设多,软件上漏配某个外设的时钟门控非常常见。我调试时有一次怎么都进不了低功耗模式,最后就是 UART 模块的时钟还在跑,白白浪费了几毫安,这种问题在嵌入式开发里太典型了,写代码时一定要养成“用哪个外设,开哪个时钟”的习惯。
6. 成本评估与扩展方向
6.1 物料成本与装配成本参考
整套系统的硬件成本,不含外壳和线缆,大致可以拆成几个部分。PIC18F96J94 主控芯片在合理批量下的价格属于中等偏下水平,比 ARM 方案要低。PJ85718DM 模块作为前端采集单元,价格会比自搭模拟电路稍贵,但它省去了仪表放大器、基准源、滤波电容这些元器件,综合算下来 PCB 面积和调试工时都省了,性价比反而是划算的。尤其是项目要兼顾多路温度测点的时候,模块化的前端优势更明显。
装配成本方面,我建议模块和主控板之间做成接插件形式,不要直接焊死。这样模块万一损坏可以单独更换,不用整板报废。当然接插件也要选带锁扣的,否则 HVAC 设备长期震动,插头松脱的隐患很大。这个细节看起来小,现场吃过亏就会懂。
6.2 后续扩展方向
这套架构的扩展性很好。首先,PIC18F96J94 本身有丰富的外设资源,如果后续增加湿度传感器、压力传感器,只需要通过 I2C 或者单总线接入,固件里增加对应的协议解析即可。其次,远程通信接口可以考虑从 RS-485 换成以太网或者无线透传模块,代码里的数据上报模块可以抽象成“发送函数指针”,上层逻辑不用怎么动,只需要替换驱动层。
如果想做物联网化,可以在远程通信路径上加一个边缘网关,PIC18F96J94 把温度数据通过 RS-485 上报到网关,网关再转成 MQTT 推送到云端。这样主控端的代码几乎不用改,却能把监测范围从本地局域网扩展到远程云平台。我做这个项目时,刻意把数据格式设计成 Modbus 的通用寄存器,原因就是后续接入网关时,不需要定制协议转换。
6.3 个人实操体会
这套系统调试到最终稳定运行,我最有感触的一点是:温度监测项目从来不缺传感器和芯片,缺的是对“稳定”这两个字的耐心。PJ85718DM 把前端采集做得简单干净,PIC18F96J94 把数据处理和通信做得稳当有力,两者组合起来,整个系统架构清晰,问题边界明确。出问题的时候,我总能快速判断是模块问题、通信问题还是主控逻辑问题,而不是像以前单芯片方案那样,所有故障都混在一起,排查起来非常煎熬。
最后再分享一个小技巧:一定要在代码里保留足够的调试信息输出,哪怕是做产品阶段,也可以在编译宏的控制下预留一段 UART 日志打印功能,把每个通道的原始值、滤波值、报警状态周期性打印出来。有一次现场温度偶尔异常,就是靠这段日志抓到了探头因为接线松动引起的偶发断线,否则这种概率性问题可能要排查好几天。保留日志占用的 Flash 可能只有一两 KB,但它救场的能力绝对值得。