
1. 项目背景与核心需求拆解温度监测这件事看起来简单真要做到“本地能看、远程能查、长期稳定”里面门道不少。我最近在做一个嵌入式和 HVAC暖通空调场景下的温度采集方案主控用的是 STM32F423RH温度传感器选的是 PJ85718DM。这套组合不是随便挑的背后有很明确的工程考量。先说这个项目要解决什么问题。HVAC 系统里温度是最核心的控制变量之一。无论是楼宇空调的送风温度、回风温度还是机房精密空调的机柜进风温度都需要实时、准确地采集。传统做法是用几个独立的温度传感器加一个简单的 MCU本地显示一下就算了。但现在的需求变了一方面设备要能本地实时显示当前温度方便现场运维人员巡检另一方面数据要能上传到远程监控平台实现集中管理和告警。这就对硬件选型和软件架构提出了更高要求。STM32F423RH 是 ST 家的一款高性能 Cortex-M4 MCU带 FPU主频 100MHzFlash 1.5MBSRAM 320KB。这个配置在温度监测这种场景里算是“高配”了但为什么选它因为 HVAC 场景往往不只是测温度还要跑 Modbus、跑 LCD 刷新、跑数据记录甚至要跑简单的 PID 控制。F423RH 的算力和存储空间足够把这些任务都塞进去不用外挂太多芯片整体 BOM 更简洁。PJ85718DM 是一颗数字温度传感器支持 I2C 接口测温范围覆盖 -40°C 到 125°C精度在常温段可以做到 ±0.5°C。它的关键优势在于出厂校准、直接输出数字量不需要额外的 ADC 和运放电路。对于 HVAC 这种对成本敏感、但对可靠性要求高的场景这种数字传感器比传统的 NTC 热敏电阻加 ADC 的方案要省心得多。这个项目适合谁参考如果你正在做嵌入式温度采集、HVAC 控制器开发、或者工业物联网的数据采集节点这套方案可以直接借鉴。哪怕你用的是别的 MCU 或传感器里面的架构思路、调试方法和避坑经验也是通用的。2. 硬件架构设计与选型逻辑2.1 为什么选 PJ85718DM 而不是 NTC 或热电偶温度传感器选型是这套方案里第一个要拍板的事。市面上常见的方案有三类NTC 热敏电阻、热电偶、数字温度传感器。NTC 便宜但需要分压电路和 ADC而且非线性严重软件要做查表或拟合批量生产时每个板子都要校准产线成本高。热电偶适合高温场景但需要冷端补偿电路复杂精度也一般。PJ85718DM 这类数字传感器直接通过 I2C 输出温度值出厂已经校准好软件上读寄存器就行省去了模拟电路设计和校准环节。从成本角度看PJ85718DM 单颗价格比 NTC 贵但算上 ADC 通道、运放、校准工时和产线测试成本整体方案成本反而可能更低。尤其是多路温度采集时数字传感器的优势更明显——I2C 总线可以挂多颗地址可配布线也简单。2.2 STM32F423RH 的外设分配与资源规划F423RH 的外设很丰富这个项目里主要用到以下几块I2C1接 PJ85718DM标准模式 100kHz 或快速模式 400kHz。温度采集对速度要求不高100kHz 足够抗干扰也更好。USART2接本地串口屏或调试终端用于本地显示。USART3接无线模块或以太网模块用于远程数据上传。TIM2做 1 秒定时中断触发温度采集任务。GPIO控制本地 LED 指示和蜂鸣器告警。资源分配上I2C1 的引脚要选带硬件 I2C 功能的避免软件模拟带来的时序抖动。F423RH 的 I2C 支持 SMBus 和 PMBus兼容性不错。USART3 如果接以太网模块建议用 DMA 发送避免阻塞主循环。2.3 电源与抗干扰设计要点HVAC 现场环境通常比较恶劣电机启停、继电器动作都会带来电源波动和电磁干扰。温度传感器如果供电不稳读数会跳变。我的做法是PJ85718DM 的 VDD 用 LDO 单独供电和 MCU 的 3.3V 之间加磁珠隔离电源引脚就近放 100nF 和 10uF 电容。I2C 的 SDA 和 SCL 上拉电阻用 4.7kΩ如果总线较长可以降到 2.2kΩ但要注意功耗。PCB 布局上传感器尽量远离发热元件如 LDO、MCU 本体如果测的是环境温度传感器要放在板边或通过排线引出避免板子自身发热影响读数。这一点在 HVAC 控制器里特别重要因为控制器本身可能装在密闭盒子里内部温升能有 5-10°C。3. 软件架构与核心代码实现3.1 整体软件框架设计软件上我采用了一个轻量级的时间片轮询架构没有上 RTOS。原因很简单这个项目的任务数量不多实时性要求也不算苛刻用 RTOS 反而增加复杂度和内存开销。主循环里做三件事处理 I2C 温度读取、刷新本地显示、打包上传远程数据。定时器中断负责置标志位主循环检测标志位执行对应任务。这种架构的关键是任务执行时间要短不能有阻塞操作。I2C 读取温度大概几百微秒LCD 刷新如果用的是串口屏发送指令也是毫秒级以太网发送用 DMA 就不阻塞。整体下来主循环一圈大概 10ms 以内响应很流畅。3.2 PJ85718DM 的 I2C 驱动编写PJ85718DM 的 I2C 地址默认是 0x487 位地址如果总线上挂多颗可以通过 ADDR 引脚改地址。读温度的过程是先发送指针寄存器地址 0x00然后读两个字节高字节在前低字节在后。温度值是一个 12 位有符号数分辨率 0.0625°C。#define PJ85718DM_ADDR 0x48 1 #define TEMP_REG 0x00 float PJ85718DM_ReadTemp(I2C_HandleTypeDef *hi2c) { uint8_t buf[2]; int16_t raw; float temp; HAL_I2C_Mem_Read(hi2c, PJ85718DM_ADDR, TEMP_REG, I2C_MEMADD_SIZE_8BIT, buf, 2, 100); raw (int16_t)((buf[0] 8) | buf[1]); raw 4; // 低4位是无效位 temp raw * 0.0625f; return temp; }这段代码里有个细节原始数据是 16 位但只有高 12 位有效所以右移 4 位。如果温度是负值右移操作要小心符号扩展用int16_t强制转换后再移位能保证负数正确。3.3 本地显示与远程上传的协同本地显示我用的是串口屏通过 USART2 发送指令更新温度值。远程上传走 USART3 接 4G 模块或以太网模块数据格式用 JSON方便云端解析。这里有个坑如果本地显示和远程上传都在主循环里做当网络不稳定时发送函数可能阻塞导致本地显示卡顿。解决办法是把远程发送做成非阻塞的用环形缓冲区加 DMA发送完成中断里再处理下一包。typedef struct { float local_temp; float remote_temp; uint32_t timestamp; } TempData_t; void SendRemoteData(TempData_t *data) { char json[128]; snprintf(json, sizeof(json), {\lt\:%.2f,\rt\:%.2f,\ts\:%lu}, >float CalibrateTemp(float raw_temp) { // 两点校准25°C时偏高0.3°C40°C时偏高0.5°C float offset 0.3f (raw_temp - 25.0f) * (0.5f - 0.3f) / (40.0f - 25.0f); return raw_temp - offset; }这个补偿系数不是拍脑袋来的是实测数据拟合出来的。每批板子可能略有差异如果产量大建议抽检几块做校准取平均值。4.2 多次采样与数字滤波温度读数偶尔会跳变尤其是 I2C 通信受干扰时。我在软件里做了两级滤波第一级是连续读 5 次去掉最大最小值剩下 3 次取平均第二级是一阶低通滤波系数 0.2让温度变化更平滑。#define FILTER_N 5 float TempFilter(float new_temp) { static float buf[FILTER_N] {0}; static uint8_t idx 0; static float last_avg 0; float sum 0, min, max; buf[idx] new_temp; if (idx FILTER_N) idx 0; min buf[0]; max buf[0]; for (int i 0; i FILTER_N; i) { sum buf[i]; if (buf[i] min) min buf[i]; if (buf[i] max) max buf[i]; } float avg (sum - min - max) / (FILTER_N - 2); last_avg last_avg * 0.8f avg * 0.2f; return last_avg; }这个滤波逻辑在 HVAC 场景里很实用因为温度变化本来就慢滤波带来的延迟可以接受但抗干扰能力明显提升。4.3 远程温度监测的数据上报策略远程上报不是越频繁越好。上报太勤流量和服务器压力大上报太慢告警不及时。我的策略是正常状态下每 30 秒上报一次如果温度超过阈值立即上报并且上报间隔缩短到 5 秒温度恢复正常后再回到 30 秒。这样既保证了告警实时性又节省了流量。阈值设置要根据具体场景来。比如机房温度一般设 28°C 告警35°C 严重告警。HVAC 送风温度可能设 12°C 到 18°C 为正常范围。这些参数最好做成可配置的通过远程指令下发不用重新烧录固件。5. 常见问题与排查技巧实录5.1 I2C 通信失败排查I2C 读不到数据是最常见的问题。我的排查顺序是先用示波器看 SCL 和 SDA 波形确认有没有上拉、时序是否正常然后检查地址对不对PJ85718DM 的地址是 0x48但 HAL 库函数里要左移一位变成 0x90最后看电源传感器供电是不是 3.3V有没有虚焊。有一次调试I2C 死活不通查了半天发现是上拉电阻焊成了 10kΩ加上总线电容偏大上升沿太缓MCU 识别不到高电平。换成 4.7kΩ 后立刻正常。这个坑很典型I2C 的上拉电阻值要根据总线电容和速度来算不是随便选一个就行。5.2 温度读数跳变或偏差大读数跳变通常是电源噪声或地线干扰。可以在传感器 VDD 和 GND 之间并一个 100nF 电容尽量靠近引脚。如果还跳检查 I2C 走线是不是太长有没有和电机线、继电器线捆在一起。HVAC 柜子里强电弱电混走很常见I2C 线一定要远离强电。偏差大则可能是传感器自热或附近热源影响。PJ85718DM 的工作电流很小自热可以忽略但如果它旁边有个 LDO 在发热读数就会偏高。解决办法是把传感器挪远一点或者用排线引出来。5.3 远程数据丢包或延迟远程上传丢包先查网络信号强度4G 模块的话看 RSSI 值。如果信号没问题检查发送缓冲区是不是太小JSON 字符串拼接时有没有溢出。还有一点容易忽略USART3 的波特率和模块是否匹配有时候模块默认 9600代码里写 115200数据就全乱了。延迟大的话看看是不是在主循环里做了阻塞发送。改成 DMA 加环形缓冲后延迟会明显改善。另外服务器端的接收频率也要考虑如果服务器处理慢客户端发太快也会丢。5.4 常见问题速查表现象可能原因排查方法解决措施I2C 无应答地址错误、上拉缺失、供电异常示波器看波形万用表测电压检查地址左移、换 4.7kΩ 上拉、确认 3.3V温度跳变电源噪声、地线干扰示波器看 VDD 纹波加滤波电容、远离强电读数偏高附近热源、自热用手摸传感器附近挪远热源、排线引出远程丢包信号弱、缓冲区小查 RSSI、看发送日志增强信号、扩大缓冲显示卡顿阻塞发送、任务过长测主循环耗时改 DMA、拆分任务6. 实操心得与扩展建议这套方案跑下来我最深的体会是温度监测的难点不在读传感器而在系统级的稳定性和可维护性。传感器本身很成熟I2C 协议也简单但放到 HVAC 现场电源、干扰、网络、显示每个环节都可能出问题。所以设计时一定要留余量电源多一级滤波、I2C 多留几个地址、远程协议留扩展字段、固件留 OTA 升级接口。另外本地和远程的温度数据最好做一致性校验。我遇到过本地显示 25°C远程收到 85°C 的情况查了半天是 JSON 拼接时浮点数格式化出了问题%.2f写成了%d把浮点数的内存解释成整数了。这种低级错误在调试时很容易忽略建议在发送前打印原始数据核对。后续如果要扩展可以加一路继电器输出温度超限时直接控制风机或阀门不用等远程指令。还可以加 SD 卡做本地数据记录断网时数据不丢恢复后补传。这些扩展在 F423RH 上都有足够的外设支持硬件上只需要加少量器件。最后分享一个小技巧PJ85718DM 的 I2C 地址可以通过 ADDR 引脚配置如果总线上要挂多颗记得把 ADDR 引脚接不同的电平别都悬空。悬空时地址不确定可能冲突。这个细节在数据手册里写了但很容易被忽略。