做嵌入式控制板的人多半都有过这种经历:传感器布了一堆,结果真正想用的那一路温度总是不对;要么是因为探头离发热源太近,要么是长线拉过去噪声串了一路。PJ85718DM 这颗双通道温度传感器配合 STM32F303ZE,倒是把“本地温度”和“远程温度”这两件事理得比较干净。所谓本地,就是传感器芯片自带测温点所处的环境温度;所谓远程,则是通过延长接线放在远端测温点的探头所读到的温度,比如 HVAC 风管里的送风温度,或者机柜功率模块表面的温度。这篇内容就围绕这套组合,把硬件接法、底层驱动、滤波处理和现场校准的思路完整梳理一遍,适合正在做嵌入式控制器、暖通空调电控或者设备状态监测的朋友参考。
1. 为什么本地温度要留一份,又要多测一路远端温度
很多项目最开始只测一个温度点,比如只关心风管里的送风温度,或者只关心控制板附近的环境温度。但实际跑起来就会发现问题:现场故障往往同时混合了两个信号源,一个是设备自身环境的变化,一个是远端监测点真实状态的变化。没有本地通道当作参照,碰到远端读值异常时,很难判断到底是探头坏了,还是周围环境本身就出了问题。
HVAC 系统里最典型的例子就是空气处理机组。控制器放在电控柜内,柜内散热风扇、开关电源、继电器都在发热,柜内温度可能比机房环境高出好几度。你真正要控制的却是风管内的温度,这必须靠远程探头去测。如果只盯着柜内温度做控制,送风温度和回风温度都会失控;如果只盯着风管温度,控制器自身过温时又无法及时发现。两个温度都留在系统里,才能做出正确的判断:哪个温度影响了设备的保护动作,哪个温度用于控制回路。
嵌入式系统里也是类似逻辑。以机箱内的主板为例,PJ85718DM 的本地测温点用来反映电路板微环境温度,远程探头则贴在功率器件或外部电池包上。功率器件的温度变化速度可能远快于主板环境温度,并且两者之间有热阻隔离。一旦本地温度比远程温度高很多,通常说明是通风或者散热设计不足,而不是负载过大;反过来,远程温度快速拉升而本地温度正常,则多半是负载端异常。这样“一快一慢、一近一远”的配合,排查问题会舒服很多。
1.1 本地与远程在术语上的真正含义
不少第一次用这类芯片的开发者会把“远程”理解成 TCP/IP 或云端的远程监控,其实在硬件层面,这里的远程指的是信号线引出去的远端探针。PJ85718DM 这类双通道温度传感器,内部包含一个本地测温单元,同时预留了一组外部探头接口,通过读取对应的寄存器,能同时拿到“芯片自己所在位置的温度”和“外部探针所在位置的温度”。
本地测量通常依赖芯片内部的热敏元件,它反映的是 PCB 附近的热状态,响应快但容易受到板上局部热源的影响。远程测量则是通过外部探头来实现,常见探头可以是二极管、热敏电阻或热电阻,具体取决于这颗芯片支持的接口类型。把探头接到需要监测的物体表面,就可以避开主板上各种发热元件的干扰,获取更接近真实工况的温度。
由于本地和远程两个通道的物理原理不同,它们的精度、响应速度和对噪声的敏感程度也不完全一样。本地通道的走线短,受干扰小;远程通道要经过一段外部引线,这段引线的材质、长度、屏蔽方式,都会直接影响最终读数质量。理解了这一点,后续做布线和校验时就明白为什么不建议拿细长的普通杜邦线去接远程探头了。
1.2 为什么这套组合适合同时兼顾 HVAC 与嵌入式
STM32F303ZE 本身具备比较丰富的外设资源:多个 I2C 接口、多路 ADC、多个串口,还有不错的中断响应能力。PJ85718DM 通过 I2C 总线连接微控制器,整个系统只需要两根信号线加电源线,对 PCB 面积敏感的控制板来说很友好。F303ZE 的处理能力用来做温度轮询、滤波、报警状态机以及对外通信都有余量,所以即便后续需要接多路探头、增加数据显示,也不会编程很吃力。
另一个优势在精度与速度的平衡点。HVAC 控制系统通常不要求每毫秒更新一次温度,但在冷库、恒温恒湿等应用中却要求长期稳定;嵌入式功率设备的保护则要求响应足够快,以减少器件过热损坏的风险。PJ85718DM 允许通过配置寄存器和滤波策略来调整更新频率与响应速度,F303ZE 则负责按不同场景选择不同的参数组合。两者配合起来,既能在舒适性空调里把温度波动控制在很小范围,也能在功率模块保护时及时触发阈值。
对于研发阶段的调试,F303ZE 的调试接口也很方便。可以直接通过调试器观察 I2C 总线上的寄存器值,也能在代码里设置断点检查每一路原始温度,这对校准和排障都有帮助。
2. 最小硬件系统:从四个引脚到两线总线
PJ85718DM 接 STM32F303ZE 的硬件其实非常精简。常规设计只需要四根线:VDD、GND、SDA、SCL。如果是研发初期的面包板或转接板方案,甚至只需要把传感器小板放到目标位置附近,再拉一组排线到 MCU 板即可。
不过,硬件精简并不意味着可以掉以轻心。越简单的接口,越容易在细节上出问题。下面按最小系统、远程探头布线、PCB 摆放三个层次说明。
2.1 电源退耦与 I2C 上拉电阻
PJ85718DM 的供电通常支持 2.7V 到 5.5V 区间,因此既可以由 STM32F303ZE 所在的 3.3V 系统供电,也可以接入 HVAC 控制板常见的 5V 电源轨。无论用哪一路供电,靠近芯片电源引脚处必须放一个 0.1μF 的陶瓷电容,用于高频退耦。如果传感器离 MCU 较远,最好再并联一个 10μF 电容,避免长走线引入电源跌落和噪声。
I2C 总线是开漏结构,所以必须在 SDA 和 SCL 上分别接上拉电阻。对于通常的 400kHz I2C 通信速率,两个 4.7kΩ 上拉电阻接 VDD 是比较稳妥的常见做法。如果总线上的设备比较多,或者走线较长,可以考虑减小到 2.2kΩ,但不要盲目减小,否则上拉过强会让信号边沿变差,反而可能引起通信错误。
下面是一个最小系统接线说明:
- VDD:3.3V 或 5V。
- GND:与 MCU 共地。
- SDA:接到 STM32F303ZE 的 I2C1_SDA 引脚,外部 4.7kΩ 上拉。
- SCL:接到 STM32F303ZE 的 I2C1_SCL 引脚,外部 4.7kΩ 上拉。
只要这四个点的连接正确,则第一步“读回温度寄存器”的硬件基础就有了。PJ85718DM 的从机地址通常由 ADDR 引脚的高低位配置决定,常见地址区间在 0x48 到 0x4F 之间,实际值以器件资料中的地址跳线对照表为准。为了避免同一总线上多片冲突,不同板卡上的地址跳线要错开配置。
2.2 远程探头的引线选择与线长控制
远程温度探头的引线是整个系统里最容易踩坑的地方。短距离实验时,用几厘米的排线没有任何问题;但到了实际机柜或风管安装场景,探头到主板之间的距离可能达到 1 米甚至 5 米以上,这时就必须考虑引线电阻和外部干扰。
远程探头建议优先使用双绞线,最好再加上一层屏蔽层。双绞线可以抵消一部分电磁耦合,而屏蔽层则能阻挡变频器、继电器等强干扰源产生的尖峰噪声。屏蔽层选择单端接地,通常接到控制板的 GND 或屏蔽接地点,不要两端都接,否则会形成地环路,反而把噪声引入信号回路。
接线长度方面,几百毫米到数米的范围内,只要探头输入阻抗足够,一般问题不大。需要特别注意的是接线端子:尽量选择螺丝式端子或压接端子,避免使用焊接不牢靠的插簧端子。实际项目里最常见的“远程温度偶尔跳到 -40°C”故障,追查到最后往往是远程探头的接插件氧化或松动。
另外,远程探头引线要避开继电器输出线、交流电源线等强电回路。如果无法避开,交叉时要尽量保持垂直走向,并行距离越长越容易耦合噪声。
2.3 PCB 布局与热扰动控制
本地通道虽然只测芯片周围温度,但 PCB 布局会影响测量结果是否贴近真实环境。设计时不要把 PJ85718DM 紧挨着 DC-DC 电感、功率电阻或 MCU 主控芯片,这些局部热点会使本地读数偏高数度。最佳位置是放在板边、通风路径上,或者与待测环境温度更接近的区域。
如果同一块板上还使用了网络变压器、开关电源模块等发热大户,可以考虑在传感器下方铺一小片接地铜箔,而不是直接把传感器放在大散热铜皮中央。过大的铜皮会把其他器件的热量导到传感器下方,让本地读数失真。
远程探头的接插件放在 PCB 边缘也更合理。这样外部探头引线可以就近接入,不会跨过整块板子去绕远路。绕线的路径长了,既增加了噪声拾取面积,也让维护人员不容易看清接线位置。
3. 固件层温度数据链路:轮询、滤波与温度转换
硬件焊接完成之后,紧接着就是让 STM32F303ZE 把 PJ85718DM 的数据读回来。固件部分的重点工作有三个:初始化并确认 I2C 通信、正确转换寄存器数据、以及对原始读数做必要的滤波。
3.1 I2C 初始化与设备地址探测
以 STM32F303ZE 的 I2C1 为例,在初始化代码中需要配置 GPIO 复用功能为开漏模式,并设置合适的时钟频率。使用常见驱动代码可以简化为:
/* I2C1 GPIO 配置 */ GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_I2C1_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; /* PB6=SCL, PB7=SDA */ GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* I2C 外设配置 */ hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; /* 100kHz,远距离更稳 */ hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0x00; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(&hi2c1);初始化之后,第一步不是急着读温度,而是先确认设备在线。我习惯在启动时做一个设备探测:
if (HAL_I2C_IsDeviceReady(&hi2c1, PJ85718DM_ADDR, 5, 100) == HAL_OK) { sensor_online = 1; } else { sensor_online = 0; }这一步虽然简单,但带来的价值很大。它能快速区分“温度读不出来”是硬件接线问题还是寄存器读取问题。如果设备探测失败,优先检查电源、地址引脚和 SDA/SCL 是否接反。
3.2 寄存器读取与 0.1°C 分辨率转换
温度数据的读取方式一般是这样:先向器件写入温度寄存器地址,再连续读取对应字节。PJ85718DM 通常会输出多字节的温度数据,其中本地温度和远程温度各有独立的寄存器地址空间。为了兼容不同型号的寄存器映射,最好的办法是定义一个抽象层,把“读本地温度”和“读远程温度”封装成两个函数。
一个常见的读取流程可以用伪代码表示:
uint8_t raw[3] = {0}; uint8_t reg = PJ85718DM_REG_LOCAL; HAL_I2C_Master_Transmit(&hi2c1, PJ85718DM_ADDR, ®, 1, 100); HAL_I2C_Master_Receive(&hi2c1, PJ85718DM_ADDR, raw, 2, 100); int16_t val = (raw[0] << 8) | raw[1]; if (val < 0) val += 0x2000; /* 处理可能的补码符号位 */ float temp_local = val * 0.0625f;如果器件输出的是 8 位整数温度加 4 位小数的方式,则转换系数会不一样。以 0.0625°C 分辨率为例,每一位 LSB 对应 1/16 摄氏度,所以读取到的 12 位二进制数值乘以 0.0625 就是实际温度。若器件手册定义 0.1°C 分辨率,就把系数改成 0.1。
有一点需要提醒:不同寄存器地址返回的数据格式不同,远程通道往往是 12 位或 13 位数据,本地通道有可能是 10 位数据。如果统一用同一种转换系数,在小数位上会出现偏差。因此一个保险的做法是把“字节拼接”和“数据格式转换”分别封装,只有拿到器件手册确认各通道位数后,才填上正确的系数。
3.3 滤波与斜率防抖
单纯的原始值直接用于控制回路很容易造成输出抖动。尤其是远程探头经过长线接入时,读数在小数位上来回跳是很正常的现象。这时就要在 MCU 内部做数字滤波,但要注意不能把滤波做得太狠,否则传感器真实变化也被抹平了。
我比较常用的一阶惯性滤波方式如下:
/* 简单的 EMA 滤波,alpha = 1/16 */ float ema_local = 25.0f; float raw_local; float next_ema(float current, float raw) { return current + (raw - current) / 16.0f; } /* 每次采样到新温度后调用 */ ema_local = next_ema(ema_local, raw_local);为什么要用 1/16 而不是 1/2?1/16 能明显压住高频抖动,同时又能在一两秒内跟随上 HVAC 场景中缓慢变化的温度。如果做功率器件保护,1/16 可能偏慢,可以动态切换滤波系数,在报警阈值附近使用更快的响应。
除了滤波,还需要做斜率检测,也就是判断温度变化速率。正常 HVAC 场景中,温度在短时间内不会出现超过每秒钟 0.2°C 的突变;如果固件发现类似“每秒跳了 5°C”的现象,多数情况下不是真实温度变化,而是远程探头接触不良、短路或通信数据产生了瞬时空洞。比较稳妥的做法是将该次采样标记为可疑值,用上一次有效值替代,并在状态寄存器里置一个警告位。
需要注意的是,斜率检测不能简单保留旧值太多次,否则一旦真实故障导致温度持续快速上升,系统会一直用旧值掩盖问题。合理的策略是连续三次可疑值后,就把状态从“正常”切换为“数据异常”,并停止使用该通道做控制决策。
4. HVAC 场景与嵌入式场景的差异化配置
同样的硬件,在不同的应用场景中,轮询周期、滤波参数和报警阈值可能是完全不同的。如果直接拿 HVAC 模板套到嵌入式功率保护上,或者反过来套,都会出问题。
4.1 暖通场景:采样周期与安装隔热
HVAC 应用里的温度对象通常是风管内的空气温度或水系统里的水温。这类对象的热惯性很大,温度变化以分钟甚至十分钟为尺度,所以没必要用很高的采样频率。采样周期放在 1 秒左右已经足够,甚至在多数楼宇控制应用中,2 到 5 秒更新一次也完全能接受。
由于采样频率低,滤波可以适当加强。比如把 EMA 的系数从 1/16 改成 1/32,这样能进一步抑制噪声,又不会对风温控制产生可感知的延迟。报警阈值也应当考虑环境温度的缓慢漂移,比如风机盘管回风温度设定为 26°C 时,建议设置成 28°C 报警,而不是 26.5°C 就频繁报警。
安装层面上,远程探头要稳妥地固定在风管或水管表面。很多现场人员会用绝缘胶带把探头缠在管道外壁,这样测到的其实是管壁温度,和内部流体温度存在偏差。正确做法是使用带有导热硅脂的探头固定件,让探头与管壁充分接触,并在外部包裹保温棉,减少环境温度对管壁读数的干扰。
本地通道在暖通项目里也不单纯是摆设,它常常用来监控控制箱内部过温。由于柜内器件发热,本地温度通常会比风管温度高,这个差值可以用作控制器散热性能的长期监测指标。比如某个柜子刚投用时本地温度比远程低 2°C,用了半年后变成高 3°C,那就说明柜内积灰或散热风扇老化,应该安排巡检了。
4.2 嵌入式场景:快速响应与噪声抑制
与 HVAC 不同,嵌入式系统里的功率器件温度可能因为负载变化在几秒钟内迅速升高。采样周期建议控制在 100 毫秒到 200 毫秒之间,滤波器也要保持较快的跟随能力。EMA 系数可以增加到 1/4 或 1/2,宁可多接受一些噪声,也要保证温度突变时能及时看到。
噪声抑制不能只靠滤波。嵌入式系统中往往有高速数字信号、PWM 驱动信号、电机驱动等干扰源。远程探头线在这种环境里的布局比软件滤波更重要。如果硬件位置已经固定但噪声仍然明显,可以在信号线上并一个小电容,比如几十皮法的陶瓷电容,但要注意 RC 滤波会延缓信号响应,过大的电容会让温度响应变慢,需根据实际调试结果取舍。
报警策略建议采用“一级预警 + 二级保护”的方式。一级预警只记录数据和点亮报警灯,不切断输出;二级保护才真正触发停机或降功率。触发阈值要参考器件规格书,并预留余量。比如功率器件最大允许 150°C,一级预警在 125°C,二级保护在 135°C,既留出了处理时间,又不会因为温度瞬间抖动而频繁停机。
在嵌入式项目中,本地温度常常被用来做电路板环境参考。如果发现 MCU 附近环境温度并不高,而功率器件温度飙升,说明热阻路径可能出了问题;如果两块温度同时飙升,大概率是柜内整体散热失效。这个规律在排查变频器、伺服驱动类设备时非常有用。
4.3 数据出口:串口帧与参数上报
温度采集最后总要输出给上层控制器或监控平台。STM32F303ZE 上有多个串口可用,在 HVAC 系统中常见的方式是定期把本地温度和远程温度按固定帧格式发送出去,再由协议网关转换成标准总线协议。
一个简单的串口帧格式可以设计成:
| 字段 | 长度 | 说明 |
|---|---|---|
| 帧头 | 1 字节 | 固定值 0xAA |
| 地址 | 1 字节 | 设备地址或通道号 |
| 本地温度 | 2 字节 | 有符号整数,单位 0.01°C |
| 远程温度 | 2 字节 | 有符号整数,单位 0.01°C |
| 状态 | 1 字节 | 故障/正常标志 |
| 校验 | 1 字节 | 累加和或 CRC8 |
把温度数据先放大 100 倍再发出去,可以保留小数精度,又避免收发双方为了小数点位而约定不一致。状态字节里如果检测到远程探头异常,就可以直接置位,上层收到后可以立即提示维护人员检查探头接线,而不需要等到温度值明显异常才被发现。
如果项目要求走实时总线,也可以直接用 F303ZE 的 CAN 外设或者加一颗串口转接芯片,把上述帧封装到对应的交通方式中。底层温度采集代码不需要大改,只需要把“输出”部分的接口从串口抽象成通用发送函数。
5. 校准与排障:零星漂移、长线跳数,怎么摸清规律
说实话,最费时间的往往不是写驱动,而是现场排障和校准。温度传感器本身出厂精度一般都不错,但在系统层面,受引线电阻、局部发热、装配接触等因素影响,最终读数和真实温度之间总会有偏差。下面把这些常见问题按“校准方法、远程探头故障、上电检查顺序”三个方面展开。
5.1 固定点校准与双通道偏差修正
如果现场有条件,最简单的校准方式是用一个稳定的已知环境温度做对照。比如把远程探头和参考温度计同时放在同一个恒温空间中,等待读数稳定后,记录两者的差值,将这个差值写入固件的偏移量修正中。
固定点校准更严谨的做法是用冰水混合物做 0°C 参考,再用沸水或恒温槽做另一个温度点参考。实际操作时,将探头封装在不透水的保护管内,放入冰水混合物中,等待 3 到 5 分钟稳定后,记录读数。然后再放入恒温槽,记录第二个点的读数。通过两点线性修正,可以把传感器在量程中段的非线性误差显著拉低。
代码层面上,可以在转换函数中加入修正参数:
float corrected = raw_temp * slope + offset;其中slope和offset在校准过程中计算得到。两点校准的计算公式很简单,这里不展开,但需要提醒的是:如果在 0°C 和 50°C 两个点做校准,那么修正只在 0 到 50°C 范围内有较高置信度,超出这个区间后会外推,未必准确。
本地通道与远程通道也要分别校准,不能共用一个修正值。原因在前文说过,本地通道测的是芯片内部温度,受 PCB 热影响;远程通道测的是远端探头,受引线电阻和探头个体差异影响。忽略这一点,会导致两个通道在同一环境下显示不同温度,增加现场误判的概率。
5.2 远程探针线材问题:噪声与接触热阻
远程温度读数不稳定,最常见的故障表现有两种:一是读数每隔几秒就跳几度,二是读数一直偏低或偏高。前者多半是干扰或接触不良,后者多半是线阻或探头与被测表面接触不好。
干扰性跳数在示波器上可以看到远程引脚上的高频毛刺。处理方法是换屏蔽双绞线,并将屏蔽层单端接地。同时检查是否与强电回路距离过近,如果布线已经固定,可以在线上加磁环抑制高频噪声,或者把 I2C 时钟降到 100kHz。
接触热阻问题从电信号上看很难察觉。远程探头如果只是贴在功率器件表面,中间留了空气隙,那么读数会明显低于表面真实温度。这种情况在 HVAC 里也很常见,比如探头用扎带绑在铜管上,接触面积很小,导致读数跟随性变差。解决方法是使用固定耳片或卡簧,配合导热硅脂填充接触空隙,必要时用聚酰亚胺胶带或固定胶做好机械固定。
另一个容易忽略的点是端子氧化。用了几年的控制柜,接线端子表面会产生氧化层,造成接触电阻时大时小。远程通道对这种变化尤其敏感,故障现象是在某次维护之后温度读数忽然变得异常,但实际上接线没变,只是端子的氧化状态发生了变化。重新剥线、清洁端子、压接牢固后,读数通常就能恢复正常。
5.3 上电检查顺序与现场必备工具
现场如果遇到温度读取失败,我建议按固定顺序逐项排查,而不要两头乱动。
第一步,用万用表测量 PJ85718DM 的 VDD 和 GND 电压,确认供电正常,浮空或电压跌落都可能导致设备不响应。第二步,测量 SDA 和 SCL 在静止状态下的电压,正常情况下应被上拉到高电平,如果接近 0V,说明总线被拉死,很可能有设备挂死或上拉电阻缺失。第三步,用 I2C 扫描程序确认设备地址是否能在总线上被枚举到,这一步能过滤掉大部分地址配置错误。第四步,读取状态寄存器和原始值寄存器,确认器件确实返回了一段合理范围内的数据,而不是全 0 或全 1。
为了在现场做这些检查,提前在固件里预留一个“寄存器读取诊断命令”会非常方便。通过串口发送一条调试指令,就能把设备在线状态、本地原始值、远程原始值、滤波后数值、状态标志一次性打印出来。这个命令平时可以留在代码里不删,甚至可以在正式固件中永久保留,只要保证外部无法轻易触发即可。
另外,不要忽略电缆长度对总线时序的影响。如果传感器放置位置离 MCU 超过一二十厘米,建议把 I2C 时钟配置为 100kHz 而不是默认的 400kHz。虽然速度慢了一点,但温度采集本身并不要求高吞吐量,稳定反而是更重要的指标。
就这套系统而言,我自己的习惯是在首次调试阶段全程开着一个串口监视器,通过简单的命令行查看温度原始值、滤波值和状态位,顺手记录半小时数据。磨刀不误砍柴工,把这些基础工作做完,后续无论是做控制算法还是做远程监控,都不用再回头折腾底层问题了。