ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

PIC18F86J50+PJ85718DM实现HVAC温度监测与远程上报方案

PIC18F86J50+PJ85718DM实现HVAC温度监测与远程上报方案

聊到 HVAC 和嵌入式设备里的温度监测,很多人第一反应是:不就是接个传感器、读个数吗?但真正在现场做过项目的人都清楚,麻烦从来不在“读”上,而在怎么把温度安全、可靠地送到该看的人手里。我前阵子参与一个小型暖通机组改造,要求在本地控制柜里显示送风、回风温度,同时把数据同步到办公室的监控终端。当时的思路是用 PJ85718DM 做温度采集前端,配一颗 PIC18F86J50 单片机做控制和中转,通过 USB 虚拟串口接上位机,再把数据推到远程监控平台。整套东西成本不高,代码量也不算大,但从硬件接线到固件调试,踩了不少值得记录的坑。这篇就把这个方案的完整设计、关键参数和现场经验整理出来,给正准备做类似温度监测项目的朋友一个可以照着抄的底稿。

1. 方案选型:本地与远程温度监测的痛点与器件分工

1.1 HVAC 现场到底需要什么样的温度数据

先说现场需求。暖通机组里的温度不是一个孤立的测量值,它直接参与控制逻辑。回风温度低于设定值时,要判断是启动辅助加热还是加大风机频率;送风温度过高时,要联锁压缩机或调节冷水阀开度。这些判断对延迟敏感,传感器如果频繁通讯失败或者数据跳变,控制器就会误动作。所以本地方案首先必须稳定。

另一个层面是运维视角。现场控制柜里的表盘只有本地人员看得到,负责能耗管理的同事需要远程看到各机组温度变化趋势,用来诊断风机盘管有没有堵、冷媒量是不是少了。这就决定了系统必须有一个“本地采集 + 远程上报”的双路径结构。很多成品温控器也能做远程,但价格高、接口封闭、不方便二次开发;自己用分离器件搭则灵活得多。这也是这个项目不用现成温控模块的根本原因。

我在设计时把系统拆成了三层:传感器层负责把物理温度变成数字量,主控层负责读取、滤波、判断和通讯,上位机层负责展示数据并转发到远程。这样拆的好处是每一层都可以独立测试,传感器坏了只换传感器,主控程序升级不影响上位机,远程链路断了也不影响本地控制。项目里一共有 12 个温度测点,分布在三台机组上,如果每个点都要开发一套逻辑,管理负担会很大,所以统一走一套协议、一套处理流程是最省事的。

1.2 器件分工:PJ85718DM 管采样,PIC18F86J50 管上报

选 PJ85718DM,看中的是它的数字量输出和自带调理电路。如果是用 NTC 热敏电阻配 ADC,虽然器件单价便宜,但每一路都要做分压电阻、滤波电容、非线性校准,而且在低压差、长走线场景下误差很难控制。PJ85718DM 相当于把感温头、信号调理、模数转换和数字通信封装在一起,我读出的是已经换算好的温度值,省掉一大块标定工作。

PIC18F86J50 这边,这颗 8 位机带硬件 USB 外设,做上位机数据链路时不用再去费劲做电平转换和协议栈,直接虚拟串口就能跟电脑通信。它还有多个优先级中断和比较充沛的 GPIO,后续要扩展继电器控制、蜂鸣器报警也很顺手。相比用树莓派这类方案,这颗单片机不加风扇不装系统,上电就跑,稳定性更适合长期通电的 HVAC 环境。两块芯片各司其职:PJ85718DM 负责“把温度变成数”,PIC18F86J50 负责“把数变成可上报的信息”。

这里我整理了一个简单的方案对比表,供选型参考。

方案成本本地控制实时性远程扩展二次开发难度长期稳定性
成品温控器高好通常封闭难好
树莓派方案中受系统干扰好中中
PIC + 数字传感器模块低好依赖上位机链路易好

我当时选第三套,最核心的考量就是稳定可维护。HVAC 现场环境里电源波动、变频器干扰、人员误操作都很多,单片机方案不容易被这些问题带崩,出了问题也容易定位。

2. 硬件搭建:接线、电源与 I2C 通路上容易忽略的细节

2.1 引脚分配与模块地址设置

