做嵌入式项目或者搞暖通改造的朋友大概率都遇到过这种场景现场要测的温度点位越来越多但每个点位的要求完全不一样。有的点位只关心本地告警比如控制柜内部温度超了现场就得响铃拉闸有的点位要往上送比如风管进出口温度、机房回风温度监控大屏上得能看到变化趋势和历史曲线。我用一颗 PJ85718DM 数字温度传感器配合 R7FA4M3AF3CFB144 这颗 MCU搭了一套既能本地轮询显示、又能远程上报的温度监测系统把采集、滤波、告警判断、协议上送这条链路整个跑通了。这篇就按从硬件到软件、从本地到远程的顺序把选型依据、接线细节、固件逻辑、协议设计还有现场校准的坑都写出来给正在做嵌入式测温或 HVAC 监控的朋友一个能直接参考的样本。1. 项目背景与整体架构设计为什么把温度监测当成一个完整系统来做1.1 嵌入式和 HVAC 两块“领地”的测温需求差异先说个容易被忽略的前提同样是测温度嵌入式设备和 HVAC 现场的诉求其实差别很大。嵌入式设备里的温度监测比如功率器件散热片温度、电池仓温度、控制板环境温度特点是点位少、变化快、离主控近核心诉求是“实时响应 本地保护”。温度一旦超限MCU 得立刻进中断、关输出、亮告警灯晚了设备可能就烧了。而 HVAC 场景完全反过来。风管送风温度、回风温度、冷热水管表面温度、机房环境温度点位多且分散传感器离主控经常有十几米甚至几十米数据变化相对缓慢重点在于“稳定采集 长期趋势 远程汇聚”。运维人员需要看到的不是某一秒的瞬时值而是设备运行 24 小时、一周的温度曲线用来判断风机盘管效率、判断冷站有没有异常。这两类需求混在一起最怕的就是方案一刀切。如果只做本地轮询远程平台拿不到数据如果只做远程上报现场又缺失了实时保护能力。我这次的思路是让一颗主控同时承担两种角色本地用 I2C 总线快速访问传感器做实时判断远程通过通信模块把整理好的数据帧定时送出去。本地要快远程要稳两条线互不干扰。1.2 感知层、主控层、传输层与应用层的分工整个系统我按四层来划分每一层只解决一个问题后期维护和排查故障会省很多事。层级职责本项目的具体实现感知层采集温度并数字化PJ85718DM 多点布设I2C 总线挂载主控层数据读取、滤波、阈值判断、协议组帧R7FA4M3AF3CFB144 固件逻辑传输层数据搬运与远程链路本地串口调试 工业级 DTU/串口服务器走 MQTT应用层展示、告警、趋势存储本地 LCD 与 RGB 状态灯 远程监控平台感知层选数字温度传感器而不是模拟 NTC原因在于长线传输。NTC 的分压信号走十几米线压降和电磁干扰会直接把精度吃掉PJ85718DM 输出的是数字信号I2C 在合理布线下传几米问题不大现场抗干扰能力明显好一截。主控层负责把原始寄存器值变成有意义的温度工程值并且做一道滤波避免把瞬时毛刺当成真实温度变化。传输层是嵌入式设备和外部平台之间的交界处协议一定要格式清晰、校验完善否则远程平台解析时头痛。应用层就按客户实际需求来本地要能看远程要能查告警要能推。数据流向也非常直接主控轮询 I2C 总线上的每颗传感器把温度值写入一个环形缓冲区做滤波然后按本地逻辑判断是否触发告警同时把满足上报条件的数据帧交给串口外发模块DTU 再通过 TCP 链路把数据推给 MQTT Broker订阅端最终在页面上展示。这套链路看起来不复杂但每一环都有值得展开讲的细节。2. PJ85718DM 的选型逻辑与硬件接线细节2.1 I2C 接口数字温度传感器到底解决了什么痛点PJ85718DM 是一颗 I2C 接口的数字温度传感器内部集成温度传感单元和 ADC直接输出数字量省掉了模拟前端的设计。它的关键参数我是按数据手册实际核过的温度测量范围 -55℃ 到 125℃在 -10℃ 到 85℃ 范围内的典型精度为 ±0.5℃默认分辨率 12 位对应 0.0625℃ 的 LSB。这个精度放在嵌入式和 HVAC 场景里都够用比一般 NTC 方案的“校准后勉强 ±1℃”要稳得多。选它而不是选模拟 NTC 或者单总线方案还有一个原因I2C 总线天生的多点能力。一颗 PJ85718DM 的 7 位从机地址可以通过 A0、A1 引脚配置成多个不同的地址同一根总线上可以挂多颗传感器。理论上 I2C 地址空间有限但实际挂 4 到 8 个温度点很轻松。相比单总线方案那种严格时序、每个传感器还要单独编号识别的麻烦I2C 的寻址逻辑对开发者友好太多出问题也好排查。另外这颗传感器还带一个可配置的 ALERT 引脚可以工作在比较器模式或关断模式。比较器模式下当温度超过上限且低于下限时ALERT 引脚会被拉低可以直接接到主控的外部中断脚上实现“温度越限立刻触发中断”不需要主控一直轮询等待。这种硬件级的告警机制在嵌入式保护场景里非常实用省去了软件轮询的响应延迟也降低了主控的运行负担。2.2 多点布线与上拉、供电、防干扰的实操注意硬件接线看起来简单但实际布线时的小细节决定了整个系统稳不稳。典型接法是每个传感器四根线VCC、GND、SDA、SCL另加 ALERT 线按需接入。工作电压我统一用 3.3V和主控 I/O 电平一致不需要额外的电平转换。SDA 和 SCL 需要上拉电阻阻值我选了 4.7kΩ如果总线挂了 4 颗以上传感器、线长超过 1 米可以把上拉电阻降到 2.2kΩ 来补偿线上的电容保证上升沿足够陡峭。地址分配方面同一批传感器默认地址是一样的必须通过 A0、A1 引脚来错开。我把 4 个测温点分别配成 0x48、0x49、0x4A、0x4B对应 A0/A1 组合为 00、01、10、11。这里有个容易踩的坑地址引脚不能悬空悬空会导致地址随机不稳定最好直接用跳线或者 PCB 上的焊盘固定到地或 VCC避免后期现场飞线接触不良。供电上我也吃过亏。HVAC 控制柜里通常有 24V 交流、变频器输出、接触器线圈这些强电干扰源传感器电源如果和继电器共用一个 DC-DC温度跳变会非常明显。所以我的做法是传感器供电单独走一路 LDO输出端加 10μF 钽电容和 0.1μF 陶瓷电容去耦信号线和电源线都尽量远离变频器输出线。传感器到主控的连线超过 2 米时我建议用屏蔽双绞线屏蔽层单端接地不要两端都接否则容易形成接地环路反而引入噪声。2.3 PCB 布局和探头安装的位置学问如果传感器是贴片封装直接焊在 PCB 上布局位置比选型还重要。很多开发者把传感器放在 CPU 旁边、电源电感底下结果测出来的“环境温度”其实是 PCB 局部热点的温度比真实环境高好几度。我的习惯是传感器放置位置遵循两个原则一是远离大功率器件和散热片至少要留 5mm 以上间距二是尽量靠近进风口或者外壳开孔方向让传感器接触的是环境空气而不是被加热的板内空气。HVAC 现场用的通常是带引线的探头式封装需要把传感器固定到风管表面或水管表面。这里有个关键工艺探头和被测表面之间必须填充导热材料比如导热硅脂或者导热胶垫并且用卡箍或扎带施加一定压力。空气的导热系数极低如果探头只是“贴着”管壁中间隔了一层空气响应速度和读数都会偏差很大。我当时在风管上测回风温度第一次读数偏低 2℃ 多拆下来重新涂导热硅脂压紧后读数立刻接近参考温度计这个教训很深刻。还要注意线缆长度和直径的匹配。I2C 总线如果走 5 米以上除了降低上拉电阻还要考虑总线电容是否超出规格必要时可以在主控端加一颗 P82B96 这类 I2C 总线缓冲器来扩展线长。对于 HVAC 现场动辄十几米、二十几米的分布式点位更稳妥的做法是分区采集每个区域由本地子板采集后再通过 RS485 汇总而不是所有传感器都硬拉到主控上。具体怎么选看成本和现场条件但提前规划好走线路径总比事后补救强。3. R7FA4M3AF3CFB144 主控侧的固件实现3.1 这颗 Cortex-M33 MCU 的资源和选型理由R7FA4M3AF3CFB144 是 RA4M3 系列里的一颗 MCU核心是 ARM Cortex-M33主频 100MHz带 TrustZone 安全扩展。存储资源方面它提供了 1MB Flash 和 256KB SRAM对做温度采集和协议处理来说非常充裕。外设配置上LQFP144 封装带来了大量的 SCI 串口、I2C、SPI、CAN、USB 以及 12 位 ADC这意味着我不需要外挂额外的通信芯片一路串口接 DTU一路 I2C 接传感器一路串口留作调试资源完全够用。选它而不是更便宜的 8 位 MCU原因有两个。第一温度监测虽然逻辑简单但远程协议栈、断线缓存、MQTT 组帧、多区滤波这些功能叠加起来8 位 MCU 的 Flash 和 RAM 会非常紧张而且调试起来繁琐。第二Cortex-M33 上可以直接跑厂商提供的 FSP 图形化配置框架初始化代码自动生成复杂外设的驱动不用自己从寄存器啃起开发周期可以压缩一大截。对做产品的人来说省下来的时间比省几块钱芯片成本更值钱。接口丰富还有一个隐藏优势后期扩展余地大。比如 HVAC 项目做到一半客户要求新增 CAN 总线接到楼宇自控系统这颗芯片自带 CAN 控制器改固件就能完成再比如需要接入 4G 模块做远程告警短信多出来的一路 SCI 串口直接就能用。如果当初选了资源刚好卡住的 MCU后期需求一变就要换平台重写那才是真正的成本黑洞。3.2 基于图形化配置工具的工程搭建与 I2C 驱动开发环境我用的是 e2 studio 配合 FSP 配置工具。流程大概是新建工程时选择芯片型号 R7FA4M3AF3CFB144FSP 会自动拉出对应的引脚封装图和时钟配置页面。在 Stacks 页面添加一个 I2C Master 驱动绑定到具体的 SCI 外设引脚上然后配置速率为标准模式 100kHz。温度传感器不需要高速率100kHz 更稳抗干扰能力也好一些这是实测下来的经验400kHz 在长线上偶尔会有通信失败的问题。配置完外设之后还需要手动确认引脚的电气属性。I2C 引脚要设为开漏模式并启用内部上拉。注意FSP 默认生成的引脚配置可能不包含内部上拉如果不加外部上拉电阻又没开内部上拉总线会直接拉不起来读出来全是 0xFF。我建议外部 4.7kΩ 上拉为主、内部上拉作为冗余两层保障更放心。生成代码后I2C 驱动的使用就变得很简洁。FSP 会把驱动实例封装好调用g_i2c0.p_api-write和read就能完成一次传输。需要注意的是I2C 读温度寄存器通常要先写寄存器地址再发起读操作这属于“写-读”组合事务最好用驱动提供的writeRead接口一次完成避免分两次调用导致总线状态被其他任务打断。如果驱动实例不支持组合事务也可以用write后紧跟read但一定要在同一个临界区内操作。3.3 温度读取、滤波和本地状态机的固件逻辑温度寄存器的读取和转换是整套固件里最基础也最关键的部分。PJ85718DM 的温度寄存器是 16 位高字节在前低字节在后其中高字节的高 8 位是整数部分低字节的高 4 位是小数部分低 4 位是无效位。也就是说12 位有效数据左对齐存放在 16 位寄存器里转换成十进制时需要先右移 4 位再乘以 LSB 值 0.0625。如果测量温度可能为负还要处理补码符号位。完整转换代码大致是这样的int16_t raw (int16_t)((uint16_t)reg_hi 8 | reg_lo); int16_t value raw 4; // 去掉低4位无效位得到12位有符号数 float temperature (float)value * 0.0625f; if (temperature 125.0f || temperature -55.0f) { // 数据错误置位传感器故障标志 sensor_error_flag | (1 sensor_index); }转换之后我不会直接把瞬时值拿去用。嵌入式现场尤其是 HVAC 环境风机启动瞬间、变频器换挡瞬间都会在温度读数上叠加尖峰毛刺。我采用“中值滤波 滑动平均”两级处理先取最近 5 次采样做中值滤波去掉最大值和最小值中的异常毛刺再对中值滤波后的结果做 4 次滑动平均让曲线平滑一些。这套组合在实测中效果很好既保留了真实的温度变化趋势又不会被偶发尖峰触发误告警。本地状态机我划分成三个状态正常、预警、告警。正常状态下只做采集和上报预警状态下点亮黄色状态灯但不上传紧急告警只有当温度超过硬阈值并且持续 5 秒以上才进入告警状态点亮红色灯并通过 ALERT 引脚触发中断。这个“持续 5 秒”的判断必须做否则现场空调一启停温度瞬时冲一下系统就会疯狂误报。阈值参数我放在 Flash 里保存方便现场通过串口指令修改不需要重新编译固件。4. 远程温度上报协议设计与网络链路落地4.1 本地数据与远程平台之间的通信路径选择远程通信方案我先列了三种串口转以太网模块、串口转 4G DTU、自带 WiFi 的模块。对比下来串口转 4G DTU 在我这个项目里最合适原因是现场没有现成的有线网络而且部分点位在移动过程中也需要巡检4G 链路不受布线位置限制。如果是在已有局域网覆盖的机房用串口转以太网模块会更经济稳定WiFi 模块则适合对布线敏感、且信号环境干净的场景。方案优点缺点适用场景串口转以太网稳定、延迟低需要网线部署有局域网覆盖的机房、楼宇串口转 4G DTU部署灵活、不受布线限制有流量费用、依赖信号覆盖分散点位、野外或移动巡检WiFi 模块无线上报、成本适中信号易受干扰室内无线覆盖好的环境DTU 的配置也比较直接设置串口波特率和我主控的串口一致比如 9600 或者 115200工作模式选 TCP Client连接 MQTT Broker 的 IP 和端口。数据格式我选用透传模式也就是 MCU 输出的原始字节流由 DTU 原样打包到 TCP 链路里MQTT 那边再按定长帧解析。这样 MCU 端逻辑最简单不依赖 DTU 内置的上报协议后续更换 DTU 品牌也不影响固件。选 4G DTU 还有一个好处断线重连机制通常由模块自身管理MCU 不需要实现复杂的 TCP 重连逻辑。我只需要在 MCU 侧保证“数据帧写得出去、写失败有缓存”链路的建立和维持交给 DTU。这种职责分离是嵌入式联网项目里很实用的做法不要什么东西都自己造轮子工业模块已经解决的问题就交给模块。4.2 定长数据帧的格式设计与解析代码远程协议我最看重的是可调试性和健壮性。JSON 虽然直观但在串口透传和嵌入式解析场景下并不友好一帧数据长度不定解析端还要做字符串分割出错时很难定位。所以我选择了定长二进制帧每一帧的字节数固定解析逻辑简单到可以用一个状态机直接跑非常容易移植到任意语言的后端服务里。帧格式我设计成下面这样字节偏移字段说明0帧头固定 0xAA 0x552长度后续数据长度固定 0x0C3设备 ID1 字节区分现场多台设备4点位编号1 字节对应传感器挂载序号5-6温度值有符号 16 位单位 0.01℃7状态位bit0 告警bit1 预警bit7 传感器故障8帧序号1 字节做缓存补传和去重用9-10CRC16对前面所有字节做 CRC16 校验11-12帧尾固定 0x0D 0x0A温度值用 0.01℃ 为单位放大好处是整数传输避免浮点精度问题。MCU 端组帧代码就是按顺序填充结构体然后计算 CRC16 后追加帧尾。解析端也要做一版我一般用 Python 写一个解析函数验证数据收到一帧就print出来对比原始字节调试阶段非常直观。uint8_t tx_buf[13]; tx_buf[0] 0xAA; tx_buf[1] 0x55; tx_buf[2] 0x0C; tx_buf[3] device_id; tx_buf[4] sensor_idx; int16_t temp_x100 (int16_t)(temperature * 100.0f); tx_buf[5] (uint8_t)(temp_x100 8); tx_buf[6] (uint8_t)(temp_x100 0xFF); tx_buf[7] status_flags; tx_buf[8] frame_seq; uint16_t crc crc16(tx_buf, 9); tx_buf[9] (uint8_t)(crc 8); tx_buf[10] (uint8_t)(crc 0xFF); tx_buf[11] 0x0D; tx_buf[12] 0x0A;4.3 定时上报、变化上报与断线缓存的落地策略数据上报如果不加策略要么频繁刷屏浪费流量要么漏掉关键瞬态。我的策略是“定时上报 变化上报”相结合。默认每 5 分钟上报一次所有点位这个周期足够 HVAC 趋势分析使用。同时设置一个变化阈值当任一传感器的温度与上次上报值差超过 0.5℃ 时立即上报该点位保证温度突变的瞬态能及时出现在远程平台。告警帧是最高优先级。进入告警状态后立即上报一帧告警数据并且之后每 30 秒重发一次直到告警解除。这个重复发送的设计是很多项目忽略的细节现场实际出现过一次告警帧发出后因为网络抖动平台没收到而 MCU 以为发出去了就不再管结果温度超限了半小时监控端完全不知情。所以对于重要状态宁可多发几次也不要依赖单次投递的“恰好成功”。断线缓存我用的是一个简单的环形队列。串口发送失败或者 DTU 反馈链路断开时待发送的数据帧不丢弃而是写入一段预分配的环形缓冲区每条记录带上帧序号和存储时间戳。等到链路恢复MCU 先发送当前帧再按顺序补发缓存里的帧。帧序号在这里派上用场平台收到重复帧时可以根据序号判断是重复数据还是新数据补传的帧时间戳允许覆盖但不影响当前实时帧的展示。缓存深度我取了 64 帧按 5 分钟周期算可以覆盖断电断网 5 个小时的数据足够应对大部分临时故障。5. 现场实测与校准记录5.1 读数偏差的三个来源系统上线之后第一件事就是对实测数据做校准而不是直接采信出厂参数。我手里的参考基准是一支水银温度计和一支已校准的工业数字温度计把传感器和参考温计放在同一个恒温环境下比对采集一整天数据后分析差值。实测中发现读数偏差主要来自三个来源。第一是传感器自身的绝对精度。虽然手册保证 ±0.5℃但同一批次的个体差异依然存在。有的传感器在 30℃ 附近偏差 0.3℃有的则 -0.4℃批量使用时如果不校准远程平台看到的各点位之间绝对温度会互相矛盾比如同一根回风管两端读出差了 0.8℃运维会误以为风管有异常。第二是主控板上其他热源对传感器的影响。这个前面已经提过PCB 布局的时候如果没有充分考虑散热片和电源芯片的热量会通过引脚和铜箔传导给传感器。尤其是用引线探头时引线自身如果贴在某个发热元件上面也会带来额外的温差。第三是被测表面的接触热阻。风管表面温度、水管表面温度这些场合探头安装工艺直接决定读数。没有导热介质、压紧力度不够、探头和表面接触面积太小都会导致读数比真实值低。我把这列为“系统性偏差”因为它不会随机跳变而是稳定偏小或偏大可以通过校准修正一部分但更根本的办法还是改善安装工艺。5.2 两点校准法算出斜率和截距对于线性度比较好的传感器两点校准就够了。校准原理很简单既然传感器输出和真实温度近似成线性关系那就找到一组真实温度和原始读数的对应点算出斜率和截距把原始读数映射到真实温度上。具体操作是取两个温度点一个低温点比如把探头放进 15℃ 的恒温水浴记录原始读数一个高温点比如 45℃再记录一次。然后按公式算斜率 k (T_ref2 - T_ref1) / (T_raw2 - T_raw1)截距 b T_ref1 - k * T_raw1校准后值 k * 原始读数 b我在现场用 4 颗传感器做了一组实测传感器编号15℃参考值15℃原始读数45℃参考值45℃原始读数计算斜率 K计算截距 B1号15.015.345.045.20.9930.2102号15.014.845.044.71.020-0.0633号15.015.145.044.80.989-0.1874号15.015.545.045.60.9700.130这些斜率和截距的差异看似不大但在 45℃ 的高温端2 号传感器的偏差已经接近 0.3℃放在需要精确控制送风温度的 HVAC 场景里不可忽视。所以我最终的方案是把每颗传感器的修正参数写进 Flash 里每次开机读取然后固件里加一层校准函数float calibrated_temp slope[sensor_idx] * raw_temperature offset[sensor_idx];批量生产中这个校准环节可以做成半自动化流水线工装里固定一支参考温度计自动读取传感器原始值然后算出 K、B 直接写入 Flash。一台设备校准只需要几十秒却能换来整批产品的数据一致性非常值得投入。5.3 变频器干扰、末端压降和接地环路现场踩坑的记录也要写一下。第一个案例是空调机组变频器启动瞬间某一路传感器温度跳变 2℃ 后又恢复。排查下来不是传感器坏了而是传感器供电线离变频器输出线太近变频器启停时的高频噪声耦合进了电源和 I2C 信号线。处理办法是把传感器供电回路改成独立隔离 DC-DC信号线换成屏蔽双绞线并且把屏蔽层单端接在主控的地上问题随即消失。第二个案例是远端传感器偶尔读不到数据。主控在柜内最远的传感器点位走了大概 8 米线I2C 通信偶发失败。这类问题的典型原因是总线电容过大和末端电压跌落。我的处理是降低 I2C 速率到 50kHz同时把上拉电阻从 4.7kΩ 换成 2.2kΩ并把传感器供电电压从 3.3V 提到 3.3V 高精度 LDO 的输出端保证远端传感器电源电压不低于 3.15V。如果之后再出现通信失败就该考虑在远端加 I2C 总线缓冲器或者改成 RS485 传输方案了。第三个案例更有代表性两个传感器读数完全一致但都明显偏低参考温度计都显示正常。我拆开现场接线发现探头的屏蔽层被两端接地了现场其他设备的漏电流通过屏蔽层形成了一个接地环路在电感效应下给传感器引入了一个直流偏置。把屏蔽层改成单端接地后读数马上恢复正常。这类问题从代码上看完全无解必须靠现场排查和走线规范来避免所以我在项目文档里专门加了一条硬性规定所有传感器屏蔽层只能单端接地。最后再分享一个我个人的习惯温度传感器硬件设计好了、固件跑通了不要急着批量部署先把样机带着探头放进恒温箱从 -10℃ 到 70℃ 做一遍完整的温度循环记录每一颗传感器的原始读数。这个过程能提前暴露虚焊、封装不良、导热失效这类“软件永远看不见”的问题。另外Flash 里保存校准参数和阈值参数这件事一定要留一份在线的串口修改命令现场调试点位时不用反复烧录能省下大量调试时间。这个项目的完整链路和校准流程已经稳定跑了几个月的现场目前看下来当初针对每个细节做的取舍最后都为减少返工换来了实际回报。