☰
基于PIC18F67K40与PJ85718DM的双路温度监测系统设计与实现
2026/10/11 1:19:50 网站建设 项目流程

1. 项目缘起与整体设计思路

嵌入式温度监测这件事,说起来简单,做起来坑不少。我最早接触这类需求是在一个HVAC控制板的项目里,当时的要求很朴素:本地要能看到机房回风温度,远程中控室也要能读到同一路数据,而且两边的读数不能打架。最开始想用一颗带Wi-Fi的SoC一把梭,后来发现现场电磁环境复杂,无线方案在金属风管旁边丢包丢到怀疑人生,于是老老实实回到"本地传感器+MCU+有线远程"的经典组合。这套方案的核心就是标题里提到的两颗器件:PJ85718DM负责把温度变成数字量,PIC18F67K40负责采集、处理、显示和转发。

先把这个项目的定位说清楚。它解决的是双路温度监测问题:一路是贴近热源的本地温度,用于面板显示和本地联锁;另一路是远程温度,通过通信总线送到上位机或中控PLC。适合谁来参考?如果你正在做暖通空调控制、冷库监控、机房环境采集、工业烤箱温控这类项目,并且希望用一颗主控同时搞定本地显示和远程上报,那这套思路可以直接抄。哪怕你是刚上手PIC18系列的新手,只要跟着把I2C时序和UART协议调通,剩下的就是体力活。

为什么选PIC18F67K40而不是更便宜的PIC16?这里有个选型逻辑。PIC18F67K40是8位机里比较"富"的一颗:128KB Flash、3.5KB RAM、自带LCD驱动模块、多个UART和I2C/SPI外设,还有充足的可编程I/O。HVAC场景往往需要驱动段码LCD做本地显示,如果外挂一颗LCD驱动芯片,BOM成本和PCB面积都上去了。K40自带LCD控制器,直接省掉一颗芯片,这是它在这个场景里最大的价值点。另外它的工作温度范围覆盖工业级,风管附近温度波动大,商用级芯片容易在冬天启动时出问题。

再说PJ85718DM。这是一颗数字温度传感器,I2C接口,出厂校准,不需要外部调理电路。相比热敏电阻加运放的方案,它的优势在于:第一,数字输出免去了ADC标定和温漂补偿;第二,I2C总线可以挂多颗,未来要扩展多点测温只需改地址;第三,精度在常温区间足够HVAC使用。热敏电阻方案虽然便宜,但每颗都要单独标定,量产时的一致性管理很痛苦。我踩过的坑是:早期用NTC加分压,结果一批板子因为电阻公差导致读数偏差两三度,返工标定花了两周。换成数字传感器后,这个问题直接消失。

整体架构可以这样理解:PJ85718DM通过I2C挂在PIC18F67K40的MSSP模块上,MCU周期性读取温度寄存器,做滑动平均滤波,一路送LCD显示,一路通过UART打包成协议帧发给远程主机。远程主机可以是另一颗MCU、工控机或者带串口的触摸屏。如果传输距离超过几米,UART要转成RS-485差分信号,这个后面会细说。整个数据流是"采集—滤波—显示—上报"四步,每一步都有讲究,下面逐个拆。

2. 核心器件解析与硬件连接要点

2.1 PJ85718DM的寄存器与读数机制

PJ85718DM这类数字温度传感器的核心就是几个寄存器:温度值寄存器、配置寄存器、地址寄存器。温度值通常是16位,高字节整数部分,低字节小数部分,分辨率常见0.0625度或0.125度。读的时候要注意,必须一次性把两个字节读完,如果只读高字节,内部指针可能停在错误位置,下次读就乱了。我见过有人分两次读,结果温度每隔一次就跳变,查了半天以为是传感器坏了,其实是读时序的问题。

