资讯动态

单总线温度传感器与STM32在HVAC远程测温中的工程实践

发布时间:2026/10/22 16:57:58 来源:尧图企业网站定制
前阵子调一套 HVAC 控制器温度采集部分用的是 PJ85718DM 这颗单总线数字温度传感器主控是 STM32F722VE 这颗 Cortex-M7 内核的高性能 MCU。项目要求覆盖两种距离控制器机箱内部回风温度还有顺着吊顶走到风管另一侧的送风温度最远的探头离主控超过十米。折腾完硬件和驱动后发现这套组合用在嵌入式和 HVAC 场景里确实顺手但有不少坑不会出现在数据手册里今天把这些实测经验整理出来给后面做类似本地和远程测温方案的朋友做个参考。1. 温度采集方案选型为什么是 PJ85718DM 配 STM32F722VE1.1 从 HVAC 现场需求反推传感器要求HVAC 温控系统对温度采集的要求说高不高说低也不低。回风温度、送风温度、室外补偿温度、冷热水盘管进出水温度这些点位大多分布在设备间、吊顶、风管内部和主控板之间隔着几米到几十米的线缆。精度要求通常是 ±0.5°C 以内采样周期在秒级即可和控制环路相比算慢变量。传统做法是 NTC 热敏电阻加一路 AD 采样成本低但有一个很麻烦的问题NTC 的引线电阻和线路噪声会直接叠加到测量结果里。距离一长要么用三线制、四线制消除线阻要么加前端调理电路调试成本立刻上来了。PT100 铂电阻精度好但调理电路更贵而且接入 MCU 还得过一路模拟前端。PJ85718DM 这类单总线数字温度传感器把模拟信号链的麻烦从源头消掉了。传感器内部直接完成温度到数字值的转换通过单总线协议读出来每个芯片还有唯一 64 位 ROM 编号可以在同一条总线上挂多颗天然适合多点测温。12 位分辨率下最低位对应 0.0625°C工程上做 ±0.5°C 控制余量充足。HVAC 领域最常用的三种测温方案对比下来数字单总线方案在中等距离、多点位、低成本这三件事上平衡得最好。方案精度布线复杂度多点扩展抗干扰单点成本NTC 热敏电阻中受线阻影响高需三线/四线补偿每点一路 AD弱需滤波低PT100 铂电阻高高需调理电路每点一路采集中中高PJ85718DM 单总线高数字输出低一根总线挂多颗靠 ROM 识别中需注意布线中低1.2 PJ85718DM 的接口特性与 STM32F722VE 的配合点PJ85718DM 在协议层面采用单总线命令集和常见的单总线温度传感器兼容比如 0xCC 跳过 ROM、0x44 启动温度转换、0xBE 读暂存器。这意味着驱动移植成本很低以前写过单总线驱动的人基本改改延时函数就能用。主控选 STM32F722VE 不是大材小用。这颗芯片有一个很多人没注意到的优势Cortex-M7 在 216MHz 主频下做单总线时序非常轻松。单总线的读时序要求在微秒级别精确采样主频越高、CPU 抢占越少时序抖动越小。另一个原因是它接口资源足够丰富除了温度采集还同时承担触摸屏、RS485、以太网远程上报等工作一颗芯片把本地采集和远程通信全包了板子体积和 BOM 成本反而更低。这里补充一句个人看法很多人觉得温度传感器随便找个低端 MCU 也能驱动何必上 F7。但你要是在同一个项目里跑 RTOS、控制多路 PWM、还要处理 Modbus 协议PJ85718DM 的软件时序经常会被高优先级任务打断而 STM32F722VE 的性能余量允许用简单可靠的阻塞式驱动配合短临界区搞定不需要花大量精力去写复杂的 DMA 或超时补偿逻辑。工程上用“更高性能的主控换更简单的软件设计”这笔账通常是划算的。2. 本地与远程测温的硬件布线设计2.1 主干线拓扑与上拉电阻取值传感器离主控十几米第一件事是确定拓扑。我的做法是绝对不搞星形连接。假设总线上挂了 6 个传感器每个传感器各自拉一根线到主控汇合点在主控板那么末端反射、线间串扰、寄生电容都会叠加在一起波形惨不忍睹。正确做法是像 RS485 一样走总线型一根双绞线或屏蔽线从主控附近开始串联穿过所有传感器安装位置最近和最远的传感器实质上都在同一条物理总线上。布线距离拉长以后上拉电阻要重新算。常用 4.7kΩ 上拉在短线没问题但在十几米的线缆上会出问题因为线缆分布电容大RC 时间常数变大下降沿和上升沿被拉缓。单总线对上升沿要求没那么苛刻但下降沿过缓会直接影响复位和写时序。我实测了 15 米带屏蔽双绞线、线间电容约 50pF/m 的情况4.7kΩ 上拉时上升沿明显变钝偶发抖动换成 2.2kΩ 后波形干净不少。如果距离超过 20 米再降成 1kΩ。但要注意上拉太小会增大器件功耗对远端的供电能力要求也更高所以不要一味求小够用就行。// 上拉电阻经验值参考典型 3.3V 供电双绞线室温环境 // 3m : 4.7kΩ // 3m ~ 15m: 2.2kΩ // 15m : 1kΩ且尽量保证每个分支点短接、末端无分枝2.2 防静电与抗干扰电路HVAC 现场和实验室环境完全是两回事。风机、压缩机、交流接触器一启停母线电弧和感性负载会产生强烈的瞬态干扰。这些干扰会通过线缆耦合进单总线轻则读错数据重则把 GPIO 口打坏。所以远程传感器线缆在进入主控板的地方我要求硬件同事必须加保护电路。最简单的做法是三个器件一个 3.3V 稳压管或 TVS 管放在总线引脚对地限制瞬间高压一个 100Ω 的电阻串在总线入口配合后级电容形成 RC 滤波削弱高频噪声如果传感器由主控板供电那么供电脚还要加一个 470μF 电解电容或者超级电容容灾。有人会问单总线是不是只要传感器侧也加保护就行理论上两端都加最好但实际施工中远程探头装在风管里那地方没有 3.3V 参考地在传感器侧加稳压管经常因为地电位不一致产生额外泄漏电流。比较务实的方案是只做主控入口保护远程侧用环氧封装的传感器头线缆选择带屏蔽层并一端接地。这样做下来我在现场用示波器看过总线上的干扰幅度从最初的 2V 多毛刺压到了 0.3V 以下。注意如果你做的是末级 HVAC 设备现场可能和强电共箱体。总线线缆务必走单独的线槽不要和 220V 动力线绑在一起走。哪怕只是平行走线超过半米日后的稳定性也会大打折扣。3. 单总线驱动在 M7 上的落地要点3.1 先搞定精密时序用 DWT 做微秒级延时在 STM32F722VE 上写单总线驱动很多人顺手就用 HAL_Delay。我劝你趁早放弃这个想法。HAL_Delay 基于 Systick默认分辨率 1ms单总线的时序是微秒级的就算你改 tick 频率HAL_Delay 调度期间还受中断影响抖动很大。更好的做法是利用 Cortex-M7 的 DWT_CYCCNT 周期计数器实现微秒延时它是硬件计数器几乎没有软件抖动。// 初始化 DWT 周期计数器必须在项目初始化阶段调用一次 void dwt_delay_init(void) { CoreDebug-DEMCR | CoreDebug_DEMCR_TRCENA_Msk; DWT-CYCCNT 0; DWT-CTRL | DWT_CTRL_CYCCNTENA_Msk; } // 微秒延时函数基于 CPU 周期数分辨率和精度远高于 HAL_Delay void dwt_delay_us(uint32_t us) { uint32_t ticks us * (SystemCoreClock / 1000000U); uint32_t start DWT-CYCCNT; while ((DWT-CYCCNT - start) ticks) { // spin } }SystemCoreClock 在 STM32F722VE 上通常是 216000000也就是一个周期约 4.63ns。延时时间精确到微秒级别对于单总线协议完全够用。注意这里用了无符号减法做周期计数溢出保护只要每次延时不超过约 4294 秒就不会有问题。有了这个延时函数复位脉冲、写时隙、读时隙就可以用标准的阻塞方式实现。个人经验是先把 GPIO 配成开漏输出模式这样天然具备线与能力也方便上拉电阻外部接。3.2 读 ID、温度转换、CRC 校验的完整流程单总线的读写流程不复杂但细节很重要。以读温度为例顺序是复位脉冲、设备存在应答、发送跳过 ROM 命令0xCC、发送温度转换命令0x44、等待转换完成、再次复位、发送跳过 ROM 或匹配 ROM 命令、发送读暂存器命令0xBE、连续读出 9 个字节温度两个字节 告警阈值 配置字节 CRC。// 读取单个温度值整数形式单位 0.001°C便于上位机直接显示 int32_t pj85718dm_read_temperature(void) { uint8_t scratchpad[9]; int32_t temp_raw; ow_reset(); ow_write_byte(0xCC); // Skip ROM ow_write_byte(0x44); // Start temperature conversion while (ow_read_bit() 0); // 等待转换完成传感器会拉低电平直到转换结束 ow_reset(); ow_write_byte(0xCC); // Skip ROM ow_write_byte(0xBE); // Read Scratchpad for (int i 0; i 9; i) { scratchpad[i] ow_read_byte(); } if (ow_crc8(scratchpad, 8) ! scratchpad[8]) { // CRC 校验失败返回错误码交由上层做健康度处理 return OW_CRC_ERROR; } temp_raw scratchpad[1] 8 | scratchpad[0]; return (int32_t)temp_raw * 625 / 10; // 12位分辨率LSB0.0625°C转为 0.001°C 单位 }特别注意等待转换的那句while (ow_read_bit() 0)。传感器启动转换后会主动把总线拉低转换完成后释放。读取这个“忙状态”的方式也是读时隙和读数据位完全一样。这种方式比固定延时 750ms 更高效尤其在同一总线上挂多颗传感器时可以做到“谁先转换完谁先被读取”总线利用率和现场响应速度都更好。CRC 校验不能省。HVAC 现场的电磁干扰很现实没有 CRC 你根本分不清读回来的 0.0625°C 是真值还是干扰凑出来的值。CRC8 多项式是 x^8x^5x^41实现网上到处都是我建议把读到的每个字节都送进 CRC包括温度字节和配置字节最后和暂存器里的 CRC 字节比对。宁可这次数据丢也不要拿脏数据去驱动 PID 调节。3.3 多点 ROM 搜索与传感器分组挂载远程和本地测温的典型场景是同一总线挂 5 到 10 个探头。只要挂在同一条总线上就一定会遇到 ROM 搜索问题。搜索算法不复杂核心流程是逐位探测每一位读两次第一次读该位的原码第二次读反码通过“线与”特性判断冲突情况。// ROM 搜索的核心位探测逻辑 uint8_t ow_rom_next_bit(uint8_t bit_choose) { uint8_t bit_a ow_read_bit(); uint8_t bit_b ow_read_bit(); if (bit_a bit_b) { return OW_ROM_ERR; // 两个设备该位都为 1读到的只能是 1属于异常 } if (!bit_a !bit_b) { // 冲突位一条总线上既有 0 也有 1 // 根据搜索方向选择 0 或 1bit_choose 来自搜索栈 return bit_choose; // 返回 0 或 1 } // 一个为 1、一个为 0说明所有设备该位相同 return bit_a ? 1 : 0; }实际工程中我不建议自己在项目里临时写这个算法除非你有一整块时间用来调试。稳妥的办法是先用单点读取方式验证所有传感器都能正常响应然后在固件里做一次上电到断电的动态扫描从 64 位全零开始每一位按上述逻辑确定收集出所有 ROM 编号存入列表之后每次读取温度时直接用 MATCH ROM0x55命令点名读取。这样容错率最高也方便本地和远程分组的固件配置。分组建议用两路独立的 GPIO 总线而不是把所有传感器塞进同一条总线。本地组走机箱内部的短线远程组走长线。两路物理隔离最大的好处是远程线缆被雷击或短路时不会拖着本地组一起失效其次本地组和远程组的供电、上拉电阻、保护电路可以分别配置远程组用低阻上拉、本地组用标准上拉。很多人贪图省一根线把所有探头全挂一条总线上。我见过每个传感器带不同长度支线的案例最后总线反射严重干扰一大就整组掉线。分两路以后即使远程组故障本地组依然能维持最低限度的回风温度监测这个冗余设计在 HVAC 系统里价值很高。4. HVAC 采样调度非阻塞状态机与数据健康度4.1 温度环路的采样周期设计HVAC 温度控制是慢过程温度采集周期通常 1 秒到 5 秒完全够用。但单总线的转换时间却有讲究。PJ85718DM 在 12 位分辨率下典型转换时间约为 750ms如果总线上有 8 个传感器最傻的写法是循环 8 次“转换–等待–读取”每个周期要 6 秒以上控制环路根本没法用。正确的做法是广播启动转换。给整条总线发送一次跳过 ROM 命令加转换命令所有传感器会同时开始转换等待 750ms 之后再用 MATCH ROM 逐个点名读结果。这样一来总耗时变成了一次转换等待 750ms 加上 8 次短读总周期可以压缩到 1 秒左右。// 广播转换 点名读取8 个传感器总耗时约 750ms 8 * 20ms void temp_bus_start_conversion(void) { ow_reset(); ow_write_byte(0xCC); // Skip ROM广播 ow_write_byte(0x44); // 所有传感器同时启动转换 } int32_t temp_bus_read_point(uint8_t *rom_id) { int32_t temp; ow_reset(); ow_write_byte(0x55); // Match ROM for (int i 0; i 8; i) { ow_write_byte(rom_id[i]); } ow_write_byte(0xBE); // 读暂存器 // ... 读取 9 字节和单点读取一致 return temp; }这个广播转发的思路是所有单总线多点测温项目的关键优化点。同样的总线上挂多少传感器成本只增加一点点读取时间而不会把等待时间成倍累加。实测下来9 个探头加一个广播转换单轮全量采集在 900ms 内完成更新周期 1 秒绰绰有余。4.2 状态机与温控任务降级既然用了 RTOS 或前后台大循环温度采集就不能是阻塞的 900ms 死等。我习惯把整个采集流程切成状态机每个系统 tick比如 10ms推进一次采集任务和其他任务共享 CPU互不阻塞。typedef enum { TEMP_STATE_IDLE, TEMP_STATE_START_CONV, TEMP_STATE_WAIT_CONV, TEMP_STATE_READ_POINTS, TEMP_STATE_PUBLISH } temp_state_t; temp_state_t temp_state TEMP_STATE_IDLE; void temp_task_tick(void) { switch (temp_state) { case TEMP_STATE_IDLE: if (temp_cycle_trigger()) { temp_bus_start_conversion(); temp_state TEMP_STATE_WAIT_CONV; temp_conv_start_ms now_ms(); } break; case TEMP_STATE_WAIT_CONV: if (now_ms() - temp_conv_start_ms 800) { temp_state TEMP_STATE_READ_POINTS; } break; case TEMP_STATE_READ_POINTS: // 逐个读取读取失败标记该通道无效 temp_state TEMP_STATE_PUBLISH; break; case TEMP_STATE_PUBLISH: // 数据平滑、阈值判断、送入调控队列 temp_state TEMP_STATE_IDLE; break; } }除了调度我还为每个温度点维护了健康度字段当前值、上一有效值、连续失败次数、数据有效标志。连续三次 CRC 失败我就认为当前温度点失效对应通道标记为“无效”温控逻辑改用上一有效值或同组均值连续失效超过 60 秒触发告警但不允许把无限循环取出的僵尸数据送进 PID 环路。这个“数据健康度”设计在 HVAC 里非常重要因为温度探头失效时错误的超低温读数会直接让系统进入满负荷加热或制冷状态现场损失很大。温控的最终目标是舒适和节能宁可保持旧值维持设备稳定运行也不要因为一个坏数据让系统剧烈振荡。状态机里最容易被忽略的是切换通道时总线上的时序间隙要足够长避免上一通道的读过程影响下一通道复位。我一般在每个通道读取结束后插一个 200μs 的空闲时间这个问题就不会出现。5. 远程上报把温度数据送到上位机的那段路5.1 系统级远程STM32F722VE 作为采集网关的接入方式如果你的“远程监测”不仅指远程风管探头还指把数据传到中控室那 STM32F722VE 天生适合当采集网关。它自带以太网 MAC配合 PHY 芯片能直接上 Modbus TCP也可以用现成的 RS485 加 Modbus RTU成本更低。我的建议是在固件里把温度数据整理成一张统一的寄存器表不论走串口还是走以太网上位机看到的数据结构完全一致。举个栗子寄存器地址 0x100 到 0x10F16 个通道的温度值每个温度用 16 位有符号数表示单位 0.01°C寄存器 0x120 放每个通道的有效标志位0x121 放全局告警状态码。上位机只管轮询这张表不需要关心下位机总线上到底挂了几颗传感器、哪一颗失效了。// 简化版温度寄存器表结构 typedef struct { int16_t temp_100x[16]; uint16_t valid_flags; uint16_t alarm_flags; } temp_register_map_t;实际项目中我用 STM32F722VE 的以太网做主链路、串口做调试备份链路。主链路断了上位机几分钟后会发现通信超时但本地控制环路不受影响系统继续按最后有效的温度数据运行。这种降级设计在楼宇自控调试阶段非常救命因为你永远不知道现场网络交换机会在哪一刻断电重启。5.2 长线实测和故障复盘硬件和驱动做完了我在实际现场跑过的测试数据列出大概情况本地组总线长度约 1.5 米上拉 4.7kΩ测试 24 小时读取成功率 100%。远程组走 15 米屏蔽双绞线上拉换成 2.2kΩ 后读取成功率稳定在 99.9% 以上偶发的失败集中在压缩机启动瞬间加了 TVS 和 RC 滤波后失败率进一步下降。还有一次很奇怪的故障远程组温度读数稳定但每隔约 10 分钟有一次超过 ±1°C 的跳变。排查了很久才发现是同一线槽里有一根 220V 输出线用的继电器触点在零点切换时产生干扰毛刺。把远程总线挪开 30cm 或者增加屏蔽层接地后问题彻底消失。这个案例说明现场布线的物理隔离比固件里的任何滤波算法都有效。6. 实测数据与几个必须记住的坑场景线长上拉电阻实测结果备注本地机箱内1.5m4.7kΩ24h 成功率 100%无强干扰远程风管15m2.2kΩ成功率 99.9%需 TVS 保护远程风管 强电并线15m2.2kΩ偶发数据跳变移开线槽或屏蔽接地远程风管不加保护15m4.7kΩ频繁 CRC 失败干扰无法容忍坑一上拉电阻千万别看着数据手册照抄。数据手册给的是典型应用电路的推荐值不会考虑你的线缆长度和现场干扰。一定要根据实际距离现场测一遍波形有振荡就降阻有毛刺就加滤波。坑二单总线器件供电方式要提前定死。寄生供电模式在短距离、传感器数量少时勉强能用但到远程长线、多传感器场景就是给自己挖坑。我建议统一采用外部供电3.3V 电源线单独拉一根给远端传感器数据线只是纯信号线电源和地单独走。这样阻容负载更易控干扰也小得多。坑三对 STM32F722VE 这类 M7 内核延时函数不要在运行后再修改主频。我踩过的坑是在低功耗模式下切换了时钟频率导致 DWT 延时按新的 CPU 周期计算单总线时序全部错掉传感器一个都读不到。要么降低功耗时保留总线时钟不变要么改变主频后重新初始化 DWT。坑四CRC 一定要做而且一定要把传感器上报的 CRC 字节和自己算出来的对比不要只看温度字节是否在合理范围。HVAC 现场太嘈杂了干扰可以同时把多个字节污染成“看起来合理”的值只有 CRC 能发现这种错误。坑五不要让温控任务在传感器读取时被打断。如果用了 RTOS给温度采集任务挂一个信号量在单总线读取期间关闭调度或使用临界区。STM32F722VE 有一个很实用的特性可以用 MPU 把温度采集相关的 RAM 区设为非缓存区域避免 DMA 和 CPU 在缓存一致性上出问题如果没有用 DMA那问题不大但开了 DCache 的 M7 用户要留心。最后一个实际体会这套 PJ85718DM 加 STM32F722VE 的方案真正关键的不是驱动代码本身而是把“采集—校验—调度—上报”这条链路当成完整的数据通道来设计。单点读温度谁都会写但要让它在带压缩机、带变频器的 HVAC 现场稳定地跑上几个月布线、上拉、保护、健康度这些工程细节一个都不能省。把这几个坑避开这方案在嵌入式设备里做本地和远程温度监测是我近期用过最省心的一套组合。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