做嵌入式温控这一行,谁都知道“测温”不难,难的是怎么把温度测准、测稳,还要在工业现场那种电磁环境里不出幺蛾子。最近我在做一套 HVAC 控制器的温度监测单元,选型阶段拿到了 PJ85718DM 这颗芯片,配合 STM32L152ZD 做主控,一下子把“本地温度 + 远程温度”两个需求全解决了。这个组合平时不多见,但实际用下来思路很清晰,项目也顺利落地了。这篇文章就把我当时的方案选型、硬件设计、软件实现和调试过程完整写一遍,给同样做嵌入式测温或者 HVAC 设备开发的工程师做个参考。
先说清楚这套方案到底是干嘛的。PJ85718DM 是一颗集成了本地温度传感器和远程温度检测通道的芯片,它不光能测自己周边的环境温度,还能外接一个二极管测温探头(比如常见的 2N3906 这类三极管的 BE 结),通过检测二极管结压差来算远端温度,最典型的使用场景就是风管温度、电机线圈温度或者散热器表面温度。STM32L152ZD 则是低功耗设计里很顺手的 Cortex-M3 系列 MCU,芯片本身带段码 LCD 控制器,做 HVAC 面板显示很合适。两者用 I2C 一接,硬件简单,软件也不复杂,整套下来无论是做变风量末端、恒温器还是工业仪表,都能直接抄作业。
我接下来按项目推进的顺序讲,从方案选型到硬件设计、从软件驱动到调试踩坑,一步步拆开说。中间会穿插不少我实际操作中总结的经验,这些细节常规文档上很少写。
1. 方案选型:为什么是 PJ85718DM 和 STM32L152ZD
1.1 PJ85718DM 解决的不只是“多点测温”
传统做法里,嵌入式设备要测两个位置的温度,方案无非几种:一,挂两个独立温度传感器,比如两个 LM75 或者两个 DS18B20,各测各的;二,本地用一个传感器,远端用 NTC 热敏电阻加一路 ADC 采集;三,用热电偶加冷端补偿。这些方案都有明显短板:两个传感器的功耗和成本翻倍,NTC 的线阻误差很头疼,热电偶更是要额外处理冷端和放大电路。
PJ85718DM 这类“本地 + 远程”二合一芯片,设计思路完全不同。芯片内部有一个本地感温单元,同时引出 D+ 和 D- 两个引脚,用来接一个外部二极管结。远程测温的基本原理是:给二极管施加两个不同大小的偏置电流,测量两种电流下的 Vbe 差值,根据 PN 结方程,这个 delta Vbe 与绝对温度呈线性关系,芯片内部 ADC 把这个差值数字化,再查表或者按系数换算成温度值。这里的核心优势是,温度信号不是以电压绝对值为载体,而是以两个电流下的压差为载体,抗干扰能力强得多,而且不需要热敏电阻那样的标定。
在 HVAC 应用里,这套思维非常合适。比如中央空调的送回风温度、压缩机电机表面温度、风阀执行器内部温度,这些点要么离主板远、要么处于强电附近,用二极管探头走线比把传感器小板挪过去方便得多。把 PJ85718DM 放在主控板上,只拉两根线到远端探头,整体系统简洁、成本低,还避免了多点传感器校准的麻烦。
1.2 STM32L152ZD 的定位:低功耗和面板显示两头兼顾
选 MCU 的时候,我一开始犹豫过要不要上更强的 M4 系列,后来发现对于温度监测这种活儿,绝大多数算力都是浪费。STM32L152ZD 是 Cortex-M3 内核,主频虽然不算高,但处理 I2C 通信、LCD 段码刷新、PID 控温逻辑都绰绰有余。真正让我决定选它的原因是两个:一是这颗芯片的 STOP 模式功耗非常低,2 微安左右,这对 HVAC 现场仪表或者电池供电的温湿度变送器特别重要;二是它内置段码 LCD 控制器,可以直接驱动液晶显示温度、设定值和状态,省掉一颗外部 LCD 驱动芯片。
还有一个容易忽略的点:STM32L152 的 I2C 外设在低功耗模式下可以保持寄存器配置,配合外部中断唤醒,能实现“传感器报警引脚触发 MCU 从 STOP 醒来”的链路。这意味着系统可以不定期轮询,而是靠 PJ85718DM 的 ALERT 输出去敲 MCU 的门,整体功耗可以压得非常低。这正好呼应了嵌入式温度监测里最常见的需求:既要“知道温度超限了”,又不想让主控一直傻乎乎地睁着眼睛。
2. 硬件设计:把传感器和主控之间的路铺好
2.1 PJ85718DM 外围电路与最小系统
先讲芯片本身的外围电路。PJ85718DM 正常工作电压我这次用的是 3.3V,和 STM32L152ZD 共用一组电源。电源引脚旁边我没有省料,放了 0.1µF 陶瓷电容和 1µF 的钽电容并联,放在芯片电源脚尽量近的位置。这个组合是为了高频去耦和低频储能同时兼顾,温度传感器这种模拟味道很重的器件,电源纹波直接影响转换结果,不能只图省事放一个小电容。
SDA 和 SCL 两个 I2C 引脚需要接上拉电阻。我选了 4.7kΩ,这个值在 400kHz 速率下是比较通用的选择。单片机那边如果也有内部上拉,记得关掉或者评估并联后的等效阻值,我遇到过并联后上拉太强导致下降沿变慢的情况,波形看着就一股“拖泥带水”的味道。ALERT 报警输出引脚同样接了一个 4.7kΩ 上拉到 3.3V,开漏输出,低电平有效,这个信号我引到了 STM32L152ZD 的一个 EXTI 引脚上,用来做硬件唤醒。
远程二极管部分的连接,D+ 和 D- 分别接到探头的正负端。如果探头用的是三极管的 BE 结,PNP 三极管比如 2N3906 的接法是 E 极接 D+,B 极接 D-,C 极悬空。这个极性接反会造成读数完全不对,不是简单的“偏高偏低”,而是可能出现离谱的负值。我一开始在这个细节上翻过车,后来养成了习惯:原理图标注引脚极性,PCB 上也印丝印,防止产线装配时装反。
2.2 PCB 布线原则:远程测温的成败都在这
很多工程师拿到这类远程温度传感器,第一步就把 PCB 布线想简单了,觉得不就是两根信号线嘛,拉过去就行。实际在 HVAC 现场,变频器、压缩机、继电器都是强大的干扰源,远程测温走线稍不注意,温漂和跳变能把你逼疯。
我这次的做法是这样:D+ 和 D- 从芯片出来以后,优先使用双绞线结构,PCB 上做不到双绞线就做差分走线,两根线紧贴着平行走,间距保持 0.2mm 以内,尽量保证等长。远端二极管接口两边还加了 RC 滤波,具体位置我放在了芯片侧,串联电阻选 100Ω 左右,对地加 1nF 电容。这里要注意,滤波电容不能加得太大,否则远程测温的动态响应会变慢,而且有些芯片的滤波算法会和外部电容互相影响,轻则读数滞后,重则振荡。
本地温度测量虽然不需要走线,但芯片自己会发热。PJ85718DM 的本地感温单元测的是芯片周围的环境温度,如果把它放在发热元件旁边,比如功率电阻或者 MCU 附近,读数会明显偏高。我的处理方式是:把传感器芯片放在 PCB 的边缘区域,下方不做大面积铺铜,尽量和发热源拉开距离。STM32L152ZD 本身功耗不高,但长期运行也会有温升,所以两个芯片之间留了至少 1cm 的隔离带,中间只有信号线穿过,没有铜皮连着两侧。
2.3 STM32L152ZD 最小系统要管好的几个引脚
STM32L152ZD 最小系统本身不复杂,但有几个地方容易走神。一个是 VDDA/VREF 引脚,温度监测对 ADC 精度要求高,VREF 必须要稳定,我用了 10µF 和 0.1µF 的组合去耦,并且没有把 VREF 直接接到 VDDA,而是单独走线到电源输出点。另一个是复位引脚,我加了 100nF 电容,防止现场继电器动作时复位波动。
时钟方面,SVL 这个项目里我用了外部 8MHz 晶振作为主时钟,另外接了 32.768kHz 的 LSE 晶振给 RTC 用。本来考虑过用内部 HSI 省两个元件,后来想想 HVAC 设备一年到头跑 24 小时,系统时钟精度和稳定性的优先级更高,外部晶振虽然占一点位置,但求个安心。I2C 的时钟我直接从 PCLK1 分频出来,配置成 400kHz,实测没有因为时钟源误差导致通信异常。
3. 软件实现:温度数据从寄存器到工程量的完整链路
3.1 I2C 通信初始化和寄存器配置注意事项
软件第一步是把 I2C 跑起来。STM32L152 的 I2C 外设初始化有固定套路:开时钟、配 GPIO 为开漏模式、设置时序、使能外设。有一点容易犯迷糊:STM32L152 的 I2C 外设是 V1 版本的,和后来 F4 上的 V2 版本寄存器完全不一样,网上抄代码时务必确认内核系列,否则 initialize 函数编译通过但实际跑不起来。
PJ85718DM 的从机地址由地址引脚决定,默认地址我看资料是 0x48 这个档位(实际以规格书为准),一根地址线拉高就变 0x49,可以在单个 I2C 总线上挂两片。我的板子上只挂了一片,但软件还是留了地址参数,方便以后扩展。初始化流程按顺序走:先读设备 ID 寄存器确认芯片在位,然后配置转换分辨率、报警阈值和 ALERT 模式。
把报警阈值配好很重要。以 HVAC 应用为例,比如风管温度报警上限设 45°C,下限设 5°C,这个值直接写到高/低阈值寄存器里。ALERT 模式我选择了比较模式而非中断模式,比较模式的好处是:温度回到正常范围后,报警引脚自动释放,不需要 MCU 去清标志,对于睡眠唤醒这种场景特别省事。中断模式则必须软件读状态寄存器才能清,否则报警引脚一直锁住。
3.2 本地温度读取的代码骨架
我习惯把温度传感器驱动封装成一个独立模块,对外只暴露temp_init()和temp_read()两个接口。读取本地温度时,流程是:先发起始信号和写命令,选中温度寄存器;然后发起读操作,连续读两个字节,拼成一个 16 位值。这里需要特别注意符号位。PJ85718DM 这类芯片的温度寄存器用二进制补码表示正负温度,如果高位是 1,说明现在是零下,直接当无符号数拼出来会得到 200 多度的荒谬值。
下面是一段我实际用的读取代码骨架,比较简单,但结构可以直接套。
uint16_t temp_raw; float temp_c; temp_raw = i2c_read_reg_16bit(TEMP_DEV_ADDR, REG_TEMP); if (temp_raw & 0x8000) { temp_raw |= 0xF000; /* 符号扩展,保留低位数据 */ } temp_c = (int16_t)temp_raw * 0.0625f; /* 具体 LSB 值以规格书为准 */这里0.0625f是常见 12 位分辨率下的温度系数,也就是一位 LSB 代表 0.0625°C。有些芯片在更高分辨率模式下系数会变成 0.0078125,实际开发时根据寄存器配置来定。我在代码里用一个宏定义好,方便调试时切换。
3.3 远程温度读取与非线性处理
远程温度的读取流程和本地差不多,但它的原始值代表的是远端二极管结的温度,而不是芯片周边温度。读取方式同样是连续读两个字节拼成 16 位值,换算系数也类似,但转换关系可能多了一个偏移或斜率修正,具体由芯片的数据手册给出。我这次用的 PJ85718DM,远程通道的 LSB 系数和本地相同,只是数据需要经过一个非线性校正表做进一步处理。
校正表这块是远程测温软件里最有价值的环节。二极管结的 Vbe-T 特性虽然理论上接近线性,但实际受制于工艺、封装和串联电阻,会有非线性。如果产品要求全温域误差在 ±1°C 以内,光靠芯片内部的固定曲线是不够的。我的做法是在产测环节做两点校准:冰水混合物作为 0°C 参考点,恒温槽作为高温参考点,测出实际读数点和理论值的偏差,拟合出偏移和斜率两个校准系数,存到 STM32L152ZD 的内部 Flash 里。每次启动读出来,和原始换算结果做一次线性修正。这个方法简单直接,效果却非常明显。
软件滤波也必不可少。HVAC 现场的温度变化本身很慢,一秒采一次完全足够,我做了队列缓存,取最近 16 次转换结果,先去掉最大最小值,再对剩余值求平均。这个一阶中值滤波能把偶尔出现的尖刺毛刺滤掉,同时又不会像滑动平均那样带来肉眼可见的滞后。
3.4 低功耗模式下的采样策略
STM32L152ZD 的优势要发挥出来,软件上必须采取“间断采样 + 报警唤醒”的策略。我在正式版的固件里没有让 MCU 一直循环读温度,而是这么设计的:
先把 PJ85718DM 配置成单次转换模式。在睡眠前,MCU 通过 I2C 发一个启动转换命令,然后立即进入 STOP 模式。芯片转换完成后,温度值会锁存在寄存器里。如果温度没有超限,STOP 模式的唤醒就交给低功耗定时器,每 2 秒醒来一次,用 I2C DMA 快速读温度再继续睡;如果温度超过阈值,PJ85718DM 的 ALERT 引脚拉低,MCU 的 EXTI 外部中断把它唤醒,立刻进入报警处理流程。
这里有个细节要提醒:I2C 通讯在 MCU 睡眠期间,总线上不能有设备主动发起通信,否则会挂在半道上。我们的 I2C 两个引脚配置成外设模式,不是普通 GPIO 模式,睡眠时外设保持空闲状态,不会被误拉低。上拉电阻此时也在睡眠时继续耗电,我评估过两个 4.7k 上拉在 3.3V 下的漏电大约在几百微安级别,对整体功耗有影响但不能省,因为省掉上拉,I2C 就无法可靠唤醒通信了。如果对功耗要求极致,可以考虑把上拉切换到 MOS 管控制,睡眠时断开,但这种做法会增加复杂性,我这个项目没有采用。
4. 本地与远程温度校准:为什么读数和你预期不一样
4.1 本地温度自发热的影响
本地温度读数最容易出现的问题是“偏高”,而且具有欺骗性:偏高幅度看起来不大,大概 0.5°C~1°C 之间,但恰恰是这种“感觉不太离谱”的误差最难排查。原因在于芯片工作时的自发热。PJ85718DM 在连续转换模式下,内部 ADC 和信号调理电路一直在工作,芯片自身的功耗转化为温升,而本地传感器恰恰测的就是封装附近温度,等于把加热器放在温度计旁边。
改善手段有三个方向:一是改单次转换模式,转换一完成就切断部分内部电路,数采间隔拉长后自热影响会明显下降;二是在 PCB 布局上避免传感器周围铺铜,因为铺铜是散热通道,热量顺着铜皮传过来,芯片温升更高;三是做静态补偿,在代码里根据工作模式预设一个偏移量,比如连续模式下补偿 -0.4°C,单次模式下补偿 -0.1°C。这个偏移量需要实际测温标定,不能拍脑袋写。
4.2 远程二极管的串联电阻和 Beta 误差
远程测温的误差来源和本地完全不同,最大头是串联电阻和晶体管放大倍数。远程二极管到芯片之间的导线、探头自身的引线框电阻,都会在电流切换时造成额外的电压误差。芯片内部如果支持串联电阻抵消功能,需要确认开启。这个功能实现原理是:在两种不同电流下分别采集电压,通过计算差分值来消掉串联电阻上的电阻压降。如果芯片没有这个功能,就只能严格控制电缆长度和电阻,或者用四线制接法。
三极管当作二极管用时,Beta 值误差也会影响 Vbe-T 曲线。不同批次的 PNP 三极管,Vbe 有可能偏差几十毫伏,反映到温度上就是几度的问题。所以产测校准不能省,而且每台设备最好都做存储校准系数。我在现场调试时见过最夸张的情况:两个看起来一模一样的探头,插在同一个测试点,读数差了 2.3°C。后来一查,一个是原厂封装的二极管探头,另一个是产线自己用贴片三极管做的,两者 Beta 和串联电阻都不一样,校准之后才拉回来。
4.3 校准流程如何落地
我这次项目的产测流程很简单:预装烧录阶段,设备上电后进入校准模式。第一步读取本地温度,此时设备必须和环境温度完全一致,一般是在恒温间里放半小时以上;第二步接标准探头读取远程温度,用恒温槽产生一个精确的设定温场;第三步上位机通过串口下发标准温度值,MCU 内部计算出偏移和斜率,写入 Flash 的最后 4 个字节。之后设备重启,正常运行模式下会自动加载校准量。
这个流程最好在单板阶段完成,不要在整机装配后再做,因为整机外壳散热不均,标准温场建立困难。另外校准数据和固件版本最好绑定,固件升级时把校准区单独保留,不要整片擦除。我吃过这个亏,某次升级把校准数据覆盖了,产线上几十台设备全部返工校准,教训深。
5. 现场调试实录:四个典型问题和对应解法
5.1 远程温度读数周期性跳变
项目做到硬件联调阶段,第一个遇到的问题就是远程温度读数每秒钟跳一次,幅度在 0.5°C~1°C 之间,规律性很强。用示波器夹在 D+/D- 上能看到,每当板子上的继电器吸合,走线上就会叠加大幅度的毛刺。这不是传感器坏了,而是共模干扰通过探头线耦合进差分回路。
处理办法分两步走:硬件上,D+/D- 线上加共模磁珠,并且把探头线换成屏蔽双绞线,屏蔽层单端接地;软件上,把采样窗口安排在继电器动作之后 50ms 再启动,避开干扰最剧烈的时间窗。双管齐下后跳变彻底消失,读数稳得像是画出来的直线。这里我提醒一句:不要一上来就靠软件滤波去“压”干扰,那是在治标不治本,硬件上的问题必须根治。
5.2 读出来的温度数值是 0 或者满量程
有一次调试时发现,远程通道读出来一直是 0.00,开始怀疑芯片坏了,换了一片还是同样问题。最后查出来是探头接线极性接反了。这类传感器对 D+/D- 极性非常敏感,接反后输出电压差极性完全相反,芯片内部转换出来的数值要么饱和到负值,要么直接钳位到 0。解决方法很简单:把探头两根线对调。但产线装配如果不注意丝印标识,很容易批量返工,所以原理图和 PCB 上一定要有清晰的极性标注。
5.3 ALERT 引脚频繁误触发
报警阈值设在 40°C,正常运行时温度在 39°C 附近徘徊,结果 ALERT 引脚一会有信号一会没有,MCU 被频繁唤醒。原因很好理解:温度原本就在阈值附近波动,哪怕波动幅度只有 ±0.5°C,也会反复穿越阈值。解决方法是配置芯片的迟滞寄存器,我设了 +2°C 迟滞,也就是温度升到 40°C 触发报警后,必须降到 38°C 以下才会解除,这样不会来回翻转。
另外我还加了一层软件消抖:在中断服务函数里不立刻处理报警,而是置一个标志位,主循环里连续读到三次超限才真正进入报警状态。这个设计看起来简单,但在现场能避免大量无谓的报警短信和夜间误报。
5.4 整机电流比预期大很多
低功耗调测阶段,整机平均电流怎么都压不下去,原本预估几十微安级别,实测到毫安级别。检查了一圈,问题出在 STM32L152ZD 的 GPIO 配置上。I2C 的 SCL/SDA 引脚在睡眠时虽然由外设接管,但我还有两个普通 GPIO 接到了报警 LED,睡眠时忘了把这两个引脚配置成高阻输入,结果内部上拉一直在灌电流,一路多出几百微安。另外 LCD 背光没有在睡眠时关闭,也贡献了不少电流。把所有外设引脚在睡眠前统一走一遍状态配置,电流立刻降到预期范围。
这类低功耗问题最好用排除法:睡眠前把所有外设关掉,然后逐个打开定位耗电源,一次只变一个变量,不要一起调,否则很难找到真凶。
6. 应用扩展思路:这套组合还能往哪些方向走
6.1 从 HVAC 延伸到嵌入式系统热管理
PJ85718DM + STM32L152ZD 这套组合不只能在空调设备上用。嵌入式设备里如果主控芯片功耗大,比如跑 Linux 的应用处理器,可以利用远程测温通道把二极管探头贴在 CPU 散热器或者功率模块的基板上,实时监控结温,再配合风扇调速。STM32L152ZD 在这里扮演“热管理协处理器”的角色,负责收集温度数据、执行风扇 PWM 控制、上报给上层系统。这种分工会让主控从温度采集的负担中解放出来,系统整体可靠性也更高。
6.2 通过通信接口扩展为多节点温控系统
单个 STM32L152ZD 的 I2C 总线上可以挂多片 PJ85718DM,地址引脚可以配置成多个不同地址。如果现场有多个测点需求,比如空调机组的送风、回风、盘管、压缩机、室外温度,一片主控可以同时管理八个测温点,每片传感器负责本地和远程双通道,测点数量可以轻松扩展。上位机或者楼宇自控系统则可以通过 RS485 或者 Modbus 协议,把温度数据整合到整个管理平台里。这个扩展思路在工业空调和机房监控领域非常实用。
6.3 关键经验总结
最后分享几个我个人踩过坑后沉淀下来的经验。第一,远程温度传感器的布线质量决定了系统精度的上限,软件滤波只能修补不能创造奇迹,好的现场安装才能拿到好的数据。第二,任何补偿和校准参数都要有可追溯性,在 Flash 里单独划区域管理,不要和固件更新互相干扰。第三,出问题时先简化问题:本地温度准不准,锚定芯片本身有没有问题;远程温度准不准,再检查探头、线缆、极性。一步一步排除,不要一上来就怀疑芯片和软件。这套思路帮我解决过很多现场看起来神秘莫测的故障,希望也能帮你在类似项目里少走弯路。