☰
PJ85718DM与PIC18F86J50的嵌入式温度采集方案:从硬件到固件实战
2026/10/22 1:01:45 网站建设 项目流程

做嵌入式温度采集的同行,应该都遇到过这种尴尬:系统里明明只有一个“测温度”的需求,真到选型落地的时候,NTC要分压、要校准、要担心引线电阻,单总线传感器又容易被现场干扰折腾得整条总线都挂掉。前阵子我手头一个HVAC控制板的项目就卡在这一环——不光要测板载环境温度,还要同时盯几个分布在风道、电加热器附近的远端温度点,主控用的是PIC18F86J50,最后我把方案定成了“PJ85718DM做前端温度采集,主控走I2C汇总”,实测下来比预想稳很多,也踩了不少文档上不会写的坑。

这篇文章就把这套思路完整拆开:从为什么选PJ85718DM与PIC18F86J50这个组合,到本地/远程温度通道的硬件接法、固件里的寄存器换算和报警逻辑,再到HVAC现场常见的干扰、总线锁死、校准问题,尽量写成一份可以直接拿去复现的实操记录。嵌入式里的“本地温度”和“远程温度”看起来只是测量距离的差别,实际涉及电路、固件和现场布线三层问题,逐层说清楚,后面调试能少走很多弯路。

1. 这到底是干什么的:方案定位与选型思路

1.1 本地温度和远程温度,在嵌入式里其实指两件事

“本地温度”比较好理解,指的是传感器所在电路板或设备本体上的温度,比如控制板内部的环境温度、功率器件附近的风道温度。在HVAC场景里,这一路数据通常用来做风扇调速、过热保护、柜内温度补偿。

“远程温度”就有两种含义,这也是很多人一开始容易混淆的地方。第一种含义是半导体结温测量,也就是用一颗专门的温度监控芯片去测外部PN结二极管的压降变化,从而得到功率管、IGBT这类器件的真实结温,PJ85718DM的远程通道就是干这个的。第二种含义是分布式测温,即现场有好几个物理位置需要测,比如风机盘管出风口、电辅热入口、回风管道,温度和主控板隔着几十厘米到几米,这时候就把数字温度传感器作为从设备挂在同一条I2C总线上,由主控轮询读取。

我这套方案把两种“远程”都覆盖了:PJ85718DM本身负责本地温度加一个二极管结温,I2C总线上再挂一到两个数字温度传感器节点负责风道和房间侧的远程温度。主控PIC18F86J50不需要自己去做ADC采样和线性校正,所有温度数据都以数字形式汇总到I2C总线上,这是这套方案最核心的架构思路。

1.2 为什么是PJ85718DM + PIC18F86J50,而不是其他组合

先说传感器端的选型对比,这直接决定了项目调试的难易程度。

方案优点缺点
MCU内置ADC + NTC热敏电阻成本低、采购方便非线性需要查表、引线电阻会引入误差、对电源纹波敏感、需要逐点校准
DS18B20单总线单根线可挂多个节点、成本低时序要求严格,现场长线电容大时容易ROM搜索失败,一旦某个节点异常可能拖死整条总线
PJ85718DM + I2C从传感器节点数字输出、双向报警、精度稳定、可扩展多个远端节点硬件上需要I2C上拉和地址规划,固件上要处理总线错误

我之所以选PJ85718DM,主要看中它的几个特点:第一,它内部集成了本地温度传感器,同时提供一个远程二极管测量通道,一颗芯片解决两个测温需求;第二,I2C/SMBus接口是标准协议,PIC18F86J50的MSSP硬件模块可以直接对接,不需要软件模拟时序;第三,这类芯片通常带ALERT和THERM引脚,可以硬件触发报警,不用主控一直轮询温度值判断阈值,对HVAC这种需要实时保护的应用很实用。

