在做一款针对智能楼宇和小型机房的 HVAC 控制器时,我碰到过一个很实际的问题:控制器本身要测回风温度,同时还要拉一根线到房间远端测送风温度,这两路数据直接决定压缩机和风机的启停逻辑。传感器选来选去,最后用了 PJ85718DM 配合 STM32L433RC 来做,整体方案做下来,稳定性和开发效率都超出预期。这篇博文会把整套思路从选型、硬件连接、软件驱动到低功耗调优完整整理出来,包括踩过的坑和调试记录,希望对做嵌入式和暖通控制的朋友有参考价值。
1. 项目思路与方案选型:为什么是“本地+远程”双通道监测
1.1 嵌入式和 HVAC 场景中的温度监测痛点
先说说为什么温度监测在 HVAC 领域这么讲究。空调控制器的核心逻辑其实不复杂:采集温度,和设定值比较,再决定输出。但难点在“采得准”和“采得稳”。
第一个痛点是精度。空调系统里,回风温度和送风温度的差值往往只有几摄氏度,如果传感器精度不够或者漂移大,控制逻辑就会反复震荡,压缩机频繁启停,既费电又不舒服。第二个痛点是布线。嵌入式控制器内部空间很小,但传感器可能要装在风道里、房间远端或者室外机附近,一条模拟线拉过去,线阻、干扰、压降都会影响读数。第三个痛点是功耗。很多 HVAC 从设备是电池供电或依靠极低功耗的休眠机制工作,比如温控面板、无线传感器节点,几个月甚至一年不换电池都是基本要求。
这些痛点叠加在一起,解决方案就很明确了:用数字接口的温度传感器,直接输出温度值,避免模拟链路的一切麻烦。这也是我在这个项目里选择 PJ85718DM 的主要原因。
1.2 器件选型:PJ85718DM 与 STM32L433RC 的组合逻辑
PJ85718DM 是一颗 I2C 接口的数字温度传感器,内部集成了温度传感元件、ADC 和数字接口,温度数据直接通过寄存器读出,不需要额外的信号调理电路。它支持多地址配置,一条 I2C 总线上可以挂多颗传感器,正好满足“本地一块、远程一块”的双通道需求。
主控这边选了 STM32L433RC,核心原因有三点。第一是功耗表现,这颗芯片的 STOP 模式功耗在微安级别,配合传感器休眠机制,整个节点的平均功耗可以压得很低。第二是内置 LCD 驱动,HVAC 面板几乎都要显示温度和状态,传统方案要外挂 LCD 驱动芯片,这颗片直接省掉了。第三是外设丰富,I2C、UART、ADC、比较器都有,后期如果想扩展 Modbus 通信或者 PWM 风机控制,不用换主控。
选型时我也对比过其他方案,比如直接用 NTC 热敏电阻加 ADC 采样,成本更低,但需要软件做查表和线性化,每个传感器还要校准,量产一致性不好。又比如用模拟输出的温度传感器,虽然接线简单,但长距离传输容易受干扰。综合来看,PJ85718DM 的数字输出、寄存器读取方式和多地址特性,和 STM32L433RC 的低功耗定位非常契合,这套组合确定下来后,硬件设计和软件架构都没有走弯路。
2. 硬件连接设计与底层驱动实现
2.1 PJ85718DM 的引脚连接与 I2C 总线配置
PJ85718DM 的引脚不多,核心就是电源、地、I2C 数据线、I2C 时钟线和地址配置引脚。我在实际画板时,把传感器放在两个位置:一个贴在主控板上,负责测本地环境温度;另一个做成小板,通过端子引脚拉线出去,放在风道或者房间远端。
电源上要特别注意,传感器的 VDD 可以接到 STM32L433RC 的 3.3V 上,但必须在传感器旁边放一个 0.1uF 的陶瓷去耦电容,如果小板拉线较长,还要加一个 10uF 的电解电容。数字传感器的供电纹波会影响内部 ADC 的参考基准,导致读数波动。
I2C 总线的上拉电阻也需要仔细选。STM32L433RC 的 I2C 引脚内部有弱上拉,但信号完整性不够,必须外部加上拉。我实测下来,I2C 速率 400kHz 时用 4.7k 欧姆上拉比较合适,如果线长超过 30cm,降到 100kHz 速率,上拉改成 2.2k 欧姆,这样信号沿更快,抗干扰能力也更好。一旦发现 SDA 波形边沿太缓,优先减小上拉的阻值。
地址配置这块要提前规划。PJ85718DM 的地址引脚可以接高电平、低电平或者悬空,组合出多个地址。我的做法是:本地传感器地址设为 0x48,远程传感器地址设为 0x49,代码里直接枚举,后续扩展第三路传感器,只需要再加一个地址。
2.2 STM32L433RC 的工程初始化与 I2C 驱动实现
软件这边我用的是 ST HAL 库,建工程时把 I2C1 外设、GPIO 和串口调试都配好。时钟树里注意给 I2C1 分配正确的时钟源,否则通信速率会偏。初始化 GPIO 时,I2C 的两个引脚要配置为开漏输出,加上拉,复用功能选 I2C。
温度读取的流程分四步:发设备地址、写寄存器指针、读两个字节的温度数据、换算成实际温度值。下面是核心代码片段,寄存器编号和换算公式基于常见 I2C 数字温度传感器的协议,具体型号以数据手册为准:
#define PJ85718DM_ADDR_LOCAL 0x48 #define PJ85718DM_ADDR_REMOTE 0x49 #define REG_TEMP_MSB 0x02 #define REG_TEMP_LSB 0x03 float read_temperature(uint8_t dev_addr) { uint8_t reg = REG_TEMP_MSB; uint8_t data[2] = {0, 0}; int16_t raw = 0; int16_t temp_signed = 0; float temperature = 0.0f; HAL_I2C_Master_Transmit(&hi2c1, (dev_addr << 1), ®, 1, 100); HAL_I2C_Master_Receive(&hi2c1, (dev_addr << 1), data, 2, 100); raw = (data[0] << 8) | data[1]; temp_signed = (int16_t)(raw & 0xFFF0) >> 4; temperature = temp_signed * 0.0625f; return temperature; }这里有个关键点:温度寄存器的高字节和低字节,有效数据只占高字节的全部和低字节的高 4 位,所以先把 16 位原始数据与 0xFFF0 做掩码,然后右移 4 位,得到一个 12 位的带符号整数,再乘以 0.0625 摄氏度步进,得到实际温度。这个步骤最容易出错,代码里掩码和移位顺序写反,读出来的温度就是乱的。
2.3 温度数据换算与精度分析
数字温度传感器输出的是二进制补码。举个例子,如果读到的原始数据是 0x01A0,高字节 0x01,低字节 0xA0,掩码后得到 0x01A0,右移 4 位得到 0x001A,也就是十进制的 26,乘以 0.0625,结果是 1.625 摄氏度。
零下温度的情况更要小心。如果寄存器读回 0xFFE0,掩码后还是 0xFFE0,右移 4 位得到 0x0FFE,但这个值是无符号的,必须先把 16 位数据按照有符号数解释。我习惯先定义成 int16_t,再右移,这样符号位会正确扩展。测试时用零下温度的风扇吹传感器,读出的负温度数值一定要验证一下。
精度方面,PJ85718DM 标称精度通常在正负 0.5 摄氏度以内,12 位分辨率对应 0.0625 摄氏度的量化步进。实际使用中,传感器的自热效应比 ADC 本身的误差更明显。传感器通电后自身会有微弱发热,如果贴在大功率器件附近,读数会偏高。我在布局时让本地传感器离电源芯片和 MCU 保持 10mm 以上,必要时在传感器底部挖一个断开的铺铜岛,只保留 GND 连接,这样测出来的温度更接近真实空气温度。
3. 本地与远程测温的完整实现路径
3.1 本地温度采集:板级环境监测与热管理
本地温度传感器的用途有两个:一个是监测 HVAC 控制器所在环境的空气温度,直接参与控制逻辑;另一个是监测主控板附近的温度,防止局部过热。这两个目标对传感器摆放位置的要求是冲突的,前者要求传感器尽量暴露在空气中,后者要求传感器靠近热源。我的处理方式是折中:本地传感器放在板子边缘、通风孔附近,尽量不靠近 MCU 和功率 MOS,这样测到的温度更接近环境温度,同时也能在板级温度过高时给出预警。
数据读取频率上,HVAC 应用不需要像电机控制那样高速采样,温度变化本身是慢变量。我最初写的是 100ms 读一次,后来发现 CPU 频繁唤醒回头读取数据,反而增加不必要的功耗。最终调整为 1 秒读一次,控制周期完全跟得上。如果后续要做 PID 温控,可以把这个周期缩小到 200ms,但也要配合温度滤波算法,否则采样噪声会直接传进 PID 输出。
3.2 远程温度接入:长线传输与多节点架构
远程传感器是这套方案里最容易出问题的部分。我的第一版设计直接拿 I2C 线拉了两米,结果数据偶发错误,温度读数偶尔跳到 80 度。排查后发现是线缆的分布电容太大,加上没有屏蔽,环境里的干扰脉冲直接耦合进了 SDA 线。
后面我调整了远程传输策略:距离在 3 米以内时,用屏蔽双绞线连接传感器小板,I2C 速率降到 100kHz,STM32 的 I2C 引脚配置为开漏输出,上拉电阻改为 2.2k,加了 TVS 管和串联 100 欧姆电阻,实测基本稳定。距离在 10 米以上时,不再直接跑 I2C,而是把每个远程传感器接到一个小 MCU 上,小 MCU 通过 RS485 总线及 Modbus 协议和主控通信。STM32L433RC 只需配一个 USART 接口,加一个 RS485 收发器,就能挂载多个远程节点,每个节点有独立的 Modbus 地址,抗干扰能力也更强。
两种方案的数据处理方式不一样。I2C 直连方案是主控主动拉数据,代码简单;RS485 方案则需要实现一个简单的主从轮询机制,主控定时发送读温帧,从站回传温度值。从站代码的要点是地址匹配和 CRC 校验,温度数据本身只有两位字节,但 CRC 校验必须做,HVAC 环境里电机启停会产生强干扰,没有 CRC 的通信链路一旦错一个字节,控制逻辑就乱了。
3.3 数据融合与 HVAC 联动控制策略
两路温度数据读回来后,不能直接拿来当成一回事。我最终确定的三级控制策略是这样的。
第一级是温差判断。空调控制的核心不是单点绝对温度,而是回风温度与设定点的差值,以及送风温度与回风温度的差值。送风温度比回风温度低很多,说明制冷正常;反之则可能缺冷媒或者风机故障。这个逻辑用本地传感器测回风,远程传感器测送风,非常合适。
第二级是滤波处理。远程传感器受电机干扰时会产生瞬间跳变,我做了限幅滤波和滑动平均的二级处理。具体是在软件里保存最近 5 次采样值,若某次采样和前一次的差值超过 2 摄氏度,则判定为异常值丢弃,再用二次滑动平均滤波输出。这样处理之后,即使远程线上有一个强干扰脉冲,系统也不需要掉电复位。
第三级是告警与备份。本地传感器和远程传感器的正常工作范围是 -10 到 70 摄氏度,超过范围读取值直接按 0 度处理,并置位对应的故障标志位。本地传感器掉线时,控制逻辑自动切换到远程传感器单点工作模式,保证空调系统不停机,只报警提示维修。这套容错逻辑在实际运行中帮了不少忙,远程传感器因接线松动掉线时,空调没有全停,只是降低输出维持运转。
4. 低功耗策略与系统稳定性的工程化改造
4.1 低功耗模式选择与定时采样调度
STM32L433RC 进入低功耗之前,要把不需要的外设时钟全部关闭。I2C 外设在唤醒采样期间打开,采样完成立刻关闭。温度传感器的功耗相对固定,主控的低功耗状态决定整个节点的平均功耗。
我在项目中把主控设置为 STOP2 模式,用 RTC 定时唤醒。采样周期 3 秒,每次唤醒后读两路温度,更新 LCD 显示和控制输出,整个过程大约 30ms,然后重新进入 STOP2。实测功耗可以这样估算:
平均电流 = (30ms * 采集工作电流 + 2970ms * 停止模式电流) / 3000ms假设采集工作电流 6mA,STOP2 模式电流 2uA,那么平均电流大概是 (0.036 + 2.970.002)/3 = 0.062mA。一块 1000mAh 的电池可以跑接近一年半,如果采样周期拉长到 10 秒,功耗还能更低。
这里有个容易被忽视的细节:I2C 总线上的上拉电阻在 STOP2 模式下一直挂着,如果主控的 I2C 引脚内部上拉没有关闭,外部上拉电阻就会持续消耗电流。我在原理图上给远程传感器的上拉电阻加了一个 MOS 管控制的电源切换,只在采样时给传感器和上拉供电,休眠时彻底断电。这个改动把待机电流又降了 1mA 级别,非常值得做。
4.2 数据稳定性与防火防错设计
数字温度传感器虽然比模拟方案抗干扰,但不代表可以完全不做保护。我在远程传感器接口的输入端加了 ESD 防护管和串联电阻,防的是楼宇施工时有人带电插拔端子。
软件层面还有一个必须做的事:I2C 总线死锁恢复机制。I2C 协议里如果从机正在发送数据时主机复位,SDA 线可能被从机拉死,导致后续通信全部失败。处理办法是在每次 I2C 通信前,先把 SCL 引脚切换为普通 GPIO 输出模式,手动拨动 9 个时钟周期,释放可能被拉死的总线,然后再重新初始化 I2C。这个逻辑放在定时器中断里,每 100ms 检查一次 I2C 通信错误计数,一旦超限就执行恢复流程。
温度数据的存储也要做冗余保护。STM32L433RC 内部有 Flash 和 EEPROM 模拟区,我把每周整点时刻的温度数据和故障计数写到 EEPROM 模拟区,掉电后重新上电可以恢复最近的状态记录。分析售后问题时,这份数据非常有用。
5. 常见故障与调试排查实录
5.1 I2C 无应答与总线卡死问题
调试过程中遇到最多的故障是 I2C 通信超时,传感器不应答。排查顺序我总结成了固定套路:先量 VDD 是否有 3.3V,再量 SDA 和 SCL 对地电阻,确认上拉存在,然后示波器抓波形,看主机发出的地址帧是否完整。如果是远程传感器完全不应答,优先检查地址引脚焊接和连接线序,地址配置错位是最常见的原因。
还有一种情况是通信 OK 但温度读数异常,比如实时数据为 0 或者满量程。我先检查传感器地址是否被换掉,再看读取的寄存器是不是温度寄存器。曾遇到过一次低字节读取时序不对,导致温度始终跳在 0.25 度的倍数上,改正后读数恢复正常。
5.2 温度跳变与读数波动排查心得
有个典型案例:远程传感器装在风道里,离风机电机很近,运行时读数忽高忽低。示波器抓 SDA 线时发现,信号上有明显的振铃噪声,塞上拉电阻之后还是不行,最终加了屏蔽双绞线并让信号线远离电机动力线,问题解决。
软件滤波在这类故障里能兜底,但不能迷信。如果一个噪声脉冲直接在 I2C 帧的应答位注入了错误,读到的温度可能是一个完全合法的非法数值,不会被限幅滤波识别。硬件上防干扰才是正道,软件滤波只能算保险。我在培训开发人员时一直强调:数字传感器不等于数字天真,布局和线缆的讲究一点都不能少。
5.3 功耗异常与器件选型的后期验证
整机调试时发现待机电流比理论值高出不少,逐路排查最后定位到 LCD 驱动电路的偏压电阻一直在耗电。低功耗产品里最怕这种“看起来没工作,实际上一直在耗电”的外围电路。解决办法是给 LCD 偏压供电加了一个 MOS 开关,只在点亮 LCD 时接通,其他时间彻底断开。
功耗测量的方法也值得一提。不要只看整机电流,要用高精度万用表串联到电源入口,并配合示波器电流探头观察唤醒瞬间的电流波形。电流波形能直观看到软件卡在哪个外设初始化上了,比光看平均电流更能定位问题。
下表是我整理出的几个高频问题速查,供遇到类似问题的朋友快速对照:
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| I2C 枚举失败 | 上拉电阻太大/地址错误 | 量对地电阻、查地址引脚电平 |
| 温度读数跳变 | 线缆屏蔽差、干扰耦合 | 改用屏蔽双绞线,降低 I2C 速率 |
| 温度读数整体偏高 | 传感器贴热源近/自热效应 | 远离发热器件,加通风孔 |
| 待机电流偏大 | 上拉电路/LCD 偏压未断电 | 万用表测各电源域,逐路排除 |
| 掉线后无法恢复 | 无总线恢复机制/看门狗配置不对 | 加 SCL 释放逻辑,启用 IWDG |
6. 后续可扩展的方向
这套温度监测方案做完之后,我一直在想它的复用价值。PJ85718DM 加 STM32L433RC 的组合,本质上是一个“低成本、低功耗、可多路扩展”的温度采集与显示平台,换一个外壳和应用逻辑,就能用在冷链运输记录、机柜温度监控、农业大棚环境监测这些领域。
如果只是需要单点测温,把远程传感器省掉,代码里删掉一路读取逻辑就行。如果要升级到 8 路温度采集,可以把 RS485 总线上挂更多从站节点,主控软件只需要增加一个节点注册表,在配置里维护每个节点的地址和位置名称,控制逻辑不用大改。
通信接口上还能加蓝牙模块,STM32L433RC 有低功耗外设和串口,接一个低功耗蓝牙透传模块,手机端直接看实时温度曲线。我一直觉得,硬件设计的价值不在于堆料,而在于用最合适的外设组合解决实际场景里最痛的问题。这套方案的每一层,从传感器选型到总线抗干扰,再到低功耗调度,都是围绕“现场工程可靠”和“长期维护省心”这两个目标来落地的。做 HVAC 设备的朋友如果手头有类似的测温需求,完全可以照着我这个思路,先把单路调通,再按着文中提到的要点去扩展多路,踩过的坑大部分都能提前避开。