
去年在做一个机房空调改造项目时我接到一个需求控制器要同时监测“本地”和“远程”两组温度。本地指控制柜内部环境温度远程指三十米外送风管道里的空气温度。主控用了 STM32F745VG传感器选了两片 PJ85718DM一片放柜内一片甩到风管里。这个组合听起来简单真正落地时却牵扯到长线驱动、供电方式、单总线时序和现场干扰远不是“读个寄存器”那么简单。断断续续踩了两个星期的坑我把完整过程整理成这篇记录给正在做 HVAC 控制器或嵌入式多点测温的朋友当参考。1. 项目需求拆解与选型理由1.1 HVAC 温度监测到底在测什么HVAC 场景里的温度监测一般围绕三个对象回风温度、送风温度、盘管进出口温度。我这次的需求是“本地温度 远程送风温度”本质上属于送风温度监测。送风温度直接影响风阀开度、水阀流量和压缩机能耗采样数据的稳定性和实时性直接决定整个调节系统的动作节奏。如果温度值上下乱跳控制器会频繁修正输出阀门和风机容易来回振荡最终表现就是温度控不住、能耗还高。所以温度检测的第一要求不是“快”而是“稳”。除此之外HVAC 现场往往有变频器、接触器和电动阀这些设备启停瞬间会产生强烈的电磁干扰。传感器本身精度再高信号线被干扰吃掉读回来的数据也没法用。这个背景决定了后续所有硬件设计和代码编写的大方向先保证传输可靠再谈采样精度。1.2 为什么用 PJ85718DM 做温度探头PJ85718DM 是一种单总线数字温度传感器测温范围 -55°C 到 125°C典型精度 ±0.5°C内部支持 9 到 12 位分辨率可配。选择它不是因为参数最顶尖而是因为它特别适合 HVAC 这种“传感器在现场、主控在柜内”的分布式布局。单总线方案最大的优势是接线简单传感器到控制器只需要一根数据线加电源和地现场施工人员非常容易理解。第二个优势是数字输出直接由 GPIO 读取不需要经过 ADC 和运放省掉了一堆模拟前端电路。第三个优势是单总线支持长距离传输十几米到三十米在做好上拉和屏蔽的前提下完全可用。成本也低批量采购很划算。我需要补充一句如果你追求更高的绝对精度比如正负 0.1°C 级别或者要求几十毫秒内快速响应应该考虑 I²C 类数字传感器配合屏蔽线短距离部署。但在本项目“远程部署 长线传输 成本可控”的需求里PJ85718DM 是目前最合适的选择。1.3 为什么主控选 STM32F745VGSTM32F745VG 是一颗 Cortex-M7 内核的 MCU主频最高 216MHz带双精度浮点单元和 DSP 指令。单看“读两个温度传感器”用 F0 或者 G0 系列就绰绰有余但我选它是有明确考虑的这个平台后续还要跑 PID 调节算法、LCD 人机界面、RS485 Modbus 通信以及一部分数据记录和报警逻辑。温度采集只是整个系统的一个子模块选型不能只盯着当前这一个传感器代码要看整体算力需求。M7 内核的浮点性能对滤波和 PID 帮助很明显。温度滤波我要做中位值平均PID 要做浮点积分如果用 Cortex-M0 内核纯软件算也不是不行但实时性会受影响。大容量的 RAM 也可以让我放心把连续采样缓存放到内存里不用频繁操作 Flash。总结一句话PJ85718DM 解决“温度怎么测”的问题STM32F745VG 解决“测回来之后怎么处理”的问题。2. 硬件设计与连接经验2.1 PJ85718DM 的两种接法选哪种心里要有数PJ85718DM 引出脚主要有三个GND、DQ 数据线、VDD 电源。接法上常见两种三线外部供电和两线寄生供电。三线制就是把 VDD 接 3.3VDQ 接 MCU 的 GPIO 并在外部加上拉电阻GND 与控制器共地。寄生供电则把 VDD 和 GND 短接传感器完全靠 DQ 线上的信号能量工作。做长距离测温我强烈建议优先选三线外部供电。寄生供电虽然少一根线但传感器在温度转换瞬间需要的电流很大。线一长线路阻抗压降明显转换过程中电压跌落传感器内部逻辑复位寄存器会一直停留在 85°C。这个故障非常隐蔽后面我会单独讲。稳定的做法就是多拉一根电源线让传感器在转换期间有充足的能量。STM32F745VG 的 GPIO 是 3.3V 电平所以 DQ 上拉直接接到 3.3V 即可。如果控制板上有 5V 系统想用 5V 给传感器供电必须确认所选的 GPIO 引脚支持 5V 容忍否则需要加电平转换电路不能直接怼进芯片引脚这个坑不值得踩。2.2 长线传输怎么处理尤其是上拉电阻单总线传感器在短距离板级连接时非常稳定但一旦进入 HVAC 现场动辄十几米二十几米的线缆问题就出来了。最常见的就是上升沿变缓导致传感器应答信号没被主机识别到或主机发出的时序被线缆电容吃掉。我在项目里第一次用 4.7kΩ 上拉电阻拉到 25 米屏蔽双绞线上结果每隔几分钟就出现一次 CRC 错误远程温度偶尔跳到 85°C。把上拉电阻换成 2.2kΩ 后问题直接消失。上拉电阻到底选多少取决于线缆长度和分布电容。短距离用 4.7kΩ 没问题长距离建议降到 2.2kΩ 甚至 1kΩ。上拉电阻太小会加重 GPIO 驱动负担太大又带不动线缆电容所以需要实测波形来判断。手头有示波器的话直接看 DQ 线上的上升沿如果边沿超过 2 微秒还达不到高电平阈值就参考减小上拉电阻或增加有源上拉。线材方面推荐屏蔽双绞线屏蔽层要单端接地不要两端都接。HVAC 现场变频器辐射和电机干扰非常凶单端接地可以避免形成地环流。数据线的 MCU 端还可以串一个 100Ω 电阻再对地并一个 100pF 电容做 RC 滤波。注意 RC 会进一步拉缓上升沿如果线长已经超过 30 米这个电容可以去掉或者减小到 33pF不然时序容易出问题。2.3 本地与远程探头的隔离与安装细节有些 HVAC 控制柜里直接装变频器大功率开关瞬态会通过接地回路串扰到传感器信号。本地探头离 MCU 近受干扰通常小远程探头走了几十米线感应的共模干扰很容易耦合进来。我实际项目中就把远程传感器的供电从主控 3.3V 改成了一路独立的 DC-DC 隔离模块数据线中间加了数字隔离器再进 GPIO。隔离器会引入额外延迟但对单总线这种低速协议影响不大只要隔离器响应时间在微秒级以内就能正常工作。加了隔离之后远程传感器通信稳定性明显提升尤其是在空调压缩机启动的瞬间数据基本不出现毛刺。安装位置也是大坑。本地探头不要贴在变压器、继电器或者功率电阻旁边否则测的是器件温度而不是柜内空气温度。风管里的远程探头要避免金属外壳直接贴合管道壁最好用隔热套或者支架让探头悬在气流中间。很多工程师把大量精力放在芯片选型上结果探头安装位置不对测出来的数据偏差好几度前面所有工作都白费。3. 单总线驱动与温度换算3.1 单总线时序基础先把时间窗搞清楚单总线协议的核心就是精确时间窗口。复位时主机拉低总线至少 480μs然后释放并等待传感器应答写 1 和写 0 的时间窗口不一样读时序要求在特定时间点采样。这些窗口都是用微秒级延时控制的HAL_Delay 这类毫秒级延时函数不能用必须自己实现微秒延时。在 STM32F745VG 上我用了 DWT 计数器做微秒延时。DWT 是 Cortex-M 内核里的调试监视单元有一个 32 位周期计数器 CYCCNT可以精确到 CPU 周期。先使能 CoreDebug_DEMCR 里的 TRCENA 位再打开 DWT_CTRL 的 CYCCNTENA 位然后通过ticks us * (SystemCoreClock / 1000000)换算延时周期。这样得到的时间精度很高在 216MHz 主频下足够支撑单总线协议的时间要求。另外要特别留意中断干扰。单总线时序进行中如果来了一个中断比如 UART 接收中断或者 SysTick 中断整个时间窗会被打乱导致读写时序完全错位。最简单的办法是在单总线传输期间关闭全局中断读完一个字节再打开。两个温度传感器轮询间隔几百毫秒关中断几十微秒对系统实时性的影响几乎可以忽略。3.2 关键代码实现与换算逻辑下面给出一段简化的代码框架。读取 PJ85718DM 温度的标准流程是先复位总线然后发送 Skip ROM 命令0xCC再发送温度转换命令0x44等待转换完成再次复位总线发送 Skip ROM 命令发送读暂存器命令0xBE连续读取 9 个字节最后做 CRC 校验并换算温度。#define OW_PORT GPIOB #define OW_PIN GPIO_PIN_0 static void ow_delay_us(uint32_t us) { uint32_t start DWT-CYCCNT; uint32_t ticks us * (SystemCoreClock / 1000000U); while ((DWT-CYCCNT - start) ticks) {} } static uint8_t ow_reset(void) { uint8_t presence; GPIO_InitTypeDef gpio {0}; /* 配置为输出拉低总线至少 480us */ gpio.Pin OW_PIN; gpio.Mode GPIO_MODE_OUTPUT_OD; gpio.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(OW_PORT, gpio); HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_RESET); ow_delay_us(500); /* 释放总线切换为输入等待应答 */ HAL_GPIO_WritePin(OW_PORT, OW_PIN, GPIO_PIN_SET); gpio.Mode GPIO_MODE_INPUT; gpio.Pull GPIO_PULLUP; HAL_GPIO_Init(OW_PORT, gpio); ow_delay_us(70); presence HAL_GPIO_ReadPin(OW_PORT, OW_PIN); ow_delay_us(450); return presence; }写位和读位的函数实现相对繁琐我直接说时序参数写 0 时拉低总线 70μs 左右写 1 时拉低 6μs 后释放读时序时主机先拉低 3μs释放后在 15μs 窗口内采样。每个位操作之间要留出足够的恢复时间不能连续操作不等待。完整的函数建议单独封装成ow_write_byte和ow_read_byte。温度换算非常直接16 位有符号寄存器值乘以 0.0625 就是摄氏温度。代码实现上先把buf[1] 8 | buf[0]转成int16_t再乘 0.0625f。12 位分辨率下典型转换时间是 750ms这个等待不能省。如果对温度刷新率有更高要求可以把分辨率配成 10 位转换时间会缩短到原来的四分之一左右但牺牲 0.25°C 精度HVAC 场景一般不建议这么换。3.3 滤波与校准直接抄作业的方案PJ85718DM 本身读数比较稳定但长线传输时数据偶发毛刺很难完全避免。我用的是“中位值平均滤波”连续采 5 次去掉一个最大值和一个最小值剩下 3 个取平均。这个方法对脉冲干扰特别有效而且实现简单不需要浮点矩阵运算。代价是输出频率会慢一些但 HVAC 温度变化本来就以秒级甚至分钟级计算1 秒出一个稳定温度足够用。滤波代码思路是维护一个环形缓冲区每次新的原始值入队满 5 个点后做排序去极值平均。不要在中断里做排序把原始数据丢进队列主循环空闲时再处理。滤波后的值才是参与 PID 和报警逻辑的温度。校准方面用标准水银温度计或商用高精度温度探头与 PJ85718DM 放在同一个热源里等读数稳定后记下偏差做单点软件偏移即可。实测下来PJ85718DM 在 -10°C 到 60°C 范围内的一致性不错单点偏移就能把误差控制在 0.2°C 以内。如果想做得更细可以在低温和高温两个点做两点校准线性插值出每个时刻的校正值。但这是在冷热循环测试设备上才能实现的普通应用没必要这么重。3.4 多点挂载与分通道选择实操方案PJ85718DM 支持单总线上挂多个传感器通过 ROM 码区分设备。这个功能听上去很方便但我在 HVAC 长线场景里实际测试下来强烈建议不要把所有探头都挂到同一条总线上。原因有两个第一每个探头引脚都有分布电容多个探头并联会明显拉缓信号边沿导致时序余量变小第二如果每个探头到主控的距离不一样分支线就是一根根“天线”反射信号会让波形带上毛刺CRC 错误率直线上升。我的做法是本地和远程各占一个 GPIO软件里抽象成两路独立的“温度通道”。虽然多占一个 IO但每个通道的时序互相独立排错也容易。如果探头距离都很近比如都安装在同一个控制柜内确实可以共用一个 GPIO 通过 ROM 寻址区分但远程那一路建议永远独立走线。本地通道 GPIO 我用了 PB0远程通道用 PB1注意避开调试口和晶振引脚就行。4. 实测数据与稳定性分析4.1 测试环境和方法实测地点选在某设备机房的空调机系统上。本地探头放在控制柜内部远程探头通过 25 米屏蔽双绞线伸到空调送风管中部。参考温度用一支经过校准的商业温度计放在送风口附近。采集程序每 1 秒打印一次两个探头读数连续运行 8 小时统计 CRC 错误率和温度跳变次数。测试之前我做了硬件检查两个探头都是外部供电远程探头供电处实测 3.28V没有明显跌落数据线上拉到 3.3V上拉电阻使用 2.2kΩ屏蔽层在控制柜侧单端接地。软件每次读取前做总线复位失败则重试三次失败才上报故障。4.2 现场数据表现从稳定运行段截取一组数据时间本地温度(°C)远程温度(°C)参照温度(°C)10:00:0035.419.619.710:00:1035.319.519.610:00:2035.419.619.710:00:3035.519.619.7远程探头与参照温度计偏差在 0.1°C 到 0.2°C 左右说明长线传输和探头安装都没有引入明显误差。8 小时连续运行期间没有一次温度跳变也没有出现 CRC 错误。对比之下之前用 4.7kΩ 上拉电阻时大约每 5 分钟出现一次 CRC 错误远程读数偶尔跳到 85°C。换用 2.2kΩ 上拉之后问题彻底消失这就是长线驱动能力不足的典型表现。这套系统在空调机组上运行了三周远程温度参与送风温度 PID 调节本地温度用于柜内过热保护。整体控制效果稳定温度波动范围控制在设定值的正负 0.3°C 以内说明温度采集链路本身没有成为整个控制系统的瓶颈。5. 常见问题速查与实战避坑5.1 问题排查速查表现象可能原因排查方法全部读到 85°C传感器上电后未执行温度转换长线寄生供电转换时掉电检查供电方式发转换命令后等 750ms 再读改为外部供电CRC 校验频繁失败上拉电阻不合适线缆过长时序被中断干扰调整上拉电阻拆短线路对比关闭中断测试时序温度持续跳变电源纹波大探头靠近变频器或继电器屏蔽层接地不当示波器观察 DQ 波形加 RC 滤波屏蔽层单端接地本地探头正常远程异常远程线缆接触不良供电线压降太大探头安装位置受热源影响检查接线端子测远程供电端电压更换安装位置读数稳定但偏高探头金属外壳贴到管道或散热片加隔热垫让探头测量空气温度5.2 排查过程实录项目中最折磨人的问题是“远程探头偶尔跳到 85°C”。刚开始我以为传感器坏了换了一片还是同样现象。后来把示波器夹在 DQ 信号线上发现在空调压缩机启动的那一刻数据线上会叠加一个很大的毛刺紧接着就开始出现错误读数。这就是典型的强电干扰耦合进信号线。当时的处理顺序是第一步把远程传感器改成外部供电解决了转换期间掉电的隐患第二步把数据线上拉电阻从 4.7kΩ 换成 2.2kΩ增强了驱动能力第三步在 MCU 端加 RC 滤波把高频毛刺吸收掉第四步屏蔽层从“两端接地”改成“单端接地”。做完这四步问题就再也没有出现。如果你也遇到类似现象可以按这个顺序逐一排查通常不需要一次性全改。5.3 温度采集代码里的几个细节第一读取暂存器之后一定要校验 CRC。PJ85718DM 支持 CRC8 校验多项式是 0x8C代码实现不算复杂。HVAC 现场长线穿墙过桥偶尔一个脉冲就能让数据错一个位CRC 校验不过就重读比任何滤波都可靠。第二传感器复位失败时不要急着报错可能只是它还在忙重试三次每次间隔 5ms仍然失败再报故障这样可以避免空调系统在开机瞬间误报警。第三温度转换命令发出后如果立即读暂存器读到的还是上次的旧值注意区分“旧数据”和“错误数据”。第四GPIO 输出速度配置会影响信号边沿质量。单总线时序用 GPIO 模拟时建议把输出速度调到低速档减少过冲实测边沿更干净。第五不要一边读单总线一边开一堆高优先级中断。我最初就是在读取过程中开着 UART 中断结果时不时冒出 CRC 错误后来把传感器操作集中到一个低优先级任务里关中断处理问题彻底消失。5.4 关于 85°C 的补充说明85°C 是这类单总线传感器上电复位后的默认寄存器值。如果你读回来总是 85.0°C说明传感器没有成功执行温度转换而不是环境温度真的有 85°C。最常见的两个原因一是供电电流不够转换期间电压被拉低内部逻辑复位二是转换命令发出后等待时间不足。先查供电和命令时序再查硬件。程序里读到 85°C 时不要立即触发高温报警先连续确认至少三次。HVAC 系统中高温报警会直接联动停机误报带来的损失比漏报还大。用软件把这种“复位值”当无效数据处理再配合连续采样确认机制系统稳定性会提升一截。最后再分享两个体会这个项目让我印象最深的是温度监测项目的成败往往不在芯片精度而在探头安装和走线。PJ85718DM 标称误差在正负 0.5°C 以内但如果探头贴着金属管壁或者被保温棉裹住读出来的偏差可能到好几度。一定要先解决“传感器到底测的是哪里”的问题再谈测量精度。另一个体会是单总线这类协议看着简单时序窗口却非常敏感。用 STM32F745VG 时我一开始在读取温度的过程中开着所有中断结果时不时出现 CRC 错误。后来不仅关闭中断还把所有的传感器操作集中到一个低优先级任务里问题才彻底消失。嵌入式测温项目稳定比花哨重要得多。