I2C地址方面,这类传感器一般有7位地址,其中几位可以通过ADDR引脚拉高拉低来配置。这意味着同一条总线上最多能挂8颗同型号传感器,做多点测温时非常方便。但要注意,地址引脚不能悬空,必须明确接VCC或GND,悬空会导致地址不确定,总线扫描时可能时有时无。我在一块样板上就吃过这个亏,ADDR脚忘了处理,结果上电后有时能读到有时读不到,用逻辑分析仪抓波形才发现地址在飘。

上拉电阻的选择也有讲究。I2C总线的SDA和SCL必须接上拉,典型值4.7kΩ。如果总线电容大(走线长、挂的器件多),上拉要减小到2.2kΩ甚至1kΩ,否则上升沿太缓,高速模式下会误判。但上拉太小又会导致低电平灌电流过大,超过器件的驱动能力。经验公式是:上拉电阻最小值 = (VCC - VOL) / IOL,其中IOL是器件低电平灌电流能力,一般3mA左右。3.3V系统下,最小约1kΩ。实际选型时,我一般先用4.7kΩ,如果波形上升沿超过1微秒再往下调。

2.2 PIC18F67K40的MSSP与LCD模块配置

PIC18F67K40的MSSP模块可以配置成I2C主模式。配置步骤大致是:设置SSPCON1的SSPM位选择I2C主模式,设置SSPADD寄存器写入波特率,然后使能MSSP。波特率计算公式是:SSPADD = (Fosc / (4 * 目标波特率)) - 1。假设系统时钟16MHz,想要100kHz的I2C速率,SSPADD = (16M / (4 * 100k)) - 1 = 39。这个值要写对,写错了通信直接不通,而且不会报错,只是波形频率不对,新手很容易在这里卡住。

LCD模块是K40的亮点。它支持最多8个公共端和多个段,能直接驱动段码屏。配置时要设置LCDCON寄存器选择偏压和驱动模式,还要配置LCDPS分频。段码屏的对比度靠VLCD引脚上的电阻分压网络调节,这个电阻值要根据屏的规格来选,选大了对比度不足,选小了功耗高。我一般先用可调电阻调出合适对比度,再量出阻值换成固定电阻。

这里有个实操细节:LCD模块和I2C模块共用一些引脚资源,分配引脚时要查数据手册的引脚复用表,别把LCD段和I2C的SDA/SCL分到同一个脚上。我见过一个设计,PCB画完了才发现冲突,只能飞线解决,非常难看。建议在原理图阶段就把引脚分配表列出来,逐个核对。

2.3 电源与去耦的实战经验

数字温度传感器对电源噪声比较敏感,尤其是HVAC板子上往往有继电器、风机驱动这些大电流负载。PJ85718DM的VCC脚旁边必须放0.1μF陶瓷电容,而且要尽量靠近引脚。如果板子上有电机或继电器,建议再并一个10μF钽电容做低频滤波。我遇到过温度读数偶尔跳变0.5度的情况,查了很久,最后发现是继电器吸合瞬间电源跌落导致的,加了电容后问题消失。

地线处理也不能马虎。模拟地和数字地如果混在一起,大电流回流会在小信号地上产生压降,影响传感器。虽然数字传感器比模拟传感器抗干扰强,但电源和地的干净程度仍然直接决定读数稳定性。我的做法是:传感器和MCU的地尽量单点汇聚到电源入口,大电流负载的地单独走,最后在电源处汇合。

3. 固件实现:从采集到上报的完整链路

3.1 I2C读取温度的标准流程

先给一段可参考的读取流程,用C语言描述,基于PIC18的MSSP库函数风格。实际写的时候,起始、停止、发送字节、接收字节这些底层函数要先封装好。

#define SENSOR_ADDR_W 0x90 // 写地址 #define SENSOR_ADDR_R 0x91 // 读地址 #define TEMP_REG 0x00 // 温度寄存器 int16_t read_temperature(void) { uint8_t msb, lsb; int16_t raw; I2C_Start(); I2C_Write(SENSOR_ADDR_W); I2C_Write(TEMP_REG); I2C_Start(); // 重复起始 I2C_Write(SENSOR_ADDR_R); msb = I2C_Read_ACK(); lsb = I2C_Read_NACK(); I2C_Stop(); raw = ((int16_t)msb << 8) | lsb; raw >>= 4; // 根据分辨率右移 return raw; }

