在嵌入式项目里摸爬滚打久了,你会发现一个很有意思的现象:很多看似高端的“温度监测”,真正拆开看,需求其实就两件事——一是把探测点上的温度变成数字,二是把这个数字送到该去的地方。“本地”和“远程”这俩词听着玄乎,落到硬件上往往就是一颗传感器的两个通道、一颗主控的一次总线访问。我自己在做HVAC和嵌入式设备方案时,反复对比过好几类测温方案,最后在某个控制器改造项目里定下了一套特别顺手的组合:PJ85718DM做前端测温,STM32L432KC做采集与上报。
这套东西干的事情说简单也简单:PJ85718DM支持本地结温测量,同时还能通过D+/D-引脚外接一个远端PN结探头,一颗芯片同时拿到两路温度。STM32L432KC负责配置传感器、读回原始数据、做滤波处理,再通过串口或者后续扩展的无线模块把结果送出去。对嵌入式热管理、HVAC管道温度、设备柜内环境监测这类场景,这套方案很能打。下面的内容会拆开讲清楚每个环节的思路、寄存器配置、实际测量数据和调试时遇到的坑。
1. 需求拆解:一块芯片怎么同时管“本地温度”和“远程温度”
1.1 标题里的“本地”和“远程”到底指什么
我接触到这个需求时,现场提出的要求就是“控制柜里要测一个环境温度,风管深处还要测一个介质温度”,这两个测温点相距好几米。最初大家第一反应都是装两个独立传感器,一个放柜子里,一个埋风管里,然后拉线到主控板。这方案本身没毛病,但实际一算账问题就来了:第二个传感器要占一路I2C或者1-Wire总线,拉线距离长了信号质量会变差,还得单独处理供电和地线压差。
后来我把目光放到PJ85718DM这类带“本地+远端”双通道测温的芯片上,思路马上就通了。这里的“本地温度”是芯片自身结温,实际反映的是芯片所在PCB位置附近的温度;“远程温度”是通过D+/D-引脚接入的外部PN结产生的温度信号,可以把这个PN结用引线延伸到几米外的探测点。就是说,一颗芯片放在控制柜里,它自己测柜内环境温度,同时把远端探头埋在风管里测管道温度,两路数据一起往回传。
再往大里说,远程温度在系统层面还有第二种实现方式:多颗PJ85718DM挂同一条I2C总线上(通过A0/A1地址引脚区分),各自带一个远端探头,由STM32L432KC统一汇总。这种方式特别适合几十个测点的HVAC楼宇自动化场景。一套方案从单点覆盖到多点,扩展起来不用换主控和总线架构。
1.2 为什么是PJ85718DM加STM32L432KC这套组合
先说传感器端。PJ85718DM是数字输出,I2C接口,温度数据直接以二进制补码形式放在寄存器里,不用像NTC热敏电阻那样另外做查表和线性化。它的测量精度,本地典型能做到±0.5°C,远端通道看探头质量,工程上控在±1.5°C以内问题不大。这些指标对嵌入式保护和HVAC控制完全够用,甚至富余。
更关键的是它的远端测温原理。它内部会产生两组不同的偏置电流去激励外部PN结,测量两种电流下的基极-发射极电压差(ΔVbe),再换算成绝对温度。这个原理让远端探头可以用廉价的通用小信号三极管实现,只要把三极管的基极和集电极短接就当二极管用。这就比传统的Pt100、热电偶方案便宜得多,而且不需要冷端补偿和恒流源电路,传感器集成度直接拉满。
主控端选STM32L432KC,看中的是几点。第一是低功耗,这是L系列的核心卖点,STOP模式电流能到微安级别,配合PJ85718DM的关断模式,电池供电的无线测温节点一年换一次电池完全可行。第二是性能不弱,Cortex-M4F,80MHz主频,做温度滤波、阈值判断、协议解析都绰绰有余。第三是封装紧凑,比如UFQFPN32封装用在空间紧张的控制板里很合适。综合下来,这组合的物料成本比传统“铂电阻+调理电路+ADC+MCU”低一大截,调试工作量还小得多。
1.3 适用场景与影响范围快速扫描
| 应用领域 | 典型测温点 | 本地通道用途 | 远端通道用途 |
|---|---|---|---|
| 嵌入式电源模块 | PCB环境、功率MOSFET散热器 | 判断电路板环境温度 | 贴装功率管,做热降额和过温保护 |
| 工业控制器柜 | 柜内空气温度 | 柜内环境监控 | 柜内某个发热元器件表面温度 |
| HVAC空调系统 | 风管送风温度、回风温度 | 控制器盒内温度 | 风管内介质温度,参与PID调节 |
| 楼宇自控节点 | 多个房间温度 | 节点本地温度 | 远端房间/管道温度探头 |
这套测温方案更大的影响在于把“温度采集”和“温度决策”拉近到了同一颗主控里。以前HVAC系统要用传感器采集温度,再通过总线传给楼宇控制器做决策,链路长、延迟高、故障点多。现在STM32L432KC既能采集PJ85718DM的本地和远程温度,又能直接在本地做PID逻辑或者越限保护,还能通过串口把结果主动上传。温度数据的价值被真正就地释放了。
2. 硬件设计:核心细节与选型考量
2.1 PJ85718DM关键引脚与接口电路
芯片和主控的连接电路非常简洁,外围元件少到令人舒适。核心引脚就5个:VDD、GND、SCL、SDA、ALERT(部分封装还有A0和A1地址选择脚)。VDD接3.3V,对电源质量有一定要求。在HVAC设备里,板子上往往有继电器、接触器这类大功率负载,电源噪声特别脏。我的做法是VDD和GND之间并两个电容:一个0.1µF陶瓷电容滤高频,一个1µF电容兜底,两者尽量靠近芯片供电引脚放置。
SCL和SDA是开漏结构,必须接上拉电阻。阻值别拍脑袋选,速率的权衡原则是:总线上拉电阻越小,上升沿越陡,但灌电流也越大。I2C标准模式下(100kHz)用10kΩ很稳;400kHz快速模式建议用4.7kΩ。如果总线上挂了多颗PJ85718DM,总线电容会变高,上拉电阻降到2.2kΩ更保险。我在项目里通常直接按400kHz配4.7kΩ,从没出现过沿太缓导致的通信错误。
ALERT引脚是开漏输出,低电平有效,可以配置成比较模式或中断模式。比较模式下,只要温度越过阈值,ALERT就一直拉低,直到温度回到阈值以内;中断模式下,每次越限只触发一次,需要通过读取状态寄存器或写配置寄存器来清除。硬件上我把ALERT接到STM32L432KC一个带EXTI功能的GPIO上(我用的PA0),这样MCU不用轮询读温度,温度越限瞬间就能从睡眠中被唤醒。
2.2 远端PN结探头:从感知点到芯片的接线设计
远端探头是整个系统里最容易翻车、也最考验基本功的部分。原理上不复杂:PJ85718DM通过D+和D-引脚向外部的PN结注入偏置电流,测量不同电流下的正向压降变化。为了让这个PN结尽量接近“理想二极管”,工程上最好用小信号三极管(比如SOT-23封装的通用NPN)把基极和集电极短接,等效成一个二极管。之所以不用普通的整流二极管,是因为小信号管的结电容小、漏电流低,温度响应的一致性和线性度更好。
探头结构上,我的惯用做法是把三极管用导热硅脂贴在铜块或导热柱上,外面用特氟龙套管保护,做成一个小探头。如果是测量HVAC风管温度,直接把探头插进风管里,用支架固定住,注意不要让探头贴着金属管壁,否则测到的是管壁温度而不是空气温度。
接线是最容易埋雷的地方。D+和D-要用双绞线或者屏蔽双绞线,屏蔽层在靠近MCU的一端单点接地。引线长度我建议控制在3米以内。为什么这么限制?因为PJ85718DM内部虽然有一定抗噪声能力,但引线过长时寄生电容和感应的共模噪声会直接影响ΔVbe测量的信噪比,温度读数会跳得让你怀疑人生。超过3米的需求,更可靠的做法是在远端放一个带PJ85718DM的小节点,节点自己测,数据通过RS485或无线传回,而不是硬拉长探头线。
这里特别提醒:D+接PN结的正极(三极管的基极短接端),D-接负极(发射极),接反了温度读数会乱掉,要么显示一个完全离谱的正值,要么直接报错。我第一批样机就有两套接反的,现象全是远端温度显示在-127°C到-89°C之间跳动,查了两天才发现不是芯片问题,是接线反了。
2.3 STM32L432KC的低功耗与抗干扰设计
STM32L432KC供电我用的是一颗低功耗LDO,3.3V输出,前级是宽压输入(可以兼容HVAC控制器的24V电源)。要注意的是,如果系统里同时存在强电和弱电,一定要先做隔离,测温系统的地必须和继电器驱动的地严格分开,只在单点汇接到电源负极,否则继电器动作瞬间的电流突变会在地线上砸出很大的尖峰,污染I2C和温度信号。
功耗设计上,STM32L432KC的优势能发挥到什么程度,取决于软件怎么配合硬件。我在无线测温节点里用过一个典型调度:MCU进入STOP2模式,关闭I2C外设,PJ85718DM配置成关断模式(shutdown),系统全睡眠电流能做到几微安。每隔15秒由LPTIM定时器唤醒MCU,给传感器上电,等转换完成(13位分辨率典型转换时间320ms左右),读取两路温度,滤波、判定、存储或者上报,再回到睡眠。这样一算,两节AA电池跑一年很轻松。
PCB布局方面,我的原则是“传感器区和功率区坚决分开”。PJ85718DM和STM32L432KC尽量靠近放置,I2C走线短而直。D+/D-的走线在PCB上要平行走,下面完整铺地,两边用地线包围。远端探头连接器的位置要远离继电器、变压器、开关电源的MOSFET区域。如果板子上实在没法避开强干扰源,我建议在D+/D-靠近芯片处并联一个1nF的差模电容,能非常有效地吸收耦合进来的高频毛刺。
3. 软件实现:驱动、滤波与报警逻辑
3.1 I2C驱动与寄存器配置
软件部分从底层I2C初始化开始。我用的是STM32的HAL库,硬件I2C1,引脚配成PB6(SCL)和PB7(SDA),复用功能AF4。I2C时钟配置成400kHz快速模式,关闭模拟噪声滤波反而时常是因为HVAC设备里噪声不轻,所以我会把数字滤波打开,这个选项在I2C_TIMINGR寄存器里能配,HAL库也提供了开关接口。
初始化PJ85718DM的核心是写配置寄存器。我用的样片寄存器映射大致如下:
| 寄存器地址 | 名称 | 说明 |
|---|---|---|
| 0x00 | 本地温度MSB | 12位带符号温度的高字节 |
| 0x01 | 本地温度LSB | 低字节,低4位为0 |
| 0x02 | 远端温度MSB | 12位带符号温度的高字节 |
| 0x03 | 远端温度LSB | 低字节,低4位为0 |
| 0x04 | 配置寄存器 | 转换模式、报警模式、分辨率 |
| 0x05~0x08 | 本地/远端上下限阈值 | 报警用的比较阈值 |
| 0x09 | 状态寄存器 | 各路报警标志位,读取后自动清除 |
配置寄存器我通常写入0x64,含义是13位分辨率、连续转换模式、报警中断模式、ALERT低有效。注意一点:连续转换模式最简单,但功耗大一些;如果走低功耗路线,改成单次触发模式(one-shot),每次读温度前先写一次触发位,等转换完成再读,能省不少电。
初始化顺序我踩过坑,正确的流程是:读取芯片ID寄存器确认器件在位(防止I2C地址配错导致后面所有操作都是对牛弹琴),然后写配置寄存器,再设置本地和远端的上下限阈值,最后读一次状态寄存器把历史报警标志清掉。这个顺序执行完,芯片就进入稳定工作状态了。
3.2 本地和远程温度的读取与滤波处理
读取温度数据本质上就是连续读寄存器0x00到0x03这4个字节。要注意的是,12位分辨率的温度数据存在高字节和低字节里,低字节只有高4位有效,低4位恒为0。拼接时先把16位数据读出来,带符号右移4位,再乘以LSB权重0.0625,就得到了真实的摄氏度值。
给出一段核心读取代码:
#define PJ85718DM_ADDR 0x48 #define REG_LOCAL_TEMP_MSB 0x00 #define REG_REMOTE_TEMP_MSB 0x02 #define REG_REMOTE_TEMP_LSB 0x03 uint8_t pj85718dm_read_regs(uint8_t reg, uint8_t *buf, uint8_t len) { if (HAL_I2C_Master_Transmit(&hi2c1, PJ85718DM_ADDR << 1, ®, 1, 100) != HAL_OK) { return 0; } if (HAL_I2C_Master_Receive(&hi2c1, PJ85718DM_ADDR << 1, buf, len, 100) != HAL_OK) { return 0; } return 1; } float pj85718dm_read_remote_temp(void) { uint8_t msb = 0, lsb = 0; int16_t raw; pj85718dm_read_regs(REG_REMOTE_TEMP_MSB, &msb, 1); pj85718dm_read_regs(REG_REMOTE_TEMP_LSB, &lsb, 1); raw = (int16_t)((uint16_t)msb << 8) | lsb; raw >>= 4; // 去掉低4位无效位 return (float)raw * 0.0625f; // LSB = 0.0625°C }代码本身没什么玄机,真正的功夫在滤波上。HVAC环境里风机启动、继电器吸合、变频器工作,都会在探头线上感应出噪声,让原始温度数据时不时冒出几个离谱的尖峰,比如正常25°C的读数突然跳到-40°C再跳回来。单纯做滑动平均,效果不好,因为一个尖峰能污染一整段均值。
我的做法是两级滤波串联:第一级用5点中值滤波,把窗口内的数据排序后取中间值,专门干掉突变毛刺;第二级用10点滑动平均,平滑正常波动带来的随机噪声。实测下来,本来跳变幅度能到好几度的数据,滤波后能在±0.2°C以内稳定下来。代价是引入了几十秒的响应延迟,但温度本身变化慢,这个延迟对HVAC控制和过热保护完全无所谓。如果确实需要快速响应(比如功率器件热保护),可以把滑动平均窗口缩短到3点,自己权衡。
3.3 温度越限报警与远程上报逻辑
报警逻辑的实现,我强烈建议用ALERT中断而不是轮询。PJ85718DM的ALERT引脚在温度越限时自动拉低,触发STM32的EXTI中断。中断服务程序里做的事很简单:读状态寄存器,判断到底是本地还是远端的哪一路越限,记录下来,然后清标志。
这里有一个容易忽略的细节:状态寄存器一旦读取,报警标志位会被自动清除。如果配置成了中断模式,下次温度越限仍然会触发新的ALERT;但如果配置成了比较模式,读到标志位后ALERT引脚会一直保持低电平直到温度回到阈值内。我在第一次做中断模式时以为读状态清标志就万事大吉,结果第二次越限时发现中断没来——因为我把配置写成了比较模式却按中断模式的逻辑处理。选择哪种模式,一定要和后续状态清除逻辑匹配,否则报警就成了一锤子买卖。
数据上报方面,STM32L432KC的串口自由度很高。最简单的做法是用printf通过UART把本地和远程温度拼成一帧发出去,接一个USB转串口给上位机显示。更工程化的做法是走MODBUS RTU协议,把温度和状态寄存器映射成保持寄存器,让楼宇控制系统直接读。再往后扩展就是无线化,串口接一个低功耗蓝牙或LoRa模块,温度数据周期上报。因为STM32L432KC已经做了本地滤波和报警判定,无线模块只管收结果,逻辑非常干净。
4. 实测记录:嵌入式与HVAC两类场景的数据表现
4.1 嵌入式场景:功率器件表面温度追踪
第一个实测场景是在一块直流电源模块上:远端探头贴在功率MOSFET的散热器表面,本地通道测PCB环境温度,STM32L432KC板载供电并记录数据。负载拉到一个固定值,让模块持续发热升温,然后断电自然冷却,记录完整的热曲线。
| 时间点 | 本地温度(°C) | 远端温度(°C) | 红外测温枪读数(°C) |
|---|---|---|---|
| 0分钟 | 26.1 | 28.3 | 28.9 |
| 5分钟 | 30.2 | 45.6 | 46.2 |
| 10分钟 | 33.5 | 58.7 | 59.4 |
| 15分钟 | 36.1 | 65.2 | 66.1 |
| 20分钟 | 37.8 | 69.4 | 70.2 |
| 25分钟 | 38.9 | 71.5 | 72.3 |
| 30分钟 | 39.3 | 72.8 | 73.0 |
远端通道和红外测温枪的偏差基本在1°C内,表现符合预期。这里能明显看出本地和远端的差异:功率管散出的热量还没把整块PCB环境加热起来,远端温度已经飙到70°C以上了。这种场景下,如果只做一个柜内环境温度传感器,过温保护根本反应不过来;有了贴装在发热器件上的远端探头,可以在温度到达危险阈值前提前降频或拉断负载。
4.2 HVAC场景:风管温度与新风温度对照
第二个场景是HVAC风管:远端探头放在送风管内,本地通道测控制器盒内温度。用一支经过计量校准的Pt100探头放在旁边做参考,连续记录12小时,覆盖了空调风机启停和白天夜间温差变化。
实测下来,稳态时PJ85718DM远端读数和Pt100参考值的偏差在±0.8°C以内,误差主要来自探头位置差异和空气流动不均。风机启动瞬间,两个通道都有短暂波动,远端幅度稍大一些,大约有1°C左右的瞬时毛刺,但经过软件滤波后,送到控制逻辑里的数值曲线非常平滑,完全可以直接参与PID控制。
风管里还碰到一个有意思的现象:风速较高时,探头表面的对流换热强,测到的温度更接近真实空气温度;风机停机后,探头周围空气基本静止,读数会缓慢飘向管壁温度。这说明探头位置对HVAC测温准确性影响非常大。我后来把探头固定在了风管弯头后面的混合区,也就是气流比较均匀的地方,读数的代表性明显改善。
4.3 数据背后另一个值得注意的规律
把两组实测数据放在一起看,能提炼出对方案选型有指导意义的结论。第一,PJ85718DM的本地通道适合做趋势监测,因为PCB环境温度热惯性大,数值稳定,不需要高响应速度。第二,远端通道因为探头直接接触被测对象,响应速度快得多,适合做保护逻辑和反馈控制的输入。一套方案兼顾两类需求,这是很多单通道传感器做不到的。
第三,关于滤波参数的取舍。HVAC风管温度变化本身就慢,用10点滑动平均几乎不会觉得迟钝;但嵌入式功率器件的热保护如果套用同一套滤波参数,响应延迟会变大,可能导致保护动作慢半拍。我的做法是两路温度各配一套滤波参数,远端在嵌入式场景下用3点滑动平均,在HVAC场景下用10点滑动平均,灵活性就是软件配置的事。
5. 常见问题与排查速查表
5.1 远端温度读数跳变和毛刺
这是遇到最多、也最让人头大的问题。温度数据偶尔跳到-40°C或者+100°C以上,过一会又恢复,频率不定。排查思路按优先级排列下去:先看探头的D+/D-是否接反,接反的典型表现是读数乱跳或者整体严重偏移;再看引线是不是用了双绞/屏蔽线,屏蔽层是否接地,我见过有人在工业现场用普通平行导线拉了两米,一开机近端传感器的继电器一吸合温度就跳;再看布线路径是不是贴着继电器和开关电源,这些干扰源对毫伏级的ΔVbe信号来说就是灾难。
软件上的兜底方案是加中值滤波,直接丢掉突变尖峰,效果立竿见影。硬件上的补救则是给D+/D-引脚间并联1nF电容形成差模滤波,相当于在芯片输入端加了一道低通。这两招用上之后,绝大多数毛刺问题都能压住。
5.2 I2C读取失败、卡死或读到0xFF
I2C总线卡死最经典的现象是SCL和SDA中某一条被长期拉低,所有通信都无响应。在PJ85718DM这类纯从设备身上,多半是总线进入了异常状态,主机端需要发送9个SCL时钟脉冲让从设备复位状态机,然后再发一个START信号重新初始化。我在初始化代码里特意加了这么一段恢复逻辑,设备上电后第一次通信前先做一次总线恢复,消除了带电插拔带来的锁死问题。
另外一个常见误区是器件地址。PJ85718DM的7位I2C地址由A0/A1引脚电平决定,常用默认地址是0x48。但STM32的HAL库发送时要求左移一位的8位地址,很多新手在这里翻车:明明写的0x48,实际上发出去的是0x90,跟芯片期待的对不上。调试时最好先用I2C扫描代码确认设备在哪个地址有ACK响应,再开始读写寄存器。
5.3 ALERT报警失灵,温度早超过阈值了却没反应
报警不触发,九成是配置寄存器里的报警模式和中断清除逻辑没配对。比较模式下ALERT会保持低电平,直到温度回到阈值区间;中断模式则要求读取状态寄存器清除标志位后,才能触发下一次报警。如果配置成了比较模式,但程序里一读到ALERT拉低就把状态清了,那相当于让报警器闭嘴了。反过来,配置成中断模式但不读状态寄存器,第二次越限时ALERT不会重新触发。
还有一个隐蔽问题:阈值寄存器的格式是11位带符号数,不是12位。设置阈值时如果直接拿温度读数右移4位后去写,符号位处理错乱会让阈值变成一个奇怪的值,报警当然就不准了。写阈值寄存器前先读回验证一次,能省不少白头发。
5.4 低功耗模式下温度读数异常
低功耗唤醒后立即读温度,经常读回来一个旧值或者明显错的数。原因在于PJ85718DM从关断模式恢复到完成一次温度转换需要时间,13位分辨率下典型转换时间是320ms左右。唤醒后立刻去读寄存器,转换还没完成,读出的自然是上一次残留的数据。解决办法是唤醒后先延时等待转换完成,或者更优雅的做法:读取状态寄存器里的转换完成标志,确认转换结束再取数。
这里给一个实际用过的调度示例:STOP2唤醒后初始化I2C(约1ms),给PJ85718DM写单次触发命令(几毫秒),进入等待转换完成标志的循环(最长等400ms,超时则报错),读取两路温度、滤波、处理、上报,重新关断传感器和I2C外设,返回STOP2。整个周期在500ms左右,对比15秒的睡眠周期,占空比只有3%,电池功耗基本可以忽略。
最后分享一点我自己的体会。温度监测这个事,看起来就是“读个数”,但真正做扎实,从探头选型、引线布置、PCB布局到软件滤波、报警策略,每一环都可能把误差和故障放大。PJ85718DM加STM32L432KC这套方案最大的价值,是它把测温链路做得足够短:远端PN结把温度变成电参数,芯片把这个参数变成数字,主控负责加工和分发。链路短,意味着排查问题快,也意味着可靠性容易被验证。如果你手上正好有类似的嵌入式和HVAC温度监测需求,建议照着这套思路先搭一个原型,把远端探头接到真实被测对象上做对照测试,数据会告诉你后续该怎么调整。