硬件第一件事是确定引脚分配。PIC18F86J50 的 I2C 模块可以映射到多个引脚组合,我选了一组不与 USB 冲突的引脚。PJ85718DM 这边,先用万用表确认模块丝印上的 VCC、GND、SCL、SDA,再按照模块手册设置地址。很多数字传感器模块都有 A0、A1 地址配置引脚,如果现场测点比较多,需要把地址错开,避免两条总线上的设备冲突。

我这次的接法如下表。

信号PJ85718DM 引脚PIC18F86J50 引脚备注
VCC3.3V稳压输出 3.3V按模块规格选择
GNDGNDGND必须共地
SCLSCLRC3/SCLI2C 时钟
SDASDARC4/SDAI2C 数据
ALERTALRRB0可选报警输入

这里要提醒一句:不同批次的模块引脚顺序可能不一样,接线前务必对着模块实物数据手册核对,不要只看网上教程里的图片。我自己就吃过亏,照着旧版本模块的引脚定义接新模块,结果 SDA 和 SCL 接反,调试了半个多小时才发现。

2.2 电源去耦:解决读数跳变的第一个突破口

HVAC 控制柜里通常有变频器和接触器,电源噪声是常事。我第一次通电时发现温度读数偶尔跳变,用万用表测传感器电源纹波超过 200mV,根源就是开关电源在变频器负载变化时下拉严重。后来在模块电源入口加了一颗 100uF 电解电容和 0.1uF 陶瓷电容,再用 LDO 单独给传感器供电,问题明显缓解。

如果现场只有 24V 交流变压器,要先做好整流滤波,再接 DC-DC 隔离模块给 MCU 和传感器供电,隔离电容很重要。3.3V 与 5V 混合供电时,务必确认 PJ85718DM 的 SDA/SCL 引脚是否兼容 3.3V,不稳妥就加电平转换器,或者干脆选 3.3V 版本模块,避免 I2C 钳位电路异常导致通讯失败。

2.3 通信时序与上拉电阻选择

PJ85718DM 如果是标准 I2C 接口,总线上需要接上拉电阻。实际经验是:短线用 4.7k,超过 1 米用 2.2k 或 1k,不要为了省电用 10k,因为寄生电容一大,上升沿就会变缓,单片机容易误读。如果模块支持 OneWire 类接口,时序更敏感,必须在微秒级的延时上严格测试,优先生成延迟函数而不要依赖 for 循环凑时间,因为编译器优化等级不同会有很大差异。

我在项目里用 I2C 方式,配置成 100kHz 标准模式,读取一次温度大约几十毫秒,对控制逻辑和远程上报来说完全够用。选择低速模式不是为了慢,而是为了在长线传输时减少沿抖动,给线缆寄生电容留足充放电时间。这个思路跟串口通信里“能 9600 就不用 115200”一个道理,能用低速解决可靠性问题时,没必要追求高速。

3. 固件实现:从传感器读数到远程上报的完整链路

3.1 主循环状态机与温度读取代码

固件整体是一个带状态机的裸机循环:上电初始化时钟、GPIO、I2C 外设和 USB CDC,然后进入主循环。每个循环周期里依次执行温度转换命令、等待转换完成、读取数据、校验、滤波、上报。很多人会偷懒直接连续发读命令,但很多传感器模块从发出转换命令到数据就绪需要时间,连续读很容易拿到上一次的旧值或者正在跳变的中间值。

我这里给一段简化的温度读取代码,实际寄存器地址和解析方式以所用模块的手册为准。

#define TEMP_SLAVE_ADDR 0x48 #define TEMP_REG_DATA 0x00 uint8_t read_temperature(float *temp) { uint8_t buf[2] = {0}; uint8_t ret = i2c_write_read( TEMP_SLAVE_ADDR, TEMP_REG_DATA, buf, 2 ); if (ret != I2C_OK) { return 0; } int16_t raw = (buf[0] << 8) | buf[1]; // 以常见的 12 位温度传感器精度为例,分辨率为 0.0625℃ *temp = raw * 0.0625f; return 1; }

代码里最关键的一点是重试机制。I2C 读一次失败,不代表模块真的坏了,可能是总线被瞬态干扰拉了一下。我在实际项目里做了三次重试:第一次失败后延时 10ms,再试第二次;第二次失败后延时 50ms,再试第三次;三次都失败才把对应通道标记为故障。这样处理下来,两个多月运行时间里几乎没有出现过误报故障的情况。

