做嵌入式温度采集这几年,我最大的感受是:传感器本身通常不贵,真正花时间的是怎么把数据稳定地拿到手,再送到该去的地方。前阵子接手一个HVAC改造项目,现场要同时盯三路温度:压缩机回气管、新风机出风口和控制柜内部环境温度,中控室还要能实时看到曲线。我用了手头现有的PJ85718DM数字温度传感器和STM32F767ZG主控,把本地采集和远程上报这一整套链路跑通了。这篇文章就把这套方案的选型思路、硬件接线、固件实现、HVAC联动逻辑和现场踩坑记录写清楚,给同样在嵌入式和暖通场景里做温度监测的朋友做个参考。不管你是在做设备巡检、机房环境监控,还是给风机盘管做联动控制,这套组合都能直接抄作业。
1. 项目目标与整体架构
1.1 这个系统到底要解决什么问题
HVAC和嵌入式设备里的温度监测,看着简单,拆开以后其实有四个层面的需求。
第一是多点测量。一个机柜、一台空调外机、一条风管,往往需要同时看多个测点。回气管温度、出风口温度、环境温度,热力变化不同步,只测一个点很难判断设备是否健康。第二是精度和一致性。HVAC控制逻辑里,0.5摄氏度的误差就可能导致压缩机频繁启停或者除霜误动作,所以传感器之间的读数差异不能太大。第三是本地实时响应。温度突变时需要及时联动继电器、风机或者报警器,不能等远程服务器处理完再动作。第四是远程可见性。现场无人值守,数据要能传到中控室或者云平台,否则测温系统就失去了监控价值。
这个项目围绕以上四点展开:本地用PJ85718DM挂在一条总线上实现多节点采集,主控用STM32F767ZG做数据处理和逻辑判断,远程通过以太网以MQTT协议把温度数据推送到中控平台。整体架构并不复杂,但每个环节的选择背后都有明确的理由。
1.2 为什么是 PJ85718DM + STM32F767ZG
先说传感器。PJ85718DM是一颗数字温度传感器,单总线方式工作,支持一根数据线上并联多个芯片,每一颗都有独立序列号,可以逐个寻址读取。这一点在HVAC现场特别友好,因为现场走线空间有限,一根双绞线串下去就能带十几个测点,比每个点都拉独立模拟量线省太多功夫。
它的测温范围和分辨率也够用:测温范围覆盖了HVAC常见的-20到100摄氏度区间,12位分辨率下的最小温度步进是0.0625摄氏度,足以驱动滞回控制和简单的风阀联动。而且数字传感器的优势是抗干扰能力强,温度值直接以数字方式输出,不像NTC热敏电阻那样需要长距离传输毫伏级模拟信号,线缆稍微长一点就会把噪声和温度误差混在一起。
再说主控。STM32F767ZG这颗芯片属于Cortex-M7内核,主频能跑到216MHz,带双精度浮点运算单元。做温度监测其实用不到这么强的算力,但它有两个硬件外设很关键:一是内置以太网MAC控制器,只需要外接一颗百兆PHY芯片就能接入局域网络,适合做远程数据上报;二是有丰富的高定时器和DMA通道,采集多点数据、控制继电器输出、刷新LCD屏幕都可以并行推进,不会因为某个环节阻塞导致温度轮询卡顿。M7核心在后期如果要叠加更复杂的能效分析算法,也不会显得吃力。从产品迭代的角度看,选择F767算是一种超前冗余,短期用不满,长期不用换平台。
1.3 数据流与模块划分
整套系统的数据流可以分成三段来描述。第一段是传感器网络:PJ85718DM按设定周期完成温度转换,主控通过单总线协议依次读取每个节点的数据,存放在结构体数组中。第二段是本地处理:主控对原始温度做滤波、校准、越限判断,并根据设定值控制继电器输出,驱动风机、加热器或者电动阀。第三段是远程上报:主控把所有测点的温度打包成JSON报文,通过MQTT发布到内网Broker,中控室的上位机订阅对应主题后实时刷新图表,同时存档供后续分析。
这种分段设计的最大好处是各模块耦合度低。测温逻辑不依赖网络状态,网络断开时本地控制依然正常工作,数据也不会丢失;远程链路只是把结果转发出去,不会反向干扰采集流程。实际运行中即使断网半小时,重新连上后上报补传数据即可,HVAC系统的安全底线不受影响。
2. 硬件准备与接线设计
2.1 PJ85718DM 的关键特性与引脚定义
PJ85718DM 的引脚排列相当简洁,实际用到的只有电源正、地、数据线和可选的地址配置线。供电范围是3.0V到5.5V,数据线是开漏输出,所以必须外接上拉电阻。芯片内置EEPROM用来保存用户配置,比如报警阈值和分辨率设置,断电后配置不丢失。这一点在批量布点的时候很有用,可以在出厂前把每一个传感器的报警阈值写死,现场安装完直接使用,不需要主控在每次上电时重新下发配置。
我这里拿到的样片手册显示,它的12位分辨率对应的温度转换时间典型值为750毫秒。如果系统里挂了8个节点,一轮转换时间就是6秒左右,对HVAC这种温度变化平缓的场景完全够用。如果某些测点需要更快刷新,可以把分辨率降到9位,转换时间会缩短到原来的四分之一,但温度步进也会相应变大。
需要注意的是,单总线的器件虽然允许挂在同一条数据线上,但每条总线的寄生电容总和限制了挂接数量。按照手册建议,线缆长度50米以内、并联节点数不超过10个是稳妥区间。如果现场确实需要更长距离或者更多节点,宁可分成两路总线分别接在不同GPIO口上,也不要硬把20个设备塞进一条线。否则信号边沿变缓,通信很容易偶发失败。
2.2 STM32F767ZG 引脚分配与外设选择
我给STM32F767ZG做引脚规划时,主要考虑的是后续可扩展性,而不是刚好够用就行。单总线数据线接在PD1上,配置成开漏输出模式,并外接4.7k欧姆上拉电阻到3.3V。以太网部分是用内置MAC加外部PHY实现RMII接口,占用一组固定引脚,这部分需要查阅芯片数据手册的引脚复用表仔细核对,因为不同封装和不同PHY芯片的接线方式会有差异。
继电器控制输出放在PB0到PB3,全部通过光耦隔离后驱动中间继电器,避免感性负载关断时的反向电动势打坏主芯片。另外留了两路RS485接口,一路接现场触摸屏,一路作为备份通信口,万一以太网链路挂了,中控室还可以通过Modbus RTU读到温度数据。这样虽然增加了几十块钱硬件成本,但给了现场调试极大的灵活性。
电源设计上,主控板和传感器总线分开供电。主控板用5V输入,经过DC-DC得到5V给继电器线圈和传感器总线,再通过LDO降到3.3V给MCU和PHY。传感器总线单独供电的好处是,即使主控3.3V部分因为某些原因跌落,传感器端的转换仍然可以保持正常,便于排查问题。
2.3 单总线网络的硬件设计要点
单总线网络看起来就一根数据线,但细节都在外围电路上。上拉电阻的取值很关键,我用4.7k欧姆是常规值,如果线缆较长,可以换成1.5k欧姆以增强驱动能力。不过阻值不能太小,否则在低电平时数据线灌入电流过大,可能超过传感器端口允许值。
每个传感器的电源引脚旁边要放一个100nF的去耦电容,并且电容尽量靠近传感器管脚。对于HVAC环境,传感器可能会靠近电机或者变频器安装,空间里电磁干扰比较严重,我会在数据线上串一个100欧姆的小电阻,并对地接一个肖特基二极管做静电防护。这些措施看起来不起眼,却能省掉后期大量排查随机通信错误的时间。
在总线末端,我习惯加上一个5.6k欧姆的终端匹配电阻到地。这不是规范强制要求,但在总线较长、节点较多时,匹配电阻能明显改善波形过冲。调试时如果通信不稳定,可以先用示波器看数据线波形,过冲大就加终端电阻,边沿缓就调小上拉电阻,这是最有效的两个旋钮。
2.4 远程通信硬件选型
远程上报我选用了STM32F767ZG内置以太网MAC加外置百兆PHY的方案。之所以没有用WiFi模块,一方面是因为暖通机房中钢结构多、墙体厚,无线信号衰减严重;另一方面是有线网络天然稳定,不会出现信道拥挤导致的延迟抖动。HVAC设备通常部署在楼宇弱电间附近,拉一根网线比在夹层里调WiFi信号靠谱得多。
如果现场连网线也不方便,替代方案是用4G DTU模块,通过串口转4G把MQTT数据送到云端服务器。这种方案的好处是部署灵活,但需要考虑流量费用和数据延迟,目前在一些热力站项目里也能看到。无论哪种方式,STM32F767ZG的串口资源足够富余,应用层协议可以保持一致,只是底层传输通道不同而已。
3. 固件设计与核心逻辑实现
3.1 单总线底层驱动与 CRC 校验
单总线协议的关键在于时序,初始化复位脉冲、写0、写1、读时隙的时序要求都有严格的时间窗口。我在实现时直接用HAL库的微秒延时函数配合GPIO翻转,保证每个时隙都在规定范围内。这里有个容易踩的坑:HAL_Delay只能毫秒级延时,不能用于微秒级时序,必须用DWT计数器或者定时器来做微秒延时。
读取温度和配置信息时,芯片会返回一段包含CRC校验码的数据。CRC校验务必做,别省。现场一根总线几十米,感应雷、变频器启停都可能让数据出现单比特错误,没有CRC的话一个错误字节就可能把温度从25度跳到80度,导致控制逻辑误动作。我用的CRC算法是针对单总线数据流的标准CRC-8,核心代码如下:
static uint8_t calc_crc(uint8_t *data, uint8_t len) { uint8_t crc = 0; while (len--) { crc ^= *data++; for (uint8_t i = 0; i < 8; i++) { if (crc & 0x01) { crc = (crc >> 1) ^ 0x8C; } else { crc >>= 1; } } } return crc; }每条PJ85718DM芯片都有一个64位序列号,其中最后一个字节也是CRC,所以总线搜索时先读序列号再用CRC校验,可以排除掉一半因接线错误导致的假设备。实际调试中,CRC校验不通过时我会先用示波器看波形,而不是改代码加延时,因为大多数时候问题出在硬件参数上。
3.2 多节点轮询与任务调度
有了底层驱动,下一步就是构建多节点管理逻辑。上电后主控先执行一次总线搜索,把所有在线的传感器序列号遍历出来,存入一个链表或者数组。每个节点记录序号、序列号、最新温度、上次读取时间、连续故障次数等信息。
正常的读取周期我设置为10秒循环一次。每次循环先发复位脉冲,然后发送匹配ROM指令,指定要读取的序列号,再发送温度转换命令。这里有个值得注意的优化:所有传感器可以同时触发转换,等所有节点都转换完成后再依次读温度,而不是一个一个来。具体做法是先广播转换命令,等待750毫秒到1秒,然后再逐点读取。这样一轮的总耗时从“节点数乘以转换时间”缩短为“转换时间加节点数乘以读取时间”,8个节点的轮询周期从6秒压到2秒左右,效果很明显。
任务调度我用一个简单的状态机来完成。整个系统状态分为传感器初始化、轮询采集、滤波处理、远程上报、控制输出五个阶段。每个阶段由SysTick产生10ms基准时基驱动状态切换,不会出现因为调用延时函数而让其他任务停滞的情况。这种轻量级调度比塞一个RTOS更适合这个场景,代码清晰,单片机资源占用也低。
3.3 温度滤波、校准与异常处理
现场温度数据的原始值直接拿来用是不够稳妥的。HVAC设备启动时,压缩机回气管温度可能因为电磁干扰瞬间跳变一下。所以我用了两级处理:先做滑动中值滤波,再做递推平均。
滑动中值滤波的做法是取最近五次的温度值,去掉最大值和最小值,剩下三个取平均。这样对付偶发性的尖峰干扰效果很好,而递推平均则用来抑制低频波动,让控制逻辑读取的温度曲线更平滑。但这种滤波会带来响应滞后,所以我的控制输出判断使用的是一级滤波后的即时数据,而不是多级滤波后的平滑数据。简单说就是:给人看的曲线可以平滑,给控制逻辑用的数据尽量保持快速响应。
校准方面,由于PJ85718DM的出厂精度在生产时已校准过,通常不需要逐点校准。但同一批次多颗传感器放在同一恒温环境下,读数也可能相差0.2摄氏度左右。如果控制逻辑对多路温度一致性要求高,我建议在恒温箱里做一个两点校准,把每颗传感器的偏差系数存入EEPROM,主控读取后做线性修正。两点校准选0度和50度两个校准点,出来的线性度足够应对HVAC场景。
异常处理也必须考虑:当某个传感器连续读取失败超过三次,我会把它标记为离线,同时用上一次的有效温度作为控制依据,而不是使用一个错误值。这样即使中途传感器损坏,也不会导致现场冷机或者热机失控。每出现一次读取失败,都会累加故障计数,并在远程报文里带上告警字段,让运维人员提前介入。
3.4 远程上报协议设计与 MQTT 实现
远程上报的协议选型我最终用了MQTT,原因很简单:HVAC现场的数据量不大,但需要频繁更新,MQTT的发布订阅模型非常契合这种模式。主控作为客户端连接内网MQTT Broker,温度数据以主题的形式发布,中控室上位机订阅对应主题,就能实时收到数据。
STM32F767ZG的以太网协议栈我移植了轻量级LWIP,物联网框架选了一个适合MCU的MQTT客户端库,连接参数配置成自动重连模式。每次上报的报文设计得比较紧凑,格式如下:
{ "device": "hvac-2f-unit01", "ts": 1712345678, "points": [ {"id": 1, "temp": 23.4}, {"id": 2, "temp": 55.1}, {"id": 3, "temp": 31.2} ], "alarm": 0 }这里的ts使用的是Unix时间戳。为了保持时间同步,我通过SNTP协议从NTP服务器获取时间,每6小时同步一次。时间戳的意义在于中控端可以做历史数据归档和趋势回溯,如果没有统一时间轴,多个设备的数据对比就会乱套。
断线重连的逻辑也值得提一下。MQTT断线后,不要立即重连,而是采用退避策略:第一次等待3秒,第二次10秒,第三次30秒,最多等待5分钟。这样避免了多台设备同时断线后同时重连造成Broker瞬间拥堵。数据上报失败时,温度数据会先缓存在主控的RAM环形缓冲区里,能存大约200条记录,重新连上后按时间顺序补发。对于HVAC来说,200条记录足够覆盖极端断网情况下的数据补传需求。
4. HVAC 场景中的控制联动逻辑
4.1 HVAC 系统的测温特点与精度要求
HVAC系统测温,跟普通消费电子测温有显著区别。首先是温度变化速率差异大:新风管道里的温度变化缓慢,但压缩机排气管的温度在启停瞬间能在一分钟内波动几十度。其次是测温点与执行机构的相对位置关系会影响控制策略:如果传感器紧邻加热器,反馈速度太快容易导致振荡;如果传感器安装在回风口,反馈滞后又可能让温度过冲。
我一般把测点分成三类:控制用测点、保护用测点和监测用测点。控制用测点负责参与温度闭环控制,比如房间温度传感器;保护用测点用于超温告警和紧急停机,比如压缩机排气管;监测用测点只做记录和故障诊断,比如设备运行环境温度。三类测点在软件里处理方式完全不同,保护用测点要求最快响应,不做滤波;控制用测点适度滤波;监测用测点可以深度平滑。PJ85718DM的0.0625摄氏度分辨率应对这些场景富余量很大。
4.2 滞回控制与 PID 控温的取舍
HVAC控制最常见的是滞回控制,也就是常说的回差控制。设定目标温度25度,上下回差各0.5度,温度低于24.5度启动加热,高于25.5度停止加热。这种方式实现简单,避免了继电器在目标温度附近频繁吸合,实际项目中最常用。
我在STM32F767ZG里实现的控制代码如下:
#define SETPOINT_TEMP 25.0f #define HYSTERESIS 0.5f if (temp_c < (SETPOINT_TEMP - HYSTERESIS)) { heater_on(); } else if (temp_c > (SETPOINT_TEMP + HYSTERESIS)) { heater_off(); }这套逻辑看着简单,但有两点必须注意。一是不同区域的回差不能一样,风盘型空调送风温度控制回差可以放到1度,热水供暖回差0.3度左右更合适。二是温度采集周期要和控制周期解耦,我让温度每10秒采集一轮,但控制判断每500毫秒执行一次,用最新缓存温度做判断。这样执行机构动作及时,又不会因为温度更新过快导致误判。
如果项目要求更高的控温精度,可以升级为PID控制。STM32F767ZG自带的FPU让PID计算非常轻松,但PID参数整定在HVAC场景里往往比写代码更耗时。我的经验是:优先用滞回控制满足绝大多数需求,只有在客户明确要求±0.2度以内控温时才上PID,而且要把积分限幅和输出限幅都提前设好,防止积分饱和导致大幅过冲。
4.3 多区域优先级的经验做法
一台HVAC控制器带多个区域时,不同区域的优先级往往是设计难点。电梯厅和大厅共用一台冷水机组,但大厅的人流量和温度变化频率完全不同。处理办法是在软件里给每个区域分配一个优先级权重,并且定义优先级切换条件。
我的项目里用了一个直接可落地的策略:当任意区域温度超过保护值,比如48度时,系统进入紧急制冷模式,所有阀门全开;否则按照各区域温度偏离目标值的大小来动态分配阀门开度。偏离量最大的区域优先满足,偏离较小的区域等偏差收敛后再调节。这个策略通过一段有限状态机实现,不需要特别复杂的算法,但要在代码里预留充足的上下限位值,防止区域阀门频繁摆动。
多区域联动的另一个细节是传感器故障降级。某个区域传感器离线时,保护逻辑必须自动把该区域视为高优先级并执行安全动作。看起来反直觉,但现场设备的安全性优先于舒适性。一旦传感器恢复,系统再退出降级模式。
5. 实测数据与运行效果
5.1 现场测试环境与部署方式
测试在客户机房一个典型的HVAC控制柜进行。三个PJ85718DM传感器分别部署在冷媒管回气管表面、新风管道内部和控制柜内部空间。传感器的数据线走的是屏蔽双绞线,屏蔽层在控制柜侧单端接地。STM32F767ZG主控放在控制柜顶层,通过网线连接到内网交换机。
测试持续了72小时,期间人为制造了几种边界条件:断电重启、拔掉传感器线、断开网线、触发一次压缩机强制启停。记录数据包括本地控制动作、远程报文接收率、传感器故障恢复时间等。
5.2 本地读数与参考仪表对比
为了验证PJ85718DM的准确性,我在同一测点旁边放置了一台工业级参考测温仪,精度等级0.1度,每5秒记录一次。对比结果让人满意:三个测点的稳态误差都在正负0.2摄氏度以内,动态响应过程中最大偏差出现在压缩机排气管升温阶段,实测偏差约0.4摄氏度,主要原因是参考仪表探头响应速度更快,传感器本身的热时间常数起了一定的延迟作用。
这个结果表明,PJ85718DM作为闭环控制用传感器没有问题,但保护用温度测点如果允许冗余设计,最好在关键管路上同时装一个模拟量传感器作为备份,避免单点故障。
5.3 远程链路的稳定性表现
72小时里,MQTT连接保持了稳定在线,只出现过两次短暂断线,一次是内网交换机固件自动重启,另一次是监控人员误插了网线。两次断线重连时间分别用了7秒和40秒,补发数据经核对没有缺失。
运行参数汇总如下:
| 项目 | 实测结果 |
|---|---|
| 温度上报周期 | 10秒 |
| MQTT在线时长 | 71小时31分钟 |
| 断线次数 | 2次 |
| 报文平均延迟 | 180毫秒 |
| 补发数据缺失 | 0条 |
| 传感器离线恢复时间 | 最快3秒 |
这里需要说明的是,报文平均延迟180毫秒包含内网交换机和Broker处理时间,实际主控到Broker的物理链路耗时只有十几毫秒。如果接公网服务器,延迟还会上升,但只要不超过3秒,对HVAC监测场景都可接受。
6. 常见问题与排查技巧实录
6.1 传感器读到固定值或者 CRC 校验反复失败
这个现象八成不是芯片坏了,而是电气层面有问题。先量数据线电压是否在正常范围,再确认上拉电阻和供电是否正常。单总线对时序很敏感,SPI或I2C设备挂在同一排插针上时,引脚电平变化可能影响总线,排查时可以把其他外设暂时断开,只看单总线波形。
还有一种情况是新买的PJ85718DM不是全新出厂状态,EEPROM里残留了未知配置。遇到CRC反复失败,先对所有传感器执行一次复位命令,再重新读取。如果复位后CRC仍然失败,大概率是传感器已损坏或者焊接不良,可以换一颗新芯片测试。
6.2 某一路传感器长时间无响应,其他路正常
这种问题属于单点故障,先检查该传感器和总线的物理连接,特别是中间有端子排的地方,氧化和接触不良是最常见原因。如果接线没问题,再检查这一颗传感器是否被错误设置了地址。部分PJ85718DM芯片允许通过外部地址引脚修改总线地址,地址冲突时会出现搜索不到、读取超时等现象。
从软件排查角度,可以在总线上只挂这一颗传感器执行单点搜索,看是否正常。如果单点能搜到,说明是地址碰撞;如果连搜都搜不到,硬件问题概率更大。这一招能快速缩小排查范围。
6.3 温度值偶尔跳变,波动幅度很大
跳变一般来自干扰,第一步做滤波脚够用,但要从源头想清楚干扰哪里来。HVAC现场的感性负载启停会产生几十伏的瞬态电压,如果传感器数据线和动力线平行走线超过2米,感应电压足以干扰信号电平。对策是把传感器线和动力线分开走管,并且采用屏蔽双绞线。
软件层面,我给温度数据加了一级惯性限幅:相邻两轮温度差值超过5度时,本轮数据先舍弃,重新读取一次确认。这个逻辑配合中值滤波基本能杜绝跳变进入控制算法。要注意限幅阈值不能设置得太小,否则真实温度突变也会被错误滤除,比如压缩机排气管的温度快速上升场景就不适用较小的限幅值。
6.4 远程上报断线后长时间无法重连
MQTT重连失败先看配置参数,服务器地址、端口、客户端ID、用户名密码是否都正确。最容易踩的坑是客户端ID冲突,两台设备用了同一个客户端ID,MQTT Broker会把后连接的那台设备判定为新会话,导致先连接的那台被踢下线。解决方法是客户端ID使用设备序列号或者MAC地址,保证全局唯一。
另一个容易忽略的问题是NAT超时。设备在内网通过路由器访问公网Broker时,TCP连接可能因为长时间无数据被路由器强制关闭。应对办法是让主控每30秒发送一次心跳包,同时配置MQTT的keepalive参数为60秒。这一个细节很多人容易忽略,但实际部署中最常见。
6.5 现场排查速查表
把上面几个经验整理成一个速查表,方便现场排查时直接对照:
| 故障现象 | 优先检查 | 次要检查 | 备用手段 |
|---|---|---|---|
| 全部传感器无响应 | 总线供电、上拉电阻 | 复位时序 | 示波器看波形 |
| 单个传感器无响应 | 接线端子接触 | 地址冲突 | 单点搜索 |
| CRC校验失败 | 通信波形边沿 | 线缆长度 | 更换短网线测试 |
| 温度跳变 | 动力线干扰 | 滤波逻辑 | 加屏蔽处理 |
| MQTT频繁掉线 | 网络配置 | 心跳参数 | 换有线直连 |
现场排查的时候,我习惯先动手后动脑。但这里的动手不是盲目换件,而是有顺序地测试:先看电源,再看波形,然后看软件日志。如果一上来就怀疑程序有问题,反而容易在错误方向上反复浪费时间。
7. 可扩展方向与个人体会
这个项目做到目前阶段,本地多点采集和远程上报已经稳定运行。如果项目再往下推进,我最想补的两个方向:一是把采集到的温度数据跟设备能耗数据做关联分析,通过温度变化速率和累计运行时间判断设备健康度,实现预测性维护;二是加入更灵活的用户交互界面,比如用一块7寸触摸屏显示所有测点温度曲线,支持直接设定区域温度目标值,替代现在需要连接电脑改参数的方式。这两个需求从硬件资源上看,STM32F767ZG都有足够的余量支撑,不需要更换主控平台。
最后分享一个之前踩过最深坑:单总线传感器在批量安装时,连接器的压接工艺千万不能省。我第一版项目因为贪图方便,用了普通杜邦线直接插接传感器,结果现场运行一周后出现好几个测点间歇性离线。后来全部改成螺丝端子压接,再加上线耳固定,故障率直接降到零。温度监测系统看起来技术门槛不高,但细节决定成败,大部分“神秘故障”最后都出在物理连接上。希望这套从选型到排障的完整记录,能帮你少走这些弯路。