做HVAC控制系统的同行,应该都遇到过这种尴尬:面板上显示的温度数据挺正常,可现场就是忽冷忽热,一排查发现是传感器装错了位置,或者单路测温点根本覆盖不了整个风道的真实状态。我后来在相关项目里把测温方案拆成两路——本地放一颗PJ85718DM盯着板卡自身环境,远端风道口再挂一颗同型号传感器,统一交给STM32F405ZG收数据。这一改,控制逻辑和故障诊断都顺了很多。
这篇就是把这条技术路线完整梳理一遍,从硬件布局、I2C通信、数据融合到现场调试的坑,适合正在做HVAC控制器、嵌入式设备监控或边缘网关测温功能的开发者。哪怕你没用过这两颗芯片,读完至少能知道数字温度传感器项目里哪些环节最容易翻车。
1. HVAC项目里为什么要同时盯住"本地"和"远程"两个温度点
1.1 回风、送风和盘管:HVAC控制最缺不了的就是温度反馈
HVAC系统说起来是调节空气温湿度,本质上是在跟热惯性和空间分布做博弈。一台空气处理机组里,需要测的地方不止一处:回风温度反映房间平均状态,送风温度决定末端出风的舒适度,盘管进出风温差则能判断换热效率。传统的做法是用NTC热敏电阻加调理电路,一个点一个点地采,但NTC的B值一致性、长线电阻压降、自热误差都需要额外补偿,批量生产时校准很费劲。
用数字传感器之后情况会好很多。PJ85718DM这种带I2C接口的芯片直接把模拟前端集成进去了,MCU侧只要按寄存器读数据就行,省掉了运放、分压电阻和标定表。更关键的是,多颗传感器可以挂在同一条I2C总线上,通过地址引脚区分。这意味着"本地+远程"的架构不需要多占MCU的ADC通道,总线上挂两颗芯片,代码逻辑几乎一模一样,只是寄存器地址不同。
1.2 "本地温度"管理的其实是电路板自己的命
很多人一提温度监测,第一反应是测环境温度,却忽略了控制器自身也在发热。STM32F405ZG跑在168MHz,旁边还有开关电源、继电器驱动芯片、通讯模块,柜内温度常年比环境高好几度。如果只想着测远端风管,板子上热得过了头没人知道,轻则数据漂移,重则电解电容鼓包、焊点加速老化。
本地测温点的价值就在这里:它是板载健康监测的核心输入。我的做法是把一颗PJ85718DM放在PCB上远离发热源的边缘区域,让它尽可能反映气流经过板卡后的真实温度,而不是贴在某个稳压器旁边测局部热点。这样得到的本地温度既能用来做超温保护,还能间接判断柜内散热风扇是否失效。
1.3 单点测温的天然盲区——空间温差与热滞后
只测一个点的最大问题是"管中窥豹"。HVAC现场里,风管入口和出口温差能到十几度,冷凝器附近和回风口更是天差地别。单颗传感器如果装在控制板上,它感受到的其实是机柜内微环境温度,和末端用户实际体验到的温度可能有明显偏差,控制算法再精致也白搭。
另一个容易被忽略的因素是热滞后。传感器本身有热容,响应快慢取决于封装和接触方式;而风道内气流又不断变化,紧贴风管壁测出来的温度和气流中心温度也有差异。多点测温可以从空间维度把这种滞后和梯度暴露出来:两侧读数同时缓慢变化属于正常工况,单侧跳变则说明问题出在对应区域。
1.4 两个测温点怎么分工:控制靠远端,健康监测靠本地
在整套逻辑里,我的分工很明确:远端PJ85718DM的读数作为冷冻阀、加热器、风机变频的反馈量,参与PID调节;本地PJ85718DM的读数负责设备保护和故障预警。远端关注的是"用户感受",本地关注的是"硬件安全",两者互补但不混用。这样设计的好处是控制环路的调节目标稳定,不会因为PCB温度起伏产生误动作;本地温度即使参与判断,也只在超温或温差异常时才发挥作用。
2. 传感器布局与硬件联调:PJ85718DM放在哪、STM32F405ZG怎么接
2.1 PJ85718DM适合做这件事的参数底气
大部分I2C温度传感器芯片的参数集中在几个维度:测量范围、精度、分辨率、转换时间、功耗、报警输出。PJ85718DM在这个项目里能扛住本地和远程两个角色,主要靠的是它±0.2°C的典型精度和16位温度寄存器,0.0625°C的LSB足够分辨HVAC工况里的细小温差。测温范围覆盖-40°C到+125°C,冷库场景和机房高温环境都能容纳。
转换时间也值得注意。某些高精度芯片转换一次要几百毫秒,在控制环路里会显得迟钝;PJ85718DM默认的转换时间大约几十毫秒,配合STM32的DMA批量读取,双通道刷新频率可以做到每秒十次以上,足够PID使用。芯片还带一个可编程的报警输出引脚,可以在硬件层面做超温中断,不占用MCU轮询资源。
2.2 本地传感器的布局禁忌:别把测温点的热量拱手让给开关管
PCB布局是我吃过大亏的地方。第一版我把本地PJ85718DM放在板子角落,看起来避开了CPU,但旁边正好走过一路12V转5V的DC-DC电感,结果调试时发现本地读数总是比实际环境高4°C多,而且跟随负载波动。后来拿热成像仪扫了一圈,问题一目了然:电感附近的铜箔大面积铺铜,热量顺着地平面导到了传感器底下。
正确的做法是给本地传感器留出"热隔离区":周围不要铺大铜皮,传感器底面不要走电源平面,尽量靠近进风口或结构散热孔。如果板内空间实在紧张,可以把传感器立装,让测温面垂直对准气流方向,也能减少底板热传导的影响。还有一点,和功率器件之间至少留出3到5毫米空气距离,必要的时候在底层对应位置挖掉铜皮。
2.3 远程传感器线缆的走向、屏蔽与ESD保护
远程这颗PJ85718DM通常要离开主控板一段距离,少则几十厘米,多则几米。I2C是为板内通信设计的,长线传输最大的敌人是线缆电容和噪声耦合。我在项目里用了一米左右的四芯屏蔽线:电源、地、SCL、SDA各占一芯,屏蔽层在控制器端单端接地。为什么单端接地?因为两端都接会形成地环路,在HVAC这种有变频器的现场反而会引入更多干扰。
线缆末端加上基本的ESD保护是必须的。现场施工人员可能带电插拔,一颗SOT-23封装的TVS管,结电容越低越好,接到每根信号线上,对地钳位。我自己在传感器一侧还串了33Ω的阻尼电阻,和总线上拉电阻配合,能明显改善反射。
2.4 供电方案与I2C上拉电阻的取值思路
PJ85718DM是典型的低压芯片,3.3V供电就能跑,而且I2C电平可以直接兼容STM32F405ZG的IO。远程供电我单独走一路滤波后的3.3V,不在总线上共享给其他噪声源,传感器旁放100nF去耦电容,靠近电源引脚焊接。
上拉电阻的取值没有万能答案,要结合线缆长度和挂载数量。板内短走线我习惯用4.7kΩ,远程长线降到2.2kΩ,保证上升沿足够陡峭。实测下来,1米线缆、2.2k上拉、400kHz速率下,波形沿大约几百纳秒,还能接受。如果线缆超过两米,与其加大上拉电流,不如把速率降到100kHz,或者用总线缓冲器,强行拉高频率只会让波形恶化和EMI变差。
3. I2C总线上的时序与寄存器操作:从配置到稳定读数的完整代码
3.1 初始化参数:400kHz、7位地址和时钟延展的取舍
STM32F405ZG的硬件I2C资源很丰富,我用的是I2C1,引脚分配的PB6/PB7是默认位置。代码层面优先确保400kHz模式,因为两块传感器的量很小,宁可牺牲一点时钟余量也要拉高通信效率。如果现场线缆长、干扰又大,我会干脆降回100kHz,反正HVAC控制周期本来也不快。
#include "stm32f4xx_hal.h" I2C_HandleTypeDef hi2c1; void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 400000; /* 400kHz */ hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0x00; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } }这里特意把NoStretchMode关掉,允许传感器做时钟延展。有些低端芯片在ADC转换期间会拉低SCL让主机等待,如果关闭时钟延展,读到的可能是上一帧的旧数据,甚至在中间错位。
3.2 读取温度寄存器的字节序问题,以及符号扩展
PJ85718DM的温度寄存器是16位,高字节在前。要留意的是,温度有正负之分,低温时高字节最高位是符号位,直接把两个字节拼接成uint16_t再做除法,会出现很大的正数。正确做法是先声明int16_t,把两个字节按大端组装,让编译器保留符号,再除以256得到浮点温度。
float read_local_temp(void) { uint8_t reg_addr = 0x00; uint8_t buf[2]; if (HAL_I2C_Mem_Read(&hi2c1, PJ_LOCAL_ADDR << 1, reg_addr, I2C_MEMSIZE_8BIT, buf, 2, 100) != HAL_OK) { return NAN; } int16_t raw = (buf[0] << 8) | buf[1]; return raw / 256.0f; }注意HAL_I2C_Mem_Read的地址参数要左移一位,因为HAL库接收的是8位地址字节。这个细节我见过不少人踩坑,明明是同一颗芯片,读写结果却时好时坏,最后发现是7位地址和8位地址没对齐。
3.3 中值滤波加滑动平均:让读数不再乱跳
HVAC现场最不缺的就是干扰源:压缩机启停、风机变频、继电器开合。哪怕传感器本身抗干扰能力不错,读数偶发毛刺也避免不了。我在软件里做了两层处理:先取连续五次采样做中值滤波,剔除最大值和最小值;再跟滤波结果做一次带遗忘因子的滑动平均,α取0.3,兼顾响应速度和平滑度。
static float smooth_value(float new_sample, float prev_value) { return 0.7f * prev_value + 0.3f * new_sample; } float median5(float a[5]) { /* 这个函数做5个元素排序,取中间的 */ ... }滑动平均的α不要取得太大,否则对快速温升的响应太慢;也不要太小,不然滤不掉毛刺。0.3是我试了几组值之后比较稳的组合,实测远端温度读数从原来±1°C的跳动收敛到±0.2°C以内。
3.4 报警引脚与自检:掉线、断线和超温的硬件级拦截
PJ85718DM的报警输出引脚我看重的是它能在超温时直接拉低,接STM32的外部中断引脚后,即使主循环卡死也能触发保护。报警阈值通过配置寄存器写入,比如本地温度超过85°C就拉低报警信号。这里要小心的是报警模式可配置成比较输出和锁存输出,我用的是锁存模式,进入报警后必须软件读回状态寄存器才能解除,避免温度在阈值附近抖动导致继电器反复吸合。
线缆断掉之后的处理逻辑也定义的很明确:连续三次I2C通信超时,就认为远程传感器失联,此时不再使用该路温度参与控制,而是置一个故障标志,本地传感器继续工作,控制算法切到单点模式,同时通过Modbus报故障。
4. 两路温度的数据融合:温差算法比看单个数值更能发现问题
4.1 温差的概念:本地与远端的正常范围是多少
两颗传感器都读回来后,表面上只是多了几个浮点数,实际上要做的判断非常多。第一步是建立"正常温差带"。这个带跟产品形态有关:在我做的环境控制项目里,远端风道温度通常比本地低3到8°C,因为风道里吹的是经过处理的冷风,而控制板所在的机柜更暖和一些。
我会先在设备试运行阶段采集一天的温差数据,画出上下包络,把这个正常范围写进配置参数。之后运行过程中,每两秒计算一次本地温度和远端温度的差值,持续超出包络就触发诊断流程。这个思路的本质是把"绝对温度是否正常"这种模糊判断,转换成"相对温差是否异常"这种更敏感的判断。
4.2 用温差识别过滤网堵塞与风道短路
温差不仅能反映自身故障,还能反映被控对象的状态。举例说,远端传感器装在送风管道中端,当过滤网堵塞时,风量下降,换热效果变差,远端温度会向环境温度靠拢,和本地温度的差值变小;而风道短路的特征更隐蔽,送风还没送到末端就从短路路径回到回风口,远端温度出现不规则波动。依靠单个温度点很难区分这两种情况,但结合温差变化的趋势和速率,能比较有把握地给出告警提示。
这并不是什么高深算法,就是工程直觉加数据验证。我在现场用一台人为堵塞了过滤网的样机测试,温差确实从5°C左右慢慢缩小到1°C以内,而且伴随压缩机频繁启停。这个信号比单看温度绝对值的告警提前了十几分钟,对运维来说很有价值。
4.3 校准手段:冰点槽与水浴对比,以及软件补偿量的写入
数字温度传感器出厂精度虽然不错,但批量装配、焊接应力和电源噪声都可能引入偏差。批量校准的成本太高,我一般只做抽检和一次性的软件补偿。最省事的方法是把传感器放进冰水混合物里稳住,等读数不再变化后,记录偏差值。常压下冰水混合物的温度接近0°C,这是一个便宜又稳定的校准参考点。
PJ85718DM通常有温度偏移寄存器,把偏差值写入之后,芯片内部会对读数做修正,这样就不用在上位机层面额外加减偏移量了。实测中,一颗读数偏高0.3°C的传感器,校准之后偏差回到0.05°C以内,效果很明显。
4.4 远程传感器断线时的降级策略
前面提到通信超时三次才判失联,但失联后的控制策略同样重要。我的策略是:故障状态下,控制算法不再直接用远端温度,而是用本地温度加一个默认温差的经验值做估算,同时把调节力度改成偏低档,避免误判导致风机全速或强制制冷。这有点像自动驾驶里的"降级模式",宁可保守一点,也不要因为数据缺失做出危险动作。
交给运维端的告警信息要尽量清晰:哪一路传感器,最后一次有效温度是多少,失联了多久。这样现场检修时不用重新扫总线,直接带着可能的原因去查线缆接头就行。
5. 实测中的三个坑:示波器、自热和长线噪声
5.1 I2C走线超过半米后的波形畸变:上拉电阻与线缆电容
第一次把远程传感器接上线缆调试时,读到的温度一会儿正常一会儿全部变成0xFF,偶尔还拉着I2C总线卡死。示波器夹上SDA一看,上升沿软得像正弦波,幅值也没拉到3.3V。问题出在线缆分布电容太大,而4.7kΩ上拉电阻的驱动能力不够,充电时间常数过长。
解决办法很简单,把上拉电阻换成2.2kΩ,同时把通信速率从400kHz降到100kHz。再测波形,上升沿干净多了。经验是:线缆长度每增加一米,上拉电流就要相应加大,否则要么降速,要么加缓冲器,三选一总得走一条路。
5.2 本地传感器被主控发热"绑架":布局调整实测
这个坑在2.2节提过,这里补充一个实测数据。布局调整之前,本地传感器读数在整机满载时比环境温度高4.2°C;调整布局并挖掉底部铜皮后,同样工况下拉到了1.1°C。这1°C的差距在HVAC控制里可能只是微不足道的偏差,但对于超温保护阈值来说,可能就是正常工作和误报警的边界。
建议大家在硬件阶段就做一次热仿真,没有仿真工具就用热成像仪拍板子。我后来养成了习惯,每次板卡改版,先通电跑半小时,看板子哪里发黄,再决定传感器往哪里放。
5.3 交流环境下测温跳变:远程线缆的屏蔽与滤波
HVAC现场有变频器和大功率风机,我曾遇到一种奇特的干扰现象:远程传感器在风机低速运行时报数正常,一旦风机全速运转,读数开始跳变。后来发现是数据线屏蔽层在传感器侧也被接地了,地环路把风机噪声引入总线。把屏蔽层改成控制器端单端接地后,问题立刻消失。
如果传感器距离特别远,信号线上还要考虑共模电感。有一回客户现场线缆走了五米,怎么屏蔽都压不住,最后在控制器接口加了一个共模电感,加上串阻,才算消停。这类问题很难在实验室复现,最好一开始就按比较严酷的现场环境留设计余量。
5.4 一个周期性的怪现象:误判超温报警的调查过程
项目测试阶段出现过一次很有意思的故障:报警继电器每隔一小时就动作一次,但不是硬件问题,也不是真的超温。后来抓了I2C波形才发现,定时器触发的读取任务和Modbus通信任务在争抢I2C总线,偶尔会出现读取时序被拉长,报警引脚恰好在这种时候被误读成触发状态。
排查过程给了我很深的印象:问题不一定出在传感器本身,还要检查总线调度。最后我在驱动层加了一个互斥信号量,确保同一时刻只有一个任务能发起I2C访问,报警误触发的频率直接降为零。如果你的嵌入式系统里也挂了很多外设共享一条I2C总线,这个坑几乎肯定会遇到。
6. 从单板监测到HVAC系统联调:串口帧、Modbus与继电器的联动
6.1 串口输出温度帧的结构设计
调试阶段最需要的是能直观看到两颗传感器的工作状态。我给STM32F405ZG写了一个简单的调试串口输出,每秒发一帧ASCII文本:本地温度、远端温度、温差、报警状态。这在联调时非常管用,打开串口终端就能判断传感器有没有装反、是不是在合理工作区间。
正式交付时,文本帧换成了紧凑的二进制帧,帧头、长度、传感器地址、数据、CRC16校验一应俱全。格式简洁一点,上位机解析起来也轻松,不用依赖特定的调试工具。
typedef struct { uint8_t head; uint8_t len; uint8_t addr; float temp_local; float temp_remote; uint8_t flag; uint16_t crc; } temp_frame_t;6.2 Modbus RTU接入上位机的思路
大部分HVAC上位机或楼宇自控系统都认Modbus协议。把两路温度映射成保持寄存器是件很顺手的事:比如40001存本地温度乘以100的整数,40002存远端温度乘以100的整数,40003存温差。乘100是为了保留两位小数,PLC和组态软件处理起来也简单。
这里有一个实际建议:Modbus轮询周期不要设得太短。STM32F405ZG吞吐量完全不是瓶颈,但上位机带宽和现场的干扰要留余量,一般500ms轮询一次就绰绰有余了。寄存器加只读属性,防止现场误写。
6.3 间歇读取与低功耗模式的取舍
HVAC控制器往往常年上电,对功耗不是极度敏感,但也别把CPU用得太满。我的做法是主循环每500ms唤醒一次,每次连续读两帧温度数据做平均,其余时间让MCU进入WFI等待中断。这样处理器占用率很低,发热也小,本地传感器测出来的温度也更接近真实环境。
需要注意的是,进入低功耗模式之前要把I2C总线状态处理干净,否则某些传感器会在总线空闲后进入睡眠,下次唤醒时第一帧数据要丢弃,避免用了旧的寄存器缓存值。
6.4 后续扩展:无线传感器节点和云端上报的可能性
如果后面要把这套方案扩展到更多测点,PJ85718DM其实还能挂好几颗,只要地址线允许,一条I2C总线上就能组一个密集的温度阵列。换成无线方式时,我可以把其中一部分传感器节点改成LoRa或WiFi透传,STM32F405ZG这边仍然负责解析和上报,架构上是兼容的。
至于云端上报,无非是给STM32配一个网络模块,把温度帧封装之后推到MQTT broker,上位机或者手机App做可视化。硬件能力已经在那里了,难的是连接稳定性、断线补传和告警规则这些工程细节,这些又是一套新的话题了。
做温度监测的这几年,我最深的体会是:传感器选型、I2C调通、布局优化这些事做完,整个系统反而才刚刚开始。真正的价值藏在数据的融合方式里——两颗传感器之间那点温差,往往比单板的绝对温度更有说服力。如果你也正在做类似项目,希望这套"本地加远程"的思路能帮你少走几步弯路。下次遇到奇怪的温度读数,先别急着怀疑芯片,拿示波器量一量总线和热成像仪扫一扫板子,答案往往比想象的简单。