3.2 数据滤波、阈值判断与配置参数保存

读到的温度不能直接用,HVAC 设备启动和停机瞬间会产生尖峰,机械振动也可能让传感器探针瞬间接触不良。我在固件里做了三步处理:第一步剔除明显越界的野值,比如突然跳变超过 5℃ 就保留上次数值;第二步做滑动平均,取最近 5 次有效数据的平均值;第三步才进入控制逻辑。同时给每组温度设置上限和下限报警阈值,阈值参数放到配置区,方便现场用串口命令调整,而不需要改固件重烧。

这里要注意的是,阈值判断时不要直接用滑动平均后的值做单一比较,因为启动瞬间的温度变化是正常的,直接用平均值判断容易误报警。我加了一个“持续确认”逻辑:只有当温度越界状态维持 3 个周期以上才真正触发报警标志。这个思路就像门禁系统不会因为一次刷卡失败就锁门一样,连续几次失败才会触发报警,减少误报。

3.3 上位机解析与远程推送的最小闭环

单片机通过 USB CDC 虚拟串口把数据打成文本帧发到上位机,帧格式很简单,比如“T1:23.4 T2:24.1 T3:22.8\n”。上位机端写一个简单的串口解析脚本,把数据转换成结构化内容,再通过 MQTT 或 HTTP POST 推到远程服务,实现真正意义上的“远程温度监测”。这整套方案里最费时间的不是单片机固件,而是上位机侧数据格式兼容问题,因为不同人员写的小工具互相不统一,换一台电脑就乱套。所以从一开始就要定好一个固定帧格式,并把这套格式文档化。

下面是 Python 读取串口并推送数据的示例。

import serial import json import requests ser = serial.Serial('/dev/ttyACM0', 115200, timeout=2) while True: line = ser.readline().decode('utf-8', errors='ignore').strip() if not line: continue parts = line.split() data = {} for item in parts: key, value = item.split(':') data[key] = float(value) print(data) # 推到远程监控服务 try: requests.post( 'http://your-server:8080/api/temp', json=data, timeout=2 ) except requests.exceptions.RequestException: # 网络不可用时先放本地队列,后面再补传 pass

注意这里演示了生产环境里很重要的一个思路:网络不可用时不能丢数据。我在项目里把上报请求放到独立线程,网络不通时数据先写本地队列文件,等网络恢复后再逐条补传。这样远端看到的温度曲线是连续的,不会被网络抖动切成一段一段的。

4. 实测调参:校准、抗干扰与长期运行可靠性

4.1 两点校准:把“模块准”变成“系统准”

任何模块出厂都有精度指标,但装进 HVAC 管道和机柜后,还要做系统级校准。我的做法是准备一支经过标定的高精度温度计,把传感器探头和标准温度计放在同一恒温环境中,比如保温杯装温水,稳定后读数,记录两组温度值;再换一个低温点,比如冰水混合物,做两点线性修正。修正公式是:真实值 = 斜率 × 测量值 + 截距。把斜率和截距写进单片机的 Flash,读出后先修正再上报。

实测下来,模块本身在 0~70℃ 内线性度不错,主要是安装位置导致偏差。比如探头紧贴金属水管和悬空测空气的差别可能超过 2℃,这不是传感器的错,是安装方式的问题。所以校准前一定要先定好安装规范:测空气温度要加百叶罩防辐射,测管道温度要涂导热硅脂,测回风温度要放在气流混合均匀的区域。传感器选得再好,安装位置不对,校准也救不回来。

校准数据示例:

测点标准温度计读数模块原始读数修正后读数
低温点0.2℃0.5℃0.2℃
高温点50.1℃49.7℃50.1℃
运行过程34.8℃34.4℃34.8℃

4.2 长线布线与变频器干扰的实测处理

温度采集点分布在机组各部位,走线通常超过 1 米。我踩过的坑是:I2C 线走得太靠近变频器输出线,读值开始出现间歇性错误,用示波器看 SDA 线上叠着尖峰。处理办法是换成屏蔽双绞线,屏蔽层单端接地;传感器供电单独走一路,不要和风机调速电源共用。如果模块支持单总线,它对时序更敏感,干扰会导致搜索设备失败,所以能用 I2C 模式就尽量用 I2C 模式。