这段代码的关键点:重复起始条件不能省,否则读出来的可能是别的寄存器。读最后一个字节要发NACK,告诉传感器读完了,如果发ACK,传感器会继续输出下一个寄存器的数据。右移位数取决于传感器分辨率,0.0625度对应右移4位,0.125度对应右移3位,这个要查手册确认,移错了温度就整体偏了。

温度值转换成实际摄氏度:如果raw是带符号的12位值,乘以0.0625即可。负温度的处理要注意,传感器一般用补码表示,直接按有符号数处理就行。我见过有人把负温度读成很大的正数,就是因为没做符号扩展。

3.2 滑动平均滤波的参数选择

原始读数会有±0.25度左右的抖动,直接显示会跳得眼花。滑动平均是最简单有效的办法。窗口大小怎么选?太小滤波效果差,太大响应慢。HVAC场景温度变化缓慢,我一般用8点或16点窗口。8点窗口的响应延迟大约是采样周期的8倍,如果1秒采一次,延迟8秒,对空调控制来说完全可以接受。

实现上用一个环形缓冲区,每次新数据进来替换最老的数据,然后求平均。注意求和变量要用32位,8个12位数据加起来可能超过16位范围。这个细节不注意,温度会在某个点突然跳变,因为16位溢出了。

#define FILTER_SIZE 8 int32_t temp_buffer[FILTER_SIZE]; uint8_t buf_index = 0; int16_t filter_temperature(int16_t new_val) { int32_t sum = 0; temp_buffer[buf_index] = new_val; buf_index = (buf_index + 1) % FILTER_SIZE; for (uint8_t i = 0; i < FILTER_SIZE; i++) { sum += temp_buffer[i]; } return (int16_t)(sum / FILTER_SIZE); }

除了滑动平均,还可以加一个限幅滤波:如果新值和上次值差异超过2度,认为是干扰,直接丢弃。这个在继电器频繁动作的板子上特别有用。

3.3 本地LCD显示与远程UART协议设计

本地显示部分,把滤波后的温度值拆成整数和小数,查段码表送到LCD数据寄存器。刷新率不用太高,2Hz足够,刷太快反而增加功耗和EMI。显示格式建议固定宽度,比如"25.5C",避免数字位数变化导致显示跳动。

远程上报的协议设计是重点。我推荐用简单的帧格式:帧头+地址+命令+数据长度+数据+校验+帧尾。比如:

字段字节数说明
帧头20xAA 0x55
设备地址1本机地址
命令10x01表示温度上报
数据长度1后续数据字节数
数据N温度值,高字节在前
校验1前面所有字节异或
帧尾10x0D

校验用异或最简单,虽然强度不高,但对短帧足够。如果环境干扰大,可以换成CRC8。帧头用两个字节是为了降低误同步概率,单字节帧头容易在数据里出现相同值导致错位。

UART波特率选9600还是115200?如果走RS-485长距离,9600更稳,115200在几十米线上容易误码。上报周期1秒一次,9600波特率完全够用,一帧也就十几个字节。别盲目追求高速,稳定压倒一切。

3.4 RS-485远传的硬件与软件配合

UART本身是单端信号,传输距离有限,几米以内还行,超过十米就要转差分。RS-485用一对双绞线传差分信号,抗共模干扰能力强,几百米没问题。硬件上需要一颗收发器芯片,比如常见的半双工收发器,RO接MCU的RX,DI接TX,RE和DE接一个GPIO控制方向。

方向控制的时序是关键。发送前把DE拉高,等发送完成中断触发后,确认最后一个字节的停止位已经移出,再把DE拉低。如果拉低太早,最后一个字节会被截断;拉低太晚,总线占用时间过长,影响其他节点。我的做法是在TX完成中断里加一个小延时,或者查TCSTIF标志确认发送移位寄存器空。

