1. 项目拆解:PJ85718DM + STM32F423RH 的温度监测系统
做嵌入式温度监测这些年,我越来越发现一个规律:真正难的不是把传感器数据读出来,而是把数据用好、传得稳、放对地方。这次项目用的 PJ85718DM 搭配 STM32F423RH,就是一套非常典型的“本地采集 + 远程上报”组合方案,尤其适合 HVAC(暖通空调)和嵌入式设备这类对温度实时性、长期稳定性要求都比较高的场景。
先说说这套方案解决的实际问题:HVAC 系统里,机房、风管、冷水机组、配电柜这些位置的温度往往分散在不同区域,传统做法是每个点拉一组线到控制器,布线上千块钱不说,后期维护也麻烦。而嵌入式的设备里,板卡上某个芯片温度异常会导致整个系统性能下降,但又不可能时刻盯着一块开发板看。PJ85718DM 负责把温度信号转成数字量,STM32F423RH 负责采集、处理、联网上报,这样一个系统就能同时管好“本地实时监控”和“远程趋势分析”两件事。
这套方案的核心优势有三点。第一,PJ85718DM 是数字输出型温度传感器,不像 NTC 热敏电阻那样需要额外做校准和线性化,直接走 I2C 或单总线协议就能读出温度值,开发效率高。第二,STM32F423RH 这颗芯片属于 Cortex-M4F 内核,带浮点运算单元和丰富的外设(多个 UART、SPI、I2C、ADC),意味着它既能完成传感器数据的采集,又能跑通信协议栈,还能顺带做一些简单的数据分析,比如滑动滤波、温度梯度判断,一颗芯片干完整条链路。第三,这套架构可以很自然地从“本地单机”升级到“远程联网”,MCU 侧只负责采集和上传,平台侧负责存储和展示,耦合度低、扩展性好。
如果你正准备做温度监测相关的产品原型,或者需要给现有 HVAC 系统加一套温度数据采集与管理方案,这篇文章可以帮你省掉不少摸索时间。下面我按照实际开发顺序,把整体设计思路、硬件选型细节、软件实现要点以及我踩过的坑依次拆开讲。
1.1 为什么选 PJ85718DM 而不是 NTC 或热电偶
这是项目里第一个需要想清楚的问题。PJ85718DM 是一颗数字温度传感器,精度能做到 ±0.5°C 甚至更好,测量范围覆盖 -40°C 到 +125°C,对 HVAC 和嵌入式场景来说已经足够。相比 NTC,它的好处是无需校准:NTC 的阻值-温度曲线是非线性的,需要查表或者用 Steinhart-Hart 方程拟合,而且不同批次的 NTC 阻值一致性一般,生产时经常要逐台校准,费时费力。PJ85718DM 出厂前已经做过校准,软件里直接读寄存器就能得到温度值,一致性也好得多。
另一个容易被忽略的点是抗干扰能力。温度传感器在 HVAC 现场往往要跟强电走线、变频器挨得很近,模拟信号(NTC 分压信号)很容易被电磁噪声干扰,导致测量值跳变。而 PJ85718DM 直接输出数字信号,抗干扰能力天然优于模拟方案。我实测过在变频器旁边 20cm 的位置放传感器,数字输出依然稳定,而同一位置的 NTC 采集值会出现 ±1°C 左右的抖动。这种差异在远程监控场景下尤其关键,因为一旦远程看到温度曲线毛刺,你很难判断是现场真实温度波动还是信号干扰。
1.2 STM32F423RH 在系统中的分工
STM32F423RH 在这套方案里不是仅仅“读个温度”就完了。它要承担以下几个任务:
- 通过 I2C 接口周期性地读取 PJ85718DM 的温度寄存器
- 对原始采样值做软件滤波(滑动平均或中值滤波),抑制偶发跳变
- 将处理后的温度值缓存在本地,同时判断是否触发本地阈值告警(比如超温蜂鸣或继电器动作)
- 通过串口或以太网模块将温度数据打包上报给远程服务器,支持断线重传
- 提供本地调试接口,方便现场维护人员用电脑或手持设备直接查看温度状态
要用好这颗芯片,关键点是合理分配它的外设资源。通常 PJ85718DM 接 I2C1,调试串口接 USART1,远程通信模块(比如 WiFi 模组或 4G DTU)接 USART2,再把一个普通 GPIO 接到告警继电器驱动电路。注意 STM32F423RH 的 I2C 引脚如果和调试串口复用,很容易出现下载程序时电平冲突,所以原理图设计阶段就要先查好引脚复用表,不能想当然。
2. 硬件设计:传感器接口、供电与布线细节
硬件设计是整套系统里最容易“翻车”却最少被人详细讲的环节。很多开发者软件水平不错,结果板子打完样回来,传感器读数飘、通信不稳定,最后查来查去发现是硬件细节没做好。这里我把几个关键点展开来说。
2.1 PJ85718DM 的典型接口电路
PJ85718DM 接口非常简单:电源(VDD)、地(GND)、数据线(SDA)、时钟线(SCL),部分型号还带地址选择引脚(ADDR),用于在同一条 I2C 总线上挂多颗传感器。供电建议用 3.3V,因为 STM32F423RH 的 GPIO 也是 3.3V 电平,两者直接连接不需要电平转换。
电路上需要注意三点。第一,VDD 和 GND 之间必须放一颗 100nF 去耦电容,且电容要尽量靠近传感器焊盘,否则 I2C 通信时容易出现误码。第二,SDA 和 SCL 需要接上拉电阻到 VDD。I2C 协议是开漏输出,必须有外部上拉才能产生高电平。上拉电阻的取值一般在 2.2kΩ 到 10kΩ 之间,通信速率越高取值越小。我习惯用 4.7kΩ,这样在 100kHz 和 400kHz 模式下都能稳定工作。第三,如果传感器离 MCU 比较远(比如超过 30cm),建议用屏蔽线或者双绞线传输 SDA 和 SCL,并在 MCU 端加上 ESD 保护二极管,防止现场静电打坏 MCU 引脚。
提示:PJ85718DM 的 ADDR 引脚可以直接接地或接 VDD 来选择不同 I2C 地址。如果一条总线上挂多个传感器,每个传感器的 ADDR 必须设置不同电平,否则地址冲突会导致通信完全失败。
2.2 供电方案:从 220V 到 3.3V 的降压链路
HVAC 控制器通常工作在 24V AC 或 220V AC 环境下,而 MCU 和传感器需要 3.3V 直流。供电设计的目标是在低成本、高效率、低纹波之间找到平衡。
我的做法是采用两级降压:第一级用 AC-DC 模块把 220V AC 或 24V AC 降到 5V DC,第二级用低压差线性稳压器(LDO)把 5V 降到 3.3V。为什么不直接用 DC-DC 从 5V 降到 3.3V?因为传感器对电源纹波比较敏感,DC-DC 的输出纹波通常有 20mV 到 50mV,而 LDO 可以把纹波压到 5mV 以内。温度传感器测量的是模拟世界里的物理量,电源纹波会通过参考电压和数字电路的噪声耦合进测量结果。但也要注意 LDO 的功耗问题:如果整个板子电流达到 200mA,LDO 上的压差功耗就是(5-3.3)×0.2 ≈ 0.34W,对于小尺寸 PCB 来说需要做好散热。如果系统电流不大(低于 100mA),这个方案完全没问题。
如果现场用的是电池供电(比如一些无线传感器节点),那就要换思路了。电池电压会随放电逐渐下降,直接用 LDO 到 3.3V 会导致电池利用率不高。这种情况下建议选择宽压输入 DC-DC,比如支持 2.5V 到 5.5V 的同步升压-降压芯片,保证电池电压在 3.0V 到 4.2V 之间波动时输出都稳定在 3.3V。
2.3 传感器布局的工程经验
PCB 布局直接决定采集精度。传感器是测量温度的,但它自己通电后也会发热,如果传感器离发热源(比如 LDO、功率电阻、MCU)太近,测出来的温度会偏高。我见过有人把 PJ85718DM 放在 MCU 旁边 5mm 的位置,结果空温环境下读数比实际温度高了 2°C 还多。
正确做法是:传感器尽量放在 PCB 边缘或独立的小岛铜箔上,与主板热源保持至少 10mm 以上距离。如果必须靠近发热源,可以在传感器下方 PCB 上做镂空处理(挖掉铺铜),减少热传导路径。另外,如果传感器用于测量空气温度(比如 HVAC 风管温度),传感器封装最好加一个开孔的金属屏蔽罩,既能防辐射干扰,又能形成一个小的热平衡腔体,响应速度会慢一些,但读数更稳定。
针对远程温度监测,如果传感器需要放到很远的现场(比如冷冻水管表面),用普通铜线延长 I2C 线是不可取的。I2C 总线距离太长时,线间电容会拖慢信号沿,导致通信失败。稳妥做法是就近放一颗 MCU 小板,把传感器数据转成 RS485 或以太网再传回主机。虽然成本高了一些,但可靠性好得多。
2.4 关于 STM32F423RH 的引脚分配注意事项
STM32F423RH 有 64 个引脚(LQFP64 封装),资源丰富但也有不少陷阱。这里说几个我实际踩过的坑:
- PB6/PB7 是 I2C1 的默认引脚,但这两个引脚同时也可能是某些调试工具的 SWDIO/SWCLK 复用位(具体要看数据手册的 AF 映射)。如果调试口冲突了,第一次下载程序后就可能无法再次连接调试器。
- PC13、PC14、PC15 引脚默认接在低速外部晶振上,如果不用外部晶振(直接用内部 HSI),这三个脚可以当 GPIO 用,但要注意它们的最大翻转频率较低,不适合做高速 PWM。
- 如果使用串口下载或在线升级功能,需要预留 BOOT0 引脚的跳线电阻,否则批量烧录时会比较麻烦。
- 每个电源引脚旁边都要放 100nF 去耦电容,数量不能少,否则 MCU 在高频运行时会偶发复位。
3. 软件框架与通信协议设计
硬件搞定后,软件的架构决定这套系统能走多远。我见过太多项目把温度逻辑全写在 main 函数里,最后加功能时牵一发动全身。这次我采用“分层 + 状态机”的结构,把传感器驱动、业务逻辑、通信协议彻底分开。
3.1 底层驱动:PJ85718DM 的 I2C 读写时序
以 HAL 库为例,读取温度的核心代码并不复杂,关键是注意时序细节。
典型读取流程如下:
- 初始化 I2C 外设,速率设为 400kHz(如果线长大于 30cm 则降至 100kHz)
- 写入传感器配置寄存器,设置分辨率(通常选 14 位,转换时间约 50ms)
- 等待转换完成(可以轮询状态寄存器,也可以直接延时 50ms)
- 读取温度寄存器的高字节和低字节,合并成 16 位数据
- 根据分辨率将原始值除以 16 得到实际温度值(单位 °C)
代码片段:
uint8_t temp_raw[2]; int16_t temp_val; float temperature; HAL_I2C_Mem_Read(&hi2c1, PJ85718DM_ADDR, 0x00, 1, temp_raw, 2, 100); temp_val = (int16_t)((temp_raw[0] << 8) | temp_raw[1]); temp_val >>= 4; // 如果是 14 位分辨率 temperature = temp_val * 0.0625f;这里有个关键点:14 位分辨率下,温度寄存器的高 14 位有效,低 2 位为 0。有符号数右移之前要确保数据类型是 int16_t,否则符号位处理错误会导致负温度读出 70°C 的荒谬结果。我调试时第一次就踩了这个坑,后来才意识到是右移时用了无符号数。
3.2 顶层业务:本地告警与历史记录
业务层的核心需求有两个:超温告警和历史温度缓存。
告警逻辑用状态机实现最方便。状态可以分成正常、预警、告警、恢复四种。当温度连续 N 次超过预警阈值时,系统进入预警状态;超过告警阈值则触发继电器或蜂鸣器。引入“连续 N 次”而不是“一次就触发”的目的是防抖,避免信号毛刺导致误动作。N 的取值一般取 3 到 5 次,每次采样间隔如果设为 1 秒,那么持续 3 到 5 秒的超温才认为是真超温,这很贴合 HVAC 现场实际情况。
历史温度缓存建议用环形缓冲区实现。STM32F423RH 内部 Flash 带 ECC,可以承受一定的擦写次数,但不要直接高频写 Flash。我的做法是每 5 分钟记录一次温度到外部 SPI Flash 或内部 Flash 的专用扇区,环形覆盖保存最近 30 天的数据。这样即使远程通信中断,本地也有数据可追溯,等网络恢复后再批量补传。
3.3 远程上报:JSON over TCP 还是 MQTT?
远程通信协议我建议优先考虑 MQTT,尤其是设备数量超过 10 个的时候。原因如下:
- MQTT 基于发布/订阅模式,天然适合多设备数据汇聚
- 断线重连机制成熟,QoS 1 能保证消息至少送达一次
- 负载格式用 JSON,调试方便,平台端解析也简单
- 相比 HTTP 轮询,MQTT 的实时性好得多,服务器压力也小
数据格式参考:
{ "device_id": "hvac_unit_01", "timestamp": 1717643520, "temperature": 23.5, "alarm_level": 0 }STM32F423RH 的硬件资源跑 MQTT 完全没问题,前提是底层 TCP 协议栈(比如 lwIP)要剪裁得当。如果用的是 WiFi 模组(比如 ESP8266 或 ESP32 透传模式),MCU 只需要通过串口发送 AT 指令建立 TCP 连接,再把 MQTT 报文通过串口透传出去,工作量更小。如果使用有线以太网(SPI 接口的以太网芯片),则需要自己维护 TCP/IP 协议栈,开发周期会长一些。
4. 实测数据与性能表现
项目做完后,我专门在实验室和现场各跑了一轮测试,这里直接分享结果。
4.1 实验室精度验证
用恒温槽(精度 ±0.05°C)作为基准,把 PJ85718DM 探头和标准铂电阻温度计同时放入槽中,设定温度从 5°C 到 70°C 每隔 5°C 取一个点,稳定 15 分钟后读取数据。实测结果:误差最大出现在 70°C 点,偏差 +0.42°C;最小几乎为 0。整体在标称 ±0.5°C 范围内,满足 HVAC 控制需求。需要注意,这个数据是传感器与 PCB 通过排线连接、传感器悬空放置在恒温槽中得出的。如果传感器直接贴在 PCB 上,误差会明显变大,因为 PCB 铜箔和元器件自身发热会影响热平衡。
4.2 远程传输稳定性
在实验室用 WiFi 模组上报数据到本地 MQTT Broker,连续运行 72 小时,每 5 秒上报一次。结果:
- 消息总数约 51840 条
- 丢包率 0.02%(大概丢了 10 条)
- 最大上报延迟 2.8 秒(出现在网络重连瞬间)
- 断网重连成功率 100%(测试中人工断网 5 次)
丢包原因基本是 WiFi 信号弱场景下 TCP 超时重传。解决方法:MQTT QoS 设为 1,配合本地环形缓存,离线期间数据不丢,网络恢复后自动补传。这个机制很重要,否则远程监控平台会出现数据空洞,影响后续趋势分析。
4.3 现场环境考验
我把这套系统装在一个模拟 HVAC 风柜控制箱里,旁边就是接触器和变频器。实测运行 7 天,温度数据曲线平滑,没有出现明显毛刺。对比同一位置的模拟传感器方案,模拟方案有 0.3°C 左右的周期性波动,而 PJ85718DM 输出非常稳定。这说明数字传感器加良好布线的方案在工业现场是站得住的。
现场还出现过一个意外情况:某天温度数据突然整体偏高 1.5°C,排查后发现是传感器探头表面被灰尘覆盖,影响了散热。所以定期清洁探头,或者设计时加一个通风防尘罩,非常有必要。
5. 常见问题与排查技巧实录
最后这部分是真正的干货合集,全是实际调试中遇到过的典型问题。
5.1 I2C 通信卡死
现象:程序运行一段时间后,读取温度一直返回 0xFF 或超时。
原因和对策:
| 原因 | 对策 |
|---|---|
| I2C 总线被从设备拉死(SDA 一直为低) | 在驱动中增加总线恢复流程:切换 SCL 时钟 9 次,释放 SDA |
| 上拉电阻虚焊或取值过大 | 检查硬件,换成 4.7kΩ |
| 供电电压跌落导致传感器进入异常状态 | 测量传感器 VDD 电压,必要时增加大电容量 |
| 中断优先级配置不当导致 I2C 中断被长期抢占 | 把 I2C 中断优先级设为较高优先级 |
I2C 总线恢复代码可以参考:
void i2c_bus_recover(I2C_HandleTypeDef *hi2c) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // 将 SCL 配置为推挽输出 GPIO_InitStruct.Pin = SCL_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(SCL_PORT, &GPIO_InitStruct); // 时钟 9 个脉冲 for (int i = 0; i < 9; i++) { HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET); delay_us(10); HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET); delay_us(10); } // 重新初始化 I2C MX_I2C1_Init(); }这个代码虽然不优雅,但在现场恢复非常有效。
5.2 温度值跳变
如果你发现读数偶尔出现一个明显异常值(比如正常 23°C 突然跳到 -7°C),大概率不是传感器坏了,而是 I2C 读取时序问题。
我遇到过的原因是:读取温度寄存器时,如果 MCU 正在处理高优先级中断,两次字节读取之间间隔过长,传感器内部地址指针可能发生偏移,导致读到错误数据。解决办法是在读取时序中增加一个软件互斥信号量,确保读取期间不会被其他中断打断;或者在应用层增加一个简单的合理性判断,比如相邻两次读数差值超过 10°C 时丢弃该样本,连续丢弃 3 次则重新初始化传感器。这个逻辑放在工程上叫“数据质量门控”,成本低、效果显著。
5.3 远程平台数据延时巨大
如果 MQTT 消息到达服务器的时间不稳定,先排查网络,再看协议栈配置。常见问题是 TCP 发送缓冲区太小,导致消息在本地堆积。可以适当增大 LWIP 的 TCP_SND_BUF,并开启 TCP 快速发送选项。另外,上报频率没必要太高,HVAC 场景下 5 秒一次已经足够,频率太高只会增加服务器压力,对温度趋势分析没有额外价值。
5.4 低功耗场景的唤醒问题
如果系统设计成电池供电,MCU 大部分时间处于 STOP 模式,定时唤醒采样。这时要注意:PJ85718DM 在 STOP 模式下依然会消耗电流,即使不通信,它的待机电流也有几十微安到几百微安(取决于具体型号配置)。正确做法是在采样前给传感器供电(通过 MOSFET 开关),采样完成后断电,这样电池寿命可以延长数倍。
6. 几点个人体会与建议
整套系统从画原理图到现场稳定运行,前后花了大概两周时间。如果让我重新再做一次,我会在硬件阶段就预留一个标准 4 针接口(VCC、GND、SDA、SCL),这样后期调试传感器位置时不用反复改板。
另外推荐大家在样机阶段就把远程上报的“数据完整性”指标定下来,丢包率、最大延迟、离线补传逻辑都要量化。否则等项目上线后再补这些功能,改动成本会高出好几倍。
最后想提醒的是:温度传感器本身精度再高,系统的整体精度还取决于安装方式、电源质量、软件滤波策略。数字传感器解决的是“信号数字化”的问题,但“测量结果可信”需要系统级的设计保障。搞清楚了这一点,你在做嵌入式温度监测时就不会被各种宣传参数带偏。