另外还有一个容易忽略的点是屏蔽层接地方式。我在项目里一开始把屏蔽层两端都接了地,结果变频器启动瞬间反而出现了更大的地环路电流,读值毛刺更多。后来改成只在主控板一侧单端接地,干扰明显下降。这个细节在现场很值得注意,两边接地不一定是好事,单端接地往往更实用。

4.3 看门狗与断线续传:7×24 小时运行的底气

暖通机组基本是 7×24 通电,温度监测程序不能跑几天就死掉。我在固件里开了独立看门狗,主循环每周期喂狗;同时加了通信超时机制:如果上位机连续一段时间没有回应,单片机不阻塞等待,继续本地采集,数据存在内部缓冲区,等通信恢复再补传。传感器模块偶尔会无响应,我在 I2C 出错后不立即复位整机,而是先重试三次,再执行模块软复位,最后才考虑重新初始化外设。

看门狗这里要注意,喂狗的位置一定要在主循环“已经完成一整轮有效工作”之后,而不是在循环最前面随便喂。如果喂狗指令放在循环开头,主循环后半段卡死了,看门狗照样不会复位,这个保护就形同虚设。我在调试时就有一次把喂狗放在读取温度之前,后来模拟通讯卡死时设备没有按预期复位,排查了半天才意识到是喂狗位置的问题。

5. 常见问题速查表与现场维护建议

5.1 读取异常与地址冲突排查

温度数据完全读不到,这是最常见的启动期问题。先确认模块地址和代码配置一致,扫描一下总线上所有设备;再测 SCL/SDA 是否有波形,如果没有波形,查上拉电阻和引脚分配。还有一种情况是电源问题,模块需要先稳定供电才能响应,建议上电后延时 100ms 再初始化。

现象可能原因解决措施
读值固定为 0 或 255模块地址错误、I2C 地址冲突扫描总线设备地址,核对代码
读值偶尔跳变电源纹波大、线缆靠近强电加去耦电容,屏蔽层单端接地
通讯完全无响应SDA/SCL 接反、上拉电阻缺失核对引脚,用万用表测量波形

5.2 远程丢帧与延迟处理

如果是 USB 虚拟串口丢数据,检查上位机串口读取缓冲区和读取线程;如果是网络上报延迟,可能是上报端用了同步阻塞请求。我在现场把上报改成独立线程,网络不通时数据先放队列,这样不会拖慢串口解析。另外串口波特率不要设置太高,115200 足够,太高反而容易在 USB 转接环节丢帧。

还有一个经验是文本帧要带校验。我之前图省事,直接用“T1:23.4”这样不带校验的格式,有一次线缆接触不良导致某帧被截断,上位机解析出了一条 253℃ 的异常数据,差点让远程监控平台触发报警流程。后来在帧尾加了简单的异或校验位,解析时校验不过就丢弃整帧,问题再没出现过。

5.3 换探头、升级固件和维护规范

温度模块本身属于易损件,现场应留一两个备用探头。升级固件时只更新应用区,保留引导程序,这样即使新固件有问题,也可以通过串口回退。如果后续要扩展,可以把 USB 链路替换成串口 WiFi 模块或 LoRa 模块,单片机侧代码几乎不用动,只是把串口数据帧换个通道发出去,就能把监测范围扩到整个厂区。

维护时还建议建立一张测点清单,记录每个测点对应的模块地址、安装位置、校准日期和校准系数。项目运行两个月后,我回现场检查时发现有一个测点偏差变大,查记录才发现那个探头装在了阳光直射的窗户附近,和设计时的安装位置不同。有了记录,这种问题定位起来会快很多。

说实话,这套方案做完,我最深的体会是“在工业现场,稳定比花哨重要”。PJ85718DM 加 PIC18F86J50 都是很基础的器件,但把它们组合好,再配上一个清晰的协议,完全能抗住 HVAC 现场的环境考验。如果你也打算自己动手做温度监测,我建议不要一上来就追求复杂功能,先把一条链路从传感器读到上位端打通,再慢慢加报警、远程、断电续传这些外围能力。后面的扩展空间很大,成本也不高,值得一试。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进