总线上要接终端电阻,一般120Ω,接在总线两端。中间节点不接。如果距离短、节点少,不接也能凑合,但长距离一定要接,否则信号反射会导致误码。这个电阻在PCB上要预留位置,调试时根据实际情况决定焊不焊。

4. 常见问题排查与避坑实录

4.1 温度读数异常的问题速查

现象可能原因排查方法解决
读数固定不变I2C未通信成功逻辑分析仪抓波形检查地址、上拉、时序
读数跳变±0.5度电源噪声示波器看VCC纹波加去耦电容
负温度显示为大正数符号扩展错误检查数据类型用int16_t并正确移位
每隔一次读数错误寄存器指针错位检查读时序确保重复起始和NACK
远程数据偶尔错帧校验不足或干扰统计误码率加CRC、降低波特率
LCD显示闪烁刷新率过高或电源不稳降低刷新率加滤波电容

这张表是我这几年攒下来的,基本覆盖了八成以上的现场问题。遇到问题先对照查,能省很多时间。

4.2 I2C通信失败的排查思路

I2C不通是最常见的问题。排查顺序建议这样:先用万用表量SDA和SCL的静态电平,正常应该是高电平(被上拉电阻拉高)。如果量出来是低,说明总线被某个器件拉死了,可能是器件没上电或者损坏。然后量上拉电阻两端电压,确认电阻没虚焊。

接下来用逻辑分析仪看波形。重点看起始条件是否正常,地址字节是否和预期一致,从机有没有发ACK。如果从机没ACK,说明地址不对或者器件没工作。地址不对的情况很常见,有人把7位地址和8位地址搞混,写地址是7位左移一位,读地址再或1。这个一定要查手册确认。

如果波形正常但读不到数据,检查寄存器指针。有些传感器上电后默认指针不在温度寄存器,需要先写一次寄存器地址。还有人忘了在读写之间加延时,传感器转换需要时间,读太快拿到的是旧数据或无效数据。

4.3 长距离通信的稳定性优化

RS-485长距离通信出问题,八成是接地和终端电阻。总线两端的地电位如果差太多,共模电压超过收发器范围就会误码。解决办法是用隔离收发器,或者确保两端共地。共地线要和双绞线一起走,别只走信号线。

终端电阻只在总线最远两端接,中间节点接了反而增加负载。如果总线分支太多,每个分支都会产生反射,建议用菊花链拓扑,避免星型连接。我见过一个现场,八个节点星型接法,通信时好时坏,改成手拉手后立刻稳定。

波特率和线长的关系也要注意。9600波特率下,普通双绞线可以跑1200米;115200波特率下,建议不超过100米。如果必须高速长距离,用低电容专用电缆,或者降低波特率。别跟物理规律较劲。

4.4 实操心得与独家技巧

分享几个文档里不会写但很实用的点。第一,调试I2C时,先写一个最简单的扫描程序,把总线上所有能响应的地址打印出来,确认传感器地址。这个程序十分钟能写好,能省几小时排查时间。第二,温度传感器尽量远离发热元件,比如LDO、功率电阻,否则测的是板子温度不是环境温度。我见过传感器放在稳压器旁边,读数比实际高5度。第三,量产时给每块板子留一个校准接口,虽然数字传感器一致性好,但PCB布局差异仍可能导致零点偏移,留个后门方便后期修正。

还有一点关于看门狗。HVAC设备往往无人值守,程序跑飞了必须能自恢复。PIC18F67K40自带WDT,使能后定期喂狗。但要注意,I2C读取如果卡死,喂狗循环可能也卡住。我的做法是把I2C操作加上超时计数,超时就复位MSSP模块重新初始化,而不是死等。这个技巧救过我好几次现场。

5. 系统联调与扩展思路

5.1 本地与远程数据一致性验证

联调阶段最怕本地显示和远程读数对不上。验证方法很简单:用一个标准温度源(比如恒温水浴或校准过的温度计)同时对比。如果偏差在0.5度以内,说明链路正常。如果远程比本地低,可能是上报的数据没经过滤波,或者协议解析时字节序搞反了。