主控选PIC18F86J50也考虑了很久。这颗单片机是80引脚的大封装,Flash和RAM余量足,I2C、SPI、UART、USB外设齐全。项目里除了温度采集,还要跑人机交互、通信协议和PWM控制,选一颗IO和外设丰富的主控可以避免后期加功能时换平台的麻烦。PIC18F86J50的工作温度范围也足够宽,放在控制板内没有压力。

2. 硬件电路设计:本地、远程两个测温通道的关键细节

2.1 供电、上拉电阻和I2C总线基础电路

先把最小系统搭起来。PJ85718DM的工作电压我这边用3.3V,和PIC18F86J50的IO电平一致,不需要电平转换。芯片供电脚放一个100nF陶瓷电容,再并一个10uF钽电容放在稍远一点的位置,用来吸收现场电机启停时的电压波动,这个组合在实测中比单放100nF稳定得多。

I2C总线的上拉电阻是第一个容易翻车的点。板级短距离传输,SCL和SDA各用一个4.7k电阻上拉到3.3V就能工作;如果总线要引出到远程温度节点,线长超过30厘米,我会把上拉电阻改成2.2k。原因是总线电容增大后,上拉电阻太大导致信号上升沿变缓,主控可能读到错误的电平。如果远程线超过一米半,建议在总线中间加一颗I2C缓冲器,把板内总线和外部总线隔离开,而不是一味减小上拉电阻——电阻太小会让总线驱动能力不足,同时增加功耗。

PJ85718DM的地址引脚一般有A0和A1,通过接GND或VCC来设置从机地址。画板之前先查清楚芯片的默认地址,再给远程温度模块分配不同的A0/A1组合,避免地址冲突。我习惯把地址规划写在原理图注释里,比如A0=0、A1=0是本地PJ85718DM,A0=1、A1=0是第一个远程节点,这样固件和硬件对得上。

2.2 本地温度通道:PCB铺铜和热耦合的控制

本地温度测量听起来简单,实际上PCB布局影响很大。如果PJ85718DM要测的是板内空气温度,就不要让芯片周围大面积铺铜直接连到发热器件。我之前有一版PCB把本地温度传感器旁边的铜皮连到了电源芯片的地焊盘,结果温度读出来比实际环境高了好几度,因为铜皮成了导热桥,把电源芯片的热量直接引到了传感器附近。

解决办法是:传感器周围留出隔离区,不要大面积覆铜,走线尽量细;如果产品需要测散热器温度,那反而要把传感器放在热源附近,通过铜皮或者导热垫和被测对象贴合。一句话总结,先想清楚“这个温度是给谁用的”,再决定怎么布局。

还要注意传感器自身的自发热。PJ85718DM的功耗不算大,但在低风速、封闭机箱里,自发热也会让读数偏高零点几度。如果系统对绝对精度要求高,可以在固件里做一个小幅补偿,或者在结构设计时保证传感器附近有气流通过。

2.3 远程二极管通道:极性、线长和滤波容值

PJ85718DM的远程通道,本质上是测量外部PN结的正向压降随温度的变化关系,一般用三极管把集电极和基极短接成一个二极管来用,选小信号三极管比如常见的2N3904,β值稳定、一致性好。

接线上有几个绝对要点。第一,极性不能接反,接反了读出来不是温度而是错误标志;第二,远程二极管到芯片的走线长度尽量控制在1米以内。远距离测温时,走线本身的串联电阻和寄生电容都会影响ΔVbe测量的精度,这跟普通NTC接两根线不一样,不是越远越好。第三,在远程二极管两端并联一个小电容做滤波,容值从100pF到10nF之间选,但不是越大越好。电容太大反而会让测量结果变迟钝甚至出现漂移,具体取值要看数据手册的推荐范围。

