最近手头在做一套HVAC控制器需要把风机盘管、风管和新风机的温度全部纳入监控同时还要在嵌入式主板上就近采集回风温度。折腾了一圈最终选了PJ85718DM配合STM32F107VC这套组合把本地和远程温度监测一起做掉了。这篇东西就把整个设计过程、硬件连接、软件初始化和踩过的坑从头到尾捋一遍给同样在嵌入式和暖通场景里折腾温度采集的朋友做个参考。这里说的“本地温度”是挂在主控MCU附近、通过板级总线就能直接读到的温度用来做回风采样和设备自身状态监测“远程温度”则指挂在远端节点的温度节点和主控之间通过现场总线组网主控定期把各点温度拉回来统一处理。两种温度混在同一个系统里管是嵌入式应用开发里很常见的需求但传感器选型不好本地倒还好办远程这一路很容易在抗干扰和通信上栽跟头。这篇文章会把选型逻辑、硬件接法、寄存器配置、通信组网和调试经验都说明白适合正在做暖通控制器、智能楼宇采集终端或者需要在嵌入式设备里做多点温度监测的开发者参考。1. 项目整体设计与方案拆解1.1 嵌入式与HVAC场景的核心需求差异嵌入式设备里的温度监测通常有两层目的一是保护二是控制。保护层面比如功率器件或处理器核温超过阈值时要触发降频或断电这个偏重响应速度和可靠性控制层面根据环境温度调整风扇转速或加热器输出这个偏重采样精度和滤波平滑度。HVAC场景则更分散一台现场控制器旁边可能有好几个温度采集点——回风温度、送风温度、盘管出液温度、室外侧冷媒温度有些点在现场控制器主板上有些则在几十米外的风道里或设备间里。这两种场景结合起来对温度采集系统的要求很明确本地通道要实时、稳定远程通道要抗干扰、易扩展。如果只做一个本地单点采样随便找个温度传感器配个MCU就能跑但加上远程多节点之后总线选择、通信协议、节点供电这些原本不太起眼的问题就全都浮出水面了。1.2 器件选型的底层逻辑选择PJ85718DM主要看重几个点。第一它走I2C接口和STM32自带的硬件I2C外设直接对接不用额外引时序软件上少一层折腾。第二芯片提供三个地址配置引脚一条I2C总线上理论上可以挂多个方便在很多点位上就近接入。第三器件内置12位ADC和窗口报警比较器温度超过设定幅值可以直接从ALERT引脚输出中断不用靠主控软件轮询死等。像HVAC这类需要响应速度的场合硬线报警很省心。STM32F107VC当时选它则是因为它属于互联型产品线片上同时集成了多个USART、两个I2C、两个CAN控制器和以太网MAC远程节点既可以用CAN组网也可以走RS485换Modbus灵活性高。主频72MHz在跑温度和简单控制逻辑的前提下完全够用512KB Flash也足够放下Bootloader、应用固件和通信协议解析表。工作温度范围适合放在控制器箱体内不用额外做散热方案。我的体会是如果项目只做单板温度采集选个8位小单片机都行但一旦涉及“远程多节点 协议解析 本地PID”这种复合需求MCU的外设数量和Flash容量就成了隐形天花板。当时我还在F103和F107之间犹豫过最后选了F107光多出来的CAN控制器就让系统扩展空间大了很多。1.3 系统总体架构一主多从的温度采集网格整套系统的结构并不复杂。主控板是核心板上焊一片PJ85718DM用作本地回风温度采样通过I2C1接到MCU。远程侧在每个风机盘管控制盒或风道传感器盒里放一块带PJ85718DM的小板由节点端处理温度数据并通过CAN总线挂到总线上主控统一接收。这种架构的好处是本地温度实时性最好远程温度采集点可以灵活增减不必改动主控硬件。每增加一个远程点只需要在总线上增加一个从节点主控程序里增加一个节点ID的解析表项即可。另外把远程节点的ADC采样、滤波、协议封装等工作下沉到节点自身主控只做汇总和决策CPU负载能腾出来跑PID和上位机通信。说句实在话刚开始我也想过用一根长的I2C线把所有传感器串起来但测试后发现线路超过几十厘米、经过驱动器干扰区之后I2C信号就面目全非了。所以老老实实换成CAN总线做远程传输。这个选型教训在后面常见问题部分会再展开。2. 硬件连接与寄存器级实操要点2.1 PJ85718DM的引脚功能与I2C地址配置PJ85718DM是比较典型的I2C温度传感器封装引脚不算多核心引脚包括电源VCC、地GND、I2C数据SDA、I2C时钟SCL、三个地址引脚A0/A1/A2和ALERT报警输出。三个地址引脚每个可以有L、H、S三种电平状态S通常指高阻三个引脚组合下来就是27种地址实际项目中挂几十个节点也够用了。硬件上要注意地址引脚不能悬空随便接电平状态必须通过电阻明确拉到高、低或保持浮空。我当时的做法是每颗芯片旁边放一颗2kΩ排阻将地址引脚分别接VCC、GND或完全悬空芯片上电后读到的地址就固定了。如果你把地址引脚随意悬空读不到数据或地址冲突的情况会经常出现这个坑值得留意。ALERT输出是开漏结构外部必须加一颗上拉电阻到电源阻值4.7kΩ到10kΩ都行。这颗电阻别图省事省略否则中断信号拉不低MCU侧根本识别不到报警。另外ALERT脚建议引到MCU的外部中断输入引脚配置成下降沿触发这样温度越限时MCU能第一时间响应。2.2 STM32F107VC的外设分配与引脚连接我用的连接方式比较常规本地PJ85718DM挂I2C1时钟线SCL接到PB6数据线SDA接到PB7ALERT接到PB4配置为外部中断。远程CAN控制器对应的引脚是PA11CAN_RX和PA12CAN_TX通过一颗CAN收发器接到总线。I2C地址全部由硬件引脚决定主机这边的I2C地址可以忽略从机地址通过读地址位确定。STM32F107VC的电源域和引脚分配需要特别留心。控制板上有3.3V主电源和12V设备电源传感器供电从3.3V稳压输出取最好加一颗磁珠做隔离避免HVAC里压缩机和风机启动时的大电流毛刺顺着地线窜进传感器。复位、BOOT0、晶振相关的引脚按手册标准接法来这部分没什么特别但要注意I2C引脚如果和JTAG/SWD调试口冲突调试期间会非常难受。我的做法是让I2C1的SCL/SDA走PB6/PB7JTAG用PA13/PA14两边不冲突调试和采集可以同时进行。2.3 供电与抗干扰设计HVAC环境下的硬仗HVAC应用里最常见的干扰就是电机启停引发的电源跌落和辐射。压缩机启动瞬间电流可以到正常运行的数倍地线上的压降足以让温度读数跳变几摄氏度。除了前面说的磁珠隔离传感器板的地线要采用单点接地并尽量远离功率地。电源去耦电容在每个传感器板上都要加我习惯在电源管脚附近放一颗100nF陶瓷电容同时再并联一颗10µF电解电容实测对读数稳定性帮助很大。还有一个容易被忽略的点PJ85718DM和MCU之间的I2C走线不要穿过变压器或电机供电电缆附近实在绕不开就加粗走线、缩短距离并在SDA/SCL线上各加一颗10pF小电容做滤波。远程节点的CAN线则用双绞屏蔽电缆屏蔽层在控制器端单点接地这基本是暖通工程里的标准做法。总结下来抗干扰的核心思想就四个字远离、去耦、单点接地。2.4 寄存器配置分辨率、报警阈值与温度换算PJ85718DM的寄存器结构不复杂配置寄存器和温度寄存器是操作核心。温度寄存器是16位的高8位是整数部分低8位是小数部分配合12位ADC的分辨率每一位小数对应的温度是0.0625℃。换算的时候直接读两个字节拼成16位数右移4位就得到12位有效数据再乘以0.0625就是实际温度。这个换算新手最容易错的地方是把符号位当成普通数据位建议做成带符号处理的宏定义。配置寄存器里最常用的设置包括转换分辨率、故障排队次数和ALERT输出模式。HVAC场景我一般把分辨率拉满到12位故障排队次数设为4次这样瞬时干扰无法随便触发报警避免现场因为断续报警搞出误会。报警阈值寄存器里写上上限和下限值比如回风温度上限设为40℃下限设为5℃超出范围立即从ALERT脚拉低主控中断里做保护动作。3. 软件实现初始化、采集、通讯与联动3.1 硬件I2C初始化与读写函数封装STM32的硬件I2C用起来要注意一个老问题总线错误复位和超时处理。很多人一开始图方便用软件模拟I2C但那样CPU占用率高而且时序容易被中断打断。我的选择是用硬件I2C同时打开错误中断一旦检测到AF应答失败或BERR总线错误先把I2C外设复位再重新配置一次这样系统不至于被一次瞬时干扰打趴。初始化顺序也有讲究先把GPIO的复用功能模式匹配好再初始化I2C外设时钟和参数最后打开外设使能。顺序错了虽然没有硬件报错但总线上可能多出一堆自己都看不懂的ACK波形。读写函数封装时要加一个超时退出机制不要在总线卡死时让主程序死等。我用一个宏定义超时值比如100ms超时直接返回错误码主循环收到错误码后选择重试或报警。#define I2C_TIMEOUT_MS 100 #define TEMP_RESOLUTION 0.0625f // 读取PJ85718DM温度寄存器 int8_t read_temp_reg(uint8_t dev_addr, uint8_t reg, uint16_t *raw) { // 发送寄存器地址 if (HAL_I2C_Master_Transmit(hi2c1, dev_addr, reg, 1, I2C_TIMEOUT_MS) ! HAL_OK) return -1; // 读取两个字节温度数据 uint8_t buf[2]; if (HAL_I2C_Master_Receive(hi2c1, dev_addr, buf, 2, I2C_TIMEOUT_MS) ! HAL_OK) return -2; *raw ((uint16_t)buf[0] 8) | buf[1]; return 0; } float raw_to_temp(uint16_t raw) { uint16_t valid12 raw 4; float temp (int16_t)valid12 * TEMP_RESOLUTION; return temp; }这段代码里有个细节raw_to_temp函数里先把raw右移4位再按有符号的int16_t做乘法这样负数温度也能正确转换。如果不先转成有符号数温度低于0℃时会得到一个错误的大正数。3.2 本地温度采集与ALERT中断处理本地通道的读取逻辑相对简单主循环里每500ms发起一次读取读到16位温度值后经过换算转成float再放进带滑动窗口的滤波数组取窗口平均值作为最终温度。为什么要滑动平均HVAC现场的风机转速变化会引起温度探头附近气流脉动瞬时读数波动很大滑动平均后控制逻辑才稳定。ALERT中断处理优先级要高一些中断里不做费时的换算和滤波只读报警标志、记录事件并置保护标志位具体动作放到主循环处理。如果HVAC控制器里还有一个看门狗喂狗这件事千万别放在中断里做等主循环拿到新温度值再喂才能保证死循环能被看门狗救回来。这一点我们踩过两次第一次把喂狗放在定时器中断里结果主循环挂死了看门狗照样被喂着整个控制器在死循环里跑了半天才发现。3.3 远程温度采集CAN节点与协议帧设计远程节点的软件要稍微复杂一点主要是多了一个通信协议层。我们定义了一套紧凑的CAN协议帧数据帧使用标准帧格式ID按功能编码前几个字节放节点地址和传感器类型后两个字节放温度原始值再配一个校验字节。每个远程节点上电后先做自检读完PJ85718DM的配置和温度之后每隔500ms发一帧温度数据。主控端收到后按ID解析、滤波并把最新的节点温度写到共享结构体里。typedef struct { uint8_t node_id; uint8_t sensor_type; uint16_t temp_raw; uint8_t checksum; } TempCanFrame;这里有个关键细节温度原始值用整数传输不要在节点上转成float。因为CAN帧里装浮点数既浪费带宽又增加解析复杂度我们用12位原始ADC值或乘以100后的定点数主控收到后再除以100转成实际温度。实测下来整数传输可以避免很多莫名其妙的精度误差而且不同编译平台对浮点数的表示方式还不完全一致。CAN波特率这块也要算一下。我们的总线上规划最多挂16个节点每个节点500ms发一帧约8字节数据加上帧头帧尾和填充位一帧完整CAN报文大约需要15字节的传输时间。250kbps波特率下一帧大约需要0.6ms16个节点轮询一圈也就10ms左右完全足够。考虑抗干扰余量我选的是125kbps这样即使总线上有变频器干扰误码率也能控制在很低的水平。3.4 HVAC中的结果应用温度数据参与PID联动采集温度不是目的目的在让HVAC系统根据温度做动作。我们的联动逻辑大致分两层第一层是保护回风温度或盘管温度超限时ALERT硬中断会立即关闭风机或压缩机输出第二层是调节主控根据回风温度和设定目标温度的差值做PID计算输出风机转速或比例阀开度。PID参数整定时要特别注意积分限幅和抗积分饱和不然启动阶段会有一段明显的超调。远程温度在这套逻辑里是补偿因素。比如新风温度低的时候送风温度的PID目标值要做修正避免把冷风猛往室内吹。把本地、远程温度都收进决策逻辑后整个HVAC系统就有了多点感知能力比单纯靠一个探头吹风要稳得多。我后来还把各个节点的温度变化率也算了进去如果某个点温度变化率异常快大概率是风机或者阀门出了问题这个预警逻辑对维护人员很有用。4. 常见问题与排查技巧实录4.1 温度读数漂移和跳变现象读出来的温度值在正常值附近±5℃乱跳传感器附近没有任何热源。排查顺序先看供电波形用示波器量PJ85718DM电源脚有没有跌落毛刺再看I2C波形SCL/SDA上是否有振铃或幅值不稳最后检查换算是否把高字节符号位当成了普通数据。大多数跳变问题出在地参考和符号处理上。如果电源波形干净、换算没问题那就要重点查传感器探头本身有没有密封好HVAC环境里湿气进入探头外壳也会导致读数漂移。4.2 I2C通信失败现象初始化后读寄存器一直返回超时逻辑分析仪上看不到ACK。最常见原因是SDA/SCL线上缺少上拉电阻。STM32的I2C引脚是开漏输出没有上拉根本拉不到高电平。另外如果总线上挂了多个PJ85718DM地址设重了也会这样。解决方法先只挂一个传感器确认波形后用逻辑分析仪观察地址和ACK。还有一次遇到问题是上拉电阻选的太大用了100kΩ导致信号上升沿太慢换回4.7kΩ后立竿见影。I2C总线上挂多个从机时还有个先后顺序问题上电瞬间多个从机同时拉低总线容易造成总线锁定。我的做法是让传感器供电由MCU控制先让MCU初始化完I2C外设再统一给传感器上电避免竞争条件。4.3 远程CAN节点掉线和误码现象主控偶尔收不到某节点的温度帧或者解析出的温度突然跳到极值。排查经验先检查CAN总线终端电阻总线两端必须各有一个120Ω电阻少一个节点距离一远就反射严重。其次检查波特率和节点距离是否匹配。室内走线几十米内用250kbps通常没问题但HVAC现场有变频器时建议降到125kbps并开启CAN控制器的自动重发。如果只有某个节点掉线检查那个节点的电源和地线压差节点和主控之间地电位不相等最容易导致通信异常。我还遇到过一种隐蔽情况某个节点对外的金属外壳和大地之间形成了地环路导致收发器共模电压超限。解决方法是节点供电隔离或者把CAN收发器换成带电气隔离的模块。这个经验在改造老设备时特别常见老设备的接线端子经常没有预留隔离位置。4.4 标定补偿与长期稳定性问题实际项目中我们遇到的另一个坑是温度标定。PJ85718DM标称精度有界限但装配到控制器箱子内部后受主板热量影响读数会比真实环境温度高2~3℃。解决方案是做一次出厂两点标定把探头放在恒温槽里0℃和50℃各记录一次偏差把偏移量和增益系数写进Flash运行时自动修正。长期稳定性方面传感器老化会在两三年后体现出来。HVAC项目通常要跑十年以上我的建议是控制器程序里保留定期自检功能比如每个季度自动对比本地传感器和远程节点传感器的读数如果某个节点偏差持续超过阈值上位机会标记该节点需要检修。用这套方法我们的系统已经提前发现过两个需要更换的传感器避免了夏季高峰期设备误动作。故障表现排查方向常用解决手段本地温度跳变电源纹波、地参考、换算符号加磁珠/电容检查符号位I2C超时上拉电阻、地址冲突、总线竞争换4.7kΩ上拉错开供电时序远程节点偶发掉线终端电阻、波特率、地环路双端120Ω降波特率加隔离读数整体偏高内部发热、装配位置出厂两点标定软件补偿读数整体偏低探头接触不良、探头未露出检查探头安装导热硅脂填充5. 实测体会与后续扩展方向5.1 实测结果与个人体验整个系统调试完跑到现在的感受是PJ85718DM在HVAC工况且传感器供电干净的前提下读数稳定性还是令人满意的。本地通道温度波动控制在±0.3℃以内远程节点在有屏蔽双绞线和终端电阻的CAN链路上误码率低到可以忽略。设备连续通电运行了一个月还没有出现过一次因干扰导致的误报警。这里要特别提一句防守心得硬件的每个“小细节”都别省。比如ALERT上拉电阻、I2C线上那个10pF滤波电容、CAN终端电阻单看都是几毛钱的东西但合在一起决定了整个系统在恶劣环境下的生存能力。我们曾为了省一个终端电阻导致一个节点频繁掉线排查了一个星期才找到原因这个教训至今记忆犹新。温度监测系统看起来简单做得稳不稳全看这些不起眼的细节是否到位。5.2 后续扩展方向这套架构如果要往上走我建议往这几个方向扩展。一是远程节点升级为支持多通道的传感器板一块节点带两路PJ85718DM分别测风管出风和室内温度节点MCU的成本几乎不变但采集点密度翻倍。二是把CAN总线改成无线LoRa方案用于无布线的改造场景LoRa的穿透力在楼宇里表现不错但要注意数据延迟比CAN高不少适合做巡检用途而非实时保护。三是把温度数据直接推到上位机或云端做成集中监控大屏这时候STM32F107VC的以太网MAC就能派上用场了直接做TCP上报不用额外挂协议转换模块。还有一个我正在尝试的方向把每个节点的温度数据在本地做一段时序存储记录最近24小时的温度曲线。这样主控如果离线一段时间节点恢复通信后能补传历史数据对故障复盘非常有帮助。只要节点端MCU留出足够Flash或者外接一个小容量SPI Flash这个功能实现起来并不复杂。最后再分享一个小经验HVAC这种长期通电的工业类应用传感器和MCU之间的所有通信都要做成周期心跳式的不要做成事件触发式。温度变化触发上报听着很美但一旦传感器异常整个系统就变成静默故障周期上报虽然流量大一点但主控可以很快发现节点消失并报警。把每个节点的“上次在线时间”记录好节点超过三个周期没上报就直接在界面上标红维护人员一眼就能定位问题节点。这套设计思路值得所有做温度监测的朋友参考。
阅读完成 · 觉得有帮助?