基于PJ85718DM与R7FA4M2AD3CFP的HVAC本地远程温度监测设计 做HVAC控制板有一个绕不开的刚需测温度。前段时间我在做一块小尺寸的暖通控制器板子上既要跑本地逻辑又要同时采集回风温度和远端风管温度最后通过RS485把数据送给楼宇网关。MCU当时已经确定了用R7FA4M2AD3CFP测温芯片我反复对比之后选了PJ85718DM。这篇文章就把“本地远程温度监测”这条链路从硬件选型、电路设计、固件实现到现场调试踩坑的完整过程写出来给正在做嵌入式和HVAC应用的朋友当一份参考。老规矩先说清楚这篇文章不涉及复杂算法也不需要高性能处理器核心就两件事——把温度稳定、准确地测出来再让这两路温度参与实际控制逻辑。如果你手头正好有类似的项目可以直接照着下面的思路做。1. 项目背景与方案选型HVAC里为什么需要“两路温度”1.1 冷风管、回风口和室外机的温度到底给谁用很多人一听到HVACHeating, Ventilation and Air Conditioning就以为是空调实际上暖通控制器里温度点远不止“室内温度”这一个。我在做的这个项目里甲方要求监测三个关键温度回风温度、送风温度、室外环境温度。这三个点的用途完全不同。回风温度代表的是机组当前吸入空气的状态它决定了压缩机启停和风机转速的调整方向送风温度则反映制冷或制热的效果如果送风温度偏离设定值太大说明换热或者风机环节出了问题室外温度主要用于辅助判断机组的运行模式比如过渡季节是不是可以直接切换成新风模式。前两者在设备内部和风管末端可以看作“本地温度”和“远程温度”的典型组合一块主控板本地传感器装在回风口附近远程传感器拉到几十米外的风管送风口。这套思路在工装项目里非常常见。楼宇自控系统最需要的不是你本地测出来的那个温度而是远端实际风管里的温度。本地温度用来做保护和控制基准远程温度用来做效果验证和系统诊断两路缺一不可。1.2 几种测温方案的对比与取舍测温看起来简单方案其实不少。最开始我心里列了四个候选方案方案ANTC热敏电阻 MCU内部ADC方案BPT100铂电阻 模拟调理电路方案CI2C数字温度传感器比如常见的SHT30方案D单总线数字温度传感器PJ85718DM属于这一类NTC方案最便宜一颗料几毛钱但要处理非线性的B值公式还要考虑ADC参考电压漂移、引脚串扰、长线压降。PT100精度确实高但配套调理电路成本高、占PCB面积大对暖通这种量级的产品来说属于“杀鸡用牛刀”。I2C数字传感器布线距离短超过一米就需要注意信号完整性问题只适合放本地板载。单总线方案一根数据线既可以供电又可以传数据支持一线上挂多个节点还能拉几十米的线缆非常契合“本地远程”的需求。我列出表格方便对比方案精度表现单点成本多点扩展长线能力开发难度NTCADC中等依赖校准低需占用多路ADC一般受压降影响中等PT100调理电路高高成本成倍增加一般高I2C数字传感器高但受线缆限制中等地址有限难走远弱低单总线数字传感器中高中等一根总线挂多颗强中等对于暖通项目的现场环境来说远程传感器可能要走十几米甚至几十米的线单总线传感器的优势就太明显了。这也是我后来坚定选PJ85718DM的根本原因。1.3 最终选型PJ85718DM R7FA4M2AD3CFP的组合逻辑PJ85718DM这颗芯片我一开始持保留态度因为单总线时序对延时精度要求比较高但我实际测下来它的读取时序和寄存器定义基本沿用了经典单总线方案很多DS18B20上积累的经验可以直接复制过来。它内部自带12位ADC转换器输出的是数字值不需要再用MCU的ADC通道也不用做NTC那样的查表校准这就砍掉了半个软件模块。MCU选R7FA4M2AD3CFP主要看中几点ARM Cortex-M33内核主频够跑控制算法引脚数量、Flash和RAM容量都合适外设里有多个SCI串口和丰富的GPIO我可以把调试串口、RS485通信、两路温度传感器分开安排互不抢占这个系列支持多种低功耗模式后续如果做电池供电的无线采集器不用换平台。组合逻辑其实很简单PJ85718DM负责数据采集端把复杂的温度换算变成标准数字R7FA4M2AD3CFP负责逻辑控制端把温度数据变成风机、加热器、压缩机的动作。一个偏感知一个偏决策各干各的活整个系统结构就很清晰了。2. 硬件连接与电路设计把传感器布到本地和远程2.1 单总线传感器的电源与上拉设计PJ85718DM在使用上有一个参考接法VCC接3.3VGND接地数据线DQ通过一个上拉电阻连接到MCU的GPIO。上拉电阻的取值很关键官方参考值通常是4.7kΩ但这只适合线缆比较短、挂载节点少的场景。我的项目里本地传感器离MCU不到20厘米4.7kΩ完全没问题远程传感器要走二十多米双绞线这时候4.7kΩ会导致边沿变缓我换成了2.2kΩ同时把MCU侧的GPIO配置成开漏模式。有一点容易被忽略如果单片机GPIO用了推挽输出在总线上可能出现电流倒灌直接把传感器烧掉。单总线设计一定要在主控侧用开漏输出加外部上拉而不是推挽输出。如果MCU的GPIO不支持开漏模式则需要外挂MOS管来做方向切换但RA4M2的引脚是可以配置成开漏的这个麻烦就省了。电源端我还加了两个小器件靠近传感器的地方放一个0.1μF陶瓷电容去耦电源输入处加一个磁珠。不要小看这个磁珠HVAC设备里有继电器和变频风机这些负载启停产生的电源噪声很凶不加磁珠直接供电传感器读数就容易跳。2.2 远程温度点从几十厘米到几十米的走线处理本地温度点没有什么特殊之处按常规接法放在板子边缘暴露区域即可。真正需要花心思的是远程温度点。现场拉线不可能像实验室那样用短杜邦线我碰到的情况是要穿过一段金属线槽再经过两个接线端子接到风管旁边的传感器座上。远程走线我建议用屏蔽双绞线屏蔽层单端接地接在控制板的地平面这一侧另一端悬空。这么做的好处是屏蔽层不会形成地环路又能把离心风机产生的电磁干扰挡在外面。如果现场环境更恶劣比如传感器靠近变频器电缆我还会在传感器数据线上加一个小TVS管防止静电和感应闪电损坏主控GPIO。接线端子也是一个坑点。工业现场经常出现端子氧化或者接触不良的问题单总线只要断一下读回来就是异常值。我后来在端子前后各加了一级RC低通滤波数据线上串了一个几十欧姆的电阻再并一个纳法级电容到地既抑制噪声又能在一定程度上保护IO口。2.3 参考引脚分配与原理图要点下面是我在这个项目里的引脚分配思路不一定是最优解但足够清晰功能模块引脚说明本地温度传感器DQPB5开漏输出外部2.2kΩ上拉远程温度传感器DQPB6开漏输出外部2.2kΩ上拉加TVSRS485通信SCI3TX/RX标准收发器方向控制用PD1调试串口SCI1TX/RX预留打印日志本地温度传感器供电3.3V_A独立LDO磁珠隔离远程传感器供电3.3V_B与本地供电分开便于排查故障我特意把两路传感器分开供电理由是排查问题的时候非常管用。如果远程传感器读值异常我直接量3.3V_B端电压就知道是电源坏了还是通信有问题不用两块板子来回换着试。原理图上我还留了两个0Ω电阻位用来切换传感器是否启用。这样做的好处是生产阶段如果远端传感器不是标配贴片时直接不贴这部分电路成本能低一些。3. 固件实现读温度不是“读一下就行”3.1 单总线时序与PJ85718DM的初始化流程单总线说穿了就是一根线所有通信都是靠拉低、释放数据线的时长来编码的。你可以把它理解成一间只能通过一个人传话的屋子屋子里多人共用同一个麦克风想说话必须遵守严格的作息表不然就乱套了。第一步是初始化总线也叫复位脉冲MCU把数据线拉低480微秒以上然后释放。传感器检测到这个长低电平就会拉低数据线60到240微秒回应一个存在脉冲。检测到这个存在脉冲总线才算建立连接。下面是实际代码static int ow_reset(GPIO_TypeDef *port, uint16_t pin) { int presence 0; // 拉低总线要求至少480us gpio_set_output(port, pin, 0); delay_us(500); // 释放总线准备接收存在脉冲 gpio_set_open_drain(port, pin, 1); delay_us(70); // 读取总线状态低电平表示传感器存在 if (gpio_read_input(port, pin) 0) { presence 1; } // 等待整个复位周期结束约480us delay_us(450); return presence; }如果这里的delay_us不精确后续所有的位时序都会错位。我在RA4M2上用了DWTData Watchpoint and Trace的计数器来做微秒级延时而不是用SysTick。原因很简单SysTick一旦被RTOS或者中断服务函数打断延时就会变长单总线时序很容易被破坏。DWT是一个硬件计数器不依赖中断可靠得多。3.2 温度读取、多点寻址与轮询策略温度读取流程按经典单总线套路走复位-发送跳过ROM指令-发送启动温度转换指令-等待转换完成-复位-发送跳过ROM指令-发送读暂存器指令-连续读9个字节。前两个字节就是温度值。温度值是一个16位有符号数LSB表示0.0625摄氏度。代码处理逻辑float read_temperature(void) { uint8_t buf[9]; int16_t raw; float temp; // 启动温度转换 ow_reset(port, pin); ow_write_byte(port, pin, 0xCC); // Skip ROM ow_write_byte(port, pin, 0x44); // Convert T delay_ms(100); // 等待转换完成 // 读取数据 ow_reset(port, pin); ow_write_byte(port, pin, 0xCC); ow_write_byte(port, pin, 0xBE); // Read Scratchpad for (int i 0; i 9; i) { buf[i] ow_read_byte(port, pin); } raw (buf[1] 8) | buf[0]; temp raw * 0.0625f; return temp; }我用的这两路传感器分别接到了PB5和PB6两个独立的GPIO所以在软件里没有去折腾一拖多的点序搜索。原因很现实一拖多虽然省IO但多点搜索ROM和CRC校验代码量和出错概率都更高现场维护人员也不好排查。板子上引脚资源不吃紧独立分开反而是最稳的方案。每500毫秒轮询一路1秒钟完成两路温度刷新HVAC控制的时效性完全够用。3.3 滤波与校准让显示值稳定、可信温度数据就算硬件做好了软件里也还得做一层处理。我在这个项目里用了“中值滤波滑动平均”两级处理先取最近5次原始值做中值滤波去掉偶发的毛刺再把中值滤波后的结果放进一个长度为4的环形缓冲求平均。这样能兼顾响应速度和稳定度温度缓慢变化时跟随性好风机启动瞬间的突发噪声又被挡在门外。校准方面PJ85718DM芯片本身有一定的出厂精度但每颗器件之间还是会有偏差。我在生产流程里增加了一个简单校准工序把传感器探头放到冰水混合物中读出偏移量再放到恒温槽中做满度标定然后把校准系数存到MCU的Flash参数区。实际控制时使用校准后的温度值而不直接使用原始温度。校准的结果很重要尤其是HVAC系统里温差判断逻辑。如果两路传感器本身都带0.3摄氏度的系统误差可能把正常的系统误报成故障。两路传感器最好用同一个恒温源同时校准这样即使绝对温度略有偏差相对温差也是准的。4. 上层联动本地和远程温度数据怎么“用起来”4.1 迟滞控制风机和加热器不那么频繁跳变测出来的温度本身没什么意义参与控制才有价值。HVAC控制器最常见的问题是设备频繁启停。如果设定温度为20摄氏度程序写成“低于20度开加热器高于20度关加热器”你会发现温度在设定值附近抖动时继电器会咔嗒咔嗒响个不停压缩机寿命直线下降。解决办法是迟滞控制。我设定加热器启停阈值温度低于19.5摄氏度启动高于20.5摄氏度停止。这个0.5摄氏度的回差能有效避免频繁动作。更重要的是这种逻辑必须用状态机实现而不是简单if判断typedef enum { HEAT_OFF, HEAT_ON } heat_state_t; heat_state_t update_heat_control(float temp, heat_state_t cur_state) { heat_state_t next cur_state; switch (cur_state) { case HEAT_OFF: if (temp 19.5f) next HEAT_ON; break; case HEAT_ON: if (temp 20.5f) next HEAT_OFF; break; } return next; }如果用独立if很容易出现同一周期内既开又关的冲突。状态机写法看着多了几行代码但逻辑边界非常清楚后面加报警逻辑也方便。4.2 温差判断用两路温度发现滤网堵塞和风机故障本地温度和远程温度放在一起比较能诊断出很多设备隐患。制冷模式下回风温度是25摄氏度送风温度如果只有26摄氏度说明换热效果极差。这时候不是系统没开而是空气流量出了问题。我在程序里做了一个温差健康诊断模块每次成功采集到两路温度后计算送风温度与回风温度的差值如果连续5个周期差值都低于正常区间下限就输出一个“风力不足”的报警码提示现场人员检查过滤网和风机皮带。这个功能帮我们提前发现了两次风管滤网堵塞甲方反馈很不错。相反如果送风温度与回风温度差值过高说明系统可能存在混风短路或者传感器被太阳直晒也需要人工检查。温差诊断本质上是一个数据交叉验证两路传感器互为参照任何一路单独漂移都能被发现这也是当初坚持做两路温度的一个重要原因。4.3 Modbus上报与配置管理HVAC项目几乎都要接楼宇自控系统楼宇自控最常见的就是Modbus RTU协议。我把两路温度值、诊断报警码、传感器连接状态都映射到了标准寄存器表里寄存器地址内容格式0x0001本地温度有符号16位放大10倍传输0x0002远程温度有符号16位放大10倍传输0x0003温差值有符号16位放大10倍传输0x0004报警状态位标志Bit0滤网堵塞Bit1传感器故障0x0005传感器状态Bit0本地在线Bit1远程在线上传温度时我习惯把数值放大10倍再发整数这样上位机显示23.4摄氏度时传输值就是234。用整数传输的好处是兼容性更好很多老网关对浮点数支持很差。寄存器地址一定不能随便占满留出一定冗余空间方便后续加数据点。5. 调试记录与避坑清单5.1 读回-55°C最典型的单总线故障刚做完第一版样机的时候远程温度偶尔会读到-55这个离谱值这个值一看就不是真实环境温度。我第一个怀疑对象就是总线时序被干扰但示波器抓波形发现复位脉冲和读时序都还算干净。后来排查到供电端才发现在远程传感器启动转换的瞬间电流变化把3.3V_B电压拉出了几十毫伏的毛刺。PJ85718DM这类温度芯片在温度转换时会有一次突发电流如果供电那一路走线太细或者去耦电容放得太远就会引起总线信号畸形。解决办法是给远程传感器的电源入口处加了一个100μF电解电容同时把0.1μF陶瓷电容从传感器旁边挪到了更靠近DQ和VCC的位置。这之后-55这个读数再没出现在日志里。5.2 风机一启动温度就跳动第一次上电测试时发现一个很诡异的现象只要风机启动本地温度读数就会瞬间跳1到2摄氏度风机停了又恢复正常。一开始我还以为是传感器响应快真的把电机发热读出来了后来发现完全不是那么回事。用示波器在风机的供电线和传感器数据线分别挂探头发现风机启动瞬间整个控制板的地电位都跟着跳动主控地、风机地、传感器地之间存在一个较大的地环路。处理起来分了两步第一步在风机供电回路里加滤波和吸收电路减小共模干扰回灌第二步把所有传感器相关的地和功率驱动地做了单点汇接不再让风机驱动电流经过传感器地平面。另外三个传感器共用一个大地参考但各自的供电回路独立避免远端传感器GND线上流过其他大电流。5.3 低功耗模式下延时“飘”的教训项目中期我想尝试让整个采集板在空闲时进入低功耗睡眠模式这样在后端接电池方案时能省不少电。结果问题来了从低功耗唤醒后第一次读温度几乎必然失败要么存在脉冲检测不到要么CRC校验失败。排查后发现根因在时钟切换上。低功耗唤醒后系统时钟可能还处在低速RC状态此时调用delay_us返回的延时比实际短了很多单总线的时序自然就乱了。解决办法是唤醒后先做一个时钟源切换等待让MCU稳定工作在高速时钟下再执行温度读取。这个坑非常隐蔽如果你也在做低功耗版本的单总线代码一定要记得处理时钟稳定时间。5.4 给后续项目留下的几个经验做完这个控制器我再做类似项目时已经形成了一套固定打法。原理图阶段就直接预留两路传感器的独立供电和接地焊桥这样现场如果发现某一路传感器干扰大硬件调整不需要飞线。固件层面把单总线的复位、读写位、读写字节封装成独立模块用软件模拟开关切换模拟总线时序调参不需要改应用层代码。所有传感器读取函数统一加返回值状态检查不通过就直接跳过本轮控制不让脏数据进入控制逻辑。还有个细节一定要在固件里保留传感器在线检测功能。现场工人经常会把插头忘接如果固件只是读到异常值却不报错售后电话会一直响不停。我后来把所有读温度失败的情况都整理成明确的报警码调试串口一打印问题定位时间从半小时缩短到了两分钟。如果你正在做类似的嵌入式和HVAC应用我建议你按这个顺序来先确认好测点和布点再确定传感器类型和MCU型号然后花大力气设计好电源和走线最后才动手写固件。温度监测这件事硬件干净了软件就轻松了。反过来如果硬件有隐患再好的滤波算法也只是掩盖问题。把基础打牢后面整个系统都会省心很多。