还有一个很实际的经验:如果远程测温点真的离主控板很远,比如HVAC风道里的温度点要走3米线,那就不要纠结二极管测量了,直接在那个位置放一颗数字温度传感器,通过I2C总线把数据传回来,可靠性高很多。二极管测温通道最适合的是“短距离、高精度、测结温”的场景,比如测量压缩机驱动板的IGBT温度,把PJ85718DM放在驱动板旁边,二极管紧贴功率管,走线很短,效果很好。

2.4 远程数字温度节点:HVAC现场的I2C扩展

风道和房间侧的远程温度,我用的是独立的小模块,上面放数字温度传感器,通过四线制(VCC、GND、SCL、SDA)接到主控板。这类模块本身不是PJ85718DM,而是标准的I2C温度传感器,和PJ85718DM挂在同一条总线上。固件里就是一个地址表轮询的事,代码结构非常统一。

现场布线要考虑干扰问题。HVAC环境里风机、电加热器、压缩机都是干扰源,远程温度线最好用带屏蔽层的双绞线,屏蔽层单端接地。千万注意,不能在系统的两端分别接地,这样会形成地环路,反而把共模噪声变成差模噪声。我在现场遇到过一种情况:电加热器一启动,远程温度数据就开始乱跳,查了半天发现是现场施工把屏蔽层在两端都接了地,改成单端接地后问题立刻消失。

总线末端的终端处理也要做。一个常见的做法是在总线最远端的节点上预留一个电容位,通常100pF到470pF,跨接在SCL和GND、SDA和GND之间,能吸收反射,让波形更干净。如果预留了但现场没干扰,可以不贴。

3. 固件落地:寄存器、换算公式与报警逻辑

3.1 I2C初始化与基础读写函数

PIC18F86J50的MSSP模块配置成I2C主模式,波特率由SSPADD寄存器决定。代码可以直接用寄存器操作,也可以用Microchip的代码配置器生成,但关键的计算逻辑还是要自己心里有数。