字节序是个高频坑。MCU是小端,但协议里我建议统一用大端(高字节在前),这样跨平台解析不容易错。发送时手动拆字节,接收时手动拼,别用指针强转,否则换平台就出问题。

数据一致性还要考虑时间戳。本地显示是实时的,远程上报有周期延迟,如果上位机做趋势图,要记录接收时间而不是采集时间。如果对时间敏感,可以在协议里加一个采集时刻的字段,用MCU的定时器计数填充。

5.2 多点测温的扩展方法

单点玩通了,扩展多点就是改地址的事。PJ85718DM这类传感器通过ADDR引脚可以配出多个地址,一条I2C总线挂8颗,覆盖8个测点。固件里把读取函数参数化,传入不同地址,循环读取即可。注意总线电容会随器件数量增加,上拉电阻要相应减小,或者降低I2C速率。

如果测点超过8个,可以用I2C多路复用器扩展总线,或者换用SPI接口的传感器。SPI没有地址概念,靠片选区分,理论上可以挂很多,但引脚占用多。选哪种取决于你的MCU引脚余量和布线难度。

多点数据的远程上报,建议在协议里加测点编号,上位机按编号分通道显示。别把所有温度拼成一帧发,那样解析麻烦,也不利于单点故障隔离。

5.3 低功耗场景的优化

如果设备是电池供电,功耗就要精打细算。PIC18F67K40有休眠模式,I2C传感器也有单次转换模式,测完就睡。策略是:定时器唤醒MCU,读一次温度,上报,然后全部休眠。休眠电流可以做到微安级,电池寿命从几天延长到几个月。

LCD背光是耗电大户,如果不需要常亮,可以做成按键唤醒。传感器在休眠期间功耗极低,但要注意上电后的第一次转换需要等待时间,别刚唤醒就读,读到的是无效值。手册里一般会写转换时间,按那个时间延时后再读。

低功耗和通信实时性是一对矛盾。休眠期间收不到远程命令,如果上位机需要随时查询,就不能深度休眠。折中方案是周期性唤醒监听,比如每秒醒一次,醒着的时间尽量短。这个平衡点要根据实际需求调。

5.4 电磁兼容的现场处理

HVAC现场电磁环境恶劣,继电器、变频器、接触器都是干扰源。除了前面说的电源滤波和地线处理,还可以在通信线上加共模电感,在传感器电源上串磁珠。PCB布局时,I2C走线尽量短,远离高频开关节点,必要时包地处理。

软件上可以加数字滤波和重试机制。读失败就重试三次,三次都失败就上报故障而不是错误数据。这个逻辑很重要,宁可报故障也不能报错误温度,否则控制系统可能做出错误决策。我在一个冷库项目里就设置了温度合理性检查,超出-40到80度范围直接标记为传感器故障,避免误动作。

外壳屏蔽也有帮助。如果设备装在金属箱里,箱体接地能挡掉大部分空间干扰。但要注意,金属箱会屏蔽无线信号,如果设备有无线模块,天线要引到箱外。这个项目用有线通信,金属箱反而是优势。

6. 写在最后的几句实在话

这套方案我从样机到小批量跑了不下五个版本,最大的体会是:数字传感器虽然省心,但省心不等于不用心。I2C的时序、电源的干净、协议的健壮性,每一样都得抠。新手最容易犯的错是急着写应用层,底层通信没调稳就往上堆功能,结果问题一层套一层,排查起来痛苦不堪。我的建议是分步验证:先让I2C能稳定读到温度,再加滤波,再加显示,再加通信,每一步都确认稳定了再往下走。

另外,别迷信手册上的典型电路。手册给的是理想情况,实际板子上的寄生参数、器件公差、环境干扰都会让结果偏离。留足调试余量,该加的电容电阻都加上,PCB上多留几个测试点,后期排查会感谢自己。温度监测这个事,精度重要,但稳定性更重要。一个偶尔跳变的精确读数,不如一个始终如一的稳定读数。

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

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

立即咨询