1. 为什么要在同一套系统里同时测“本地”和“远程”温度1.1 本地温度与远程温度根本不是一回事很多人第一次接触温度采集时以为只要是测温度随便找个热敏电阻、温度传感器芯片往板子上一放就行。真做起嵌入式和 HVAC 项目之后才会明白本地温度和远程温度是两个完全不同的概念混在一起用早晚要出问题。所谓本地温度指的是传感器芯片封装内部或器件本身所在位置的温度。它在 PCB 板上工作周围有 MCU、电源芯片、功率器件这些发热源会直接升高中局部环境的温度。而远程温度指的是通过外部探头、引线连接去测量远端那个物理位置的真实温度比如风管送风温度、回风温度、室内温度。这两个温度之间可能差好几度甚至十几度。MCU 旁边那 5 度的温升可能让原本正常的控制逻辑误判房间过热把冷阀全开结果现场却冷得不行。所以我在做“基于 PJ85718DM 与 STM32F745ZG 的本地/远程温度监测方案”时第一件事就是把这些温度来源分开看待。这套系统面向的是嵌入式和 HVAC 两个场景嵌入式端需要关心板子本身的健康状态避免 MCU 局部过热、散热设计失效HVAC 端需要关心被控空调区域的实际温度把它作为风机盘管、新风机、冷热水阀门的控制依据。同一个系统里用一颗带本地和远程测量能力的传感器芯片配合一颗有足够算力的 STM32F745ZG 做数据处理和策略控制比堆一堆分立器件靠谱得多。1.2 PJ85718DM 在系统里到底承担什么角色PJ85718DM 是一颗数字温度传感器芯片常见封装形式下支持片上本地温度测量同时可以外接远程温度探头。简单说这颗芯片就是一个“双通道测温桥”本地点负责机板温度远程点负责被测环境温度两个读数最终通过数字接口送进 MCU。我没有把它的型号当作唯一选项但在这个项目里选它的核心原因是双通道集成度高。如果用两路热敏电阻方案得占用两路 ADC还要自己搭分压网络、做非线性校正、校准串联电阻误差整套东西下来不仅占用 PCB 面积调试成本也高。而用这类带数字接口的多通道传感器远程探头接上去之后芯片内部自动完成激励、采样、ADC 转换和对数运算MCU 只需要通过 I2C 之类的接口把换算好的数据读回来就行省下的精力可以全部放到控制算法上。实际接线时我通常把本地通道当作“板温”来看把它作为固件保护和散热告警的输入把远程通道接到 HVAC 现场测点。远程探头和芯片之间的引线可以做得比较长这一点对 HVAC 安装特别友好。因为控制器往往被装在配电箱、控制柜、吊顶检修口这些地方真正要控温的测点在房间中央或者风道深处二者之间经常隔了好几米。1.3 为什么用 STM32F745ZG 而不是普通入门 MCUSTM32F745ZG 这颗料在这套方案里不是简单跑一下 I2C 读传感器就完了。它是 Cortex-M7 内核主频最高能到 216MHz带浮点单元片上资源也很充足。HVAC 控制器往往要同时干几件事轮询多路温度、做平均温度滤波、跑 PID 控制算法、驱动三速风机、控制电动阀、刷新显示屏、和上位机走 Modbus 或 CAN 通信。如果手头只有一颗几十 MHz 的入门单片机把这些任务塞进一个裸机循环里容易把实时性拖垮。F745ZG 的另一个优势是外设多。它不止一路 I2C我可以把传感器单独挂一路 I2C 总线把 EEPROM、LCD 驱动、触摸按键挂到另外的总线上避免传感器时序被其他设备的响应速度干扰。144 引脚的封装也给了比较充分的 GPIO方便以后扩展更多数字输入输出。处理温度数据时直接使用浮点运算做滤波和校准不用像在低端 MCU 上那样逐字节模拟浮点代码写起来简单运行速度也快。当然如果项目成本压力非常大换一颗低成本的 M0/M3 单片机也是可行的你的工作量会多一些但并非做不了。这篇方案的核心是把“多通道温度采集 复杂控制逻辑”这条完整链路理清楚所以我会以 F745ZG 为主线来展开。2. 硬件搭建从传感器到 MCU 的完整链路2.1 PJ85718DM 的引脚与接入方式先说明一下不同批次、不同封装的 PJ85718DM 引脚定义和寄存器地址可能有差异我下面描述的方案是基于我手头这颗常见贴片封装的接法。拿到实际的芯片之后第一步永远是查对应批次数据手册核对引脚功能不要盲抄网上的代码和接线图。以典型接法为例传感器部分至少要引出以下信号电源引脚 VDD 和 GND通常接 3.3V。I2C 数据线 SDA 和时钟线 SCL。报警输出引脚 ALERT可以接到 MCU 的 GPIO 外部中断输入用于温度越限时快速响应。远程探头接入端通常是一组差分输入接外部温度探头。PJ85718DM 和 MCU 之间的连接很简单因为都是标准 I2C 电平只要保证电平一致不需要额外转换。STM32F745ZG 的 GPIO 可以配置成开漏输出并外加上拉电阻和传感器的 I2C 接口直接连一起就可以工作。远程探头接入端就比较关键了要注意极性接反之后读到的温度往往是不正常的或者直接出现传感器故障标志。整套硬件链路的信号方向是远程探头产生的微弱温度信号进入 PJ85718DM经过内部 ADC 和算法后转成数字温度读数本地通道同时完成板温采样MCU 通过 I2C 周期读取两个温度寄存器和状态寄存器然后进入应用层处理。2.2 电源、去耦和上拉电阻的选择温度传感器属于模拟测量器件虽然它已经把 ADC 做在芯片内部但电源噪声仍然会影响最后的读数稳定性和精度。尤其当芯片直接放在一块有继电器、有电机驱动的 HVAC 控制板上时电源的干扰会明显传导到传感器测量链路上。我在这套方案里采用的做法是传感器电源独立使用 3.3V并且在这颗芯片附近放最少一个 100nF 陶瓷电容紧贴电源引脚放置在此基础上再放一个 10uF 的钽电容或高容值 MLCC用于吸收稍低频的电源波动。MCU 的电源也需要认真处理STM32F745ZG 的 VDDA 和 VDD 不要混用要给模拟电源引脚单独加磁珠和电容保证 ADC 参考电压干净。I2C 总线的上拉电阻也需要算一下。总线速度选择 400kHz 时上拉电阻常见取值是 2.2k 到 4.7k。如果传感器离 MCU 只有几厘米用 4.7k 没问题如果传感器通过排线拉到几十厘米以外可以把上拉电阻降到 2.2k改善总线上升沿。不过上拉太小会让总线负载变大降低噪声容限。最稳妥的做法是先看一眼 I2C 总线上的总电容再根据通讯波形决定电阻值。手头没有示波器的时候优先选 4.7k 起步观察设备能否稳定读写。2.3 远程探头选型与线缆长度约束HVAC 场景里远程探头是这套系统中离现场环境最近的部分选型不能太随意。常用的远程温度探头有两种一种是传感器厂家配套的专用探头内部已经做了匹配电路直接插上就能用另一种是自制热敏电阻探头或者二极管类温度探头需要根据芯片的数据手册确认驱动电路参数。优先推荐用配套探头。原因很简单传感器的远程通道内部有一套为特定探头类型设计的激励和校准逻辑用不匹配的探头会导致读数非线性、偏大偏小甚至完全读不出来。我见过有人拿一个普通的 NTC 热敏电阻去接远程通道结果温度读到 -30 度后来换回配套探头或者按数据手册匹配偏置电阻才能正常工作。关于线缆长度远程测量的核心矛盾在于线阻和干扰。线缆越长线阻越大外部电磁噪声也越容易耦合进来。把远程探头线做成双绞线可以大大抑制共模干扰如果现场环境有变频器和继电器再用屏蔽双绞线屏蔽层单端接地。线缆长度尽量不要超过数据手册给定的上限如果实在要拉很长的线我倾向于在远程通道输入处加小容量共模滤波电容但要注意电容过大会拉长内部采样稳定时间可能导致传感器无法在设定的采样周期内完成转换造成读数异常。2.4 STM32F745ZG 侧的硬件初始化STM32F745ZG 一侧的硬件准备比较常规但有一个细节常被忽略I2C 引脚必须选择有 FC 功能且支持 3.3V 电平的引脚并把 GPIO 配置为开漏输出。如果配成推挽输出外部上拉电阻和内部驱动会打架总线波形会变难看甚至通讯出错。我建议把传感器所使用的两个 I2C 引脚单独列出来不要把其他 GPIO 复用到相邻位置。虽然 I2C 本身只需要两根线但在 HVAC 控制板上电机驱动、继电器线圈、开关电源这些强干扰源都会往导线上耦合噪声。给 I2C 走线留出独立的布线空间保持和其他高电压大电流走线有足够间距比后期在软件上拼命滤波管用得多。还可以把 ALERT 引脚接到 F745ZG 的一个外部中断 GPIO 上。正常情况下固件周期轮询温度即可但报警场景下用中断来唤醒和处理会更及时。比如远程探头断线时传感器会在 ALERT 引脚上产生低电平信号MCU 立刻进入故障处理流程比等待下一次轮询要快不少。3. 固件实现读取、换算、滤波3.1 初始化 I2C 总线与传感器配置固件开发的第一步不是读温度而是把 I2C 外设初始化和传感器配置做好。STM32 的 HAL 库把 I2C 配置封装得比较完善我一般使用以下初始化逻辑I2C_HandleTypeDef hi2c1; void MX_I2C1_Init(void) { hi2c1.Instance I2C1; hi2c1.Init.ClockSpeed 400000; // 400kHz hi2c1.Init.DutyCycle I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 0; // 主机地址可配置 hi2c1.Init.AddressingMode I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 0; hi2c1.Init.GeneralCallMode I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(hi2c1); }初始化完成后再配置传感器。不同芯片的寄存器格式不同我这里只给出典型流程先读取设备 ID 寄存器确认通讯正常然后配置转换分辨率、报警阈值和远程通道采样模式。分辨率越高每次转换需要的时间越长所以要根据 HVAC 系统的实际控制周期去平衡。房间温度变化速率通常很慢1 秒左右读一次就够了没必要追求极限速度。3.2 读取本地和远程温度寄存器的代码思路配置完成之后温度的读取逻辑非常规整MCU 先写寄存器地址再连续读取两个字节的数据最后把两个字节拼成 16 位原始值。使用 STM32 的 HAL 库时读寄存器可以这样写uint8_t raw_temp[2]; int16_t raw_temp_val; // 假设本地温度寄存器地址为 0x00 HAL_I2C_Mem_Read(hi2c1, PJ85718DM_ADDRESS, 0x00, I2C_MEMADD_SIZE_8BIT, raw_temp, 2, 100); raw_temp_val (int16_t)((raw_temp[0] 8) | raw_temp[1]);这里的 PJ85718DM_ADDRESS 需要根据实际硬件上的地址引脚设置来定义常见默认值是类似 0x48 这类地址具体要查阅数据手册。远程温度寄存器地址一般在本地温度寄存器之后读取方式完全相同。读到的是原始码值不是可以直接用的摄氏温度。换算方式通常是把整型数据右移规定的位再乘以 LSB 对应的温度增量。比如 12 位分辨率下每个 LSB 代表 0.0625 摄氏度那么真实温度就是(raw_temp_val 4) * 0.0625。要注意有符号数的移位在 C 语言里最好使用int16_t类型并且逻辑右移后再乘避免负数温度被错误转换。3.3 温度数据的平滑处理与变化率控制直接读取的温度值会有几项噪声来源远程探头引线接收的电磁干扰、传感器内部 ADC 的量化噪声以及 HVAC 设备启停瞬间造成的电源波动。如果直接把原始读数丢给控制逻辑阀门和风机就会频繁抖动室温稳定不下来控制输出也会产生磨损。我习惯在读取之后加一层一阶低通滤波代码实现如下#define FILTER_ALPHA 0.2f static float local_temp_filtered 0.0f; static float remote_temp_filtered 0.0f; void update_temperature_filter(float local_raw, float remote_raw) { local_temp_filtered FILTER_ALPHA * (local_raw - local_temp_filtered); remote_temp_filtered FILTER_ALPHA * (remote_raw - remote_temp_filtered); }这个FILTER_ALPHA可以根据采样周期调节。采样越快alpha 可以取得越小让滤波更平滑。如果希望温度显示响应更快alpha 可以调大。我通常在试机时先看原始数据和滤波数据的曲线再确定最终值而不是拍脑袋定一个数字。除了低通滤波我还会计算温度变化率。做法是把最近两次滤波值的差值除以采样间隔得到每秒变化多少度。变化率数据很有用HVAC 控制里可以用它来判断房间是正在快速升温还是已经趋于稳定从而提前调整输出而不是等到温度已经越过阈值才响应。3.4 用 ALERT 引脚和中断提升越限响应速度轮询方式的响应时间等于采样周期在某些保护场景下可能不够快。毕竟如果远程温度因为探头故障或者现场异常突然飙升最好立刻停下来做保护处理。我这里把 PJ85718DM 的 ALERT 引脚连接到了 STM32 的外部中断。当温度超过预设上限或低于下限时传感器硬件会自动置位报警输出MCU 的外部中断伺候函数立即被执行。里面只做一个最小处理设置一个报警标志然后让主循环尽快进入故障处理逻辑。不要在中断里做复杂计算避免阻塞其他高优先级任务。这个设计让系统同时具备两种响应能力常规定量控制靠周期轮询和滤波极端异常靠硬件中断快速介入。对于 HVAC 控制器来说这种“软硬结合”的响应机制是防止现场设备损坏的重要保障。4. 面向 HVAC 场景的功能增强与现场适配4.1 传感器故障检测与冗余策略HVAC 设备长期运行远程探头断线、短路、接触不良都是会发生的问题。固件不能假设传感器永远在线必须把故障检测当成一项常规功能。传感器状态寄存器里一般会有远程开路、远程短路、本地传感器故障等标志。我这里推荐一个最简单的故障判断规则读到的温度状态可能的故障原因固件处理策略远程温度超出量程上限远程探头开路或引线断标记远程故障进入防冷防热保护远程温度低于量程下限远程探头短路或接反标记远程故障切换到备用测点本地温度异常跳变芯片内部故障整体重启传感器或使用看门狗复位状态寄存器显示传感器错误芯片内部转换异常重新初始化传感器仍失败则告警如果系统里有第二个测点或者第二颗传感器可以做简单冗余。主传感器连续三次读取异常后自动切换备用通道同时产生报警供维护人员处理。不要让系统因为一个探头坏了就完全停摆也不要瞒着故障继续盲目控制。这种“带病运行 明确告警”的方式更符合 HVAC 设备的工程实际。4.2 现场安装造成的测量偏差如何校准传感器即使在实验室里很准确装上设备后也可能偏离真实环境温度。原因很常见控制器贴在墙面墙体温度比空气低传感器离回风口很近空气流速高导致散热强又或者控制箱内部发热严重让整个控制器外壳都偏热。工程校准不适合只做硬件层面的简单调零我用软件方式落地在接线端子附近预留标准温度计插孔然后在两个温度点做两点校准算出增益和偏移量写进固件的配置参数。typedef struct { float gain; float offset; } CalibrationParam; float apply_calibration(float raw_temp, CalibrationParam param) { return param.gain * raw_temp param.offset; }两点校准的做法是在设备安装现场让室内处于一个稳定的较低温度状态记录传感器读数 T1 和标准温度计读数 S1再人为把房间升到另一个稳定温度记录 T2 和 S2。然后计算gain (S2 - S1) / (T2 - T1); offset S1 - gain * T1;这套修正逻辑调试起来很直观比在数据手册里填偏移寄存器更灵活而且可以按不同安装位置单独设置参数。校准参数要保存在外部 EEPORM 或 Flash 参数区不能写成死代码否则现场设备每台都要重新编译固件维护成本太高。4.3 温控策略如何结合本地和远程温度有了本地和远程温度HVAC 控制就比单纯用一个传感器丰富很多。最基础的逻辑是用远程温度做环境温度控制本地温度做设备保护。举个例子远程回风温度达到设定值就降低风机档位本地温度过高就触发散热策略或者降低输出功率防止控制板长期处于过热状态。稍微复杂一点的做法是用本地温度补偿远程测量的动态误差。某些现场远程探头处于空气流速很低的位置温度响应慢半拍而控制器外壳的本地温度变化却能更快反映房间升温趋势。我做过一版策略用本地温度变化率作为前馈信号当本地温度已经快速上升而远程温度还没跟上时提前减少制冷输出避免过冲。效果很直观但需要根据现场调试系数不能盲目套用。控制算法的核心是把两个温度看作可用的状态量而不是彼此替代的关系。只要物理含义明确对应策略清晰即使代码不复杂系统表现也能比单点温控扎实很多。这也是这套方案的最终价值所在。5. 调试过程中踩过的几个比较深的坑5.1 I2C 总线锁死与强制恢复第一次调试传感器时经常出现的现象是程序跑了几分钟后I2C 总线彻底卡住所有读写都超时。用示波器一抓发现 SDA 线一直低电平SCL 时钟还在跳这就是 I2C 总线被从机拉死的典型表现。原因多半是传感器在主控复位期间收到了不完整的传输从机内部的位状态机卡死在中间状态。解决方式有两个第一个是在初始化传感器之前先手动把 SCL 线翻转 9 个时钟周期把从机状态机强制释放第二个是在硬件上给传感器加独立的电源控制引脚I2C 卡死时直接断电重启传感器。软件释放代码可以参考void recover_i2c_bus(void) { GPIO_InitTypeDef gpio; // 手动把 SCL 九次翻转释放从机 for (int i 0; i 9; i) { HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_RESET); delay_us(5); HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, GPIO_PIN_SET); delay_us(5); } }这个坑在批量设备现场更容易发生因为现场继电器动作产生的电源瞬变比实验室频繁得多。加了这个恢复逻辑后即使偶尔出现总线异常系统也能自行恢复不用派人去断电重启。5.2 PCB 布局让本地温度读数整体偏高有一版打样回来把 PJ85718DM 放在 MCU 正下方离一个低噪声的 DC-DC 电感太近。结果发现本地温度读数比室温高 12 度而且无论怎么校准都压不下去。这个不是芯片的问题是板级热耦合问题电感、MCU 和传感器在同一个热区域里热量通过 PCB 铜皮直接传到了传感器底部。解决办法有几个方向。最直接的是把传感器挪到远离热源的板边位置最好是主板的角落并且下方不布置大电流走线。很多芯片的底部焊盘也承担散热功能如果不想让板温影响测量可以考虑在传感器下方的 PCB 铜皮上做开槽处理切断热传导路径或者在 PCB 设计时单独挖掉一块铜区域。这类问题还有个排查技巧用红外热成像仪看整板温度分布可以直接找到热源和热量扩散路径。没有热成像仪的话可以把传感器芯片悬空用引线连到板上对比悬空读数和贴板读数的差异同样能判断是不是受到了板级热影响。5.3 远程探头引线造成的毛刺读数在某个测试场地远程探头从控制器走线到风管途经 2 米双绞线。设备一启动温度读数就会出现周期性跳动波动幅度接近 1.5 度。这个现场里有电机启停和继电器通断电磁干扰相当严重。我先加了共模滤波电容改善不明显又换成屏蔽双绞线把屏蔽层单端接地之后毛刺才明显减少。所以如果现场存在强干扰不要把希望全寄托在软件滤波上硬件屏蔽是根本。软件层面也补了一道中值滤波连续取 5 个采样点去掉最大最小值对中间三个取平均。虽然增加了一点采样开销但远程温度读数变得很干净。实际项目里我通常把“硬件屏蔽 软件滤波”一起用两者缺一不可。5.4 固件可观测性不足导致的定位困难还有一个我比较后悔的坑是早期版本没有把调试信息完整打出来。传感器读到的原始码、滤波值、状态寄存器、报警标志全都闷在固件里设备在现场出问题时只能靠猜。后来我把 UART 调试口做成一个简单的命令行接口输入temp命令就能打印所有相关信息输入cal就能临时修改校准参数。这个工具帮了大忙现场工程师不用拆外壳直接连串口线就能拿到内部数据。如果项目里已经有 RTOS 或者主控有网络接口还可以把这些数据通过日志系统上传。调试接口看起来不起眼但对工程化设备来说是实打实的生产力工具。6. 后续还可以往哪个方向扩展这套本地/远程温度监测框架稳定之后扩展的方向非常清晰。第一把多台控制器的温度数据汇聚起来。STM32F745ZG 自带丰富通信外设可以通过 Modbus RTU 或者 CAN 把各台控制器的本地温度和远程温度发给集中监管平台。这样可以很直观地在总控室看到各区域温度分布和故障点位。第二引入无线遥测。部分 HVAC 项目现场不适合重新布线可以用低功耗无线模块把远程温度探头的数据传回控制器只需要在固件里增加一路无线接收数据的输入通道与有线通道做统一处理。第三在算法层做得更智能。当前代码主要做的是滤波、变化率计算和简单 PID。后续可以基于远程温度和本地温度的组合结合湿度、风速等参数做一些舒适度模型实现更精细的节能控制。STM32F745ZG 的算力完全够跑这些算法不需要更换主控。最后分享一个特别实用的小习惯把所有温度换算和校准逻辑单独封装成一个模块不跟具体传感器型号的寄存器操作混在一起。这样以后哪怕换成别的温度传感器只要改底层寄存器层上层控制、显示、告警代码基本不用动。对长期维护的项目来说这种分层思路能省下大量时间。如果你正要搭一套类似的双温度采集系统建议先把本地温度和远程温度的物理边界想清楚再动手画板子写代码。硬件确定了软件框架理顺了剩下的就是耐心调校和现场验证了。