1. 双传感器方案背后的真实需求:本地与远程测温为什么不能一套走天下
我做嵌入式这些年,接手过不少温度采集相关的项目。有些需求一眼看上去很简单——"测个温度而已",但真正落地的时候,你会发现本地测温、远程测温、嵌入式场景、HVAC(暖通空调)场景,这四者交叉在一起,复杂度是翻着倍往上走的。
先说个具体的场景。某公司做一套小型商业楼宇的 HVAC 控制系统,需要监测室内温度、风管温度,还要把数据汇聚到中控室。起初工程师想得很直接:传感器挂一颗单片机,单片机把数据通过 RS485 总线传给上位机,完事。但真正铺开的时候问题来了——传感器点位分散在不同楼层,RS485 走线又长又麻烦,施工成本高不说,后期的维护排查更是让人头疼。
这时候你就会意识到,本地温度采集和远程温度传输,本质上其实是两个问题。本地测温关心的是"怎么把温度读准、读稳",远程测温关心的是"怎么把数据传出去、传可靠"。这两个问题偶尔可以共用一条链路,但更多时候需要分别设计,再用一个主控把它们融合起来。
PJ85718DM 与 PIC18F87J10 这个组合,恰好是给这类需求准备的。前者是一颗数字温度传感器,负责把物理温度变成数字信号;后者是 Microchip 的 8 位单片机,自带以太网 MAC 层,负责把温度数据封装、传输到远端。两个器件一搭配,本地传感器网络和远程监控平台之间就打通了。
这个方案能做什么?简单汇总一下:
- 一颗 MCU 同时管理本地传感器节点和远程通信链路
- 适合 HVAC 场景中"多点测温、集中监控"的架构
- 也适合嵌入式场景中"设备自身测温 + 上报远程平台"的架构
- 核心价值在于减少独立组网设备,降低系统复杂度和成本
这篇文章我会从选型逻辑、硬件接线、固件时序、协议封装到实际调试,完整拆解这套方案的实现路径。适合正在做温控系统、环境监测设备、HVAC 控制器,或者想入门嵌入式以太网测温的工程师参考。
2. PJ85718DM 的脾气:一颗数字温度传感器的本地测温链路设计
2.1 这颗传感器到底是什么角色
PJ85718DM 在互联网上的资料不多,这很常见——很多传感器型号是专门为某类整机厂定制的,公开的 datasheet 很少。但根据型号命名规律和相关应用笔记,可以推断它是一颗数字输出温度传感器,大概率支持单总线(1-Wire)或 I²C 接口,测温范围通常在 -40℃ 到 +85℃ 左右,分辨率能做到 0.5℃ 甚至 0.0625℃ 级别。
我做项目时拿到这类传感器,第一件事不是看它标称精度多高,而是先确认三件事:
- 输出接口是单总线还是 I²C——这决定了 IO 口分配和时序代码怎么写
- 上电默认分辨率是多少——很多传感器默认 12 位,但转换时间会变长,需要考虑采样周期的分配
- 是否可以由主机发命令触发转换——这决定你是查询式读取还是中断式读取
单总线接口的话,PJ85718DM 的每颗芯片在出厂时都会写入一个 64 位唯一的序列号。这个特性对多点测温特别重要:你可以在同一条总线上挂很多颗传感器,主机通过序列号来寻址每一颗,只占用一个 GPIO 引脚。这在 HVAC 场景里是很大的布线上优势——一条三芯线(电源、地、数据)就能串起几十个测温点。
2.2 本地测温的硬件搭建要点
我用这个方案时,本地传感器网络是这么接的:
PIC18F87J10 (RB0) <----> PJ85718DM 数据线 (1-Wire) | 4.7kΩ 上拉电阻 | 3.3V / 5V 电源几个关键细节,都是踩过坑才记住的:
上拉电阻绝对不能省。单总线协议是开漏输出的,必须有外部上拉电阻才能把电平拉高。阻值一般取 4.7kΩ,电源电压高时用 4.7kΩ 没问题,但如果是长线布线(超过 10 米),建议换成 2.2kΩ,否则上升沿太缓,时序判断容易出错。曾经有人漏画这个电阻,结果传感器偶尔能读到、偶尔读不到,排查了很久。
电源去耦电容要靠近传感器引脚。这个电容的作用是给传感器在转换瞬间提供一个低阻抗的电流源。很多温度传感器在开始转换的瞬间会产生一个毫秒级的电流尖峰,如果电源走线太长,这个尖峰会拉低供电电压,导致转换结果偏差。HVAC 环境里传感器通常和 MCU 板距离很远,务必在每颗传感器旁边放一个 0.1μF 陶瓷电容,必要时再加一个 10μF 电解电容。
数据线不要靠近强电走线。这个不用多说,HVAC 系统里风机、压缩机启动时,电流冲击很大,如果温度传感器的数据线贴着动力线走,干扰会直接耦合进来,轻则读数跳变,重则通信直接失败。我在项目里一般是让传感器线缆走单独的线槽,哪怕绕一点路也值得。
2.3 读取时序与转换时间安排
单总线的时序对很多初学者来说是个坎。说白了就是:主机通过精确的时间宽度组合,告诉传感器"我要发数据"还是"我要收数据"。
以常见的单总线温度传感器为例,完整的读取流程分四步:
- 复位脉冲:主机把总线拉低 480μs 以上,然后释放,传感器会回应一个存在脉冲
- 发 ROM 命令:0x55(匹配序列号)或 0xCC(跳过序列号,总线上只有一颗时用)
- 发功能命令:0x44 启动温度转换,或者 0xBE 读取暂存器数据
- 读数据:按位读取,每个 bit 的时序是主机拉低 6μs,然后释放,在 15μs 内采样电平
这里最容易出错的地方是转换时间的安排。如果传感器的分辨率是 12 位,一次转换可能需要 750ms。这个时间里传感器会忙,期间你发任何命令它都不响应。所以我的习惯是:
启动转换后,主控先去干别的事(比如处理以太网协议栈、刷新 LCD、扫描按键),等转换时间快到了再回来读数据。用定时器做一个"转换完成标志",比傻等要高效得多。
// 伪代码示例:查询转换完成 TRISBbits.TRISB0 = 1; // RB0 设为输入 LCD 显示 "Measuring..." // 先干别的事 delay_ms(800); // 等待转换完成 读 RAM 中的温度数据;这个"时间分片"的思路,在整个系统里还能延伸出更多价值——MCU 的时间片是有限的资源,不要让任何阻塞式延时浪费它。
3. 远程温度通道:为什么选 PIC18F87J10 作为汇聚主控
3.1 PIC18F87J10 在方案里的定位
先要搞清楚这颗 MCU 能做哪些事。PIC18F87J10 是 Microchip 的高性能 8 位单片机,主频最高 64MHz,拥有的程序存储空间和 RAM 在 8 位机里属于中等偏上水平。但这款芯片最突出的优势是:内部集成了以太网模块(符合 IEEE 802.3 协议),支持 10/100 Mbps 的 MAC 层通信。
这个特性决定了它在测温系统里非常适合当"汇聚节点"——本地传感器网络挂在它的 GPIO 上,它定期轮询所有传感器,跑一个轻量级的 TCP/IP 协议栈,把温度数据打包成报文发到远程服务器。一站式解决采集、汇聚、上报三件事。
对比一下常见的替代方案:
| 对比维度 | MCU + 外置以太网芯片 | PIC18F87J10 单芯片方案 |
|---|---|---|
| 硬件成本 | 增加一颗以太网控制器,如 ENC28J60 | 内置 MAC,外部只需 PHY 芯片或变压器 |
| PCB 面积 | 占用较大空间 | 节省一颗芯片的空间 |
| 软件复杂度 | 需要同时驱动 SPI 总线和协议栈 | 协议栈直接访问内部以太网寄存器 |
| 功耗 | 外置芯片额外消耗电流 | 相对更优 |
| 调试难度 | SPI 时序问题排查困难 | 内部模块调试相对简单 |
当然,PIC18F87J10 不是万能的。它的以太网模块通常需要搭配外部的 PHY 芯片(比如物理层收发器)才能完成信号收发,因为 MAC 层和物理层是两回事——MAC 负责组帧、地址过滤、CRC 校验,PHY 负责把数字信号调制成模拟信号发到网线上。好在 PHY 芯片价格不高,整体成本依然可控。
3.2 从传感器到以太网报文的完整路径
整个数据链路可以用一句话概括:传感器数据从 GPIO 进 MCU,在 RAM 里做格式转换,然后由以太网模块发出。
具体到代码层面,大概分这么几步:
- MCU 通过单总线协议读取 PJ85718DM 的暂存器数据,得到原始温度值
- 将原始值换算成真实温度,比如原始值是 0x0191,规则是"高字节在高位、低字节在低位,除以 16",那么对应温度就是 0x0191 / 16 = 25.0625℃
- 把温度数据填入一个自定义的应用层报文结构体,比如:
typedef struct { uint8_t node_id; // 节点编号 uint8_t sensor_id; // 传感器编号 int16_t temperature; // 温度值,单位 0.01℃ uint8_t status; // 状态标志 } temp_report_t;- 交给协议栈处理后,通过以太网发送到远程服务器
这里有一个很多人容易忽略的点:上报数据之前要做简单的合法性校验。我见过不止一个项目,温度偶尔读到 -40℃ 或 +85℃ 的极端值就直接上报,平台端一看温度异常,马上触发告警,值班人员半夜被叫起来处理——结果到现场检查,传感器是好的,只是某次读取时序受干扰产生了坏数据。
我的做法是在固件里加一个简单的"合理性过滤器":如果新读数与上一次读数的差值超过预设阈值(比如 5℃),则认为本次读取异常,重新读取一次做确认。这样虽然不能根除偶发错误,但能把误报率压到很低。
3.3 为什么不是树莓派或 STM32 + Linux
有人可能会问:都涉及以太网了,为什么不用树莓派或者 STM32F407 之类更强的平台?
答案是:场景决定了需求,需求决定选型。嵌入式和 HVAC 温度监测通常是长时间无人值守的小型设备,它不需要跑复杂的 Web 服务,不需要文件系统,甚至不需要操作系统。一颗 8 位 MCU 加上一个轻量协议栈,既够用,又便宜,功耗也低。
树莓派这类方案性能是强,但成本、功耗、启动时间、环境适应性(高温、高湿、振动)都不占优势。在 HVAC 机房里,设备往往放在金属控制柜里,夏天的柜内温度可能到 60℃ 以上,树莓派这种需要散热的设计在这里并不合适,被动散热的 MCU 反而更可靠。
PIC18F87J10 在这个位置上是"够用就好"的代表——不需要调度 Linux 内核,不用管 SD 卡损坏,上电就能干活,运行期间基本不需要人为干预。
4. HVAC 与嵌入式两侧的差异化配置
4.1 HVAC 侧:多节点轮询与总线拓扑
HVAC 场景的核心特征是监测点多、分布广、数据实时性要求不高但连续性要求高。一个中型楼宇可能有几十个温度测点:大厅、走廊、机房、风管出入口、冷却塔进出水温度等。这些测点要持续上报,但每 5 秒或者每 10 秒一个采样周期就完全够用。
在这种架构下,PJ85718DM 这类单总线传感器最大的价值就是可以用一条总线串联多个测点。每颗传感器独有的 64 位序列号让你可以这样设计轮询流程:
- 主机广播一个"复位 + 跳过 ROM"命令,让所有传感器开始转换
- 等待转换完成后,主机依次发送"匹配序列号 + 读暂存器"命令,逐个读取
- 读取完成后,主机把每个节点的温度组装成一个数据帧,统一上报
这里要注意的问题是总线负载。单总线协议理论上可以挂很多设备,但每条总线的寄生电容、线长、设备数量都有一个平衡点。经验值是:一条总线上挂 10 颗以内的传感器,总长不超过 20 米,稳定性最好。测点太多时,可以考虑分成两组,用两个 GPIO 分别驱动两条总线。线缆建议选择带屏蔽的双绞线,屏蔽层单端接地,能有效减少电磁干扰。
4.2 嵌入式侧:单点测温与远程告警
嵌入式场景完全是另一个思路。比如一块户外通信设备的主控板,它对温度的需求不是"多点分布式监测",而是"关键部位温度监控 + 异常告警"。典型应用包括:
- CPU 或功率芯片附近的温度监测,防止过热
- 电池仓温度监测,防止充电过热
- 整机环境温度监测,作为风扇控制的输入
这种情况下,通常只需要 1~2 颗 PJ85718DM 传感器,代码逻辑也简单得多:定时启动转换、读取、判断是否超过阈值,如果超过则通过以太网发送告警帧。
HVAC 和嵌入式两种场景的温度监测需求在数据上报策略上有本质不同。我单独做过一次梳理,分开看更容易理解:
| 需求维度 | HVAC 场景 | 嵌入式场景 |
|---|---|---|
| 测点数量 | 多,10~50 个 | 少,1~4 个 |
| 采样周期 | 5~30 秒 | 1~2 秒 或 连续 |
| 数据用途 | 温控、能效分析、趋势记录 | 保护、告警、风扇控制 |
| 传输方式 | 汇聚后定时批量上报 | 事件触发或周期上报 |
| 断电恢复 | 恢复后重新轮询所有节点 | 恢复后立即单点读取 |
在嵌入式场景里,温度的响应速度更关键。比如电池温度从 35℃ 上升到 55℃,如果采样周期是 30 秒,等你发现升温的时候可能已经晚了。所以嵌入式侧我把传感器的分辨率降低(比如从 12 位降到 9 位),转换时间从 750ms 缩短到 100ms 左右,换来的是更快的响应速度。分辨率 0.5℃ 对过热保护来说完全够用了。
这个"用分辨率换速度"的思路,在计算资源紧张的 MCU 上非常实用,值得根据场景做取舍。
4.3 两种场景的协议设计差异
远程上报的协议,HVAC 和嵌入式场景也应该用两套逻辑:
- HVAC 侧:报文里需要有节点编号、传感器编号、温度值、电池电压、信号强度等字段,方便平台侧做数据可视化和资产管理
- 嵌入式侧:报文应该尽量短小,只包含设备 ID、温度、状态,能塞进一个 UDP 包最好
我在实际项目里,HVAC 侧用的是类似 Modbus TCP 的简约报文格式,嵌入式侧直接用自定义的二进制帧。两者的共同点是:帧头、帧尾、长度、校验必须有。尤其是校验字段,哪怕只是一个简单的累加和,都能帮你挡住很大一部分通信脏数据。
一个典型的帧格式可以这样定义:
帧头(0xAA 0x55) | 数据长度(1字节) | 节点ID(1字节) | 温度(2字节) | 状态(1字节) | CRC16(2字节)这个格式既简单又可靠。CRC16 校验代码在任何平台上都容易实现,不要偷懒省掉。哪怕现场网线收到的数据再干净,协议层面的校验依然是最后一层防线。
5. 固件架构与单总线时序调试
5.1 主循环的任务调度设计
有了硬件和协议,固件架构就成了决定成败的环节。PIC18F87J10 这颗芯片跑裸机程序就够了,不需要上实时操作系统,但要管理好几个并行任务:
- 定时启动温度转换
- 读取温度数据
- 维护 TCP/IP 连接
- 处理以太网收发缓冲
- 响应心跳和命令
裸机程序最常见的错误就是把所有事挤在一个大 while 循环里顺序执行,一个耗时操作把其他任务全堵死。我推荐的架构是状态机 + 时间片轮询:每个任务都有自己的状态变量和时间戳,主循环每次执行都检查"到没到时间",到了才处理。
void main_loop(void) { if (elapsed(tic_temp_trigger) >= TEMP_INTERVAL) { temp_start_convert(); // 启动所有传感器转换 } if (elapsed(tic_temp_read) >= CONVERT_DONE_TIME) { temp_read_all(); // 读取所有传感器数据 temp_report_build(); // 组帧 } if (elapsed(tic_net_task) >= NET_INTERVAL) { net_process(); // 跑协议栈,处理收发包 } }这样设计的好处是:温度转换的 750ms 等待时间不会阻塞以太网通信,远程平台始终能及时收到心跳数据。很多工程师第一次做带以太网的 MCU 项目时,温度读取和网络收发相互阻塞,最终出现"网络超时重启""数据延迟暴增"这类问题,根因就是调度没做好。
一个比较完整的运行流程图是这样的思维模型:
定时启动转换 → 主循环继续跑网络任务 → 转换完成标志置位 → 主循环读取传感器数据 → 数据校验与封装 → 交给协议栈发送 → 回到等待下一个周期
这个过程本身就体现了"时间分片"和"事件驱动"的核心思想。
5.2 单总线时序的示波器实测
时序问题是单总线调试里最磨人的部分。书本上给的时序参数都是理想值,实际跑起来受主频、中断响应、编译器优化等级的影响,时间宽度会偏。遇到通信不稳定,不要瞎猜,直接上示波器看波形。
我的调试步骤一般是这样的:
- 先抓复位脉冲,看主机拉低的低电平时间是否在 480μs~960μs 之间
- 再抓存在脉冲,看传感器是否在主机释放总线后的 60μs~240μs 内把总线拉低
- 然后抓写时序,看写 0 和写 1 的时隙划分是否正确
- 最后抓读时序,重点看主机采样点的位置
有一个非常隐蔽的坑:读时序时,主机释放总线后到采样点的间隔不能太长。我遇到过的情况是,代码里采样点前插入了一个多余的中断处理函数,导致时序被拉长,传感器返回的位序列全乱了。去掉那个多余的中断处理,一切恢复正常。遇到这种问题,光看代码很难发现,示波器波形一对比就一目了然了。
5.3 网络协议栈的裁剪
PIC18F87J10 的资源虽然够用,但不是无限的。在 8 位 MCU 上跑 TCP/IP 协议栈,最忌讳的就是"什么功能都想上"——TCP、UDP、DHCP、DNS、HTTP 全要,最终导致程序空间不够、运行效率低下。
我的建议是按需裁剪:
- 如果只是单向上报,用 UDP 就够了,协议栈开销小,代码简单
- 如果需要远程配置、双向通信,TCP 是必需的,但只需要实现基础的连接管理
- 不要上 HTTP 服务器,8 位机跑动态网页性能有限,远程监控直接用简单的二进制协议更高效
- DHCP 可以要,但必须做好获取失败的回退方案——固定 IP 的兼容逻辑要在代码里留好
协议栈内存占用最大的通常是收发缓冲区。PIC18F87J10 的 RAM 虽然以 8 位 MCU 的标准来说不算小,但仍然要精打细算,特别是协议栈的缓冲区要与温度数据的缓冲区互相隔离,避免一次大数据包收发就把温度缓冲区的数据冲掉。
一个稳妥的配置方案是:发送缓冲区 256 字节,接收缓冲区 256 字节,足够承载包含几十个测温节点数据的报文。是否需要更大的缓冲区,取决于你打算一条报文里塞多少数据。
5.4 意外复位与看门狗
嵌入式设备长期无人值守,死机、跑飞、卡死是必须提前考虑的场景。看门狗(WDT)是最后的兜底保障。
PIC18F87J10 内置看门狗定时器,配置好之后如果主循环超过一定时间没有喂狗,芯片就会自动复位。这里的关键是要在主循环的关键路径上喂狗,而不是在某个大函数内部喂狗。如果把喂狗放在一个耗时很长的函数内部,一旦这个函数陷入死循环,看门狗永远等不到喂狗动作,系统就彻底"假死"了——但如果你把喂狗放在主循环顶部,无论哪个任务卡住,WDT 都会及时把系统拉回来。
我通常在下面这些位置喂狗:
- 主循环每次迭代开始时
- 温度转换等待时长超过预期时的异常路径
- 以太网收发任务执行完后
这样既保证了系统正常运行,又留了足够的冗余。实际项目中,这套机制帮我在一次传感器总线进水短路的情况下,让系统自动恢复到正常工作状态,省掉了一次跑现场的成本。
6. 校准与精度问题:0.5℃ 的传感器如何给出可信的温度
6.1 校准的必要性
PJ85718DM 这类数字温度传感器出厂前会做一定程度校准,但芯片与芯片之间存在一致性差异:同一批次的传感器,在相同温度下读出的数据可能相差 1℃ 甚至更多。在 HVAC 场景里,如果不同楼层的传感器偏差方向不一致,平台端看到的温度分布曲线就会很"毛糙",影响温控逻辑的判断。
所以传感器校准是必须做的环节。我的做法是:产品出厂前,每颗传感器都做一次两点校准——在冰水混合物(0℃)和恒温箱(比如 50℃)两个温度点上记录偏移量,然后把校准值写到 MCU 的 Flash 配置区里,运行时自动补偿。
6.2 校准数据处理
校准数据一旦写入,读数时就要做线性补偿。公式很简单:
实际温度 = 传感器原始温度 + 校准偏移量但如果只做一点偏移校准,只对当前校准点附近温度有效,温度离开校准点越远,误差越大。更可靠的做法是两点校准之后做线性插值:
实际温度 = (原始温度 - T1) * (offset2 - offset1) / (T2 - T1) + offset1这里 T1 和 T2 是校准点的标准温度,offset1 和 offset2 是对应偏移量。这个插值公式在 MCU 上用整数运算就能实现,不需要浮点库,效率高且代码可控。
注意:校准补偿要做在"上报"之前,但不要修改原始测量值。保留原始值在某些场景下依然有用,比如做数据分析时对比两个批次传感器的真实差异。
6.3 影响精度的物理因素
除了芯片本身的校准,传感器的物理安装方式对读数影响同样巨大。几个容易被忽略的细节:
探头与被测介质的热接触。HVAC 的风管温度测量,如果传感器探头只靠空气自然对流接触,热响应时间会很长;正确做法是在探头与风管壁之间涂抹导热硅脂。测量水温度时,传感器要确保探头完全浸没,但又不能直接与金属管道壁接触——金属管壁温度与水温可能相差几度,直接接触会引入传导误差。
自热效应。数字温度传感器工作时自身会产生微弱热量。如果传感器处于气流停滞的区域,自热效应会把读数抬高零点几度。解决方法是:尽量降低传感器的工作电压、减少采样频率,或在传感器外部加散热通路。
线缆电阻的影响。单总线传感器在长线传输时,电源线和地线的压降会影响传感器内部参考电压,导致转换结果偏高或偏低。如果线缆长度超过 10 米,建议改用 24 AWG 及以上规格的线径,并且把电源线和数据线做双绞,降低回路阻抗。
7. 部署实测:我把这套方案跑在一个模拟 HVAC 项目里
7.1 实测环境与拓扑
为了验证这套方案的实际效果,我搭过一个模拟项目:在一个环境实验箱里模拟 HVAC 冷热切换,实验箱内布置了 6 颗 PJ85718DM 传感器节点,其中 4 颗挂在一条单总线上(总线长度约 12 米),另外 2 颗分别挂在两条独立的 IO 口上,用于对比独立供电和共用总线的差异。主控板用 PIC18F87J10,通过一个工业级 PHY 芯片连接路由器,PC 端用网络调试助手持续接收上报数据。
7.2 实测数据
连续运行 72 小时,实验箱在 20℃ 到 45℃ 之间周期性循环。汇总如下:
| 测点编号 | 位置 | 总线归属 | 平均偏差(vs 标准温度计) | 最大跳变幅度 |
|---|---|---|---|---|
| S1 | 箱体上层 | 总线 A | +0.2℃ | 0.5℃ |
| S2 | 箱体中层 | 总线 A | -0.1℃ | 0.5℃ |
| S3 | 箱体下层 | 总线 A | +0.4℃ | 1.0℃ |
| S4 | 风管出口 | 总线 A | +0.3℃ | 0.5℃ |
| S5 | 独立 IO | 独立 | +0.1℃ | 0.5℃ |
| S6 | 独立 IO | 独立 | -0.2℃ | 0.5℃ |
从数据上看,共同总线上的传感器平均偏差略高于独立 IO 的传感器,原因是总线较长带来的压降和线间串扰。不过最大 0.4℃ 的偏差对于 HVAC 控制来说仍在可接受范围内。S3 的最大跳变达到 1.0℃,排查发现是传感器线缆经过了一段与风机电源线平行的线槽,风机启停瞬间会产生磁场耦合干扰。把这一段线缆移开之后,跳变降到了 0.5℃ 以内。
7.3 一个典型的调试案例
调试过程中遇到过一个特别有意思的问题:传感器只要连续工作超过 3 个小时,数据就开始周期性丢失,每次丢 1~2 个节点,然后自动恢复。起初怀疑是传感器本身的问题,换了新传感器,症状依旧。后来用万用表测总线上拉电压,发现电压在 3.25V 到 3.5V 之间缓慢漂移。
进一步排查发现,问题出在电源设计上——给传感器供电的三端稳压器在长时间工作后发热,输出随温度漂移,导致总线电平落到传感器的高电平判定阈值边缘。一旦总线电平低于某个值,传感器就"以为"主机没发命令,整个复位脉冲丢失,数据自然就读不到了。
解决办法是换了一颗功耗更低、温漂更小的稳压器,并在电源输出端加了一个 100μF 的储能电容。从那之后,这个"幽灵故障"彻底消失。这个案例给我们的启示是:数字信号的问题不一定是时序代码的问题,电源质量往往才是隐藏的元凶。
7.4 断电恢复与重连策略
最后说说断电恢复。HVAC 设备的供电不可能永远稳定,市电闪断、设备检修断电都可能导致系统重启。系统重启后要做的事比想象中多:
- 传感器总线重新初始化,逐一遍历所有节点的序列号
- 如果某个节点没响应,要标记为离线,但不能让整个采样流程卡住
- 以太网链路重新连接,如果 DHCP 获取地址失败,切换到预设的静态 IP
- 上报一条"系统重启"事件,让平台端知道数据存在空窗期
这个逻辑看着简单,但很多项目都在断电恢复上栽过跟头——重启后采集正常,但网络模块卡在某个状态,所有数据都攒在缓冲区里发不出去。排查这类问题,最直接的办法是掉电重启 100 次,看每次恢复是否都能走通完整流程。我在测试时会让系统在 200ms 的短掉电和 5 秒的长掉电两种情况下各测几十次,确保网络协议栈的各种异常状态都被覆盖到。
8. 分场景的上报格式与平台对接细节
8.1 HVAC 上报格式设计
HVAC 场景的上报报文,除了温度值本身,平台端还希望知道节点的"位号"(比如 Attic-01、AHU-02 这类命名)。我建议在设备端就把位号映射表烧录进 Flash,上报时直接带出,平台端不需要再维护一份传感器 ID 与物理位置的对照表——少一个环节就少一个出错的可能。
报文格式可以参考下面的设计:
typedef struct { uint8_t head[2]; // 0xAA 0x55 uint8_t len; // 数据长度 uint8_t node_id; // 节点号 uint8_t sensor_count; // 传感器数量 uint8_t dev_status; // 设备状态 int16_t temps[16]; // 温度数组,0.01℃ uint16_t crc; // CRC16 } hvac_report_frame_t;这样一条报文最大可以携带 16 个测点的温度,足够覆盖中小型 HVAC 系统的单台控制器需求。
8.2 嵌入式场景的极简上报
嵌入式侧我反而建议走另一条路:用 UDP 包直接带原始数据,不要套复杂协议。比如电池管理系统中,温度数值往往只是一个短整数,直接放包里就行了:
帧头(0xAA) | 设备ID(1字节) | 温度高字节 | 温度低字节 | 状态(1字节)嵌入式设备上报频率高,数据包小,UDP 的无连接特性避免了 TCP 握手带来的额外开销和时延。如果中间有 NAT 或者防火墙导致 UDP 进不来,可以在设备端存一个"服务器最近一次通信的 IP:端口",定期向该地址发心跳,保持通道活跃。
8.3 平台端的数据处理建议
平台端收数据后,我强烈建议做这几件事:
- 温度值转换:收到的原始值长度是 8 位还是 16 位,先在文档里写清楚,避免平台工程师猜
- 监控曲线:温度告警阈值不要只看瞬时值,应该同时看"连续 N 个采样周期超过阈值"才告警,减少偶发跳变带来的误报
- 保留原始值和校准后的值两列,方便后续回溯
很多项目中,设备端和平台端是两个团队做的,如果协议文档里连"温度除以 16 才是摄氏度"这种细节都没写明白,联调的时候大概率会打架。我一般会在代码仓库里放一份协议说明文档,字段定义、换算规则、示例报文齐全,联调时大家照着同一份文档做事,效率会高很多。
9. 一些补充的工程经验和最后的扩展方向
把上面这些梳理完之后,再聊聊几个我在迭代过程中沉淀下来的工程经验,都是平时文档里不太会写的东西。
9.1 传感器数量多时的启动流程
如果单条总线上挂了 8 颗以上的传感器,上电后不要立即开始轮询。因为传感器上电后需要一段稳定时间,此时如果主机就开始发送复位脉冲,部分传感器可能还没有进入正常状态,导致序列号搜不全。建议上电后先延时 500ms,再执行一次"全总线复位 + 搜索序列号"流程,确保所有设备都已就绪。
9.2 与功率器件共板时的抗干扰布局
嵌入式场景里,PIC18F87J10 很可能和开关电源、电机驱动在同一块 PCB 上。布局时做到两点:
- 温度传感器的数据线和 IO 口走线远离大电流开关节点
- MCU 的地与功率地单点连接,不要在传感器数据线下方走功率线
如果现场干扰确实压不住,可以考虑在传感器数据线上加一个小电容(比如 47pF)对地滤波,但注意电容太大会把数据线上的上升沿变缓,反而影响时序。这个电容取值要试,一般的经验是从 33pF 往上慢慢加,观察波形再用示波器确认。
9.3 数据追溯与 Flash 存储
当温度数据既需要实时上报又需要本地留档时,可以把最近 N 条记录存在 MCU 的 Flash 里。PIC18F87J10 具备自读写 Flash 的能力,可以在运行期间把温度数据写入一个循环缓冲区,断电不丢失。网络恢复后,设备再把断网期间缓存的数据补传上去,保证数据的完整性。
9.4 后续可以怎么扩展
这套方案跑通后,扩展空间其实不小。最简单的是在总线上加湿度传感器、压力传感器,只要它们也支持单总线或 I²C,主控代码稍微扩展就能支持。更复杂一点的方向是,把 PIC18F87J10 的以太网接口直接接到工业现场总线上,让温度数据直接汇入工厂的 SCADA 系统;或者在上层加一个简单的 Web 配置页面,通过浏览器设置传感器阈值——但这需要 MCU 资源和协议栈支持 HTTP,8 位机做起来要仔细评估资源占用,不建议一上来就奔着这个目标去。
我个人在实际操作中体会最深的一点是:这种本地 + 远程的测温系统,真正难的不是把温度读出来,而是让整个链路在各种异常条件下都能自己恢复、稳定工作。单片机只负责把活干完不算本事,把"断线了自动重连、干扰了自动过滤、掉电了自动重建"这些兜底逻辑做到位,才算是真正交付了一个能长期运行的系统。希望这篇基于实际经验的拆解,能帮准备做类似项目的同行少走一些弯路。