基于PJ85718DM与STM32F072RB的嵌入式双通道温度监测方案

📅 发布时间:2026/10/10 13:59:09
基于PJ85718DM与STM32F072RB的嵌入式双通道温度监测方案
1. 项目缘起与整体设计思路嵌入式温度监测这个方向看起来简单实际上坑特别多。我最早接触这类需求是在一个HVAC控制板的项目里当时的需求很朴素板子上要同时测本地环境温度和一路远程探头温度数据要能上传到上位机还要在本地做超温报警。最开始想用一颗NTC加热敏电阻分压直接进MCU的ADC结果发现精度飘得厉害标定一次管不了几天尤其是远程探头那一路线缆一长ADC读数直接被干扰淹没。后来换成了PJ85718DM这颗专用的温度传感芯片配合STM32F072RB做主控整个方案才算稳定下来。这篇文章就把我这套方案的完整设计思路、硬件连接、固件实现、标定方法和踩过的坑全部摊开讲一遍。如果你正在做嵌入式温度采集、HVAC控制器、环境监测节点这类东西这篇内容应该能帮你少走不少弯路。先说清楚这套方案到底解决什么问题。PJ85718DM是一颗支持本地和远程双通道的温度传感器本地通道测芯片自身所在位置的温度远程通道通过外接一个晶体管通常是2N3904或类似的小信号三极管把基极和集电极短接当二极管用来测远端温度。STM32F072RB是ST的Cortex-M0系列MCU自带12位ADC、I2C接口、定时器、DMA资源对于这种温度监测应用绰绰有余。两者配合能实现本地远程两路温度的同时采集、显示、报警和上传。适合谁来参考我觉得三类人最合适一是刚接触嵌入式传感器开发的学生或转行者这套方案涉及的I2C通信、ADC采样、温度换算都是基本功二是做HVAC或工业控制的工程师需要一套可靠的温度采集方案直接落地三是想了解远程温度传感原理的人PJ85718DM的远程通道工作机制值得仔细研究。整体设计上我选择PJ85718DM而不是分立方案核心理由有三个。第一远程温度测量用分立方案很难做准因为三极管的Vbe与温度的关系虽然线性度不错但需要精确的偏置电流和ADC参考自己搭电路一致性很差。PJ85718DM内部集成了远程通道的偏置电流源和16位ADC直接输出数字化的温度值省去了大量模拟电路设计和标定工作。第二I2C接口只需要两根线STM32F072RB的I2C外设直接对接布线简单抗干扰能力比模拟走线强得多。第三这颗芯片支持可编程的报警阈值和温度转换速率对于HVAC应用来说能灵活配置采样率和报警点非常实用。系统框图大致是这样的PJ85718DM通过I2C总线挂在STM32F072RB上STM32F072RB负责初始化传感器、周期性读取温度寄存器、做温度换算和报警判断然后通过UART把数据发给上位机或者显示在本地OLED上。远程探头通过一对双绞线连接到PJ85718DM的D和D-引脚本地温度就是芯片自身温度。供电方面PJ85718DM支持2.7V到5.5VSTM32F072RB是3.3V供电两者可以直接共电源不需要电平转换。注意PJ85718DM的I2C地址由ADDR引脚决定默认地址是0x487位地址如果总线上挂多个器件需要通过ADDR引脚改地址。我建议在PCB上把ADDR引脚做成可选上拉或下拉方便后期调试。2. 核心细节解析与实操要点2.1 PJ85718DM的本地与远程通道工作原理PJ85718DM的本地温度通道其实就是一个集成在芯片内部的温度传感器基于硅带的带隙电压原理。简单说芯片内部有两个工作在不同电流密度的晶体管它们的Vbe差值正比于绝对温度。这个差值经过ADC数字化后芯片内部直接换算成摄氏度存在本地温度寄存器里。你读出来的就是最终温度值不需要自己做任何换算。这一点比用NTC或者LM35方便太多NTC还得查表或者算Steinhart-Hart方程LM35虽然线性但输出是模拟电压还得占用一个ADC通道。远程通道的原理稍微复杂一点。它通过D和D-两个引脚给外接的三极管接成二极管模式提供两路不同大小的偏置电流然后测量两次Vbe的差值。这个差值同样正比于绝对温度芯片内部用16位ADC采集后换算成温度值。远程通道的精度取决于外接三极管的特性所以选型很关键。我实测下来2N3904的一致性最好MMBT3904也可以但一些杂牌三极管个体差异很大换一颗温度能差两三度。这里有个细节很多人会忽略远程三极管的基极和集电极必须短接只用基极-发射极结。如果你直接把三极管当二极管用只接基极和发射极集电极悬空也能工作但抗干扰能力会差一些。我建议还是把基极和集电极焊在一起这样等效结面积更稳定噪声更低。2.2 STM32F072RB的外设配置要点STM32F072RB在这套方案里主要用到三个外设I2C、UART和定时器。I2C用来跟PJ85718DM通信UART用来上传数据定时器用来做周期采样触发。这三个外设的配置有几个关键点。I2C配置方面STM32F072RB的I2C支持标准模式100kHz和快速模式400kHz。PJ85718DM支持最高400kHz的I2C时钟我一般用400kHz这样读一次温度寄存器两个字节大概只需要几十微秒对CPU占用极低。但是要注意I2C的上升时间跟总线上拉电阻和总线电容有关。如果走线比较长或者挂了多个器件400kHz可能会通信失败。我的经验是总线电容超过200pF就降到100kHz或者把上拉电阻从4.7k降到2.2k。实测下来2.2k上拉配400kHz在20cm以内的走线上非常稳。UART配置就简单了波特率1152008位数据位1位停止位无校验。我习惯用DMA发送这样CPU不用等着串口发完直接丢给DMA就行。STM32F072RB的UART支持DMA请求配置起来很方便。定时器我用的是TIM3配置成1Hz的更新中断也就是每秒触发一次温度采样。为什么选1Hz因为温度变化本身很慢HVAC场景下温度变化率通常不超过1°C每分钟1Hz采样完全够用而且能大幅降低功耗。如果你需要更快的响应可以提到10Hz但没必要再高了PJ85718DM的转换时间最快也要几十毫秒。2.3 远程探头的选型与布线技巧远程探头这块我踩过不少坑值得单独说一下。三极管选型上2N3904是最稳妥的TO-92封装便宜好买一致性也好。如果你需要测更高温度比如超过100°C可以考虑MMBT3904的SOT-23封装版本热阻更小响应更快。但要注意SOT-23封装的焊接温度不能太高手工焊的时候烙铁停留时间别超过3秒。布线方面D和D-最好用双绞线而且要和电源线分开走。我试过用普通的杜邦线长度超过30cm后读数就开始跳换成双绞线后50cm都很稳。如果探头离主板比较远比如超过1米建议在D和D-之间并一个100pF的电容能有效滤掉高频干扰。但电容不能太大否则会影响芯片内部的电流切换时序导致读数错误。我试过1nF直接读不出正确值100pF是上限。还有一个细节远程三极管的发射极要接到D还是D-这个取决于芯片的数据手册规定。PJ85718DM的D接三极管的基极和集电极短接D-接发射极。如果你接反了读数会完全不对通常是负温度或者固定值。我第一次接的时候就接反了读出来一直是-40°C查了半天才发现是D和D-搞反了。提示远程探头刚上电时由于三极管自身发热和芯片内部电流源的建立时间前几次读数可能不准。建议上电后延迟500ms再开始读取或者连续读三次取后两次的平均值。3. 实操过程与核心环节实现3.1 硬件连接与上电检查先列一下完整的物料清单。主控板用STM32F072RB的最小系统板传感器用PJ85718DM的SOIC-8封装远程探头用2N3904加一段双绞线另外还需要两个4.7k的上拉电阻I2C用、一个100nF的去耦电容、一个100pF的滤波电容远程通道用。连接步骤如下。第一步把PJ85718DM焊到转接板或者直接焊到主板上。SOIC-8的引脚间距是1.27mm手工焊的时候先用烙铁固定对角两个引脚然后逐个焊剩下的。注意别把引脚之间连锡焊完后用放大镜或者万用表检查一下。第二步连接I2C总线。PJ85718DM的SCL和SDA分别接到STM32F072RB的PB6和PB7I2C1然后在SCL和SDA上各接一个4.7k上拉电阻到3.3V。第三步连接远程探头。2N3904的基极和集电极短接后接到PJ85718DM的D发射极接到D-。第四步接电源。PJ85718DM的VCC接3.3VGND接地VCC和GND之间并一个100nF去耦电容。上电检查很重要别急着写代码。先用万用表测一下VCC是不是3.3VI2C总线的SCL和SDA是不是都被上拉到3.3V。然后用示波器或者逻辑分析仪看一下I2C总线上有没有波形。如果没有波形检查STM32F072RB的I2C初始化代码是不是没跑起来。我遇到过好几次是I2C引脚配置错了配成了普通GPIO而不是复用功能。3.2 固件初始化与温度读取流程固件部分我按模块拆开讲。首先是I2C初始化用HAL库的话大概是这样的hi2c1.Instance I2C1; hi2c1.Init.Timing 0x00901D22; // 400kHz 48MHz 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);Timing值需要根据你的系统时钟算我用的是48MHz主频400kHz的I2C时钟算出来是0x00901D22。如果你用的是其他主频可以用STM32CubeMX生成或者参考参考手册里的计算公式。然后是PJ85718DM的初始化。这颗芯片上电后默认是连续转换模式转换速率默认大概是8次每秒。我一般会先配置一下配置寄存器设置成1次每秒然后使能远程通道。配置寄存器的地址是0x01本地温度寄存器是0x00远程温度寄存器是0x01注意跟配置寄存器地址冲突读的时候要区分读写方向。读取温度的流程是这样的先发一个写命令指定要读的寄存器地址然后发一个读命令读两个字节。本地温度的高字节在第一个字节低字节在第二个字节。温度值的格式是16位有符号数高4位是符号扩展低12位是数据分辨率是0.0625°C。换算公式是温度 (int16_t)raw 4 * 0.0625。注意这里要先做符号扩展再移位否则负数会算错。int16_t raw (data[0] 8) | data[1]; float temp (raw 4) * 0.0625f;远程温度的读取类似但寄存器地址不同。远程温度的高字节在0x01低字节在0x02。读的时候要连续读两个字节不能分开读否则数据可能不一致。3.3 温度换算与报警逻辑实现温度换算本身不复杂但有几个细节要注意。第一原始数据的低4位是状态位不是温度数据移位的时候要移掉。第二符号扩展要正确否则负温度会变成很大的正数。第三浮点运算在M0上比较慢如果对性能有要求可以用定点数运算把0.0625换成1/16用整数移位实现。报警逻辑我设计成两级预警和报警。预警阈值设成比报警阈值低2°C当温度超过预警阈值时LED慢闪超过报警阈值时LED快闪并且通过UART发送报警信息。阈值可以通过UART命令在线修改存在STM32F072RB的Flash里掉电不丢。UART命令解析我用了一个简单的状态机接收缓冲区满了或者收到换行符就触发解析。命令格式是“SET ALARM_H 45.0”表示设置高温报警阈值为45°C。解析的时候用sscanf提取数值然后更新全局变量并写Flash。这里要注意Flash写入之前要先擦除整个页STM32F072RB的Flash页大小是1KB擦除一次大概需要20ms期间CPU会暂停所以不要在中断里写Flash。3.4 上位机数据可视化与记录数据上传到上位机后我用Python写了一个简单的可视化脚本用pyserial读串口用matplotlib实时画温度曲线。这个脚本不复杂但很实用能直观看到温度变化趋势。如果你不想写代码也可以用串口助手把数据保存成CSV然后用Excel画图。import serial import matplotlib.pyplot as plt import matplotlib.animation as animation ser serial.Serial(COM3, 115200) temps_local [] temps_remote [] def update(frame): line ser.readline().decode().strip() if line.startswith(T): parts line.split(,) temps_local.append(float(parts[1])) temps_remote.append(float(parts[2])) plt.cla() plt.plot(temps_local, labelLocal) plt.plot(temps_remote, labelRemote) plt.legend() ani animation.FuncAnimation(plt.gcf(), update, interval1000) plt.show()这个脚本每秒钟更新一次能同时显示本地和远程温度。实测下来在115200波特率下每秒传一次数据完全不会丢包。如果你需要更高的上传频率可以提到10Hz但要注意串口缓冲区的处理别让数据积压。4. 常见问题与排查技巧实录4.1 I2C通信失败排查I2C通信失败是最常见的问题表现是HAL_I2C_Master_Transmit返回HAL_ERROR或者HAL_BUSY。排查思路按以下顺序来。先查硬件。用万用表测SCL和SDA的对地电压正常应该是3.3V上拉电阻起作用。如果电压是0V检查上拉电阻是不是没焊或者焊错了。如果电压是1.5V左右可能是总线被某个器件拉低了断开所有从器件只留STM32F072RB看电压能不能恢复到3.3V。再查软件。用逻辑分析仪抓I2C波形看有没有起始条件、地址字节、ACK。如果没有起始条件说明I2C外设没初始化成功检查时钟使能和引脚配置。如果有起始条件但没有ACK说明从器件地址不对或者从器件没上电。PJ85718DM的默认地址是0x48但有些批次的芯片地址可能不同用I2C扫描程序扫一下就能确认。还有一个坑是STM32F072RB的I2C外设有已知的勘误在某些情况下会卡在BUSY状态。解决办法是在初始化之前先手动复位I2C外设或者用GPIO模拟I2C。我遇到过两次卡BUSY都是通过复位I2C外设解决的。4.2 远程温度读数异常排查远程温度读数异常的表现有好几种读数固定不变、读数跳变很大、读数为负值或者超过量程。每种表现对应不同的原因。读数固定不变最常见的原因是远程三极管没接好或者接反了。用万用表测一下三极管的基极-发射极结电压正常应该是0.6V左右。如果测出来是0V或者开路说明三极管坏了或者没焊好。另外检查D和D-是不是接反了接反了读数会固定在-40°C或者127°C。读数跳变很大通常是干扰问题。检查D和D-的走线是不是和电源线平行走得太近如果是分开走或者加屏蔽。另外检查100pF滤波电容是不是焊了没焊的话加上。如果还是跳把I2C时钟降到100kHz试试有时候是I2C通信错误导致读到了错误的数据。读数为负值但实际温度是正的可能是符号扩展没做对。检查代码里的移位操作确保先做符号扩展再移位。另外检查原始数据的低4位是不是被当成了温度数据低4位是状态位必须移掉。4.3 温度精度标定与校准方法PJ85718DM的本地温度精度典型值是±0.5°C远程温度精度取决于三极管典型值是±1°C。如果你需要更高的精度可以做两点标定。标定方法很简单准备一个冰水混合物0°C和一个沸水100°C注意海拔影响把远程探头分别放进去记录读数。然后算一个偏移量和斜率修正系数存在Flash里每次读数后应用修正。本地温度也可以用同样的方法标定但本地温度传感器在芯片内部标定的时候要把整个板子放到恒温箱里比较麻烦。如果对本地温度精度要求不高直接用出厂值就行。我实测下来不做标定的话本地温度误差在±0.3°C以内远程温度误差在±0.8°C以内。做两点标定后本地能到±0.1°C远程能到±0.3°C。对于HVAC应用来说不做标定其实也够用因为HVAC的控制精度通常只要求±1°C。4.4 常见问题速查表问题现象可能原因排查方法解决方案I2C返回HAL_BUSYI2C外设卡死读I2C状态寄存器复位I2C外设或改用GPIO模拟I2C无ACK从器件地址错误用I2C扫描程序确认ADDR引脚电平改地址本地温度固定不变传感器未上电测VCC电压检查电源连接远程温度固定-40°CD和D-接反检查接线交换D和D-远程温度跳变干扰或滤波不足检查走线和电容加双绞线和100pF电容温度读数偏大自发热对比环境温度降低采样率或增加休眠Flash写入失败未擦除检查Flash状态先擦除页再写入UART丢包波特率不匹配示波器测波形统一波特率加DMA注意这个速查表是我在实际项目中总结的覆盖了90%以上的常见问题。如果你遇到的问题不在表里先检查硬件连接再检查软件配置最后用逻辑分析仪抓波形基本都能定位到。5. 功耗优化与长期运行稳定性5.1 低功耗模式配置与实测数据HVAC应用很多时候是电池供电或者对功耗有要求所以低功耗设计很重要。STM32F072RB支持Sleep、Stop和Standby三种低功耗模式。我一般用Stop模式因为Stop模式下RAM和寄存器内容保留唤醒后不需要重新初始化而且功耗只有几个微安。具体配置是这样的温度采样用TIM3触发采样完成后进入Stop模式TIM3的更新中断唤醒。PJ85718DM在两次采样之间可以配置成关断模式功耗降到1微安以下。实测下来1Hz采样率下平均电流大概是15微安用一颗200mAh的纽扣电池能跑一年多。但这里有个坑PJ85718DM从关断模式唤醒后第一次转换需要等待大概200ms才能读到有效数据。所以我的做法是TIM3中断触发后先唤醒PJ85718DM然后等200ms再读温度读完再让它进入关断模式。这200ms可以用STM32F072RB的另一个定时器做延时或者用SysTick。5.2 长期运行的数据漂移与自恢复机制长期运行最怕的是数据漂移和死机。数据漂移方面PJ85718DM的长期稳定性还不错我有一块板子连续跑了三个月本地温度漂移不超过0.2°C远程温度漂移不超过0.5°C。但如果你的应用对精度要求很高建议每周做一次自校准用芯片内部的一个已知温度参考点来修正。死机方面STM32F072RB有一个独立看门狗IWDG我一般会启用它超时时间设成2秒。主循环里每500ms喂一次狗如果程序跑飞了看门狗会复位MCU。复位后从Flash里恢复阈值和标定参数继续运行。这个机制我实测过很多次确实能救回来。另外I2C通信失败也要有重试机制。我的做法是如果连续3次读取失败就复位I2C外设重新初始化然后再试。如果连续10次失败就触发看门狗复位。这样能处理大部分偶发故障。5.3 电磁兼容性设计与PCB布局建议PCB布局对温度测量的稳定性影响很大尤其是远程通道。我的经验是PJ85718DM尽量靠近STM32F072RBI2C走线越短越好最好不超过5cm。远程通道的D和D-走线要等长并且包地处理两边走地线减少干扰。电源方面PJ85718DM的VCC和GND之间一定要放一个100nF的陶瓷电容越近越好。如果板子上有电机或者继电器PJ85718DM的电源最好单独走一路LDO不要和电机共用电源。我遇到过好几次是电机启动时温度读数跳变后来加了LDO和电容就好了。还有一点远程三极管的引脚尽量短如果必须用延长线用屏蔽线屏蔽层接地。我试过用普通的排线长度超过50cm后读数就开始不稳定换成屏蔽线后1米都很稳。6. 方案扩展与个人实操体会这套方案的基础功能就是本地远程温度监测但扩展性其实很强。比如你可以把UART换成RS485做成总线式的多点温度监测网络一个主机带多个从机每个从机测一路本地和一路远程温度。RS485的收发器用MAX485或者SP3485STM32F072RB的UART支持RS485模式配置起来很方便。也可以加一个OLED显示屏用I2C接口的0.96寸OLED直接显示本地和远程温度不需要上位机。OLED的I2C地址跟PJ85718DM不冲突可以挂在同一条总线上。我做过一个版本用SSD1306的OLED显示效果很好成本也就十几块钱。如果要做无线传输可以加一个蓝牙模块或者LoRa模块通过UART跟STM32F072RB通信。蓝牙适合近距离LoRa适合远距离低功耗。但要注意无线模块的功耗通常比较大如果电池供电需要仔细算功耗预算。最后分享几个我在实际项目中总结的小技巧。第一PJ85718DM的配置寄存器可以设置成单次转换模式每次读温度前触发一次转换读完就自动进入关断模式这样功耗最低。第二远程三极管的基极和集电极短接后可以用热缩管包起来防止短路和氧化。第三温度数据上传的时候建议加上时间戳和校验和方便后期分析和排查问题。第四如果I2C总线上挂了多个器件建议用I2C多路复用器比如TCA9548A避免地址冲突。这套方案我前后做了三个版本从最初的洞洞板到后来的四层PCB稳定性越来越好。最开始的版本远程温度跳变严重后来加了滤波电容和双绞线就好了。中间还遇到过I2C卡死的问题后来加了看门狗和重试机制就再也没出现过。现在这套方案已经在一个HVAC控制器上连续运行了半年多没出过任何问题。如果你也在做类似的东西希望这些经验能帮你省点时间。