PJ85718DM 加 PIC32MX664F064L 这套组合,是我在嵌入式主板温度监测和 HVAC 控制器项目里用了比较长时间的一套方案。解决的核心问题很明确:一个 MCU 同时拿到本地温度和远程温度,并且温度数据可靠、可调试、可参与控制。文章面向准备做温度采集的嵌入式工程师、工控设备的开发朋友,以及想改进风机盘管或空调控制器逻辑的开发者。看完之后,从硬件接线到固件读取,再到实际场景里的调试手段,都能直接照着做。
1. 方案背景:为什么用 PJ85718DM 搭配 PIC32MX664F064L
1.1 本地与远程温度到底指什么
很多刚接触温度采集的人会被“本地”和“远程”这两个词绕晕。这里的本地温度,并不是指“在本地电脑上显示”,而是指传感器芯片自身所在位置的温度。PJ85718DM 内部集成了一个测温通道,直接测量自己管脚周围的环境温度,也就是板级温度。远程温度则是指通过专用引脚连接外部测温元件之后,测到的远处某个点的温度。
这种“一个芯片测两个点”的设计,在嵌入式领域非常实用。比如 CPU 主板、交换机、电机驱动器,既要关注板卡附近的环境温度,又要单独测量功率器件、电池模组或电机绕组的温度。传统做法是放两颗热敏电阻,再接 MCU 的 ADC,但热敏电阻的线性度差、互换性差,而且 ADC 的参考电压波动会直接影响精度。用专用温度传感器芯片就不一样,它内部有高精度 ADC 和校准逻辑,MCU 只要通过 I2C 读寄存器,就能拿到已经处理好的数字温度值。
HVAC 场景也非常典型。一套空调控制器,需要测回风温度、送风温度、室外温度、盘管水温。回风和送风通常就在控制板附近,属于本地测量;室外温度或者远端管道内的温度,传感器离 MCU 可能有几米甚至几十米,这是远程测量。PJ85718DM 这种自带远程通道的芯片,可以把远端探头通过两根线引出去,避免在远端单独放单片机或者加独立 AD 模块。
1.2 器件选型思路
PIC32MX664F064L 这个单片机的主频和外设丰富度,决定了它能同时处理好“读温度、跑 PID、操作继电器、跑通信协议”这些任务。我见过很多项目用 8 位单片机做 HVAC 控制,温度采集本身没问题,但一旦加入 Modbus 通信、LCD 显示、参数存储和多个模拟量输入,Flash 和 RAM 就开始紧张了。PIC32MX664F064L 属于 MIPS 内核的 32 位 MCU,跑 80 MHz 主频完全不是问题,I2C、UART、SPI、定时器、外部中断都齐全,做这类多任务应用游刃有余。
选择 PJ85718DM 而不是继续堆热敏电阻,主要是看中三点:
第一,双通道集成。一片芯片完成本地和远程温度采集,PCB 面积小,BOM 成本低,调试也方便。第二,I2C 接口。MCU 侧只需要两根线,SDA 和 SCL,就算以后要多点测温,也可以通过地址线挂多片,不会占用更多 IO。第三,数字输出免校验。温度值读出来就是数字,不存在热敏电阻的 Steinhart-Hart 方程计算,代码简单,误差可控。
当然,这套方案也有前提。PJ85718DM 的远程通道要求测温元件是二极管或三极管的 PN 结,不是任意一个 NTC 都可以接。这个限制在不少资料里没写清楚,导致有人把热敏电阻直接怼上去,读出来的温度完全不对。后面我会专门讲远程通道的正确接法。
2. 硬件电路设计:把传感器和单片机接起来
2.1 引脚分配与外围电路
先看 PJ85718DM 的基本外围。芯片通常有 VCC、GND、SDA、SCL、D+、D−,还可能有 OS 或 ALERT 输出脚,以及地址选择脚 A0、A1。VCC 接 3.3V,注意做 0.1μF 和 1μF 的去耦电容,尽量靠近电源引脚。SDA 和 SCL 是开漏输出,必须接上拉电阻,典型值 4.7kΩ。如果 I2C 线上挂了多个设备,上拉电阻可以适当减小到 2.2kΩ,但要考虑总线的整体负载。
连接 PIC32MX664F064L 时,I2C 引脚要查数据手册的引脚映射表,不要凭经验猜。我曾经把某个型号的 SDA1 当成 SCL1 接,结果通信完全不通,查了半小时才发现引脚映射搞错了。PIC32 这类 MCU 的引脚复用很强,同一个外设可能映射到好几组引脚,必须在初始化代码里正确设置对应引脚的配置位。
供电方面,嵌入式场景如果系统里同时存在继电器、电机、开关电源,建议传感器区域用单独的 LDO 或者磁珠隔离,避免大电流器件瞬间拉低电压,导致温度读数跳变。HVAC 场景就更要注意,风机、压缩机启停瞬间会产生很大的 EMI,控制板和传感器之间最好做到电源隔离,或者在传感器电源入口加 TVS 管和磁珠。
地址线 A0 和 A1 可以组合出多个 I2C 地址。默认状态下,芯片地址可能在 0x4C 附近,实际以手头数据手册为准。如果要在一条总线上挂多片,就把 A0/A1 分别接 GND 或 VCC,形成不同地址。多片传感器之间,SDA 和 SCL 共用,去耦电容各自放。
2.2 远程探头设计的注意事项
远程通道的 D+ 和 D− 引脚,是接外部二极管或三极管的 PN 结用的。常见接法是用小功率三极管,比如把基极和集电极短接,当作二极管来用,这样远端探头只需要两根线。为什么用三极管短接而不用普通二极管?因为三极管的 PN 结面积和电流特性更适合这种测温方式,测量一致性也更好。
远程探头到 D+/D− 的走线,是整个设计里最容易出问题的地方。距离较短时,比如板上到功率器件 10 厘米以内,直接走普通 PCB 走线问题不大。如果距离超过半米,比如 HVAC 里把探头甩到风管深处,就必须用屏蔽双绞线,屏蔽层单端接地。D+/D− 之间还要加一个小电容,常见是 1000pF 以内,用于滤除共模干扰。电容加得太大,比如 0.1μF,会明显拉长温度传感器的建立时间,导致读数滞后甚至严重偏低。
我特别想提醒的一点是,千万不要把远程通道跟 MCU 的 ADC 输入混用。PJ85718DM 的 D+/D− 是专为二极管测温设计的偏置电路,输入的电流方向和幅值都跟 NTC 分压电路完全不同。强行接 NTC 或者接成正向二极管方向接反,轻则读数异常,重则损坏芯片内部电路。
另外,D+ 和 D− 的极性必须保持正确。有人把两根线接反之后,读出的是一个负温度,或者直接读到最大值。如果发现远程温度显示成“不可用”类错误码,第一步就要查这两根线有没有接反,第二步再查探头有没有短路或断路。
3. 固件实现:读取本地与远程温度
3.1 I2C 通信流程
PIC32MX664F064L 初始化 I2C 外设,主要做三件事:设置主模式、配置波特率、使能外设。I2C 波特率在 HVAC 这类低速场景下,100kHz 或者 400kHz 都够用。温度传感器本身数据更新频率不高,不需要跑特别快,反而慢一点抗干扰。通信流程可以拆成四个步骤。
第一步,先向 PJ85718DM 发送寄存器地址,确定读哪个寄存器。第二步,发起重复起始信号,然后把从机地址改成读方向。第三步,读回两个字节,分别是高位和低位。第四步,根据寄存器格式把二进制数据换算成温度。
如果直接用寄存器操作,PIC32 的 I2C 收发需要手动处理 ACK/NACK 和总线状态,代码会偏底层。我建议在工程里做一个简单的 I2C 封装,把启动、发地址、读写字节、停止这几个动作抽象成函数,后续读任何 I2C 设备都能复用。
static uint8_t temp_read_reg(uint8_t reg) { uint8_t val = 0; // 启动 I2C 事务 i2c_start(); // 发送从机地址 + 写位 i2c_write_byte((PJ85718DM_ADDR << 1) | 0); // 发送寄存器地址 i2c_write_byte(reg); // 重复起始,切换为读 i2c_repeated_start(); // 发送从机地址 + 读位 i2c_write_byte((PJ85718DM_ADDR << 1) | 1); // 读取一个字节 val = i2c_read_byte(); // 停止 i2c_stop(); return val; }上面这段代码用的是自封装的 i2c 系列函数,在不同项目里替换成自己平台的底层驱动即可。PIC32MX664F064L 如果用 Harmony 开发环境,也可以直接用 PLIB 的 I2C API,逻辑完全一样。
读本地温度时,需要读本地温度寄存器的高字节和低字节,然后合成一个 16 位值。读远程温度同理,只是寄存器地址不同。有些型号还支持配置寄存器、状态寄存器、报警阈值寄存器。报警阈值可以在芯片内部设定,当温度超过阈值时,ALERT 引脚会拉低,告诉 MCU 温度异常。
3.2 温度换算与负温处理
PJ85718DM 输出的通常是有符号数。比如本地温度寄存器的高字节是高 8 位,低字节的低 4 位有效,把两个字节拼成一个 16 位整数,然后右移 4 位,得到带符号的 12 位温度值。最后乘以分辨率系数 0.0625°C/LSB。
static float convert_temp(uint16_t high, uint16_t low) { int16_t raw = (int16_t)((high << 8) | low); raw = raw >> 4; return (float)raw * 0.0625f; }负温度处理是新手容易踩坑的地方。当温度低于 0°C 时,高字节的最高位是符号位,若直接把两个字节合并成无符号整数,再右移,就得不到正确结果。上面的代码先转为 int16_t,再右移,利用算术右移保持符号。在实际编译环境下,绝大多数编译器都会做正确的算术右移,但如果你的开发环境比较特殊,建议用显式判断符号位的方式处理。
我习惯的做法是,每次读取之后打印原始十六进制值,再打印换算后的温度值,两者对照。这能在联调阶段快速判断是传感器问题还是换算代码问题。如果原始值始终是 0x0000,那就是根本没读到数据;如果读到了 0x1800 左右,但换算出来是负值,就要检查符号处理和右移位数。
3.3 多传感器组网与报警
一条 I2C 总线上挂多片 PJ85718DM 时,每个传感器要有独立地址。初始化阶段,MCU 依次读取每片传感器的 ID 或配置寄存器,确认通信正常。为了避免第一片传感器故障导致后续设备无法访问,可以在每片传感器的 SCL 和 SDA 线上加串联电阻,比如 220Ω,这样单片损坏时更容易隔离。
报警功能的实现,有两种思路。一种是把芯片的 ALERT 引脚接到 PIC32MX664F064L 的外部中断输入,温度越限时芯片主动通知 MCU。另一种是 MCU 定时轮询状态寄存器,例如每 200ms 读一次,发现越限就进入处理流程。前者的实时性更好,适合对温度变化敏感的散热控制;后者逻辑更简单,适合 HVAC 这种温度变化本来就慢的场景。
使用 ALERT 引脚时要注意,中断发生后必须读取状态寄存器来清除中断标志,否则芯片会一直拉着低电平,MCU 中断服务程序会被反复触发。我在一个机箱热管理项目里犯过这个错误,现象是程序每隔几毫秒就进一次中断,看起来像死机,实际上是中断标志没有清干净。
4. HVAC 场景实战:风机盘管与室外温度补偿
4.1 温度数据如何参与控制
在 HVAC 项目里,我常用 PJ85718DM 的本地通道测控制盒环境的温度,远程通道测室外温度或管道温度。以风机盘管系统为例,本地回风温度参与启停控制,远程室外温度参与冷热模式切换和节能补偿。
举个例子,夏季制冷模式下,当回风温度高于设定温度 1°C 时,启动风机和冷水阀;当回风温度低于设定温度 1°C 时,停止制冷。如果不考虑室外温度,这类控制也能工作,但容易出现“白天太阳直射导致房间温度快速升高,而控制系统反应迟钝”的情况。引入远程室外温度之后,可以根据室外高温提前加大制冷量,或者根据昼夜温差调整设定点。
这里用一个简单的 PID 控制器来调节电动二通阀的开度。温度传感器每隔 500ms 读一次回风温度,经过滤波之后进入 PID 计算,输出占空比控制三通阀或二通阀。PID 参数要根据实际系统现场整定,不能直接照搬网上现成的值。
static float pid_update(float setpoint, float measured, float dt) { static float integral = 0.0f; static float last_error = 0.0f; float error = setpoint - measured; integral += error * dt; integral = limit(integral, -1.0f, 1.0f); float derivative = (error - last_error) / dt; last_error = error; return Kp * error + Ki * integral + Kd * derivative; }积分限幅很重要。电机阀或风阀的执行机构有限位,积分项积累过大,会造成系统震荡。我调试过一套系统,开始没做积分限幅,阀门卡在最大开度位置,房间温度过冲了 3°C 才回落,客户差点以为是传感器坏了。
4.2 软件滤波与标定
HVAC 环境的温度变化相对缓慢,但传感器读数依然会受风管内气流扰动、风机启停、压缩机电磁干扰的影响。软件上要做滤波。最常用的一阶低通滤波器:
static float lowpass_filter(float current, float previous, float alpha) { return alpha * current + (1.0f - alpha) * previous; }alpha 一般在 0.1 到 0.3 之间。alpha 越大,响应越快,但噪声也越大;alpha 越小,数据越平滑,但响应滞后越明显。对于 HVAC 应用,温度变化本身很慢,alpha 取 0.1 左右很合适。如果是电机驱动器上的功率器件温度,变化可能非常快,alpha 反而要取大一些,比如 0.5。
标定方面,PJ85718DM 这类数字传感器出厂时已经做过内部校准,但不同批次之间还是存在少量偏差。如果系统要求绝对精度,比如控制在 ±0.5°C 以内,可以在调试阶段用精度更高的参考温度计做两点校准。方法很简单:把传感器和参考探头放在同一恒温环境,记录芯片读数和参考读数,求出偏移量,然后在软件里做补偿。
很多数字温度传感器还支持负温度系数调整或斜率校准寄存器。我一般不会动斜率,只补偿偏移,因为偏移补偿不容易产生非线性误差。做完偏移补偿之后,还需要在低温、常温、高温三个点重新验证,防止偏移量在不同温度段不一致。
5. 嵌入式场景实战:机箱热管理与风扇调速
5.1 测点布局与报警阈值
嵌入式主板上,最值得关注的温度点有两类:一类是板级环境温度,另一类是 CPU 或其他功率芯片的内核温度。PJ85718DM 的本地通道可以贴在板子上测环境温度,远程通道通过二极管探头直接接触 CPU 下方的测温二极管,或贴在功率 MOS 管表面测外壳温度。
测点布局上有一个容易被忽略的因素:探头的位置不要只考虑“好安装”,还要考虑“测的是哪里”。远程探头离热源太远,读数会受到周围空气温度干扰;离得太近,又可能接触到高压引脚,存在安全风险。我的经验是,功率器件表面测温时,探头要尽量靠近器件中心,和器件之间加一层绝缘导热的垫片,既保证导热能力,又避免短路。
报警阈值要结合产品的使用环境来定。普通民用设备,板级环境温度达到 70°C 就可以触发告警;工业设备可能需要到 85°C 才告警,同时还要区分“告警”和“保护停机”两个等级。触发保护动作之后,必须要有解锁条件,通常要温度降到恢复阈值以下,并且持续一定时间,比如 30 秒确认稳定,才能解除锁定。
5.2 风扇调速策略
用温度控制风扇转速,比风扇全速运转更有价值。既能降低噪音,又能延长风扇寿命。我常用的策略是分段调速加温和的 PID 闭环:温度高于起始阈值时,风扇开始旋转,转速随温度上升线性增加;温度很高时,进入 PID 闭环,把温度控制在目标值附近。
在 PIC32MX664F064L 里生成 PWM 控制风扇非常方便,直接用输出比较模块或者定时器产生 PWM。风扇本身最好用四线调速风扇,PWM 频率选在 20kHz 以上,避免可听噪音。三线风扇通过降低供电电压调速,低速下容易停转,不建议用在关键散热位置。
风扇调速还应该加入“占空比对转速”的反馈判断。如果 PWM 输出已经拉到最大,但温度仍然持续上升,说明风扇堵转或风道堵塞。此时候机箱报警而不是死等。这个逻辑在嵌入式设备里很常见,但在 HVAC 控制器里容易被忽略,导致压缩机过热保护才被发现。
6. 常见问题排查与避坑记录
6.1 读数异常
这里整理了我在实际项目中遇到最多的几类问题,基本覆盖了 PJ85718DM 和 PIC32MX664F064L 组合的典型故障。
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| I2C 通信正常,但温度一直不变 | 读错了温度寄存器,或芯片处于待机模式 | 核对数据手册,检查配置寄存器 |
| 本地温度正常,远程温度错误 | D+/D− 接反、远端探头断路 | 检查极性,量 D+/D− 两端通断 |
| 远程温度出现明显偏低 | 远程线电容过大、屏蔽层接地不当 | 减小电容到 1000pF 以内,单端接地 |
| 温度值跳动超过 1°C | 供电不稳、走线受干扰 | 加强去耦,SDA/SCL 上拉电阻调整 |
| 温度读到 127 或不可用值 | 远程传感器断线或芯片内部检测异常 | 重新插拔探头,替换探头测试 |
第 6 行那种 127 不可用值,其实在数字温度传感器里很常见。当内部采样电路发现远端二极管没有正常工作,会直接把结果置成一个错误码。遇到这种情况不要只盯着代码调,先用万用表量探头两根线的导通性,基本能快速定位。
6.2 I2C 总线故障
I2C 总线出现卡死时,现象是 MCU 发送地址之后再收不到 ACK,或者总线一直是低电平。最常见的原因是 SDA 或 SCL 被某设备拉住了。此时可以用示波器看波形,确认是否是设备上电时序问题,导致传感器先上电,MCU 后上电,然后传感器把总线拉死。
解决办法是在初始化阶段加入 I2C 总线恢复流程:当检测到总线忙时,程序主动发送 9 个时钟脉冲,让从机释放 SDA 引脚。这段代码虽然不长,但能解决很多现场问题。
static void i2c_recover_bus(void) { for (int i = 0; i < 9; i++) { scl_high(); delay_us(5); scl_low(); delay_us(5); } i2c_start(); i2c_stop(); }如果你用的是 PIC32MX664F064L 内置 I2C 外设,还有更彻底的恢复方式:把 I2C 外设复位,重新初始化。但要注意,复位外设之后,如果总线电平仍然被拉低,说明外部从机还在占用总线,这时候需要从硬件侧排查是哪颗芯片的问题。
6.3 温度漂移与干扰
温度读数漂移不一定是传感器问题。PCB 布局不合理,传感器靠近大电流走线或电源模块,测出来的温度会偏高。远程通道对干扰更敏感,因为 D+/D− 引脚的信号幅度很小,外部电场耦合会被当成温度变化。HVAC 现场到处是继电器和电机,电磁环境比较恶劣,我见过远程温度跳变 5°C 以上的情况。
排查干扰问题时,可以先把远程探头拔掉,换成一颗已知正常的二极管直接插在板端。如果读数稳定,说明问题出在外部引线上;如果读数还是不稳定,说明干扰从板内电源或地线进入。板内干扰一般通过改善去耦和减小地回路解决,外部引线干扰则要换屏蔽线,并把屏蔽层在板端单点接地。
还有一个容易被忽略的点:PIC32MX664F064L 本身也是热源。如果单片机工作频率较高,MCU 发热会通过铜皮传递到传感器附近,导致本地温度偏高。所以我建议本地温度通道不要紧贴着 MCU 的电源引脚和时钟晶振区域布置。
7. 实操心得与扩展方向
就我个人的体会来说,PJ85718DM 这类带本地和远程双通道的温度传感器,做嵌入式温度监测的优势非常明显。它让“测一个点”的成本增加不多,却能同时解决“测本地环境”和“测远端热源”两个需求,尤其适合 HVAC 控制器这种既有板级监测需求、又有远端探头需求的应用。
如果后续项目需要在一条总线上挂更多温度点,可以在现有硬件上直接扩展,不必改 MCU。每片 PJ85718DM 占一个 I2C 地址,地址不够时还可以用 I2C 总线切换器扩展。对于 HVAC 项目,也可以把读取到的温度通过 Modbus 等协议上传到上位机,只需要在 PIC32MX664F064L 里加一个串口协议解析任务,不复杂。
最后再分享一个操作上的小技巧:现场调试温度传感器时,不要只盯着最终的温度数值,要养成先打印原始十六进制数据的习惯。我用这个习惯解决过不下五次“看起来是温度不准,实际是寄存器地址或左右移顺序出错”的问题。温度采集链路并不复杂,但越简单的东西,越容易栽在细节上。