做嵌入式温度监测这类活儿,最烦人的不是传感器本身,而是“本地”和“远程”这两头都得顾。本地要把温度采得准、采得快,远程要把数据传得稳、传得到位,中间还得压住成本、功耗和调试时间。这次用 PJ85718DM 这颗数字温度传感器配合 PIC18F86J16 做主控,做了一个能同时监测嵌入式和 HVAC 场景下的本地/远程温度的方案。PJ85718DM 负责把现场温度变成数字量,PIC18F86J16 负责把数据读回来、做处理,再通过串口转远程协议上报。这套组合做下来,整体思路、硬件设计、软件流程和一些踩坑经验,我觉得挺值得聊一聊的。
1. 项目整体定位:为什么用“一颗MCU+一颗传感器”做温度监测
1.1 嵌入式和HVAC场景下的需求差异
开始画板子之前,先得把需求掰开。嵌入式场景里,温度监测往往是“过程量”,比如电源模块的发热监测、机箱内温升趋势、充电电池的表面温度保护。这类场景要求采集周期短、响应快,传感器尽量贴在热源附近,数据多为本地使用,比如触发风扇、降频、报警。而 HVAC 场景里,温度监测更偏“环境量”,测的是房间、风道、冷媒管路的温度,这类场景点位分散,传感器离控制器远,数据要汇聚到主机或者楼宇自控系统,对通信距离、抗干扰和协议互认的要求很高。
这两个需求叠在一起,意味着不能只选一个够用的传感器,也不能只写一套简单的读取代码就交差。本地要快、要准,远程要稳、要兼容,主控芯片的外设资源和处理能力就得同时扛住这两件事。PIC18F86J16 在 I/O 数量、UART 数量、存储空间上都有余量,PJ85718DM 则能直接输出数字温度数据,不需要额外搭模拟调理电路,这两者组合起来,刚好能覆盖从“单点就地测温”到“多点远程汇聚”的跨度。
1.2 器件选型的三个核心考量
先说主控 PIC18F86J16。这颗芯片属于 PIC18 增强型系列,程序存储器和数据存储器都够用,外设模块齐全,尤其是多个 UART 和 MSSP 模块(可配 I2C/SPI),这让“本地挂传感器 + 远程挂通信”能同时进行。选它还有一个现实原因:内部振荡器精度足够应付不少通信场景,硬件上省掉一颗外部晶振的位置,对小尺寸板卡来说非常友好。
再说传感器 PJ85718DM。从选型角度看,数字传感器最大的优势是省掉了信号调理链,不用关心放大器的温漂,不用纠结 ADC 的参考电压,数据直接通过数字接口送进 MCU。PJ85718DM 本身的温度分辨率和精度在常规 HVAC 和嵌入式监测里够用,而且读取时序简单,非常适合快速落地。如果用的是模拟传感器,就得额外配运放、滤波器和校准流程——不是说不行,而是试错周期会明显拉长,尤其在做样机验证的阶段,时间成本非常关键。
选型还有一点容易被忽略:传感器和主控的工作电压范围是否匹配,逻辑电平是否兼容。PJ85718DM 的工作电压和 PIC18F86J16 的 I/O 电平如果不在一个区间,通信接口上就得加电平转换,电路复杂度和排查难度都会上升。好在我在实际选型时做了核对,接口电平匹配,直接连接即可。
1.3 系统架构与数据流向
整个系统的数据流向可以简单描述为:
- PJ85718DM 采样本地温度,通过数字接口(以 I2C 为例)把原始温度寄存器值传给 PIC18F86J16;
- PIC18F86J16 对数据做格式转换、滤波和阈值判断,同时把结果打包成远程通信帧;
- 远程数据通过 UART 送往通信模块(如 RS-485 收发器或无线透传模块),再上传到监控主机;
- 监控主机下发查询命令时,PIC18F86J16 响应请求,实现远程读数和参数设置。
这样的架构好处是职责分明,MCU 是计算和协议处理的核心,传感器只管采集,通信模块只管传输。后续如果要加传感器,只需要在总线上扩展地址即可;如果要换通信方式,也只需要改 MCU 侧 UART 对接的模块类型,整体架构不用推翻重来。
还有一点值得说,远程温度的“远程”并不仅仅指物理距离远,还包括“逻辑距离远”——也就是现场设备的数据能被上位机通过协议读到。哪怕传感器就在机器旁边,只要上位机通过通信协议能远程读取到它的温度值,这套系统就已经具备远程监测能力了。我在项目中把本地采集和远程上报分开实现,这样调试时可以先单独验证 PJ85718DM 读数是否正确,再单独验证远程通信链路,问题定位会快很多。
2. 硬件设计:从原理图到PCB的落地细节
2.1 PJ85718DM 与 PIC18F86J16 的接口连接
PJ85718DM 如果按常见的数字温度传感器接法来设计,最稳的方式是走 I2C 接口。I2C 只需要两根线(SCL 时钟、SDA 数据),再加上电源和地,一共四根线就能完成连接。对 HVAC 这种可能需要把传感器小板单独引出去的场景,线少意味着走线更容易,也更容易做屏蔽和防护。
具体连接到 PIC18F86J16 时,我用了两个普通 I/O 口来做软件 I2C,而不是用硬件 MSSP 模块。不是说硬件模块不好,而是这样自由度更高,后续如果想换传感器引脚,或者跟别的功能复用引脚,改起来更灵活。当然,如果对通信速率和稳定性要求更高,把传感器接到硬件 I2C 引脚上也是完全可行的,只要初始化时把 MSSP 模块配好就行。
接口连接表大概是这样:
| 功能 | PJ85718DM 引脚 | PIC18F86J16 引脚 | 说明 |
|---|---|---|---|
| 电源 | VDD | 3.3V 电源 | 需靠近引脚加 0.1uF 去耦电容 |
| 地 | GND | GND | 尽量单点连接,避免地环路 |
| 时钟 | SCL | 普通 I/O(如 RC3) | 上拉电阻到电源 |
| 数据 | SDA | 普通 I/O(如 RC4) | 上拉电阻到电源 |
| 地址选择 | ADDR | 可接 VDD 或 GND | 用于多传感器时区分地址 |
上拉电阻这块,I2C 总线必须有上拉,我选了 4.7kΩ。总线速度快时可以改成 2.2kΩ,但要先评估引脚的驱动能力,不是越小越好。如果总线上挂了多个传感器,阻值需要相应调整。
2.2 电源与去耦:容易被忽略的精度杀手
温度传感器最怕的不是温度本身,而是电源噪声。PJ85718DM 内部有 ADC 和数字逻辑,如果 VDD 上叠加了高频纹波,转换结果就会跟着抖动。我测过的案例里,电源纹波大的时候,同一温度点读数的跳动能到十几个 LSB,这在需要精确控温的 HVAC 场景里是不能接受的。
电源处理上做了三件事。第一,传感器电源单独用一颗低噪声 LDO 供电,而不是直接从 MCU 的电源引脚上并联取电,避免 MCU 数字翻转时的噪声耦合到传感器。第二,在 VDD 和 GND 之间放了一颗 0.1uF 的陶瓷电容,位置尽量靠近传感器电源引脚,这是数据手册里最基础也最有效的做法。第三,如果系统里还有电机、继电器这类感性负载,地线布局要特别注意,不能让负载回流的电流经过传感器的地,否则实测温度会出现周期性的“毛刺”。
PIC18F86J16 的电源同样需要认真处理。芯片的多个 VDD/VSS 引脚要全部接上,不能因为“看着没用到”就悬空。每个 VDD 引脚旁边都要有去耦电容,典型配置是 0.1uF 靠近芯片,外加一颗 10uF 左右的钽电容做低频储能。我在第一版设计里图省事,少放了一颗去耦电容,结果 UART 发送数据时偶尔会触发芯片复位,排查了很久才确定是电源瞬态跌落导致的。
2.3 布局布线要点:本地测温的“物理分寸”
PCB 布局上,本地测温有一个容易被低估的核心原则:传感器要靠近被测物体,但要远离自热源。PJ85718DM 本身工作时的自热很小,但是如果把它放在 MCU 旁边,MCU 的功耗发热会直接通过 PCB 铜皮和空气传导给传感器,实测下来读数可能偏高 1~3℃,这个偏差在空调房间控制里会影响舒适度,在设备保护里可能导致误报警。
具体操作是,传感器尽可能靠近被测物,比如贴在发热元件附近或延伸到机箱外面;传感器下方不要铺大面积的电源铜皮,减少其他器件发热通过铜皮导热;如果传感器和 MCU 不得不在同一块板上,可以在传感器周围的地铜上掏一圈隔离槽,让热传导路径变长。这个做法虽然看似简单,但对读数稳定性的改善非常明显。
对于需要把传感器外置的场景,比如测风管温度,传感器小板和主控板之间用短连接线引出即可。我一般会用屏蔽线或者双绞线,屏蔽层单端接地。线长控制在 30cm 以内比较稳,超过这个长度建议改用电流环或者 RS-485 传输,而不是直接拉长 I2C 线。I2C 线过长时,总线电容增加,波形变缓,可能导致通信失败。
3. 软件实现:初始化、采集与远程上报
3.1 初始化流程与寄存器配置
软件部分从 PIC18F86J16 的初始化开始。无论用不用硬件模块,先把芯片的基础时钟和引脚方向配好。我用的是内部振荡器,配置为 16MHz,这个频率下 I2C 软件时序的时间参数比较容易算,UART 波特率误差也小。初始化的大体顺序是:
void System_Init(void) { // 配置振荡器为内部16MHz OSCCON = 0x72; // IRCF = 111, 选择16MHz while (!OSCCONbits.HFIOFS); // 等待时钟稳定 // 配置传感器引脚为数字输入 ANSELC = 0x00; // 关掉RC口模拟功能 TRISCbits.TRISC3 = 1; // SCL 输入模式(开源极输出时) TRISCbits.TRISC4 = 1; // SDA 输入模式 // 配置UART引脚 TRISCbits.TRISC6 = 1; // RX 输入 TRISCbits.TRISC7 = 0; // TX 输出 // 初始化UART,波特率9600 BAUDCON = 0x00; TXSTA = 0x24; // 使能发送,8位数据 RCSTA = 0x90; // 使能串口,使能接收 SPBRG = 103; // 16MHz下9600波特率的计算值 // 传感器软件复位(可选) Sensor_Reset(); }SPBRG 的计算方式是:目标波特率 9600,Fosc = 16MHz,16MHz/(16×9600) ≈ 104,实际接近 103 或 104 都能用。如果是 115200 波特率,SPBRG 就更小,此时误差要靠内部振荡器校准寄存器微调。实际项目里,远程通信我用的是 9600 波特率,虽然慢一点,但是抗干扰更好,远距离 RS-485 下更不容易出错。
3.2 温度采集与均值滤波
传感器读取流程并不复杂,核心是“发命令—等待转换完成—读寄存器”。PJ85718DM 类传感器一般都有触发温度转换的命令字,转换时间在几十毫秒到几百毫秒之间,实测时等待时间别省,宁可读慢一点也要读对。
读取代码的骨架:
float Read_Temperature(void) { uint8_t raw[2]; float temp; // 发送转换命令 I2C_Start(); I2C_Write(SENSOR_ADDR << 1 | 0); // 写地址 I2C_Write(CMD_START_CONVERSION); // 触发转换 I2C_Stop(); // 等待转换完成(注意不要阻塞太久) __delay_ms(50); // 读取温度寄存器 I2C_Start(); I2C_Write(SENSOR_ADDR << 1 | 1); // 读地址 raw[0] = I2C_Read(ACK); raw[1] = I2C_Read(NACK); I2C_Stop(); // 根据传感器分辨率,组合数据并转换 temp = (raw[0] << 8 | raw[1]) * 0.0625f; return temp; }简单粗暴做一次读取也能用,但实际数据会抖。尤其是 HVAC 场景里,压缩机启动、变频器工作时,环境噪声和电源扰动都会让读数发生瞬时跳变。所以我在软件里加了一个很轻量的滑动平均滤波:维护一个长度为 8 的环形缓冲区,每次读取新温度后替换最旧的一个点,输出所有点的平均值。这比单纯拿一次读数稳得多,而且滞后也在可接受范围内。
滤波的原理讲起来也不复杂:温度本身是慢变量,正常不可能在几百毫秒内跳几度,出现的跳变都是干扰或异常,滑动平均相当于把高频扰动滤掉,保留下真实趋势。如果响应速度要求很高,可以把窗口缩短到 4;如果要读数的绝对稳定,窗口可以加到 16 或 32,但要注意响应变慢。这个取舍要看具体场景。
3.3 远程上报协议设计(以Modbus-RTU为例)
远程上报这块,建议直接采用 Modbus-RTU 协议。它在 HVAC 和工业控制里太通用了,市面上几乎所有组态软件、触摸屏、PLC 都支持。自己从头定义一个私有协议也能跑通,但后续对接第三方系统会非常痛苦,没必要重新造轮子。
Modbus-RTU 的数据帧结构是:地址码 + 功能码 + 数据区 + CRC16 校验。我做了两个功能码就够用:
- 功能码 0x03:读保持寄存器,用来读当前温度值;
- 功能码 0x06:写单个寄存器,用来设置温度报警阈值。
温度值用有符号整数表示,实际温度乘 10 后存放在寄存器里,也就是 25.6℃ 存为 256。这样可以避免浮点数在 Modbus 协议里的传输麻烦,上位机拿到后自己除以 10 就行。这个做法在工业现场很常见,过程量一般都用整数加缩放因子表示。
CRC16 的计算是 Modbus-RTU 的标配,直接用查表法或者逐位计算都行。我在 PIC18F86J16 上用的是查表法,速度快,代码也不算长。发送数据时,帧与帧之间的间隔必须大于 3.5 个字符时间,这是 Modbus 协议规定的一帧结束标志。如果间隔不够,接收方会认为还在同一帧里,数据就会错乱。
3.4 中断与低功耗处理
如果这套系统用在电池供电的无线传感器节点上,低功耗就得认真考虑。PIC18F86J16 支持多种低功耗模式,我的做法是:平时 MCU 进入休眠,定时器每隔一定时间唤醒一次,启动 PJ85718DM 转换,读回温度,发送远程数据,然后继续休眠。整个周期可以根据场景设定,比如 HVAC 里 5~10 秒上报一次就够了,嵌入式设备保护里可以缩短到 1~2 秒。
这里要提醒一下,I2C 软件模拟在休眠唤醒后要重新初始化引脚状态和总线状态,尤其是 SDA 线可能停留在低电平,必须先发一个停止条件来释放总线,然后再正常通信。我在调试时遇到过休眠后第一次读取总是失败的情况,排查后发现就是总线状态没恢复,解决方法是唤醒后先让 SCL 翻转九次并发送停止位,让总线回到空闲状态。
中断的使用上,我建议远程通信用 UART 接收中断来解析协议帧,而不是在主循环里轮询 RCREG。这样 MCU 可以在空闲时休眠,收到完整一帧后再处理,整体功耗能降一个数量级。温度采集本身就不需要中断,因为转换时间固定,查询等待即可。
4. 实测过程中的问题与排查经验
4.1 I2C通信偶发失败:总线拉死与恢复
项目联调阶段遇到最典型的问题就是 I2C 偶发失败。现象是系统运行几分钟后,PJ85718DM 温度读数突然不更新,主控一直读到 0xFF 或固定值。用示波器看 SDA 波形,发现 SDA 被拉低不放,总线处于“锁死”状态。
这种问题常见原因有两个。一个是时序错误导致从机锁死:比如主机发送过程中产生了意外的停止条件或错误起始条件,从机内部状态机进入错误分支,不再响应总线上的信号。另一个是电源毛刺导致从机处于不确定状态,尤其是传感器上电时序和主控不一致的时候。
解决办法是在传感器通信失败后,执行总线恢复流程。具体就是软件里面做一个错误恢复函数:先把 SCL 和 SDA 配成输出,手动翻转 SCL 九次,同时确保 SDA 释放,最后发送一个停止条件。这一套操作能强制让总线回到空闲状态,实测大概率可以恢复通信。如果多次恢复仍然失败,再考虑断电重启传感器。
这个恢复流程我建议从一开始就写进软件里,不要等到现场出了问题才加。嵌入式系统百分之百会遇到通信异常,预留自动恢复机制是非常必要的。
4.2 温度跳变:滤波与传感器的自热问题
另一个高频问题是温度读数跳变。一开始我加了滑动平均滤波,情况有所改善,但还是会在特定情况下出现“台阶”式的跳变。后来排查发现两个来源:
第一是传感器自热。PJ85718DM 在持续供电时,内部电路会消耗电流,产生少量热量。如果传感器周围空气不流通、PCB 散热条件又差,热量积聚后读数会缓慢偏高。解决办法是降低采集频率,不要持续一直读,每次转换完让传感器尽量处于空闲状态。如果条件允许,可以周期性地给传感器断电,只在采集时才上电。
第二是数据转换时间不够。有些时候为了“快”,我把等待转换的延迟缩短,结果读到的不是完整的转换结果,导致数据出现固定倍数关系的错误跳变。这个问题后来通过阅读芯片数据手册明确了最小转换时间,把延迟调整到安全范围后,读数就恢复正常了。这里我的经验是:转换时间宁等多不可少等,多等 20ms 换一个稳定数据,完全值得。
4.3 远程通信误码:波特率误差与终端电阻
RS-485 远程通信在短距离调试时基本没问题,但一旦导线拉长到几十米,或者现场有变频器干扰,误码率就上来了。最典型的表现是上位机偶尔收到错误的温度值,CRC 校验报错,但又不是完全不通。
排查思路有三个方向。第一,检查波特率误差。PIC18F86J16 使用内部振荡器时,实际频率和标称值会有一点偏差,9600 波特率下影响不大,但如果是 38400 以上,误差就会接近甚至超过允许范围。解决方法是测量实际波特率,或者用外部晶振,或者用振荡器校准寄存器把频率调到更准。
第二,检查 RS-485 的终端电阻。长线传输时,信号反射会造成波形畸变,在总线两端各加一个 120Ω 终端电阻能有效抑制反射。需要注意,加了终端电阻后总线静态电平会更难建立,如果收发器的偏置电阻不够,反而会出现空闲时的误触发,需要把偏置电阻配合调整。
第三,检查地线。RS-485 虽然是差分信号,但两个节点之间的地电位差不能太大。最好在通信线之外再加一根地线,把两端的 GND 连起来,避免共模电压超出收发器的允许范围。这个问题在很多现场“看起来像干扰”的问题里其实是真凶,值得优先排查。
我在实测中还发现,传感器和 MCU 共地不好也会引起本地读数异常。当远程通信的隔离电源和本地电源不是同一个时,地电位差会导致 I2C 信号参考地漂移,解决办法是给远程通信加隔离模块,把通信地跟本地系统地彻底分开。
5. 扩展思路与总结体会
5.1 从单点监测到多点网络
这套方案目前是单传感器接单主控,实际要扩展也很方便。PJ85718DM 如果有地址引脚,可以通过把地址引脚接到不同电平来区分多个传感器,I2C 总线上就能挂多个。这样原来只能测一个点温度的设备,就能扩展成测回风温度、送风温度、室外温度等多个点。
多传感器接入后,软件要做两件事。一是通信时序要重新规划,不能在读取第一个传感器的时候第二个传感器正好也在输出,导致总线冲突。二是在每个传感器的数据结构里增加类型和位置标识,这样上报给上位机的数据不仅是一个温度值,还能区分是哪个位置的温度。这个字段在设计协议时就要预留,不然后续加传感器会非常痛苦。
再往后,如果点位特别多,或者传感器距离主控特别远,建议不要再拉长 I2C 总线,而是采用“就地采集 + 总线汇聚”的方式。每个区域用一个 PIC18F86J16 节点,挂附近的几个 PJ85718DM,节点之间通过 RS-485 组网,最后再汇聚到一个总控。这种两级架构在实际 HVAC 项目里非常常见,调试起来也比一根超长总线要稳得多。
5.2 最后分享一点工程体会
回头整理这个项目,我觉得最有价值的不是某一颗芯片的选型,而是整个调试思路的沉淀。在嵌入式温度监测里,十有八九的“疑难杂症”都不是单点问题,而是电源、地线、时序、滤波这些基础环节的叠加效果。PJ85718DM 和 PIC18F86J16 这套组合,胜在稳定和可控,传感器接口简单、主控外设宽裕,遇到问题时每一环都可以独立验证,不需要一上来就怀疑芯片坏了。
在整个过程中,我最大的体会是不要把“采集到温度”当成终点。硬件能把温度读出来只是第一步,真正决定系统能不能稳定跑起来的是滤波算法、通信协议、异常恢复机制和电源处理这些细节。也就是“造轮子”容易,“把轮子调圆”需要耐心。这篇内容如果能让读到的人在画板子、写代码之前就先想到总线恢复、电源去耦和滤波窗口这些问题,那这套方案的实际价值就算真正发挥出来了。