
上一个项目里接触到一款空调箱控制板需要同时监测送风温度、回风温度、盘管进出口水温还把机房里的环境温度一并传到值班室。最初的设计是每个测点一路模拟量信号线一套机组下来七八根线接线端子占了控制板将近三分之一的空间维护的时候还得拿着标签逐条核对现场施工的师傅看一次吐槽一次。后来我把测温点全部换成 PJ85718DM 这颗单总线数字温度传感器让它们挂在同一根总线上用一片 STM32F410RB 集中读取本地和远程的温度点用一条总线全部拉到 MCU再通过 RS485 上报给上位机。这套方案在样机里跑了两周温度数据稳定接线量直接砍掉一大半。这篇文章就从头到尾拆解这套方案硬件怎么接、单总线时序怎么调、固件怎么把多颗传感器管起来、实测会遇到哪些坑给同样在做嵌入式温控和 HVAC 系统的人一个可以直接抄作业的参考。1. 温控系统里“本地远程”到底要解决什么问题1.1 HVAC 场景的温度点位与接线痛点HVAC 设备里的温度测点往往分布在两个位置一类是控制板附近比如机箱内部温度、回风温度这些点离 MCU 近叫本地温度另一类在设备远端比如风管末端、盘管进出口、冷却塔管路导线可能要拉个十几米甚至几十米这类就是远程温度。传统做法是每个测点单独接一路模拟传感器NTC 热敏电阻或者 PT100每路都要占用一个 ADC 通道还要做分压电阻、滤波电容、校准表。测点一多控制板的 PCB 面积和端子数量立刻紧张而且模拟信号长线传输很容易被变频器、接触器的干扰带偏测出来的温度跳来跳去。单总线数字传感器改变的是整个布线逻辑它把温度直接转成数字量传感器里面自己做模数转换MCU 只需要一根 GPIO 引脚挂一条总线所有传感器并联在这根线上靠芯片里唯一的 64 位序列号区分彼此。本地装两颗、远程装三颗都在这条总线上主控芯片轮流寻址读取就行。这样既减少了接线数量又摆脱了对模拟采样的依赖。1.2 PJ85718DM 的关键特性PJ85718DM 的工作方式和很多人熟悉的 DS18B20 基本一致属于单总线接口的数字温度传感器引脚只有三个VDD、GND 和 DQ。DQ 既是数据线也是时钟线协议要完全靠主机产生时序来控制。芯片内部有 64 位唯一序列号出厂时烧录不会重复这是多点测温的基础。测温范围覆盖 -55℃ 到 125℃对 HVAC 的常规应用完全够用分辨率可以配置成 9 到 12 位12 位模式下每个 LSB 是 0.0625℃典型精度在 ±0.5℃ 左右属于免校准的级别贴上去就能读数。它支持外部供电也支持寄生供电即 DQ 在特定时段既是数据线又给芯片充能但寄生供电在实际工程里限制比较多我后面会专门说为什么建议外部供电。还有一个比较实用的点是报警寄存器可以给每颗传感器设置 TH 和 TL 上下限温度越限时传感器会记录一个报警标志主机读取告警状态时不用把每个字节都读出来适合做主控端的快速巡检逻辑。1.3 STM32F410RB 为什么适合这类控制板STM32F410RB 是 Cortex-M4F 内核的 MCU主频 100MHzFlash 128KBSRAM 64KB单总线测温这种 bit-banging 的活对它来说很轻松。选它不是因为性能堆料而是外设组合正好贴合 HVAC 控制板的需求它有多个 USART可以一个接 RS485 做上位机通信一个接调试串口有丰富的定时器用来做 PID 控制周期和通信超时管理还有 12 位 ADC 和比较器虽然温度走了数字总线但如果还需要采集湿度、压力、电流这些模拟量也不用再加 MCU。另外它的低功耗模式做得不错待机电流很低后面如果想做电池供电的采集节点同一颗芯片还能继续用。F410RB 的另一个好处是内部有真随机数发生器 TRNG这在做设备 ID 登记、通信加密时能派上用场。对一套要跑很多年的 HVAC 控制器来说预留这种能力比换芯片划算。2. 硬件连接的关键单总线不是随手一接就行2.1 最小系统连接与上拉电阻取值单总线的连接看起来特别简单所有传感器的 DQ 引脚并联到一个 GPIO中间接一个上拉电阻到 3.3VVDD 统一接电源GND 共地完事。但这里面最容易出问题的就是上拉电阻的值。上拉电阻的作用是让总线在空闲时维持高电平传感器想拉低总线时靠的是内部的漏极开路结构所以总线上任何时刻只有一个设备可以强调总线。电阻选太大总线电容会让上升沿变得很缓选太小传感器拉低时会分担太多电流导致低电平电压偏高。经验值是在 4.7kΩ 左右板内短距离连接完全没问题。如果总线要拉出去几米甚至十几米上拉电阻要适当降到 2.2kΩ 或 3.3kΩ补偿线缆的分布电容。还有一种做法是用 P 沟道 MOSFET 做主动上拉上升沿更陡适合特别长的总线。提示上拉电阻的 3.3V 电源必须和 MCU、传感器同源不能在两个电源域之间跨接。如果传感器用 5V 供电而 MCU 是 3.3VDQ 线上的电平转换不能省最简单的方式是在 DQ 上串一个电阻并加钳位二极管。GPIO 一定要配置成开漏输出模式。很多人第一次写单总线驱动时习惯用推挽输出结果读数据永远不对原因就是推挽输出强驱动高电平时传感器根本拉不动总线时序直接乱套。开漏模式配合上拉电阻总线才能被主机和从机共同驱动。2.2 本地和远程传感器怎样组织在一条总线上一条总线上挂多少颗 PJ85718DM 没有硬性限制总线电容才是真正约束。中短距离挂十几颗都没问题每颗传感器在温度转换时会从电源吸取几毫安的电流几十颗同时转换对电源也是一个考验。组织方式上本地传感器可以直接把 DQ 走线就近汇到 MCU远程传感器走一条双绞线出去沿途分线接到各测点。这里有一个重要的原则传感器的地址匹配是逻辑层面的和物理位置无关。你第一次上电搜索总线时读到的 64 位 ID 和物理位置没有对应关系所以工程上一定要做一步“登记”先在每个安装位置接上一颗传感器读回它的 ID记录在配置表里之后固件按配置表轮询。如果不做登记以后想判断哪个数据对应哪个测点就只能靠猜这在现场维护时是灾难。2.3 长线传输与抗干扰设计远程传感器真正考验的是硬件抗干扰。变频器启动的瞬间、接触器吸合、电机换向都会在长线上耦合出噪声噪声轻则造成 CRC 校验失败重则让单片机把噪声当成传感器应答总线直接卡死。几个比较靠谱的做法远程线用双绞线屏蔽层单端接地不要两端都接地避免地环路电流。总线入口处加 TVS 管钳位浪涌电压再做一级 RC 滤波。DQ 线上可以串一个 100Ω 到 220Ω 的电阻降低振铃幅度代价是边沿变缓所以和上拉电阻要配合调整。每个传感器的 VDD 和 GND 之间放 100nF 的陶瓷电容最好再加一个 10μF 的电解电容温度转换瞬间电流突变时能稳住电压。实际项目里如果总线上同时有传感器做外部供电还要注意传感器的 GND 和主控 GND 必须可靠连接不能依赖屏蔽层走地电流。远程点分散在几个方向上时宁可分两条总线也不要一条总线绕一大圈总线电容和噪声耦合都会成倍增加。3. 单总线时序从复位脉冲到 CRC 校验的完整链路3.1 初始化、读写时隙的时间参数怎么卡单总线协议里所有通信都是从主机主动发起开始的。第一步是复位脉冲主机把总线拉低至少 480μs然后释放在外接上拉电阻的作用下总线回到高电平这时总线上的每一颗传感器都会在 60μs 到 240μs 之间把总线拉低一段时间形成一个存在脉冲。主机检测到这个低电平就表示总线上有设备在可以继续通信。读写每一位的时间叫时隙每个时隙最短 60μs时隙之间要有至少 1μs 的恢复时间。写 1 和写 0 的区别在于低电平持续的长短写 0 时主机把总线拉低 60μs 到 120μs写 1 时主机只拉低 1μs 到 15μs 就释放剩下的时间让总线恢复高电平。传感器在时隙开始的 15μs 到 60μs 这段时间采样总线电平所以主机只要保证时序窗口正确就能把数据位传过去。读时隙稍微绕一点主机先拉低总线 1μs 到 6μs然后释放总线从机如果这一位是 0就会继续把总线拉低如果这一位是 1就什么都不做总线被上拉电阻拉高。主机必须在释放总线后的 15μs 内采样才能在从机释放总线前读到正确的电平。总结一句话读到低电平就是 0读到高电平就是 1。3.2 读取温度的完整命令流以读取单颗传感器温度为例完整流程是主机发复位脉冲等待存在脉冲。发 Skip ROM 命令 0xCC跳过地址匹配直接对总线上唯一一颗或者全部传感器操作。发 Convert T 命令 0x44启动温度转换。12 位分辨率下转换时间最长 750ms。等待转换完成再次复位。发 Skip ROM 0xCC再发 Read Scratchpad 命令 0xBE。连续读 9 个字节温度低字节、温度高字节、TH 寄存器、TL 寄存器、配置寄存器、三个保留字节、CRC 校验字节。把温度字节拼接成 16 位数据根据符号位做正负处理再乘以 0.0625 得到实际温度。如果是多点测温更高效的做法是先发 Skip ROM Convert T让总线上所有传感器同时开始转换等待 750ms 后再逐颗读取。读取时用 Match ROM 命令 0x55后面跟 8 个字节的 64 位 ID主机会先确认是不是在跟目标设备说话然后再发 Read Scratchpad。这样每颗传感器只需要一次独立的读取周期效率比逐个启动转换高得多。3.3 CRC 校验为什么不能省PJ85718DM 和 DS18B20 一样在 Scratchpad 的第 9 字节放了前 8 个字节的 CRC 校验值多项式是 x^8x^5x^41。主机读完 8 个数据字节后用同一个多项式对前 8 个字节做 CRC 计算结果和第 9 字节比对一致才认为这一帧数据是可信的。这东西在长线现场绝对不能省。我见过一个项目远程传感器布线跟变频器动力电缆走了同一个桥架读回来的温度偶尔会跳到 50 多度又跳回正常值加了 CRC 校验之后发现所有跳变的数据帧全部 CRC 错误直接丢弃重读读数立刻恢复正常。没有这层校验错误数据就会被当成真实温度送进 PID 控制器造成阀门误动作。CRC 计算在 MCU 上用查表法很轻松100MHz 主频下读一次完整数据帧加上校验时间也就几十微秒。建议把 CRC 校验放在读取函数的尾部校验失败时不要立刻重发先等一下个节拍再重读避免总线风暴。4. 固件实现把 MCU 变成一台温度采集网关4.1 驱动层开漏 GPIO 和微秒延时写单总线驱动底层就是两个函数拉低总线、释放总线以及一个微秒级延时函数。GPIO 配置为开漏模式后拉低就是往 ODR 寄存器写 0释放就是写 1开漏模式下写 1 实际是让引脚变成高阻态总线电平由外部上拉决定。读取时直接用 IDR 寄存器采样电平。延时函数是最容易被编译器坑的地方。用 for 循环空转做微秒延时开优化之后编译器可能直接把这个循环优化掉延时时间严重缩水时序就乱了。稳妥做法是使用 DWT 寄存器做精确延时或者用 SysTick 搭配微秒计数。void delay_us(uint32_t us) { DWT-CYCCNT 0; DWT-CTRL | DWT_CTRL_CYCCNTENA_Msk; while (DWT-CYCCNT us * 100) { // wait } }这条代码假设内核时钟是 100MHz每个周期 10ns延时 us 微秒需要 us * 100 个内核周期。实测下来用 DWT 延时的时序抖动控制在几个内核周期以内非常稳定。4.2 搜索 ROM把每颗传感器的唯一 ID 抄出来第一次上电或者新增传感器之后软件要做一次总线扫描把总线上所有传感器的 64 位 ID 找出来。搜素 ROM 的原理是位分支法主机发 Search ROM 命令 0xF0然后开始逐位搜索。每一位要读两次第一次所有设备输出自己 ID 当前位的“与”第二次所有设备输出当前位的补码。所以读到的两个电平组合有四种含义00 表示总线上既有这位是 0 的设备也有这位是 1 的设备出现分支01 表示所有设备这位都是 110 表示所有设备这位都是 011 表示总线上没有设备。主机在每一对读操作之后需要写一位数据。这一位的作用是指定下一步往哪个分支搜索。如果出现 00主机可以选 0 或 1并把选择记录下来遇到冲突时回到最近的冲突点走另一条分支。遍历完所有位就能恢复出一颗设备的完整 ID。对多颗设备重复这个过程直到没有新的分支为止就拿到了全部门牌号。搜索 ROM 的代码逻辑上像二叉树遍历写起来不算复杂但现场调要是遇到总线上挂的设备型号不一致时序稍微不稳搜索过程就会漏掉设备。建议在扫描时做多轮尝试把连续三次结果一致的 ID 才收入地址表。4.3 轮询调度批量转换、逐个读取、容错重试地址表拿到之后温度采集就变成固定的轮询循环。建议把流程做成状态机而不是一个死循环里做长延时。状态可以这样定义空闲状态准备新一轮采集复位总线。广播转换状态发 Skip ROM Convert T让所有传感器同时转换然后启动 750ms 的软件定时器。等待转换完成这段时间 MCU 可以去处理通信、按键、显示等其它任务。逐颗读取状态复位总线对地址表里的第一个 ID 发 Match ROM Read Scratchpad读完 9 字节做 CRC 校验校验通过就解析温度校验失败就记一次错误计数下一轮再重试。然后切到下一颗传感器的读取。全部读完回到空闲状态等下一个采集周期。这个流程的好处是异常隔离某颗传感器坏了或者接线断了不会拖垮整个总线。单总线协议里没响应就是没响应超时后直接跳过系统继续读其它传感器就好。4.4 上行链路RS485/Modbus 与 MQTT 上报STM32F410RB 把温度读回来之后要有出口。HVAC 现场最常见的上位机接口是 RS485 跑 Modbus 协议。F410RB 的 USART 很充裕接一个隔离型 RS485 收发器就能组网Modbus 寄存器表可以简单定义成每颗传感器对应两个寄存器一个存温度整数值放大 10 倍一个存传感器状态。这样上位机读温度、判断传感器故障都很直观。如果要对接物联网平台可以再加一个 UART 转 WiFi 模块或者 4G 模块把温度数据按 MQTT 协议发布到云端。MCU 侧只负责打包 JSON 格式的数据块通过串口发给模块复杂的协议解析都在模块侧完成。这样的架构里单总线多点采集和远程上报是两条独立链路温度采集的稳定性不会受网络波动影响。5. 实测数据与踩坑记录5.1 实测表本地点与远程点的读数偏差样机调试完成后我做了一轮对比测试把 PJ85718DM 的读数和一台精度 0.1℃ 的工业温度计放在同一环境里比对。下表是其中一组稳态数据测点位置传感器ID后3字节参考温度 ℃实测读数 ℃偏差 ℃机箱本地0x2A1F3C25.3225.380.06送风管远端0xB47D6023.8523.900.05回风管远端0x993E2126.1026.03-0.07盘管进水口0xC51A8B45.2045.270.07盘管出水口0x0E7F4D41.3541.28-0.07整体偏差都在 ±0.1℃ 以内对于 HVAC 控制的精度需求来说完全够用。需要说明的是这个偏差包含了工业温度计本身的误差PJ85718DM 实际精度应该更好。5.2 亲手踩过的三个坑坑一上拉电阻选大了。最初在样机里用的 10kΩ 上拉板内测试一切正常把远程传感器用 15 米双绞线接上之后CRC 错误率明显升高读时序的上升沿在示波器上看已经变成一个缓慢的斜坡。原因是总线电容太大RC 时间常数超过了读时隙的采样窗口。换成 3.3kΩ 上拉之后波形恢复CRC 错误基本归零。坑二微秒延时被优化。早期驱动里有一段 for 循环空转延时开编译优化后温度读数偶尔出现跳变查了半天发现是延时函数实际执行时间缩水到原来的一半时序窗口整体偏移。改成 DWT 精确延时之后问题消失。这个坑在单总线这种对时序敏感的外设上特别容易踩而且不查汇编都发现不了。坑三多传感器同时转换时电源跌压。系统挂了 8 颗传感器全部外部供电结果发现每次广播转换命令之后总线上的传感器会有一个短暂的电流尖峰导致长线末端的供电电压跌落几百毫伏远程传感器的转换结果偶尔偏低 0.125℃。在每颗传感器旁边补了 10μF 电容并把转换命令改成两批错开发送问题就解决了。单总线协议虽然允许广播转换但电源设计跟不上的时候分批转换比一次全转更安全。5.3 现场维护里的小技巧传感器需要更换时先读回新传感器的 64 位 ID更新配置表里的地址项再插到总线上。不要先接线后测地址否则新设备一上电就会出现在未登记设备列表里干扰正常的轮询。另外我习惯在记录配置表时顺带记录传感器安装位置的物理编号比如“送风管末端-1号”这样后期排查问题时软件里的数据能和现场位置快速对上。6. 这块方案还能怎么扩展6.1 从温度采集升级到换热效率计算多点温度拿到之后价值不只是看当前温度还能做简单的设备健康诊断。比如盘管进出口水温差变小同时送风温度偏离设定值可能说明盘管水侧结垢或者气侧滤网堵塞。温差、风量、水流量这些参数组合起来就能估算换热效率的变化趋势。STM32F410RB 的计算能力跑这些浮点逻辑绰绰有余控制程序里加几个判断条件就能实现预警功能。6.2 低功耗和无线化改造如果现场不方便布线可以把采集端做成电池供电节点。STM32F410RB 进入 Stop 模式后电流可以压到微安级别定时唤醒后花 100ms 完成一次总线扫描和温度采集再把结果通过无线模块发出去。单总线这边的传感器虽然没有真正意义上的休眠指令但可以通过降低采样频率来等效降功耗。硬件设计时要注意给传感器供电的 LDO 选静态功耗低的型号否则一整年下来电量不够看。6.3 产品化还需要补的功课真正要做成产品还有几个硬骨头要啃一是批量校准虽然芯片标称精度不错但大批量生产时还是建议贴片前做一次温度标定把每颗传感器的固定偏差记录进产线数据库二是电磁兼容单总线长线部分还要按标准过一遍 ESD 和 EFT 测试三是固件升级F410RB 的 Flash 支持在线升级最好预留一个 Bootloader温度采集固件更新就不用拆壳了。最后说点我对这套方案的感受。单总线测温不是什么新技术但它放在嵌入式控制和 HVAC 场景里解决的是实实在在的接线成本和维护效率问题。PJ85718DM 这种兼容类单总线芯片用起来跟老牌的 DS18B20 几乎一样供货和成本上会宽裕一些。STM32F410RB 做主机性能和外设都有冗余既跑得动温度采集也管得了后续的 PID 和通信。如果你手头的项目也在为多路温度测点发愁先拿一块开发板接三颗传感器跑一轮上面的流程很快就能判断这方案适不适合你。