1. 项目要解决什么问题:本地/远程温度监测的真实场景
温度监测听起来很简单——读一个温度传感器,显示一个数。但你把“本地”和“远程”四个字加进去,事情马上不一样了。我最近在调试一套嵌入式 HVAC 控制样机,要求同时采集两个温度点:一个是控制器安装位置的本地温度,一个是几十米外风管里的远程温度。一开始我也想直接用 NTC 热敏电阻,简单便宜,但算完长线压降、校准成本,果断放弃。最终方案是两颗 PJ85718DM 单总线数字温度传感器,加一颗 STM32F042K6,用一个 IO 口挂整条 1-Wire 总线,把本地和远程温度都采回来,再通过串口上传给上位机或 BMS。这篇博文把完整链路拆开讲:为什么这样选型、硬件怎么搭、单总线驱动怎么写、本地和远程测点怎么区分和校准,以及现场调试踩过的坑。
1.1 HVAC 控制器对温度采样的要求
HVAC 系统里的温度测点,本质上有两类。一类是“控制器本体”关心的温度,比如控制柜内部温度、功率器件附近温度;另一类是“工艺侧”温度,比如送风温度、回风温度、水管供回水温度、房间平均温度。前者是本地温度,后者通常是远程温度。
我在样机上要监视的就是这两个位置:本地温度放在主控板附近,用来判断风柜控制柜是否过热、散热风机是否失效;远程温度放在风管送风口处,用来参与风机变频调节和防冻报警。这类应用对采样速度要求不高,1 秒甚至 2 秒采一次都绰绰有余,因为 HVAC 系统的热惯性很大,温度不会毫秒级突变。但稳定性要求很高:不能因为一点点电磁干扰就跳变几度,也不能因为线缆长了就读出来全是 0x00。
温度精度在舒适性空调里一般做到 ±0.5°C 就够用,如果做恒温恒湿或者工艺冷却,可能要求 ±0.2°C 以内。PJ85718DM 这类单总线数字温度传感器的典型精度是 ±0.5°C,12 位分辨率下最小刻度 0.0625°C,正好落在舒适性 HVAC 的常规需求区间。如果对精度有更高要求,就需要标定修正,这部分后面会细说。
1.2 为什么选 PJ85718DM 而不是 NTC 或 I2C 传感器
选型时我在四种方案里纠结过:
| 方案 | 优势 | 劣势 | 适配场景 |
|---|---|---|---|
| NTC 热敏电阻 + MCU ADC | 成本最低、购买方便 | 长线误差大、需要查表校准、每路 ADC 独立 | 短距离、单点、成本敏感 |
| 4-20mA / 0-10V 温度变送器 | 传输距离远、抗干扰强 | 价格贵、需要隔离/采样的模拟前端、每路独立 | 工业现场远距离模拟量 |
| I2C 数字温度传感器 | 直接读数字、免校准 | 线缆短、多点挂载寻址复杂、几十米基本不可行 | 板级近距离测温 |
| PJ85718DM 单总线数字温度传感器 | 单 IO 挂多点、唯一 ID、三线传输几十米、CRC 校验 | 时序敏感、需要自己写驱动 | 本地/远程多测点、嵌入式控制器 |
NTC 方案放弃得最干脆。NTC 阻值随温度变化是非线性的,精度全靠 B 值表和分压电阻精度,更麻烦的是长线。假如把 NTC 放在 30 米外,线阻本身就参与分压,温度越高误差越大,冬天夏天还不是同一个偏差。就算软件里做补偿,线缆批次、接线长度不同,现场根本没法维护。
I2C 传感器的问题在距离。标准 I2C 一般几米内玩玩,长线电容一大,时序直接乱掉。虽然有些器件能工作在 100kHz,但几十米 I2C 的可靠性在工程上没什么保障。单总线就不同了,它原本就是为长线、低速、多节点设计的,标准速率 15kbps 左右,配合合适的线缆和上拉电阻,走几十米是常见用法。
另一个关键点是故障隔离。HVAC 现场往往同时存在变频器、接触器、电动阀这些强干扰源,单总线数字传输比模拟量抗干扰能力好,带 CRC 校验,数据错了能发现、能重试。这一点在后面调试测温跳变时帮了大忙。
1.3 STM32F042K6 在这套系统里扮演的角色
STM32F042K6 是 ST 的 Cortex-M0 内核芯片,主频 48MHz,Flash 16KB,SRAM 6KB,封装是 LQFP32,引脚少、体积小、价格低。拿来做单总线温度采集和串口上报,性能绰绰有余。我选它还有一个原因:内置 USB 2.0 Full Speed 设备控制器,而且支持内部 HSI48 时钟,不需要外部晶振就能做 USB CDC 虚拟串口,调试时直接把温度数据用 USB 线拉到电脑上看,非常方便。
用这颗芯片不只是因为便宜。Cortex-M0 虽然简单,但该有的资源都有:UART、SPI、I2C、ADC、多个定时器。我计划用 UART 接 RS-485,把温度数据以 Modbus RTU 协议传给 BMS 或上位机;USB 作为本地维护口,插线就能看到本地和远程温度。一个控制器同时具备现场总线接口和调试接口,这在 HVAC 设备里很常见。
其实用 8 位单片机也能做,但 STM32 的生态优势摆在那里,CubeMX 生成初始化代码,HAL 库现成,后续加 Modbus、加 Bootloader 都更顺手。F042 还有一个容易被忽略的优点:内置 CAN 控制器,某些嵌入式项目要求把温度上报给车辆或装备总线,这颗芯片也能直接顶上去。
2. 硬件电路设计与接线方案
硬件设计是整个项目的基础。单总线系统对电路不那么苛刻,但对布线规范和供电形式有要求。这里把 PJ85718DM 的引脚、拓扑、上拉电阻和 MCU 最小系统串起来讲。
2.1 PJ85718DM 的引脚与供电方式
PJ85718DM 是单总线数字温度传感器,常见封装是三脚直插或贴片,引脚功能基本是 VDD、DQ、GND 三根线。它工作在 3.0V 到 5.5V 范围,和常见的 18B20 协议兼容,初始化、ROM 命令、温度转换、读取暂存器的流程都是同一套。这最大的好处是驱动代码可以复用成熟的开源实现,踩坑成本低。
供电方式上,单总线传感器通常支持两种:外部供电和寄生供电。寄生供电是只拉 DQ 和 GND,靠总线上的高电平给内部电容充电,省一根电源线。我在这个项目里明确不用寄生供电,原因很简单:远程传感器距离几十米,线上寄生电容大、压降明显,转换时电流一拉,电压跌落可能让传感器复位或者转换数据错误。三根线都拉过去,成本多一根线而已,可靠性完全不一样。
正确的供电设计是:本地传感器和远程传感器都用外部供电,MCU 用 3.3V,传感器也统一用 3.3V。这样最省事,因为单总线的上拉电阻也接到 3.3V,电平完全匹配。如果你非要给远程传感器单独供 5V,必须注意 DQ 总线不能因此被拉到 5V,否则会超 STM32 引脚耐压。稳妥做法永远是把上拉电阻接到 MCU 的 VDD 侧,传感器电源即使 5V,数据线高电平也由外部上拉决定,一般没问题,但统一 3.3V 最保险。
传感器旁边要加去耦电容,本地传感器靠近 MCU 或连接端子时放一个 100nF,远程传感器末端也要放一个 100nF,如果现场干扰严重,再并联一个 10µF 电解电容。这个电容不是摆设,它直接决定单总线长线供电的稳定性。
2.2 单总线拓扑:本地传感器与远程传感器共用一根线
我最初也想过给本地和远程传感器各分一个 GPIO,这样读写逻辑最简单,也不会互相影响。但这样一来,1-Wire 的多点能力就没有意义了,而且浪费引脚和上拉电阻。更关键的是,如果以后要扩展第三个、第四个测温点,独立 GPIO 方案就撑不住了。所以这次采用单总线多点拓扑,本地和远程传感器都挂在同一条 DQ 线上。
拓扑关系可以画成下面这样:
[3.3V]----[4.7kΩ 上拉]----+---- DQ 总线 ----+----[本地传感器 DQ] | | [STM32 PA0]-----------------+ +----[接线端子]----屏蔽双绞线----[远程传感器 DQ]本地传感器放在控制器板上或者靠近端子的机箱内,远程传感器通过接线端子和屏蔽双绞线连到几十米外的风管里。STM32 的 PA0 配置成开漏输出,外部上拉电阻把总线默认电平拉高。所有器件都是开漏结构,谁要发数据谁就把总线拉低,这是 1-Wire 物理层的核心。
一根总线的好处是:发起温度转换时,可以发一次广播命令让线上所有传感器同时开始转换,然后等待 750ms,再逐个读取每个传感器的暂存器数据。本地和远程两块温度在时间上是同步采样的,这对后续做温差控制很重要。缺点也很明显:任何一个传感器短路都会把整条总线拉死,所以我建议在实际产品中,如果测温点只有两个且成本允许,可以分成两条独立总线,一个 GPIO 挂一个传感器,互为冗余。这次样机为了验证多点能力,用的是共享总线。
2.3 远程传感器线缆长度、上拉电阻与抗干扰处理
单总线能跑多远,很大程度取决于上拉电阻和线缆电容。总线空闲时,外部上拉电阻需要把线路电压充到逻辑高;传感器应答或发送“0”时,又得把线路拉低。线缆越长,分布电容越大,上升沿越慢,严重时读时隙里主机采样到的还是低电平,就会把“1”误判成“0”。
估算公式很简单:上升沿时间常数 τ = R × C。普通屏蔽双绞线的线间电容大概在 80 到 100pF/m,30 米线大约 3nF,如果上拉电阻用 4.7kΩ,τ = 4.7kΩ × 3nF ≈ 14µs。单总线读时隙从主机拉低到采样点通常只有十几微秒,这个余量已经很紧张了。所以我的经验是:线长 10 米以内,4.7kΩ 没问题;线长 20 到 50 米,直接把上拉电阻降到 2.2kΩ 甚至 1kΩ,保证上升沿足够快。降上拉会稍微增加低电平灌电流,但 1kΩ 对应 3.3V 也才 3.3mA,传感器可以接受。
除了上拉电阻,还有几个抗干扰措施必须做。远程线我用屏蔽双绞线,屏蔽层单端接地,接在控制器侧的地,不要两端都接。两头都接屏蔽层在大地电位不一致的现场会形成地环路电流,反而引入干扰。远程传感器的电源线和信号线也要和动力线分开走,别跟变频器输出线绑在一起。如果现场电磁环境特别恶劣,可以在总线接口处加 TVS 二极管,把瞬态尖峰钳位到安全电平。
还要提醒一点:远程传感器和控制器之间的 GND 必须可靠连通。单总线是单端传输,地线断了,什么都读不回来。接线端子要选择能锁紧的插拔端子,杜绝现场震动导致虚接。
2.4 STM32F042K6 最小系统与通信口预留
MCU 最小系统没太多秘密:VDD 和 VDDA 接 3.3V,每个电源引脚都放 100nF 去耦,再放一个 4.7µF 或者 10µF 的钽电容做蓄能;NRST 接 10kΩ 上拉和 100nF 对地;BOOT0 接 10kΩ 下拉,保证从 Flash 启动;SWD 调试口留出来,PA13/PA14 接排针。这些基础电路不出问题,系统就成功了一半。
时钟方面,STM32F042K6 支持内部 HSI48 给 USB 用,理论上可以不接晶振。但我的习惯是板子上放一颗 8MHz 晶振,这样 UART 波特率更准,USB 可以用 PLL 倍频到 48MHz,调试也更稳。如果为了省成本省面积,不加晶振也能跑,我后面可能会在批量版本里把晶振去掉。
引脚分配我这样规划:
| 引脚 | 功能 | 说明 |
|---|---|---|
| PA0 | 1-Wire DQ 总线 | 开漏输出,外接 4.7kΩ/2.2kΩ 上拉 |
| PA1 | 预留第二路 1-Wire | 扩展备用 |
| PA2/PA3 | USART2_TX/RX | 接 RS-485 收发器,Modbus 从机 |
| PA9/PA10 | USART1_TX/RX | 预留调试串口或扩展通信 |
| PA11/PA12 | USB DM/DP | USB CDC 虚拟串口 |
| PA13/PA14 | SWDIO/SWCLK | 程序烧录与调试 |
RS-485 收发器需要一根方向控制引脚,我一般用 PA1 或者 PA8,发送数据前置高,发送完毕置低,方向切换时要注意加一点延时,避免最后一个字节被截断。USB 接口如果项目不用,可以完全不焊,不影响温度采集功能。
3. 单总线驱动的实现思路
单总线驱动是整个固件里最需要小心的部分。它不像 I²C 有硬件外设,几乎全靠 GPIO 模拟。时序不对,轻则读出来 CRC 报错,重则传感器直接无线应答。下面按层次拆开:基础时序、温度转换流程、多点 ROM 枚举。
3.1 1-Wire 时序的四个基本功:复位、写 0、写 1、读
单总线通信可以归纳成四种基础电平操作:复位脉冲、写 0 时隙、写 1 时隙、读时隙。所有命令和温度数据都是通过这四种操作拼出来的。
标准时序可以用这张表概括:
| 操作 | 主机动作 | 从机响应/规则 | 时隙长度 |
|---|---|---|---|
| 复位 | 拉低 ≥480µs,释放 | 释放后 60~240µs 内从机拉低应答 | 总周期约 960µs |
| 写 1 | 拉低 1~15µs,释放 | 保持高电平到时隙结束 | 60µs 时隙 |
| 写 0 | 拉低 60~120µs,释放 | 保持低电平到写时隙结束 | 60µs 时隙 |
| 读 | 拉低 1~15µs,释放 | 从机拉低表示“0”,保持高表示“1” | 主机在释放后 15µs 内采样 |
写 1 的要点是“短促拉低,快速释放”;写 0 的要点是“持续拉低,占满时隙”;读时隙的要点是“主机释放总线后,必须在一个规定时间窗口内采样”,太早太晚都可能读到错误电平。
实现时序时,强烈不建议用HAL_Delay()。它最小单位是毫秒,根本没法产生微秒级精度。更稳妥的做法是用 DWT 周期计数器做一个微秒延时函数,或者干脆用定时器产生微秒基准。还有一点很关键:在执行这几个基础时序函数时,最好临时关中断,或者保证中断服务程序足够短。如果一颗 48MHz 的 Cortex-M0 在写时序中途被中断打断几百微秒,整帧通信就废了。我在样机上就是把这些微秒级函数放在临界区里执行的。
3.2 温度转换与暂存器读取流程
PJ85718DM 的单总线命令集和 18B20 兼容。我主要用到三条命令:跳过 ROM(0xCC)、匹配 ROM(0x55)、启动温度转换(0x44)、读取暂存器(0xBE)。
最简流程是这样的:
/* 1. 复位总线 */ ow_reset(); /* 2. 广播转换:0xCC 跳过 ROM,0x44 启动转换 */ ow_write_byte(0xCC); ow_write_byte(0x44); /* 3. 等待转换结束,12 位分辨率约 750ms */ delay_ms(780); /* 4. 复位总线 */ ow_reset(); /* 5. 匹配指定传感器:发 0x55 + 64 位 ROM */ ow_write_byte(0x55); for (int i = 0; i < 8; i++) { ow_write_byte(rom_local[i]); } /* 6. 读取 9 字节暂存器 */ uint8_t data[9]; for (int i = 0; i < 9; i++) { data[i] = ow_read_byte(); } /* 7. 校验 CRC,正确后转换成温度 */ if (ow_crc8(data, 8) == data[8]) { int16_t raw = data[0] | (data[1] << 8); float temp = raw * 0.0625f; }我先发广播转换命令,让总线上所有传感器同时开始转换,然后一次等待,再逐个匹配 ROM 读取。这是多点挂载时效率最高的方式,因为 750ms 的转换时间被多个传感器共享了,不会出现读一个等一次的情况。
读回来的 9 字节里,前两个字节是温度值,第 3 到第 8 字节是温度报警阈值和配置寄存器,第 9 字节是 CRC。实际开发中,我只看前两个字节和最后 CRC,中间那几字节只用于诊断。如果 CRC 不过,直接丢弃本轮数据,下一轮重新读,绝不能把坏数据拿去控制风机。
3.3 本地/远程传感器的 ROM 码识别与枚举
每个 PJ85718DM 在出厂时都有一个 64 位唯一 ROM 码,格式是:1 字节家族码 + 6 字节序列号 + 1 字节 CRC。串行总线上挂两个传感器,就必须能区分谁是谁。我这里有两条思路。
第一种最简单,开发阶段先把两个传感器的 ROM 码读出来,烧录固件时写死在代码里,一个定义为 LOCAL,一个定义为 REMOTE。优点是代码简单,不需要枚举算法;缺点是现场换传感器就要重新更新 ROM 表,运维麻烦。
第二种是支持 1-Wire 标准 Search ROM 枚举算法,上电后自动扫描总线上有几个设备,列出 ROM 码,然后在固件里维护一张“逻辑位置”映射表。比如第一次上电枚举到 2 个设备,就把扫描到的第一个绑定为本地,第二个绑定为远程;如果枚举到 3 个设备,可以把新增的那个作为第三测点。更实际的做法是上位机下发指令指定某个 ROM 码对应本地还是远程,然后把映射关系存入片上 Flash。
我的样机是两种都留:调试模式打印所有 ROM 码,上位机通过 UART 命令绑定“LOCAL/REMOTE/某编号”;正常运行时固件自动按绑定表匹配。Search ROM 算法写过一次就不再麻烦,以后现场换传感器只要重新绑定一次映射表,不用动程序。
CRC 校验在枚举和读取中都要做,枚举时校验 ROM 的 CRC 可以过滤掉错误数据;读取暂存器时校验温度帧,可以防止把干扰当温度。
4. 固件主逻辑与数据输出
硬件和驱动都跑通后,接下来就是固件的主逻辑。温度采集不能在一个大循环里简单粗暴地轮询,必须设计好任务节奏,否则容易被长延时阻塞。这里讲主循环划分、数据输出和远程总线的接入方式。
4.1 主循环任务划分:采集、滤波、上报
我把固件写成简单的状态机:
IDLE -> START_CONV -> CONVERTING -> READ_LOCAL -> READ_REMOTE -> FILTER -> OUTPUT -> IDLE主循环每秒跑一次完整流程。IDLE 状态等待时间片;START_CONV 状态发广播转换命令;CONVERTING 状态就是一个 780ms 延时,这段时间内主控可以做别的事情,比如处理通信命令、刷新看门狗;READ_LOCAL 和 READ_REMOTE 分别匹配 ROM 并读取暂存器;FILTER 做数字滤波;OUTPUT 把结果发出去。
滤波我用的是“滑动去极值平均”:每路温度保存最近 5 次采样值,去掉最大值和最小值,剩下 3 个取平均。这样做既不增加多少代码量,又能有效抑制瞬时干扰。HVAC 环境里的温度本来就是缓变量,5 次采样后才输出一个值,完全不影响控制效果。
如果后续要多任务并行,可以把状态机放到 FreeRTOS 的一个任务里,通信任务单独跑。对于 F042 这种 16KB Flash 的芯片,跑 FreeRTOS 有点紧张但可行,如果程序规模不大,状态机加裸机中断已经足够。
4.2 通过 UART/USB 输出温度数据
调试阶段,我最常用的输出方式是串口。每次采样完成,直接通过 USART 发一行 ASCII 数据:
T_LOCAL=25.31 T_REMOTE=18.62 STATUS=OK上位机用串口助手就能看到有没有更新,数据是否稳定。这种格式没有再发明协议,纯粹方便人眼观察。
如果不想接外部 USB 转串口芯片,STM32F042K6 的内部 USB 控制器可以直接做成 CDC 虚拟串口,插上 USB 线电脑就多出一个串口,免驱动调试非常舒服。用 CubeMX 把 USB 配置成 Device CDC 后,主循环调用发送函数即可。需要注意两点:USB CDC 的缓冲区是定长的,发送长字符串时要分帧;发送函数在 USB 没有连接时可能一直失败,不阻塞主循环即可。
正式产品中,ASCII 串口一般只作为维护接口,不参与控制。因为上位机解析字符串效率低,容易出错。这时推荐走下面要讲的 Modbus RTU。
4.3 接入 RS-485/Modbus 做远程监测
标题里的“远程温度监测”其实有两层含义:传感器层面,远程温度来自几十米外的测点;系统层面,温度数据还要上传给 BMS 或上位机做远程监控。后者在 HVAC 项目里几乎都是 RS-485 总线加 Modbus RTU 协议。
F042 的 UART 接一颗半双工 RS-485 收发器,A/B 两根线并到现场总线。Modbus 从机只需要支持几个功能码:03 读保持寄存器、06 写单个寄存器、16 写多个寄存器。我把温度数据映射到保持寄存器:
| 寄存器地址 | 内容 | 说明 |
|---|---|---|
| 0x0000 | 本地温度 × 100 | 25.31°C 表示为 2531 |
| 0x0001 | 远程温度 × 100 | 18.62°C 表示为 1862 |
| 0x0002 | 状态字 | bit0=本地故障,bit1=远程故障 |
用整数乘以 100,是为了避免 Modbus 协议里直接传浮点数带来的解析麻烦。上位机读取后自己除以 100 显示即可。
Modbus CRC16 校验是必须要写的,不校验的 Modbus 在工业现场很容易出问题。方向控制引脚在发送数据前拉高,发送完成后必须延时一小段再拉低,否则收发器切换太快,最后一个字节可能被自己接收或者被截断。这个坑我踩过,后来在发送函数末尾加了 1 到 2 个字符时间的延时,才算稳定下来。
5. 实机调试与校准记录
写完代码只算完成一半,真正花时间的是调试。这里记录我用示波器看波形、做精度验证和现场问题排查的过程,很多问题在原理图阶段看不出来,只有跑起来才暴露。
5.1 用示波器看总线波形
单总线调试最直观的工具就是示波器。把探头夹在 PA0 上,触发方式设成下降沿,先把时间轴调到 1ms/格,能看到一个完整的复位时序:主机拉低约 500µs,释放,随后出现一个约 200µs 宽度的存在应答脉冲。这一步能确认传感器供电正常、总线连接正常。
接着把时间轴调到 100µs/格,看写时序。写 0 时隙应该是一整段 60µs 左右的低电平;写 1 时隙是一段很短的低电平后立刻释放。如果写 1 的低电平时间超过了 15µs,传感器可能把 1 判断成 0;如果写 0 的时间不够 60µs,传感器可能漏采样。用示波器对比软件预期波形,能很快定位是延时不准还是 GPIO 配置错了。
我最长的一条远程线路有 40 米,在远程端看波形时,上升沿明显变缓,低电平幅度也略微抬升。这种情况常见,处理措施就是降上拉电阻到 2.2kΩ,并把读时隙的采样点稍微往后调,让远程传感器释放总线后有更充足的时间把线路拉高。
5.2 温度精度验证与偏差修正
PJ85718DM 的 12 位分辨率是 0.0625°C,但分辨率高不代表绝对精度高,出厂精度典型值是 ±0.5°C。HVAC 项目如果只做舒适性控制,这个精度直接可用;但要做数据记录和能效分析,我还是建议和标准温度计比对一下。
我把本地传感器放在实验室恒温环境中,远程传感器放在风管模拟段里,用一支精度 ±0.1°C 的数字温度计作为参考,在同一位置同时读数,连续记录三个时段的数据:
| 时刻 | 本地读数 | 参考温度 | 偏差 | 远程读数 | 参考温度 | 偏差 |
|---|---|---|---|---|---|---|
| 09:00 | 25.31 | 25.30 | +0.01 | 22.50 | 22.47 | +0.03 |
| 14:00 | 30.12 | 30.00 | +0.12 | 24.81 | 24.90 | -0.09 |
| 20:00 | 28.44 | 28.50 | -0.06 | 23.26 | 23.20 | +0.06 |
偏差都在 ±0.2°C 以内,说明两个传感器的一致性不错。如果发现某个传感器固定偏大或者偏小,可以在固件里加一个温度偏移量,把 offset 存到 Flash 的固定地址,利用片内 Flash 的一个扇区模拟 EEPROM 来保存。现场换传感器后重新标定一次偏移就能继续用。
温度值的计算可以直接用temp = raw * 0.0625f,如果不想引入浮点,也可以用定点:整数部分直接取高 5 位,小数部分查表,或者乘 625 再除以 10000。F042 没有 FPU,浮点运算会有少量开销,但每秒才算一次,完全可以忽略。
5.3 现场常见问题速查表
调试到现在,我遇到的典型问题基本可以整理成一张表,以后做类似项目可以直接对照排查:
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 只能读到本地,读不到远程 | 远程传感器未供电、接反、总线断开 | 用万用表量远程端 VDD/GND/DQ 电压;看复位时是否有应答脉冲 |
| 频繁 CRC 错误,数据时好时坏 | 线缆过长、上拉电阻过大、电磁干扰 | 换 2.2kΩ 上拉;用屏蔽双绞线;采样点后调;给远程端加滤波电容 |
| 两个传感器读数完全相同 | 远程传感器没挂上,本地 ROM 被匹配了两次 | 打印 ROM 码列表,确认远程设备存在;重新绑定映射表 |
| 打开变频器后读数乱跳 | 单总线受变频器谐波干扰 | 屏蔽层单端接地;远离动力线;加 TVS;必要时降低采样频率 |
| 温度读数明显偏高 | 传感器靠近发热源、阳光直晒、线束发热 | 检查传感器安装位置;确认风管内探头没有被保温棉包裹太紧 |
| 设备运行一段时间后彻底无应答 | 总线被故障设备拉死 | 确认是否有传感器损坏;改造为双总线冗余结构 |
排查远程问题时,我一直遵循“从物理层开始看”的顺序:先量供电,再看复位波形,最后才怀疑驱动代码。大多数远程问题不是软件而是接线和供电。
6. 事后复盘:哪些设计最值得坚持
项目收尾后,我把整个方案重新过了一遍,有几条经验特别想分享一下。
6.1 单总线长线的三个教训
第一,不要在远程测点使用寄生供电。省一根电源线带来的风险远大于收益。远程线路上电源压降、现场接触不良、连接器氧化,任何一个问题都会让寄生供电的传感器精度异常甚至无应答。三线制供电是最低保障。
第二,“单总线”不等于“随便一根线”。DQ、GND、VDD 必须有明确接线规范,屏蔽层只能单端接地。我见过有人为了省事,直接用普通两芯护套线拉 50 米,结果温度数据在风机启动瞬间乱成一团。换成屏蔽双绞线并做好端接后,问题立刻消失。
第三,故障隔离要提前设计。共享总线虽然方便,但任何一路传感器短路都可能让整条总线瘫痪。如果测温点是关键保护参数,建议把传感器拆到两条独立总线上,或者给每条分支加可恢复保险丝和二极管,把单点故障的范围限制住。
6.2 如果重新做一遍,我会这样改
首先,会把本地传感器单独放在一路 GPIO 上,远程传感器放另一路。虽然失去了单总线多点的演示意义,但产品上可靠性更高,而且软件也简单,本地和远程互不影响。如果后续要扩展第三、第四测点,再通过一个模拟开关切换总线或者扩展多路采样。
其次,会给远程探头做模块化设计:把 PJ85718DM 贴在一个小 PCB 上,引出三根带颜色标识的端子线,配套环氧灌封成一个防水探头。现场更换时只需拔掉旧探头、插上新探头,然后通过调试指令重新绑定 ROM 码,不需要拆控制器。
第三,固件里会加入断线报警和自恢复机制。连续多轮读不到远程温度,就把远程故障位置位,输出报警;总线如果被拉死,可以定时让远程传感器断电重启,在某些情况下能自动恢复。别小看这个功能,现场运维很多时候宁愿报警重启,也不愿意开柜门查线。
最后再分享一个非常小但很实用的技巧:在每个测温端子旁边预留一个 LED 指示位,软件里每成功读一次对应传感器就翻转一次 LED。从外面看灯在闪,说明通信健康;灯不闪,直接指向问题点。这个设计不增加多少成本,但给现场调试省了无数时间。