做嵌入式温度采集这些年,大家用最多的方案无非是热敏电阻加ADC,或者一颗集成数字温度传感器。但如果你遇到一个场景:现场要同时测两个点,一个在控制板上,另一个要伸到离主控一米开外的位置,而且温度还可能摸到一百多度,普通传感器就开始别扭了。PJ85718DM 这类带“本地+远程P-N结测温”的芯片,就是为这种需求准备的;再配上一颗 PIC18F55K42 做主机,既能现场处理控制逻辑,又能把数据送到后台。这篇我把自己在嵌入式与 HVAC 项目里用这套组合的完整思路、硬件细节、固件实现和踩过的坑一次说清楚。
1. 方案选型与整体设计拆解
1.1 为什么需要“本地+远程”双通道
HVAC 现场有个典型需求:既要测回风温度,又要测蒸发器盘管温度。两个温度点之间的差值,直接反映系统运行是否健康——温差太小,制冷剂可能不足;温差过大,可能滤网堵了或者风量不够。只测一个点,这些判断都做不了。
还有一种更常见的场景:控制板装在室内,传感器探头要伸到室外机或风管深处,两个位置相距几十厘米甚至一两米。用普通热敏电阻探针拉这么长的线,线阻、接插件接触电阻、布线寄生电容都会引入误差,而且校准非常痛苦。PJ85718DM 把两个测量通道集成在一颗芯片里:本地通道用内置温度传感器测芯片周围的温度,远端通道则通过外接一个普通三极管或二极管的 P-N 结来测另一个点的温度。单芯片解决双点测温,布线和物料成本都低。
1.2 与常规方案横向对比
很多工程师第一反应是用 NTC 热敏电阻加分压电阻接 ADC。NTC 本身非线性,要查表或者用 Steinhart-Hart 方程拟合;分压电阻的精度直接决定读数准不准,5% 的电阻就能让你辛辛苦苦写的查表程序白费。更麻烦的是长线传输:线缆电阻会和分压电阻串联,导致 ADC 采到的电压偏低,而且这个误差会随温度变化,难以在软件里补偿。
用两颗单通道数字温度传感器也能实现双点测温,但需要多占一路 I2C 地址、多铺一路走线、多处理一路异常。在 HVAC 这种强电磁干扰环境里,每多一个器件就多一个故障点。
PJ85718DM 这类本地+远程集成方案的优势在于:
- 远程测温利用 P-N 结在不同电流下的压差,引线电阻的影响被原理性地削弱,对长线不那么敏感。
- 芯片内部完成信号调理和模数转换,输出直接进 I2C,抗干扰能力远超分压电路。
- 两颗芯片、一个器件,布线简洁,逻辑也简单。
| 方案 | 测温点数 | 远程走线 | 精度主要影响因素 | 软件工作量 |
|---|---|---|---|---|
| NTC + 分压 + ADC | 1 点/路 | 差,需校准线阻 | 电阻精度、自热、非线性 | 需要查表和标定 |
| 单通道数字传感器 x2 | 2 点 | 一般,需处理长线 | 传感器自身精度 | 需要两套驱动 |
| PJ85718DM 本地+远程 | 2 点 | 好,P-N 结差分测量 | 远端三极管选择、布线干扰 | 单芯片驱动 |
1.3 主控为什么选 PIC18F55K42
主控选型时,我的核心诉求是:单电源 3.3V、有硬件 I2C、引脚够用、抗干扰相对皮实。PIC18F55K42 属于 8 位 PIC 系列,最吸引我的几个点:
第一,内部振荡器可以跑到 64MHz,不需要外挂晶振,少了两个引脚也少了起振不稳的隐患。项目上用起来省心,上电就能跑。
第二,硬件 I2C 模块是现成的,标准模式、快速模式都支持。温度传感器本身就是 I2C 接口,主控硬件 I2C 配上中断就行,不需要用 GPIO 模拟时序,软件简单很多。
PIC18F55K42 还有个特点是集成了一些可配置的外设,比如可配置逻辑单元 CLC 和带计算功能的 12 位 ADC。实际项目里,我用 CLC 做超温报警的硬件输出,不用主循环里一条条判断,逻辑简单而且响应更及时。12 位 ADC 则留着做备用,比如客户又想加一路 NTC 测湿度补偿之类的,不用换主控。
2. 核心细节解析与硬件设计要点
2.1 远程 P-N 结测温的原理
PJ85718DM 的远程通道引出两个引脚,典型命名是 D+ 和 D-。用法就是在两端并上一个外部的 P-N 结,通常用一个通用 NPN 三极管把集电极和基极接在一起,等效成一个二极管。
测量原理简单说:芯片内部向这个 P-N 结施加两个不同大小的电流,然后测量两种情况下的正向压降差。因为二极管的正向压降 VBE 本身随温度变化,但不同电流下的 VBE 差值(ΔVBE)与温度有近似线性的关系,所以可以靠这个差值推算出结温。
这里有一个关键直觉:如果线缆上有电阻,它带来的压降在两种电流下都会叠加,做减法时大概率会被抵消掉。所以这个方案天然对引线电阻不敏感。但反过来说,如果两支引线电阻不对称,或者线上耦合了共模噪声,这个优势就会被破坏。这就是远程测温布线的核心逻辑——原理替你解决了直流压降问题,但现场噪声和不对称阻抗才是真正的敌人。
2.2 远端三极管选型与接口电路
远端二极管直接选通用小信号三极管就可以,比如 MMBT3904 这类。选型时有几个实际经验:
- 选 β 值比较大、一致性好的管子。β 太低或批次差异大,会直接影响 ΔVBE 的线性度。
- 集电极和基极必须短接,集电极接 D+、发射极接 D-。方向接反,读出来就是乱码或一路猛跳。
- 管子要尽量贴近被测物,比如用导热胶贴在盘管表面或翅片之间。封装小、热容小、响应快,更合适。
接口电路上,D+/D- 之间可以加一个小电容做共模滤波,典型值在 1nF 左右。电容加太大,会拖慢 P-N 结的建立时间,测出来温度反而偏差。有工程师想“滤波嘛,越大越好”,结果 10nF 一上去,读数直接漂了好几度——这就是踩过的坑。后续我一般只放 1nF 或者干脆不放,靠软件滤波处理瞬时干扰。
2.3 硬件连接与电源设计
主控和传感器之间我用硬件 I2C 连接,上拉电阻取 4.7kΩ,总线速率跑 400kHz。VDD 用 3.3V,PJ85718DM 的电源引脚旁边放了 100nF 和 1µF 两个去耦电容,一高一低搭配,覆盖不同频率的噪声。
如果系统里还有继电器、变频风机这类强干扰源,我强烈建议在 PJ85718DM 供电入口串一个小磁珠,或者干脆用单独的 LDO 给它供电,不要直接挂在 DCDC 的输出上。DCDC 的开关噪声在远端测温这种毫伏级测量场景下是致命的。
PCB 布局有两条硬性要求:
- 远程测温线 D+/D- 要尽量短、尽量平行,不要跨过独立电源区域,也不要和继电器控制线、220V 走线平行长距离。
- 如果必须走长线,建议在 PCB 上做包地,或者在外面用双绞线连接。双绞线对共模干扰有很强的抑制作用,实测比平行线稳定很多。
寄存器映射方面,以 PJ85718DM 的典型配置为例,指针 0x00 是本地温度寄存器高字节,0x01 是低字节,0x02 是远程温度高字节,0x03 是远程温度低字节,0x08 是配置寄存器。具体地址各位的含义不同批次可能有差异,但整体框架类似,拿到手先翻数据手册确认。
| 指针地址 | 寄存器名称 | 说明 |
|---|---|---|
| 0x00 | 本地温度高字节 | 本地通道温度数据高 8 位 |
| 0x01 | 本地温度低字节 | 低 4 位有效,0.0625°C 分辨率 |
| 0x02 | 远程温度高字节 | 远程通道温度数据高 8 位 |
| 0x03 | 远程温度低字节 | 低 4 位有效,0.0625°C 分辨率 |
| 0x04 | 状态寄存器 | 远程开路/短路、温度超限标志 |
| 0x08 | 配置寄存器 | 比较模式、转换速率、关断模式等 |
2.4 现场布线与防雷防静电
HVAC 设备的安装环境比想象中恶劣:室外机风吹日晒、压缩机启停瞬间电流冲击、变频器产生的高频干扰。远程测温线就是从控制板伸到这些位置的,如果不做防护,一个 ESD 事件就能把传感器打坏。
我通常的做法是:远端传感器接口在 PCB 上做成接插件,外面用屏蔽双绞线连接,屏蔽层在控制板单端接地。如果设备安装在容易受雷击的室外,传感器引脚和 PJ85718DM 之间还要加 TVS 管,不用很贵的,低电容型就可以。别小看这条,我见过一个项目,远程探头经常莫名其妙“坏掉”,换了很多颗芯片,最后发现是室外线缆感应到的静电反复打坏传感器引脚。
3. 固件实现与数据链路搭建
3.1 主控初始化和 I2C 配置
固件我用 C 语言在 PICC 环境下写的。官方的集成开发环境叫 MPLAB X IDE,主控配置可以图形化操作,但我的习惯还是直接写代码。
第一步是配置时钟。PIC18F55K42 内部振荡器可以到 64MHz,配置完后无需外部晶振。I2C 模块配置成主模式,400kHz 快速模式。
我最初直接用图形配置工具生成代码,结果运行一段时间偶发 NACK。后来发现是 I2C 时钟太快,长走线加上传感器输入电容,总线时序裕量不够。把频率降到 100kHz 之后问题消失。对 HVAC 这种强干扰场景,温度采集本来就不需要高速,100kHz 完全够用,稳定反而更重要。
初始化代码大致如下:
void init_clock(void) { // 内部高频振荡器,配置到 64MHz OSCCON1 = 0x60; // HFINTOSC 作为系统时钟 OSCCON3 = 0x00; OSCTUNE = 0x00; while(!OSCSTATbits.HFIOFR); } void init_i2c(void) { // 主模式,100kHz,器件的 I2C 地址引脚设置后固定 SSP1CON1 = 0x08; // I2C 主模式使能 SSP1STAT = 0x80; // Slew rate 标准 SSP1ADD = 0x4F; // 根据系统时钟计算出来的分频值 SSP1CON1bits.SSPEN = 1; // 使能总线 } void init_gpio(void) { // SCK/SDA 复用引脚必须配置成输入方向,外加上拉 TRISB |= 0xC0; ANSELB &= ~0xC0; }3.2 读取温度与数据转换
PJ85718DM 的温度寄存器是 16 位格式,其中低字节只有高 4 位有效,所以一个计数值对应 0.0625°C。转换很简单:先把两个字节拼成一个整数,然后向右移 4 位,保留有效数据,再乘以 0.0625。
我封装了一个读取函数:
int16_t read_temp_register(uint8_t reg_addr) { uint16_t raw = 0; i2c_start(); i2c_send_byte(0x90); // 器件 I2C 地址写位,根据实际地址调整 i2c_send_byte(reg_addr); // 发送寄存器指针 i2c_restart(); i2c_send_byte(0x91); // 器件 I2C 地址读位 raw = (uint16_t)i2c_read_byte(1) << 8; // 高字节 raw |= i2c_read_byte(0); // 低字节,最后一字节发 NACK i2c_stop(); // 温度换算,0.0625°C/LSB int16_t temp_raw = (int16_t)(raw >> 4); int16_t temp_c = (int16_t)(temp_raw * 0.0625 * 10); // 保留一位小数 return temp_c; }需要注意的是,远程通道和本地通道读回来的原始码值,在负温下都是补码格式。拼接时强制转成 int16_t 再移位,否则温度到零下会出现奇怪的问题。我在初版代码里就在这里翻过车——零上一切正常,一到零下读数乱跳,排查了很久才发现是无符号右移导致的符号位丢失。
状态寄存器 0x04 里的远程开路标志很重要。远程三极管如果接触不良或线缆断了,读数会变成接近电源轨的乱码。我在主循环里每次读取都检查这个位,发现开路就上报错误状态,而不是把乱码当成真实温度传出去。
3.3 HVAC 控制逻辑与远程上报
这套系统在 HVAC 里的角色通常不只是一个“温度计”,而是控制逻辑的一部分。以一套风管机系统为例,本地温度测回风,远程温度测盘管:回风温度代表环境负荷,盘管温度代表制冷/制热状态。两者之差能判断系统效率。
控制逻辑我用两路温度做比较:
- 回风温度大于设定值,且盘管温度低于回风温度超过 8°C,判断为正常制冷。
- 温差小于 3°C 且持续 5 分钟,判断为制冷能力下降,置一个告警位。
- 远程温度高于 110°C 并且持续 10 秒,直接触发硬件报警输出(用 CLC 配置成数字比较,不经过主循环)。
远程上报这块,现场最常见的需求是走 RS485 到上位机或者云网关。我用的协议比较简单:Modbus RTU 最普遍,但如果你想快速验证,直接自定义个 UART 帧也行。帧格式类似:
// 本地温度 25.3°C,远程温度 84.6°C void uart_report(void) { uint8_t buf[12]; buf[0] = 0xAA; // 帧头 buf[1] = 0x01; // 设备地址 buf[2] = 0x02; // 长度 buf[3] = (uint8_t)(local_temp_c); // 本地温度整数部分 buf[4] = (uint8_t)(remote_temp_c); // 远程温度整数部分 // 计算校验和 buf[5] = compute_checksum(buf, 5); uart_send(buf, 6); }如果对稳定性要求高,建议直接上 Modbus RTU,CRC 校验成熟、调试工具也多。上位机只要取对应寄存器地址就能读到两路温度。
3.4 固件层的滤波策略
硬件上能做的是有限的,到了现场该抖还是会抖。我在固件里加了两层滤波:
第一层是滑动平均。每 200ms 采一次样,连续采 8 次,去掉最大值和最小值,剩下 6 个取平均。这样既响应速度不至于太慢,又能滤掉继电器动作瞬间产生的尖峰。
第二层是变化速率限制。HVAC 系统的温度变化本身是缓慢的,一秒内跳变超过 5°C 就认为这次采样被干扰了,直接丢弃,沿用上一轮的输出。这个逻辑简单但非常有效,尤其是旁边有变频器的时候。
采样周期不需要太频繁,200ms 对响应只有几度的温度控制来说完全够用。更频繁的采样只会引入更多噪声和 I2C 总线占用,反而得不偿失。
4. 常见问题与排查技巧实录
4.1 远程读数漂移和跳变
这是我遇到最多的问题,现象是远程温度稳定不下来,总会缓慢漂或者突然跳几度。
排查思路按优先级排序:
- 检查远端三极管的连接是否可靠。集电极和基极有没有短接,方向对不对。
- 检查走线。远程测温线和继电器控制线如果平行走,继电器一动作读数就跳,基本可以断定是耦合干扰。解决办法是改成屏蔽双绞线,屏蔽层单端接地。
- 检查 PCB 的 D+/D- 之间滤波电容。电容太大读数会整体偏,试着拆掉或者换成 1nF。
- 检查远端三极管是否靠近强热源或散热风道。有些场景下探头贴在压缩机上,压缩机一启动温度确实在快速变化,这种要区分是真实温度还是干扰。
有条件的话,可以用示波器测 D+/D- 波形,看有没有明显噪声叠加。刺很尖,多半是干扰耦合,不是传感器问题。
4.2 I2C 偶发 NACK 和总线卡死
I2C 总线在工业现场最常见的故障是偶发 NACK 或者整个总线挂死。最初我以为是传感器固件 bug,后来发现是电气层面的问题。
总线卡死有一种典型表现:SDA 被拉低,SCK 还在走,主机无论如何发停止位都释放不了。原因多半是某个时刻的电气噪声把从机状态机打乱了,从机一直等待数据,没法回 ACK,也不释放总线。我从那以后给 I2C 通信加了一个超时机制:
bool i2c_wait_complete(uint16_t timeout) { while (!I2C1STATbits.TXIF) { if (timeout-- == 0) { I2C1CONbits.SCLREL = 1; return false; } } return true; }如果连续三次超时,就把 I2C 模块彻底复位,重新初始化。这套逻辑加上之后,长时间运行的稳定性明显提升了。
还有一种提高可靠性的做法是纯粹用 GPIO 模拟 I2C 时序,并且在每次通信前把两根线都拉高。模拟 I2C 在某些强干扰环境里反而比硬件模块更耐操,因为时序完全由自己控制,卡死了解放总线也容易。代价是 CPU 占用高。我的建议是:硬件 I2C 为主,模拟 I2C 作为调试工具和兜底方案。
4.3 本地温度测出来总是偏高
PJ85718DM 的本地通道测的是芯片自己所在位置的温度,不是空气温度。如果芯片旁边就是 LDO、功率电阻或者 PIC 主控,本地温度比环境高两三度很正常。
这个不算故障,但要区分用途。如果本地温度用来做环境温度显示,就要在布局上做文章:传感器尽量放在板子边缘,避开发热元件;如果实在避不开,可以在批量时做个校准偏移,比如“实测环境 25°C 时芯片读 27.5°C,软件统一减 2.5°C”。但不要上来就减,一定要用多块板子做统计,不同风道、不同电源负载下偏移量可能不一样。
有个细节我吃过亏:第一次打样时把 PJ85718DM 放在主控旁边,主控跑起来能摸到发烫。后来改板把传感器挪到板边,本地温度读数直接降了 3°C多。布局对测温的影响,永远排在软件补偿前面。
4.4 现场干扰和继电器动作时的瞬间跳变
HVAC 设备里最经典的干扰源就是继电器开合。继电器线圈断电瞬间会产生很高的反向电动势,即使有续流二极管,磁场耦合到测温线也会造成毫伏级的噪声尖峰。
遇到这种问题,我的组合拳是:
- 继电器线圈加续流二极管和 RC 吸收,把瞬态尖峰压下去。
- 远程测温线远离继电器,尽量走板子另外一层,必要时候做包地处理。
- 软件里加“变化速率限制”,把瞬间跳变过滤掉。
- 通信和采样避开继电器动作窗口。如果继电器切换时间很短,完全可以把采样延后几十毫秒再开始。
4.5 问题排查速查表
| 现象 | 可能原因 | 处理方法 |
|---|---|---|
| 远程读数固定显示一个异常大值 | 远程三极管方向接反或开路 | 检查管子方向,检查线缆连接 |
| 远程读数缓慢漂移 | 走线受热后阻抗变化、管内结温变化 | 确认探头贴紧被测物,排除空气间隙 |
| 继电器动作瞬间读数跳变 | 继电器磁场耦合到测温线 | 加屏蔽线、RC 吸收、软件限速率 |
| I2C 偶发 NACK | 总线电容过大、速率过高 | 降速到 100kHz,缩短走线 |
| 总线挂死,SDA 被拉低 | 从机状态异常 | 通信超时复位,软件释放总线 |
| 本地温度整体偏高 | 受板上热源影响 | 调整布局,远离发热元件,统计校准 |
| 远程读数偏大且响应慢 | D+/D- 滤波电容过大 | 减小到 1nF 或去掉 |
5. 工具与调试技巧补充
5.1 调试时必备的工具
这套系统调试时,我的基础工具清单有一个逻辑分析仪。I2C 通信如果出了问题,波形一眼就能看出来:地址对不对、ACK 有没有、时序有没有毛刺。别只用示波器去抓,逻辑分析仪带协议解析,直接标出每一帧是什么内容,效率高很多。
温度验证方面,我买了一支工业级铂电阻温度计做基准。把远端三极管和基准探头绑在一起放进恒温箱,从 -20°C 到 80°C 每 10°C 记录一次读数,画一条校准曲线。如果偏差是线性偏移,可以在软件里做固定补偿;如果是非线性,就要检查三极管的选择或者硬件电路了。
5.2 关于读取时序的一个细节
PJ85718DM 内部 ADC 转换不是瞬间完成的。如果刚配置完寄存器就去读温度,很可能读到上一轮的数据。我一般在初始化后等待 100ms 再开始读,之后每次读间隔保持在 200ms 以上,这样保证每次数据都是新转换的。
有些工程师会在 PID 控制循环里频繁读温度,把 I2C 通信塞得满满的。其实温度控制不需要那么高的采样率,PJ85718DM 的转换速率本身也有上限。把采样间隔放宽,反而能让数据更稳定。
6. 最后的经验总结
这套“PJ85718DM + PIC18F55K42”的组合,我在两三个项目里跑下来,最满意的是远程通道在长线下的稳定性。只要把三极管选好、走线按规矩来、固件里留一层滤波,远程读数长期漂移可以控制在很小范围,完全满足 HVAC 的控制精度要求。
踩过最大的坑是三极管方向接反。那一次远程读数直接跳到一个很夸张的数值,排查了半天的 I2C 时序,最后用万用表量 D+/D- 才反应过来,原来是引脚定义看反了。所以这类模拟前端的东西,上电前先用万用表确认方向和通断,比你写一百行调试代码都管用。
如果让我重新搭这套系统,我会在通信层直接把设备地址做成拨码可选。现场调试时不用为每台设备重新烧录固件,直接拨码设置地址,省掉很多安装维护上的麻烦。这个小改动对批量落地非常有帮助,尤其是一栋楼里几十台设备的时候。
另外提一句,PJ85718DM 这类芯片的数据手册里常有一些应用电路图,别只当参考,照着做能少走很多弯路。我第一次就是觉得自己“懂了原理”,省略了一些推荐元件,结果现场噪声问题折腾了整整一周。测温系统想要稳定,原理要吃透,但按规格书推荐的方式先搭出来,再逐步优化,才是最快的路径。