void I2C_Init(void) { // I2C Master mode SSPCON1 = 0x28; SSPCON2 = 0x00; // 以400kHz为目标波特率,Fosc=64MHz时: // SSPADD = (Fosc / (4 * Fsck)) - 1 SSPADD = (64e6 / (4 * 400000)) - 1; // 约39 SSPSTAT &= 0x3F; // 清除SMP和CKE位 }

写一个发送起始条件和停止条件的底层函数,再做字节收发。这里有一个容易忽略的细节:每次通信异常后,如果直接重新发送起始条件,从机可能还保持在错误状态,这时候要先产生一个停止条件,让总线回到空闲状态,再重新开始通信。我封装I2C读写时会特意在出错后做“清除”操作。

3.2 读取温度寄存器与换算公式

读取PJ85718DM的温度值,标准流程是:主控发从机地址加写位,写入温度寄存器地址,然后重发起始条件,发从机地址加读位,连续读出高字节和低字节。温度数据一般是二进制补码格式,高字节和低字节拼起来后需要右移才是真正的有效数据。

下面是一个简化版的读取函数思路:

int16_t Read_Temp(uint8_t dev_addr, uint8_t reg_addr) { uint8_t hi, lo; int16_t raw; I2C_Start(); I2C_Write((dev_addr << 1) | 0); // 写命令 I2C_Write(reg_addr); I2C_RepeatedStart(); I2C_Write((dev_addr << 1) | 1); // 读命令 hi = I2C_Read(1); // 高字节,发送ACK继续读 lo = I2C_Read(0); // 低字节,最后一个字节回NACK I2C_Stop(); // 根据分辨率格式拼接 raw = (int16_t)((hi << 8) | lo); raw = raw >> 4; // 去掉低4位无效位 return raw; }

换算成实际温度时,要看数据手册给出的分辨率。以常见的12位格式为例,LSB对应0.0625°C,那么温度值就是raw * 0.0625。如果芯片是10位格式,就变成raw * 0.25。这个细节特别容易搞错,我踩过坑:用错了LSB之后,温度整体偏低,而且偏差不是固定值,随温度变化,排查了很久。

3.3 报警阈值设置与故障状态判断

PJ85718DM这类芯片都支持通过寄存器设置上限温度、下限温度和滞回值。设置好之后,芯片内部会自动比较温度值和阈值,超过范围时把ALERT引脚拉低,主控可以把这个引脚接到外部中断输入。

为什么建议用硬件报警而不是主控轮询?因为在HVAC控制里,过热保护往往需要快速响应,比如电加热器温度过高要在几毫秒内切断输出。如果只靠主控循环里读取温度再判断,循环里其他任务一多,响应时间就不可控。硬件报警引脚可以让保护逻辑和主循环解耦,这是工业现场设计里很实用的一招。

固件里还要处理故障状态。远程二极管开路、短路、测量值超出范围,状态寄存器里都有对应标志位。我一般会周期性地读一次状态寄存器,如果发现远程通道异常,先把上一次有效的温度值保留,同时报一个“温度传感器故障”的告警,而不是直接把异常值当成真实温度用于保护逻辑。

3.4 PIC端多个测温点的数据组织方式

PIC18F86J50作为主控,温度数据来自好几个地址:PJ85718DM的本地寄存器、远程二极管寄存器、还有总线上其他数字温度传感器节点。我的处理方式是定义一个结构体,把每个测温点的原始值、换算后的温度、状态、是否有效都包在一起。

typedef struct { uint8_t dev_addr; // 从机地址 uint8_t reg_addr; // 温度寄存器地址 float temperature; uint8_t error_flag; uint8_t data_valid; } Temp_Channel_T;

再建立一个轮询表,依次读取每个通道。注意I2C读取是阻塞操作,如果主循环里同时还要处理PWM输出或者串口通信,不能让一次I2C读取卡住整个系统。我的做法是把轮询放在定时中断里置一个标志位,主循环检测到标志位后才执行I2C读取,读取完成后再清标志。这样即使I2C总线出错,也不会无限阻塞主循环。

4. 标定与实战排错:HVAC现场踩坑记录

4.1 一点校准和两点校准怎么做

数字温度传感器出厂的一致性已经很好了,但电路板布局和散热环境会让每台设备有一些固定偏差。如果项目只要求±2°C以内,做一点校准就够了:在恒温环境里,等设备温度稳定,用一只校准过的数字温度计和PJ85718DM同时读数,把差值作为偏移量存到EEPROM里,后续读出后统一加上这个偏移量。

如果要求±1°C以内,就需要两点校准:分别在低温点和高温点记录实际偏差,然后做线性插值。校准系数可以放主控的EEPROM里,也可以放传感器芯片的EEPROM里。我个人的经验是,HVAC应用大多不需要两点校准,单点校准加一个良好的PCB布局,精度完全够用。真正的精度瓶颈往往不在传感器,而在空气流动和结构散热。

4.2 常见故障现象与处理速查表

现象可能原因处理办法
远程温度读数为异常值或错误标志二极管极性接反、走线断路用万用表二极管档量压降,确认0.5V到0.8V且方向正确
本地温度明显偏高PCB铺铜引热、传感器靠近发热器件检查传感器周围铜皮,留隔热区域
I2C读不到从机地址上拉电阻缺失或太大、地址冲突示波器看SCL/SDA波形,逐节点排查地址
电加热器启动后数据跳动EMI干扰、屏蔽层双端接地改用屏蔽双绞线,屏蔽层单端接地
远程温度变化迟钝滤波电容太大减小并联电容,参考数据手册推荐值
ALERT误报警阈值太接近正常温度、滞回太小放大滞回值,或固件连续3次确认再报警

4.3 总线锁死的恢复方法

I2C总线锁死是个老生常谈的问题。现象是SDA一直被拉低,主控发送起始条件后总线一直忙。原因通常是某个从机在异常时序下处于错误状态,一直占着总线。常规复位主控没用,因为从机还憋着没释放。

处理技巧是:用两个GPIO模拟I2C时钟,通过手动翻转SCL最多9个周期,把卡住的从机“推”回空闲状态。这个恢复过程可以写成一个独立函数,在I2C通信连续失败N次后自动调用。

void I2C_Bus_Recover(void) { // 把SCL和SDA切换到GPIO模式 // 手动制造9个时钟脉冲,期间把SDA拉高 for (int i = 0; i < 9; i++) { GPIO_SCL_HIGH(); __delay_us(5); GPIO_SCL_LOW(); __delay_us(5); } // 发送一个停止条件 GPIO_SDA_LOW(); GPIO_SCL_HIGH(); GPIO_SDA_HIGH(); }

这个恢复函数在实验室里几乎用不到,但到了现场特别有用。现场线缆长、干扰大,偶尔总线就会被拉死,有了这个函数,系统可以自动恢复,不用派人到现场断电重启。

4.4 HVAC现场特有的干扰问题

HVAC控制柜里有风机、有电加热器、有接触器,这些东西通断瞬间会产生很强的电磁干扰。温度采集虽然看起来是个低速弱电系统,但最容易受干扰的就是它。

重要提醒:如果远程温度读数的跳动规律和某个接触器吸合、风机启动的节奏一致,基本可以断定是干扰耦合进来的。解决顺序是:先看线缆是不是双绞屏蔽线,再看屏蔽层接地方式,再看总线滤波电容,最后才考虑固件滤波。

固件滤波不要懒。我在代码里对所有远程温度通道做了滑动平均,窗口长度取8,效果比单纯加大滤波电容好很多,而且不会拖慢响应速度。本地温度通道一般不做滤波,因为本地温度大概率用于保护逻辑,需要的是快速响应。

5. 继续扩展的方向与一点个人体会

5.1 从温度监测到风扇调速和故障联动

有了稳定可靠的本地温度、远程温度和硬件报警之后,可以顺手把风扇调速和故障联动做起来。比如用本地温度作为PID控制的输入,输出控制PWM风扇转速,远程温度用来做风道过热预警,ALERT引脚直接关联到硬件保护电路,一旦超温就全速运行或者切断加热输出。这些都是在同一套硬件上只改固件就能实现的功能,扩展性很好。

5.2 数据滤波和保护逻辑的取舍

采样滤波一定要分层。给显示用和给保护用的数据,滤波策略应该不一样。保护逻辑用原始值或者短窗口滤波,显示数据用长窗口滑动平均。如果把两者混在一起,经常会遇到“显示温度很平稳,但保护动作跟不上”的尴尬。我在项目里是把原始温度、滤波温度、有效标志一起放在结构体里,不同功能各取所需。

5.3 我实际操作中的几点体会

这套方案做下来,我最深的感触是:温度采集的坑,十个里有七个在硬件布局和现场布线上,不在固件。芯片选型选对了,传感器精度是能保证的,但PCB铺铜把热量引错地方、远程线缆屏蔽没做好、上拉电阻选得不合适,任何一个小问题都能让前面所有努力白费。

如果你正在做类似的项目,我的建议是先把板级I2C调通,只挂PJ85718DM本地通道,确认温度读数正常;再加远程二极管通道,确认结温测量稳定;最后再接远程分布式传感器,处理长线带来的干扰。每一步都在之前的基础上推进,出了问题时定位范围小很多。不要一开始就把所有节点都挂上去调,那样一旦数据乱跳,根本分不清是哪个环节出的问题。

还有一个小技巧:把每个测温点的地址、寄存器地址、校准偏移量都放到一个配置表里,固件启动时从EEPROM读取。现场如果换了传感器节点或者校准值需要修正,不用重新烧录整个固件,直接改配置就行。这个习惯帮我省了不少事,也算是在这个项目里最值得保留的经验。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询