做嵌入式的人,估计都遇到过这种场景:板子在自己桌上跑得好好的,一到现场就被吐槽“温度不准”;暖通项目里更是头疼,冷冻水管、冷凝器、送风管,每个点都想盯着,又不能每个点都塞一块带独立总线的传感器板。我前阵子用一颗 PJ85718DM 加一片 STM32F205RB,把本地与远程温度的采集统一收敛到一颗传感器上,真机跑了两轮,稳定性比之前每个测点挂一个芯片的方案强不少。
这篇文章就把这套方案的选型逻辑、硬件设计、固件实现和调试心得完整展开。核心思路是:本地温度由传感器自身测量,远程温度通过一颗普通小信号二极管或者三极管探头测量,主控 MCU 通过 I2C 总线读取两路结果。这套做法适用于嵌入式设备里的功率器件温度监测、电源板热点监测,也适用于 HVAC 场景里的冷媒管温度、风管温度、水温采集。如果你正在纠结“多点测温的成本怎么降、工程上怎么布”,这篇应该能给你一套可以直接抄作业的答案。
1. 为什么要在同一颗芯片上同时测本地和远程温度
1.1 两个场景的核心需求拆解
先说嵌入式侧。我做过一个变频器控制板的监测项目,要盯的点包括:控制板上的 MCU 附近环境温度、IGBT 或 MOSFET 功率管的壳温、电感的表面温度。前两个点相距可能只有十几厘米,但要都采集到,常规做法是放两颗 I2C 温度传感器,或者一颗传感器加一颗 NTC。NTC 这个方案最麻烦的是非线性误差和长线压降,要求高一点的时候还得每个点单独校准一板参数,生产线上工位调参就折腾人。
再看 HVAC 侧。暖通系统的监测点往往分布在主控板之外,比如冷媒管壁温度、送风道温度、水系统供水回水温度,测点与主控之间的距离从几十厘米到几米不等。工程上常见的做法是每个监测点拉一根传感器线回来,用独立传感器或模拟量模块。这么做系统会显得很“散”,每个测点都要供电、都要地址配置、都要单独处理故障,而且总线越长,接口越容易出问题。
两个场景放在一起看,共性非常明显:系统需要一个“靠近主控的本地温度参考点”,同时需要若干个“布置在远端的测点”,并且这些远端测点不希望做成完整的总线设备,只想做成一个简单的探头。PJ85718DM 这类传感器就是冲着这个需求去的——它把本地测温单元和远程二极管测温单元集成在同一颗芯片里,主控只占用一个 I2C 地址,却能读到两个物理位置的温度。
1.2 远程二极管测温原理:一根探头线为什么能传温度
远程温度测量的物理基础,是半导体 PN 结正向压降与温度存在近似线性的关系。一颗普通小信号二极管或者三极管的 BE 结,在恒定正向电流下,其正向压降随温度升高而近似线性下降,斜率大约为 -2mV/°C。传感器芯片内置一个精密电流源,把这个恒定电流送到远程探头,再测量二极管两端的压降,就能反推出探头处的温度。
你可能会疑惑:这和直接放一颗晶体管传感器有什么区别?区别在于,被测量的器件是独立于传感器芯片存在的,整个远端探头只需要一个二极管或三极管、两根线,不需要单独的供电,也不需要配置地址。传感器芯片内部的 ADC 会在不同电流点采样,用差分方式把 PN 结上的电压变化提取出来,从而消除线缆电阻、接触电阻带来的误差。这就是为什么这个方案在工程上可以容忍较长的连接线,而 NTC 方案受线缆电阻影响明显。
另外,从工程对比上看,二极管方案的整体链路更干净:
| 方案 | 精度与一致性 | 线缆影响 | 系统复杂度 | 成本 |
|---|---|---|---|---|
| NTC 热敏电阻 | 依赖 B 值校准,一致性一般 | 线阻直接进测量回路,长线要补偿 | 需要 ADC 通道、分压电阻 | 探头便宜,但校准成本高 |
| 热电偶 | 精度高,但需冷端补偿 | 线缆材料需匹配,接线复杂 | 需要放大调理电路 | 探头和调理都较贵 |
| 本地/远程二极管测温 | 芯片内部闭环测量,一致性好 | 差分采样,对线阻不敏感 | 一颗芯片两个测点,只有 I2C | 传感器稍贵,但整体链路省 |
这套方案在 HVAC 里尤其适用,因为很多测点只是“测个趋势”,但又要长期稳定。二极管探头装进一个不锈钢套管就能直接贴到管壁上,传感器芯片放在主控板上,整个系统看起来就是“主板上长出了几根温度探头”,维护起来非常直观。
2. 方案选型:PJ85718DM 与 STM32F205RB 为什么能搭在一起
2.1 PJ85718DM 的关键参数拆解
我第一次看到 PJ85718DM 的数据手册时,第一反应是“它把常见远程温度传感器的几件套集齐了”。这类芯片通常支持本地单通道加远程单通道,供电电压常见 3.0V 到 3.6V,本地测温范围覆盖 -40°C 到 +125°C,远程探头测量范围通常可以到 -40°C 到 +150°C,正好覆盖功率器件和 HVAC 管路的典型温度区间。精度方面,本地典型值在 ±0.5°C 左右,远程在 ±1°C 左右,对大多数工业监测和 HVAC 控制来说足够。
分辨率也是一个值得抠的点。常见配置是本地和远程都是 10 位到 12 位分辨率,温度 LSB 在 0.0625°C 到 0.5°C 之间。进入实际项目后,我一般把分辨率调到较高档,因为后续还要做滑动平均滤波,高分辨率能保证滤波后的数据不丢有效位。
这颗芯片的寄存器模型在我看来相当典型:一个配置寄存器控制转换模式、测温通道使能、分辨率;两个数据寄存器分别存放本地温度和远程温度;一个状态寄存器提供远程探头开路、短路等故障标志;还有偏移校准寄存器用来修正传感器与探头的系统偏差。具体的寄存器地址每个批次芯片可能略有出入,以手头数据手册为准即可,但逻辑结构基本一致,移植起来很快。
2.2 STM32F205RB 在项目里的角色
PJ85718DM 负责把温度变成数字,STM32F205RB 负责的是把所有温度变成“有人看、有人用”的数据。简单看一下主控的资源:Cortex-M3 内核、120MHz 主频、128KB Flash、128KB SRAM,板载 I2C、SPI、USART、CAN、USB 等外设。放在这个项目里,I2C 用来读传感器,USART 或 RS485 转接用来和上位机或楼宇自控系统通信,空闲的定时器用来做定时采集和软件滤波,性能余量很大。
选 F205 而不是更便宜的 M0 系列,原因有几个。首先是远程测温的工程调试往往需要反复读寄存器、看状态位,MCU 的资源不能只给采集模块用,还要同时跑通信协议、显示逻辑和报警逻辑。其次,F205 的 I2C 带有足够完善的错误标志和超时机制,在工业现场总线出错后恢复的能力更强。再者,如果后续要做 PID 控制——比如冬天根据回水温度调节电动阀开度——Cortex-M3 跑控制循环也从容得多。
如果你手头只有低主频的 M0 芯片,也不是不能用,但建议在软件上把 I2C 通信改成中断或 DMA 驱动,避免轮询等待阻塞控制任务。我在早期一版用过轮询方式,结果温度上报周期稍长,控制周期就被拖慢了,最后还是把采集逻辑放到了定时器中断里。
2.3 整体架构和数据流
整套系统的数据流向不复杂,但每一步都有讲究。传感器芯片挂在 I2C 总线上,STM32 通过 I2C 周期性读取本地温度寄存器和远程温度寄存器。读取出来的原始值要经过符号拓展、分辨率换算,变成真实的摄氏温度浮点数或者带小数的定点数。然后经过软件滤波,比如一阶低通或滑动平均,得到一个平滑的温度值。处理后的数据一方面保存在内存里供显示和控制逻辑使用,另一方面按照项目需求通过 RS485、CAN 或者无线模块上报。
HVAC 场景里我比较推荐再加一级“数据诊断层”,也就是把开路、短路、超范围这些状态和温度值一起打包上报。现场调试这个系统时,测点突然显示 -127°C 或者 +127°C 这类异常值,其实大多数情况下是探头接线松了,而不是传感器坏了。如果你在协议里没有把状态位带上去,光看温度值无法区分“真的过热”和“通道故障”,只能是误报警。主控在收到状态异常后应该抛弃当前温度值并上报故障码,而不是把异常值继续参与 PID 运算,否则阀门会忽开忽关,现场情况会非常难看。
3. 硬件设计细节:布线、供电与远程探头连接
3.1 传感器供电与 I2C 总线设计要点
PJ85718DM 使用 3.3V 供电时,我习惯在 VDD 引脚和 GND 之间放一个 100nF 陶瓷电容,如果供电走线较长,再加一个 1uF 到 10uF 的钽电容或陶瓷电容,防止现场电源波动把测量精度拖垮。I2C 的 SCL 和 SDA 是开漏结构,必须配上拉电阻。上拉电阻的取值要看总线上的设备数量和线缆长度,常规板载短距离用 4.7kΩ 没有问题;如果传感器通过接插件和线缆拉出去,我一般改用 2.2kΩ,因为线缆电容大了之后,4.7kΩ 上拉会让信号上升沿变缓,影响通信稳定性。
这里有一个容易踩的坑:I2C 总线上如果还有其他设备,上拉电阻是并联关系,不能用“每个设备边上各放一个 10kΩ”的想法去做,很容易导致总的上拉阻值过小,驱动能力过强,反而出现电平不稳。正确做法是在总线主控端统一放置一组上拉,其他设备只做去耦。
STM32F205RB 的 I2C 引脚要配置成开漏输出,并且使能内部上拉。很多人在这里会把 GPIO 配成推挽输出,I2C 波形看起来正常,但实际上总线高低电平的控制是错的。标准 I2C 要求器件只能拉低、释放,释放时依靠上拉到高电平,推挽输出在释放阶段会强行输出高电平,一旦两个设备同时操作总线就会立刻打架。
3.2 远程温度探头:二极管和三极管两种接法
远程探头有两种常见接法。接法一:直接用一颗二极管,阳极接 D+,阴极接 D-。接法二:用一颗小信号三极管,把基极和集电极短接后当作二极管使用,通常用基极-发射极结,也就是 D+ 接基极,D- 接发射极。
工程上我更推荐三极管接法。因为小信号三极管比如 MMBT3906 这类器件,它的 BE 结特性一致性比较好,批量生产时探头的个体差异小,传感器做 β 补偿时的效果也更稳定。二极管接法虽然器件更简单,但一些整流二极管的正向压降和温度特性偏离理想情况较大,可能导致远程读数偏差。
远程探头通过两根线连到传感器芯片的 D+ 和 D- 引脚。这类引脚对噪声比较敏感,因为传感器是通过测量微小电压变化来推断温度的,线缆上的共模噪声和差模噪声都会影响结果。在 HVAC 现场,远程探头经常和压缩机的强电电缆走同一桥架,这时候线缆耦合的干扰会非常明显。我通常在 D+ 和 D- 之间并联一个 1nF 到 2.2nF 的陶瓷电容,用来滤除高频噪声。这个电容的容值不能太大,太大会改变 PN 结的切换时间,反而让测量误差变大,具体上限要看传感器的数据手册,一般不建议超过 10nF。
远程探头线缆我推荐使用双绞线或者屏蔽双绞线。双绞的作用是让两根线上的共模噪声尽量一致,这样传感器的差分采样电路可以把噪声抵消掉。屏蔽层在远端探头侧单端接地,接地点选在传感器芯片的地附近,不要两端都接,否则容易形成地环路,在强电干扰下反而把噪声引入。
3.3 PCB 布局与 HVAC 现场的强电干扰规避
传感器芯片的位置我一般放在主控板上靠近 MCU 的地方,这样本地通道反映的就是主控板内部的环境温度,同时 I2C 走线最短。远程探头接口布局在板边,方便线缆引出。这里有个细节:D+ 和 D- 的走线如果必须穿过电源区域,尽量与开关电源的 SW 节点、电感下方的走线保持距离,这些区域是高 dv/dt 噪声源,即使有差分采样,仍然可能把噪声耦合进微小信号里。
HVAC 控制柜里还有一个容易被忽视的问题:继电器吸合和压缩机启停瞬间,系统地的电位可能被拉偏,甚至出现几十毫秒的强干扰脉冲。对这种场景,我会在传感器供电入口加一个小磁珠,磁珠后面再加 100nF 去耦电容,相当于在传感器供电和系统电源之间加了一道低通屏障。远程探头接口的静电防护也不能少,两根线对地之间加 TVS 二极管,防止操作人员触摸接插件时静电损坏传感器端口。
如果你要把传感器板设计成单独的小模块,与主控板通过接插件连接,那我建议在接插件上给 I2C、供电、地各留两个引脚,把地用双引脚并联,能明显降低连接器的接触电阻影响。远程探头的两个信号脚之间也要留一点间距,避免湿气结露导致的两线间漏电,HVAC 项目里冷凝水是非常常见的故障源。
4. 固件实现:I2C 驱动、寄存器配置与数据处理
4.1 STM32F205RB 的 I2C 初始化
STM32F2 系列的标准外设库或 HAL 库都支持 I2C,我习惯用寄存器加上标准外设库的风格来写,因为逻辑清晰容易排查。初始化时把 PB6 和 PB7 复用为 I2C1,配置成开漏、带上拉,然后设置 I2C 时钟为 400kHz。以系统主频 120MHz、APB1 为 30MHz 为例,I2C 的外设时钟是 30MHz,400kHz 快速模式下 CCR 寄存器可以设为 75,DutyCycle 配置为 2:1,实际总线速率会稳定在 400kHz 附近。
static void I2C1_GPIO_Init(void) { GPIO_InitTypeDef gpio; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; gpio.GPIO_Mode = GPIO_Mode_AF; gpio.GPIO_Speed = GPIO_Speed_50MHz; gpio.GPIO_OType = GPIO_OType_OpenDrain; gpio.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &gpio); } static void I2C1_Init(void) { I2C_InitTypeDef i2c; I2C_DeInit(I2C1); i2c.I2C_Mode = I2C_Mode_I2C; i2c.I2C_DutyCycle = I2C_DutyCycle_2; i2c.I2C_OwnAddress1 = 0x30; i2c.I2C_Ack = I2C_Ack_Enable; i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; i2c.I2C_ClockSpeed = 400000; I2C_Init(I2C1, &i2c); I2C_Cmd(I2C1, ENABLE); }如果你用的是 HAL 库,逻辑相同,把 GPIO 初始化和 I2C 初始化参数对应过去即可。关键点是 I2C 通信前要确认总线不忙,否则 SCL 和 SDA 被外部拉低时,直接通信会卡住。我在实际项目里加了超时机制,任何一步 I2C 操作如果超过 100ms 没有完成,就主动复位总线。
4.2 寄存器配置与温度读取流程
传感器上电后,第一步不是直接读温度,而是先读芯片的 ID 寄存器,确认通信通道没问题。这类芯片通常在某个固定地址存放 ID 值。如果读回来的值和数据手册不一致,基本可以断定接线或 I2C 地址配置有问题,没必要继续往下跑。
确认通信正常后,配置转换模式。大多数项目选用连续转换,传感器自动周期刷新温度值,主控按自己的采样周期去读取即可。如果为了省电,可以改成单次转换模式,主控每次想去读温度时先触发一次转换,等待转换完成后再读取。嵌入式电池供电场景建议用单次模式,HVAC 这种长期通电的场景我用连续模式。
配置寄存器里还要把本地测温通道和远程测温通道都使能,把分辨率配到最高档。然后按下面的流程读取:
- 读取状态寄存器,检查远程探头是否开路或短路。
- 如果状态正常,读取本地温度寄存器的高字节和低字节。
- 读取远程温度寄存器的高字节和低字节。
- 按芯片定义的分辨率换算成温度值。
温度数据的还原要看数据手册的格式。常见格式是 12 位带符号数,存在两个寄存器中的高字节和低字节高 4 位里。也就是把两个字节组合成 16 位后算术右移 4 位,再乘以 LSB 对应的温度值。本地温度的 LSB 常见为 0.0625°C,远程通道可能是 0.125°C 或更粗一些。这里特别要注意符号位,如果温度是负的,必须做符号扩展,否则会算出奇怪的巨大正数。
4.3 滤波、β 补偿与偏差校正
原始温度读数如果直接显示或参与控制,会有两个问题:一是量化噪声导致末位跳动,二是现场干扰导致偶发的跳变。我在读取温度之后统一做了一次一阶低通滤波,公式是:
y(n) = α × x(n) + (1 - α) × y(n-1)α 取 0.1 到 0.3 之间,采样周期为 1 秒时,既能滤掉高频抖振,又不会让温度响应慢得让人抓狂。如果你更在意响应速度,比如用于过热保护,可以把 α 调大到 0.5,或者直接用滑动平均加中值滤波的组合:先做中值滤波剔除明显异常点,再做滑动平均平滑。
β 补偿这个东西,很多第一次用远程测温的人会忽略。远程测温依赖的是标准硅管的 PN 结特性,但实际选用的三极管增益 β 并不完全等于芯片期望的理想值,这会导致远程温度读数和真实温度存在固定偏差或随温度变化的偏差。传感器通常提供 β 补偿配置寄存器,写入所用三极管的 β 参数后,芯片会自动修正一部分误差。我用的 MMBT3906 手册中典型 β 值靠近 100 到 150 区间,具体设置值我会在整机标定时微调。
偏差校正是最后一道保险。在实验室用标准温度源把探头放在 25°C、50°C、85°C 三个点,记录远程通道的读数和标准温度计的差值。如果差值基本恒定在某个值,直接把该值配置进传感器的偏移校准寄存器;如果差值随温度变化,就要通过调整 β 补偿参数来修正曲线斜率。整套流程下来,我的远程通道读数误差长期稳定在 ±1°C 以内完全没问题。
5. 调试实录:常见问题与排查方法
5.1 I2C 通信时好时坏,怎么定位
这套方案调试时最常出现的第一个故障,就是主控读不到传感器的 ID。示波器上看波形,通常有三种情况。
第一种是 SCL 和 SDA 完全没有波形。这时候先查 GPIO 复用配置,确认两个引脚确实配置成了 I2C 功能,而不是普通 GPIO。我曾经有一次改了板框,某个引脚被复用逻辑占用,结果 I2C 另一路信号始终是死的。
第二种是波形有,但 SDA 拉不低,波形看起来像一条被削弱的正弦。这基本就是上拉电阻取值太小,总线驱动不过来了。把上拉换回 4.7kΩ 或者 10kΩ,一般就恢复。
第三种是波形有,但是主控发送地址后一直收不到 ACK,或者 ACK 时有时无。这种优先怀疑地址错误或总线上有多个设备地址冲突。没关系,逐条排除,把传感器单独焊一块转接板,只挂这一颗芯片,读 ID 寄存器,能稳定读出后再并入原有总线,问题定位很快。
5.2 远程探头读数跳变或者明显偏离实际
探头读数跳变,我一般按三步排查。先看接线,D+ 和 D- 有没有接反,三极管接法里基极和发射极有没有搞混。再查探头端和传感器端的地,远程探头是差分测量,理论上不需要和传感器共地,但两根线本身不能有断点或氧化。最后看线缆长度和噪声环境,长线加屏蔽、加差分电容,一般能解决。
读数整体偏移,比如实际 25°C 读出来 27°C,说明系统存在恒定偏差。常见原因是使用了非理想的二极管或三极管,β 参数和芯片期望值差太多。把 β 补偿寄存器向正确方向调一两个档位,再用标准温度计对比一次,偏差会明显缩小。如果仍然有固定偏差,就用偏移寄存器把整体偏移补偿掉。
这里还有一个小技巧:远程探头的引线如果有明显的接触电阻,并且在插拔后发生变化,读数也会跟着漂移。遇到按压接插件读数变化明显的时候,不要急着调软件,先处理接触问题。HVAC 项目里的插簧端子最容易出现这种故障,换成螺纹锁紧端子会靠谱很多。
5.3 HVAC 现场电磁干扰导致的数据异常
现场最棘手的是数据本身没问题,但一开压缩机,远程温度就开始乱跳。这种基本都是传导干扰或辐射干扰。排查手段是在远程探头输入端并联 2.2nF 电容,并确认屏蔽层单端接地良好。如果还是跳,把传感器的供电从系统 3.3V 上断开,单独用一个隔离模块供电测试,排除电源轨被压缩机启停拉偏的因素。
如果干扰依然存在,那就考虑把远程探头换成普通 NTC 加独立采集模块这条路。但一般情况下,做好屏蔽、差分电容、供电隔离后,二极管方案在工业现场的稳定性已经足够。我在一个冷库项目里,远程探头通过 3 米屏蔽双绞线接到主控板,压缩机频繁启停的环境下,远程温度波动控制在 ±0.3°C 以内,表现很不错。
另外说一句,调试现场最好把温度原始值、滤波后的值、状态寄存器值同时打印出来。只打印最终温度会掩盖很多问题,看到原始值和状态位,很多“玄学”故障其实一眼就能看穿。
6. 实测数据与几点使用经验
这套方案我在两块板子上分别做了测试。一块是模拟嵌入式电源板,远程探头贴在 MOSFET 散热器上,本地测点放在 MCU 附近,上电满载运行一小时,远程读数稳定在 68.2°C 附近,波动 ±0.2°C。另一块是 HVAC 模拟柜,远程探头贴在模拟冷媒管表面,环境温度从 20°C 升到 45°C,远程通道跟随正常,与标准温度计偏差在 0.6°C 以内。两轮测试下来,我对这套组合的稳定性算是有了底气。
最后分享几个不太好写在文档里的经验。第一,远程探头的三极管批量采购后最好做一次抽检,不同批次之间 BE 结特性可能有细微差异,虽然传感器有补偿,但批量标定还是能省掉不少现场麻烦。第二,I2C 总线如果拉了较长的线缆,通信速率不要一上来就跑 400kHz,先用 100kHz 跑通整机,再逐步提速,能节省大量排障时间。第三,这类传感器芯片的量产校准数据要保留,每一批板子的温度偏差如果比较一致,说明工艺稳定;如果偏差发散,就要查焊接和探头物料质量了。
这个方案后续要扩展也很简单,传感器本身占用一个 I2C 地址,如果测点更多,就多挂几颗芯片,每个远程探头对应一路通道,主控按地址轮询即可。再往后如果要做无线冷链或远程运维,把温度数据直接接入无线模块,这套底层采集代码完全不用动。