1. 这组器件组合到底解决什么问题
先说结论:PJ85718DM 是一颗低功耗 I2C 接口数字温度传感器,PIC18F85J50 是一颗自带增强型 CAN 控制器的 8 位单片机。这两个芯片搭在一起,核心任务是解决 HVAC 和嵌入式设备里“本地温度采集 + 远程温度上报”这个老生常谈但又特别容易翻车的问题。
我在实际项目中接触过不少类似需求,最常见的就是空调机组、通风管道、冷库监控这类场景。现场一般会有好些温度测点,有些传感器就在主控板旁边,走几厘米线就能接进来;另外一些测点可能在几十米外的风管里、冷水管上、甚至是室外机组内部。如果全部用模拟量线往主控板拉,线缆成本和施工难度都上去了,长距离传输还会引入干扰和压降误差。所以比较务实的做法就是:本地测点直接挂 I2C,远程测点用 CAN 总线组网,每一条支路放一个采集节点,节点把温度打包成 CAN 帧发到主控制器。PIC18F85J50 做节点主控,PJ85718DM 做温度探头,这样的组合在嵌入式和 HVAC 场景里都很顺手。
这套系统的核心价值不在于“能测温度”,而在于用合理的成本把温度数据的采集、传输、汇聚链路打通。很多开发者在类似项目里踩坑,往往不是死在传感器精度上,而是死在总线通信、电源处理、固件调试这些不起眼的环节。这篇文章就把我从硬件选型到软件实现再到现场调试的完整过程拆开讲,尽量把每一步背后的原因也说明白,方便你直接照着做。
2. 硬件选型和整体架构设计
2.1 为什么是 PIC18F85J50 而不是常规小单片机
做温度采集节点,很多人第一反应是选一个几毛钱的 8 位单片机,配一个 18B20 完事。但在 HVAC 场景里,“远程”两个字改变了整个设计约束。远程温度节点往往分布在一条 CAN 总线上,这要求主控芯片自带 CAN 控制器,否则就得外挂一颗独立的 CAN 控制芯片,比如常见的一定要 SPI 接口配合的型号,增加物料和软件复杂度。PIC18F85J50 直接集成了增强型 CAN (ECAN) 模块,支持 CAN 2.0B 协议,这对 8 位机来说是比较稀缺的。
这颗芯片的资源详细讲一下:它是 80 引脚封装,最高运行频率 40MHz,程序存储区 64KB,数据存储区接近 4KB。最关键的是有 5 个 CAN 通道,虽然实际项目里通常只会用到其中一路,但多出来的通道意味着如果需要做网关转发或者冗余总线,留了后路。除此之外,它还集成了 12 位 ADC、多个 UART、I2C/SPI 以及比较器和 PWM,覆盖能力很强。对一个温度采集节点来说,这些资源根本用不完,反而给后续功能扩展留了空间,比如顺便采集湿度、压力或者做风机调速。
我还注意到一个容易被忽略的点:PIC18F85J50 属于 3.3V 逻辑器件,但它的 I/O 口是 5V 耐压的。这一点在实际工程里很关键。HVAC 控制柜里电源环境往往比较脏,传感器和总线收发器的工作电压各有不同,I/O 口耐压高一点就不用额外加电平转换芯片了。
2.2 PJ85718DM 这颗传感器有什么特别之处
PJ85718DM 在资料里被归类为高精度数字温度传感器,I2C 接口,测量分辨率可以配置到 12 位以上,在 -20 到 70 度区间内,典型精度能做到正负 0.5 摄氏度。这颗传感器的常规封装很小,焊盘间距标准化,适合直接贴在探头 PCB 上塞进风管或者绑在管道表面。
很多开发者习惯用传统的 NTC 热敏电阻方案,配合单片机的 ADC 去读,但 NTC 有一个绕不开的问题:非线性校正。温度区间一宽,查表或者多项式拟合就免不了;而且模拟信号在长线传输中很容易被变频器的开关噪声干扰,现场调试非常头疼。PJ85718DM 是数字输出,信号在传感器内部已经被转换成数字量,再通过 I2C 总线传输,抗干扰能力强很多。加上它的测温范围覆盖了 HVAC 常见的 -40 到 125 度工业级场景,用于空调机组、通风管道、冷冻水进回水温度都足够。
不过这颗传感器的 I2C 地址和具体寄存器偏移,不同批次或不同厂家的资料可能略有差异。我习惯的做法是把地址和寄存器定义统一放在一个头文件里,而不是散落在主程序各处,后面出问题也好排查。
2.3 本地与远程温度节点的分工方式
整体架构上,我按照“就地采集、总线汇聚”的思路设计。
一个主控板上可能直接焊一颗 PJ85718DM,当本地温度探头用。同时主控板通过 CAN 总线挂接多个远程采集节点,每个远程节点上也是 PJ85718DM 加一颗小单片机或者直接用 PIC18F85J50。远程节点的单片机负责读传感器温度,然后周期性地把温度数据组装成 CAN 报文发上总线。主控端收到后,和本地温度一起做显示、联动控制或者上传到楼宇自控系统。
这种设计的好处有三层。第一,本地温度读取延迟低,主控可以直接做闭环控制,比如风机盘管根据回风温度调节阀门开度;第二,远程节点只负责数据采集和发送,主控挂了也不影响节点继续读温度,后续数据还能补传;第三,总线上可以容纳多个测点,以后增加新测点只需要挂一个新节点,改一下波特率和节点 ID,不需要重新拉模拟量线。
硬件连接上,远程节点的单片机通过 I2C 接口读取本地传感器温度,然后单片机内部跑一个循环任务,比如每隔 500ms 读一次传感器,再通过 CAN 模块把数据发出去。主控端的 CAN 报文接收中断里解析出地址和温度值,转成工程单位后刷新显示或参与逻辑判断。
3. 核心电路设计与关键参数计算
3.1 供电和去耦设计
嵌入式设备尤其是 HVAC 控制器,最容易被忽略的就是电源完整性。我看到很多新手设计的板子,MCU 和传感器共用一个 LDO,LDO 输入端不加防反接和浪涌保护,输出端电容只有一个 1uF,结果一上电或一受干扰就死机。
我在这套方案里的做法是:
- 主电源从系统 24V 直流或 24V 交流经整流后取电,先用一颗浪涌抑制器件做钳位,再加 π 型滤波,最后进 DC-DC 转成 5V。
- 5V 之后再经过一颗低 dropout 稳压器转成 3.3V 给 PIC18F85J50 和数字传感器供电。稳压器输入输出都放 10uF 钽电容和 0.1uF 陶瓷电容并联,低频和高频噪声都能压住。
- PIC18F85J50 的每个电源引脚旁边放一组去耦电容,AVDD 和 AGND 之间单独加一颗 1uF 电容。
- PJ85718DM 的供电引脚旁边也要放 0.1uF 电容,并且尽量靠近传感器摆放。
3.3V 稳压器选型要注意压差。如果输入 5V 输出 3.3V,普通 LDO 没有问题;但如果输入在某些跌落工况下只有 4.2V,压差大的 LDO 输出会掉出 3.3V 规格,导致单片机异常复位。所以尽量选低 dropout 的型号,并预留至少 0.5V 的压差余量。
3.2 I2C 上拉电阻的计算逻辑
PJ85718DM 和 PIC18F85J50 之间走 I2C 总线,I2C 是开漏结构,必须外加上拉电阻。很多人直接抄网上现成的 4.7k 上拉,其实这个值跟总线上挂的器件数量、走线长度、通信速率都有关系。
I2C 上拉电阻的取值要满足两个约束:一是上升沿时间不能超过协议规定的最大值,二是上拉电阻不能太小,否则器件拉低时灌入电流过大,可能损伤端口。
标准模式下 I2C 上升时间最大 1000ns,快速模式最大 300ns。总线等效电容 roughly 可以用走线电容加器件引脚电容估算,比如 10pF 的引脚电容乘以器件数,加每厘米 1pF 的走线电容。如果总电容约 100pF,上拉电阻取 4.7k 算出来的 RC 时间常数大约是 470ns,标准模式够用,快速模式勉强。如果总线距离拉到 30 厘米以上,总电容增大,上拉电阻可以考虑降到 2.2k 或 1.8k,保证上升沿时间达标。
我这块板子因为传感器和单片机距离很近,走线长度不足 5 厘米,总线上只挂一个传感器,所以用 4.7k 没有问题。注意这是“基于常见实践的计算补全”,实际以你的具体布局和速率为准。
提示:不要把 I2C 上拉电阻设计成可以开关切换的形式,除非你在做低功耗产品。固定阻值最简单可靠。
3.3 CAN 物理层收发电路
PIC18F85J50 内部有 CAN 控制器,但物理层还需要一颗 CAN 收发器芯片把差分信号发到总线上。收发器选型上,我习惯用带隔离的模块或者至少带热关断保护的型号。隔离方面,如果节点和主控之间共地良好,用非隔离方案也可以;但 HVAC 现场经常存在地电位差,远程节点可能在不同的配电回路下取电,地环路一旦形成,轻则通信丢包,重则烧毁收发器。所以我建议这种项目直接用隔离型收发器,或者使用 DC-DC 隔离电源加数字隔离器再接非隔离收发器,成本多一点但换来了可靠性。
在总线端,必须注意以下两件事。
终端电阻是 CAN 总线协议要求的。总线的两端各接一个 120 欧电阻,不能每个节点都接。我见过有人图省事,在每个节点上都并了 120 欧,结果总线等效阻抗降到 60 欧甚至更低,收发器输出电流过载,通信波形畸变严重。实际做法是先规划好总线的物理两端,只在最远端的两个节点上使能终端电阻。如果 PCB 上预留了电阻位,默认不贴,确认节点处于总线末端时再焊接。
CAN_H 和 CAN_L 对地各接一个 100pF 左右的共模滤波电容,吸收高频干扰。在静电严重的场合,还要加 TVS 管做 ±24V 以上电压的钳位保护。
3.4 传感器探头防护设计
远程温度节点如果用在风管里,探头直接接触空气;如果贴管道表面,传感器外壳需要和管道保温层隔离。这两种场景下传感器的防护重点不一样。
风管里的探头建议用带透气孔的金属套管保护,传感器 PCB 套在管内,引线从另一头引出,再用环氧灌封。管道表面测温要处理好导热和隔热的关系:传感器贴在管道表面,要使用导热硅脂填充缝隙,但传感器另一侧和环境空气之间要垫隔热垫,否则测出来的是环境温度和管道温度的折中值,误差能达到好几度。
我在某个冷库项目里测过,传感器如果没有贴隔热垫,在阳光直射的风管外壁上读数能比真实管壁温度高 2 到 3 度。这个误差在 HVAC 控制里是不可接受的。
4. 软件架构与核心代码实现
4.1 软件整体框架
固件按模块划分,看起来清晰也方便维护:
- 系统初始化模块:配置时钟、I/O、I2C、CAN、定时器
- 传感器驱动模块:负责 PJ85718DM 的寄存器读写、温度转换
- 总线通信模块:CAN 报文组包和解析、错误处理
- 应用逻辑模块:主循环里的采集调度和状态机
PIC18F85J50 的时钟配置要特别留意。这颗芯片有多个时钟源,外部晶振还是内部振荡器要在配置字里先定好。工程里用的 mux 信任度不高,最容易出的问题就是配置了外部晶振但板子上没焊晶振,或者焊了晶振但起振失败。项目如果对时间精度要求不高,我优先用内部振荡器,省掉两个引脚也可以挪作他用;如果 CAN 总线上多节点需要同步,建议用外部晶振,因为 CAN 的位定时对时钟容差有要求。
4.2 I2C 读取 PJ85718DM 的底层代码
读取 PJ85718DM 温度值的基本流程是:
- 发送设备地址加写位,等待应答
- 发送要读取的温度寄存器地址
- 重新发送设备地址加读位,读取两个字节
- 将两个字节拼接成 16 位数据,按分辨率换算成实际温度
下面是我在项目中验证过的代码片段,基于 MSSP 模块的 I2C 主机模式:
uint8_t I2C_ReadTemp(uint16_t *raw_temp) { uint8_t high_byte, low_byte; I2C_Start(); if (I2C_WriteByte(PJ85718DM_ADDR | 0x00) != I2C_ACK) // 设备地址+写 { I2C_Stop(); return 1; } if (I2C_WriteByte(TEMP_REG_ADDR) != I2C_ACK) // 温度寄存器地址 { I2C_Stop(); return 2; } I2C_RepeatStart(); // 重复起始位,切换为读操作 if (I2C_WriteByte(PJ85718DM_ADDR | 0x01) != I2C_ACK) // 设备地址+读 { I2C_Stop(); return 3; } high_byte = I2C_ReadByte(I2C_ACK); // 读取高字节,发送应答 low_byte = I2C_ReadByte(I2C_NACK); // 读取低字节,发送非应答 I2C_Stop(); *raw_temp = ((uint16_t)high_byte << 8) | low_byte; return 0; }注意一个细节:读完最后一个字节时主机要回非应答(NACK),告诉从机“不再读了”,然后产生停止条件。如果最后回了 ACK,传感器会继续输出数据,I2C 总线时序容易卡死。
温度换算的时候,不同分辨率的传感器原始值转换系数不同。假设 PJ85718DM 是 12 位分辨率,那么温度的常见换算关系是:实际温度 = 原始值 × 0.0625,但这个系数一定要对照手册确认。有的传感器出厂默认分辨率是 9 位,需要先写配置寄存器提升到 12 位再读取。我在代码初始化里会显式写入分辨率配置,避免依赖默认值。
void Sensor_Init(void) { // 写配置寄存器,选择12位分辨率 I2C_Start(); I2C_WriteByte(PJ85718DM_ADDR | 0x00); I2C_WriteByte(CONFIG_REG_ADDR); I2C_WriteByte(0x60); // 12位分辨率对应的配置值,具体以器件手册为准 I2C_Stop(); }4.3 CAN 模块初始化与报文发送
PIC18F85J50 的 ECAN 模块配置和普通 8 位机的 CAN 模块有些区别,关键是几个位定时寄存器。CAN 波特率取决于系统时钟、预分频值和位时间段配置。这里以 20MHz 时钟、500kbps 波特率为例,做一个简化配置:
void ECAN_Init(void) { // 配置引脚为CAN功能 TRISBbits.TRISB2 = 1; // CANTX 作为输出由硬件控制 TRISBbits.TRISB3 = 1; // CANRX 输入 // 进入配置模式 CANCON = 0x80; while ((CANSTAT & 0xE0) != 0x80); // 波特率配置:500kbps @ 20MHz BRGCON1 = 0x00; // SJW=1, 预分频为1 BRGCON2 = 0x00; // 相位段1=1 TQ,PS1=0 BRGCON3 = 0x00; // 相位段2=1 TQ // 屏蔽和滤波器配置,先禁用所有滤波器 RXB0CON = 0x00; RXB1CON = 0x00; // 退出配置模式,进入正常模式 CANCON = 0x00; while ((CANSTAT & 0xE0) != 0x00); }位定时配置不是随便设几个值就行。CAN 协议要求一个位时间由同步段、传播段、相位缓冲段 1、相位缓冲段 2 组成,采样点位置一般在 75% 左右。实际工程中,如果总线上节点时钟精度一般,建议把 SJW 设为 1,保证重同步时有足够余量。
发送一个标准温度数据帧,可以用下面的逻辑:标准帧 ID 的低 8 位放节点地址,数据场放两个字节温度原始值和两个字节状态字。这样远程主控收到报文后,根据 ID 判断节点,从数据场解析温度即可。
typedef struct { uint16_t node_id; int16_t temperature_x10; // 温度值乘以10,单位0.1摄氏度 uint8_t fault_flags; } TempPayload; void CAN_SendTemperature(uint16_t node_id, int16_t temp_x10, uint8_t flags) { uint8_t i; uint8_t data[8]; data[0] = (uint8_t)(node_id & 0xFF); data[1] = (uint8_t)((node_id >> 8) & 0xFF); data[2] = (uint8_t)(temp_x10 & 0xFF); data[3] = (uint8_t)((temp_x10 >> 8) & 0xFF); data[4] = flags; data[5] = 0; data[6] = 0; data[7] = 0; // 发送缓冲器选择与数据填充 TXB0CON = 0x00; TXB0D0 = data[0]; TXB0D1 = data[1]; TXB0D2 = data[2]; TXB0D3 = data[3]; TXB0D4 = data[4]; TXB0D5 = data[5]; TXB0D6 = data[6]; TXB0D7 = data[7]; TXB0SIDH = (node_id >> 3) & 0xFF; // 标准ID高字节 TXB0SIDL = (node_id & 0x07) << 5; TXB0DLC = 8; // 数据长度 TXB0CONbits.TXREQ = 1; // 请求发送 while (TXB0CONbits.TXREQ); // 等待发送完成 }发送完成后清标志位。我用的是查询方式发送,适合节点数量少、发送频率低的场景;如果发送频率高或者需要处理多个优先级报文,建议开发送中断,并且在标志位清除上多下功夫,防止中断丢失。
5. 本地温度与远程温度的工程联动实现
5.1 本地温度直接驱动控制逻辑的场景
本地温度这个概念,在 HVAC 里最典型的一个场景就是房间温控器。温控器板载一颗 PJ85718DM,实时读取房间空气温度,根据设定温度和当前温度的偏差,输出信号控制电动阀开度或者风机风速。这种场景对温度读取成功率要求很高,因为控制效果直接取决于采样质量。
这里我踩过一个坑:I2C 读取偶尔会失败,失败后如果不做处理直接拿旧值参与控制,问题不大,但如果在失败时读到了一个残留的未更新值,会把错误数据送进 PID。我的处理方式是每次读取返回一个状态,主循环里用一个滑动滤波器对成功的温度值做平滑。连续读取 8 次,去掉最大值最小值取平均,既能抑制偶然的坏点,也能让温度变化看起来更自然。
系数选择上,滤波时间常数不能太大。比如 8 次平均后的数据,对突然升温的响应会滞后,影响温度控制的动态性能。我的经验是 4 到 8 次滑动平均足够了,再大的窗口会出现控制振荡。
5.2 远程温度节点报文轮询机制
远程节点发 CAN 报文,有两种思路:节点主动周期上报,或者主控定期轮询。周期上报实现简单,但如果总线上节点很多,所有节点同一时刻上电,会产生报文风暴,总线冲突概率很大。轮询机制则要求主控维护一张节点列表,按顺序发请求帧,节点收到请求后回温度帧。
我在这套系统里用的是周期上报加随机延迟的方式。每个远程节点在收到复位命令后,会随机等待 100 到 900 毫秒之间再启动周期发送,避免上电时报文集中在同一时刻。上报周期设为 500 毫秒,对 HVAC 控制来说完全够用,总线负载率也很低。
远程节点内部的定时基准是单片机的定时器中断,每 10 毫秒进一次中断,累计 50 个中断也就是 500 毫秒触发一次采集和发送。定时器初值要根据主频重新计算,不要想当然。比如系统时钟 20MHz,定时器预分频 1:8,16 位定时器要产生 10ms 中断,计数值可以算出来,初始化代码里要有注释,以后换时钟频率也好改。
5.3 故障处理与状态回传
远程温度节点的故障类型主要有:传感器通信失败、温度超范围、节点供电异常、总线错误计数超限。这些状态要实时反馈给主控,不能只发一个温度值了事。我在数据结构里固定用一个字节做故障标志位:
- bit0:传感器通信超时
- bit1:温度低于量程下限
- bit2:温度高于量程上限
- bit3:内部存储校验错误
- bit4 到 bit7:保留
主控端收到故障标志后,可以决定是继续显示最近一次有效温度、显示故障警告,还是把对应节点的控制输出强制切换到安全状态。比如冷库的化霜温度探头如果故障了还盲目按当前值控制除霜,可能把库温带偏。
5.4 主控端数据整合与显示逻辑
本地温度直接通过 I2C 在启动时读取一次,后续在线更新。远程温度通过 CAN 接收中断收到后,存放到一个环形缓冲区,主循环里再解析。这种中断只做数据搬移、主循环做业务逻辑的方式,能避免在中断里做耗时的数据处理。
显示方面,如果系统带了 LCD 屏,一般会显示当前各节点温度的列表。为了不让显示刷新影响 I2C 和 CAN 时序,我通常把显示刷新的频率控制在 2 到 5 赫兹,并且只更新变化了的字段,而不是整屏重绘。否则会出现屏幕闪烁,甚至因为共用一条总线导致传感器读取超时。
6. 常见问题与调试技巧实录
6.1 传感器 I2C 无应答问题
现象:单片机发送设备地址后,SCL 正常,SDA 一直收不到 ACK。
排查步骤:
- 用示波器或逻辑分析仪测量 SDA 是否在应答位被拉低。如果 SDA 一直是高电平,说明传感器没有应答。
- 确认传感器供电有没有起来,传感器供电引脚电压是否在规格范围内。很多传感器在上电瞬间需要至少 5ms 稳定时间,上电后紧接着就去读它,可能它还没准备好。
- 确认 I2C 地址是否正确。PJ85718DM 的实际地址可能由地址引脚决定,也可能固定。仔细查手册,不要只看网上的例程。
- 确认上拉电阻是否接到正确的电源轨。如果上拉接的是 5V,而传感器供电是 3.3V,SDA 可能被拉到一个超规格电压,传感器内部保护二极管导通,器件误操作。
我遇到最隐蔽的一次,是因为 PCB 上 I2C 的两根线在排线连接器里被插反了,SCL 和 SDA 互换。逻辑分析仪一抓波形就看出来,建议先量引脚通断再换器件。
6.2 CAN 总线通信间歇性失败
现象:温度数据偶尔丢一帧,节点多了之后丢包率明显上升。
大部分情况下,这是位定时配置与总线波特率不匹配导致的发送错误。CAN 控制器在发送时会监控总线电平,如果它发送的位和监控到的位不一致,就会产生位错误,连续产生错误后进入总线关闭状态,节点就“离线”了。
排查位定时问题最直接的方法是看 CAN 总线的波形。用示波器在终端电阻两端抓 CAN_H 和 CAN_L 的差分波形,看位时间的宽度是否和预期波特率一致。如果每一位的时间有抖动,大概率是预分频配错了,或者采样点位置过于靠边。
另一个常见原因是终端电阻放置不当。前面提过,终端电阻只在总线两端接。如果总线上中间某个节点也接了 120 欧,信号反射会在末端叠加,造成位错误。
6.3 远程节点持续重启问题
远程节点如果放在室外或者配电柜里,电源环境很差。我遇到过一个案例:节点每次继电器吸合时都会重启,后来定位到是 DC-DC 电源模块的输出在负载突变时跌落,单片机瞬间掉电。解决办法是把 DC-DC 的输入端电容加大到 100uF,输出端再并联一个 100uF 电解电容。对于电源要求不高的产品,这种并联大电容的办法最简单有效。
如果重启还是偶发,另一个隐蔽原因是看门狗超时。如果主循环里的某个操作耗时太长,比如在 I2C 通信失败时没有加超时保护,挂在 while 里等 ACK,那么看门狗就会把芯片复位。I2C 通信一定要加超时机制,不能无限等。
我常用一个简单的 I2C 超时实现:在等 ACK 的循环里加一个计数器,超过限制就退出函数返回错误码,再让主循环重新初始化 I2C 总线。
6.4 温度读数跳变误差大问题
跳变一般分两类:真实环境波动和信号链路干扰。
真实波动比如风管里气流不稳定、空调压缩机启停造成冷媒温度摆动,这种通过滤波可以缓解,但不建议滤得太狠,否则控制响应变差。
信号链路干扰的表现是温度值稳定,但偶尔蹦出一个明显离谱的值。优先检查 I2C 供电脚旁边的去耦电容有没有贴错位置,传感器探头线是否和变频器输出线走在同一个线槽里。如果现场干扰确实难治,把传感器换成屏蔽线、屏蔽层单端接地,通常能解决。
还可以在软件上做一个“合理性检查”:温度原始值转换后如果超过设定的上下限,或者和上一次有效值相差超过一个阈值,就丢弃这次数据,用上一次的值顶上。阈值我会根据具体应用设定,比如室内温度变化速率一般不超过每分钟 2 度,管道温度变化可能更快一点,这个参数要现场根据实际情况微调。
6.5 传感器探头线束长度限制与对策
PJ85718DM 走的是 I2C,I2C 本身不适合长距离传输。如果你的远程节点和传感器之间隔着几十厘米以上,建议把传感器放在节点板上,通过总线与主控通信,而不是把 I2C 拉长线。I2C 长线的电容会导致上升沿变缓,通信速率不得不降下来。
我在一个项目里把 I2C 线拉到 2 米多,标准模式 100kbps 勉强能通,但温度读数偶尔出错。后来改走传感器节点模式,彻底解决。如果你确实要在节点板上外接探头,线长控制在 20 厘米以内比较稳妥,并且用双绞线传输 SCL 和 SDA。
7. 从这套方案里沉淀下来的几点经验
这套温度和通信方案我在几个不同项目里反复用过,每次都会积累一些小经验,最后再整理几条确实有参考价值的。
第一,尽量在原理图阶段就把测量点标清楚。这个测点是本地还是远程,走 I2C 还是 CAN,探头放在什么环境,这三件事决定了后面所有设计和成本。等到 PCB 做出来才发现某个测点离主控太远,再改就很被动了。
第二,通信协议的帧格式要留足扩展余地。温度数据帧里留几个保留字节,以后故障标志、节点固件版本、在线状态这些信息都能往里面塞,总线协议不用大改。
第三,在软件里把“温度采集”和“温度使用”解耦。采集任务只管把温度读到缓冲区,控制逻辑只管从缓冲区取数。这样后续想换传感器、改采样频率,都不需要动控制代码。
第四,调试时优先用逻辑分析仪抓 I2C 和 CAN 波形,不要靠猜。很多所谓“灵异问题”,按下脚一看波形就清清楚楚了。I2C 抓 ACK、CAN 抓帧格式,这两样工具调试效率最高。
这套方案的可扩展性不错。如果后续项目需要把远程温度数据接入以太网或者无线模块,只需要在 PIC18F85J50 的 UART 口接一个网关模块,把 CAN 数据解析后转成 JSON 格式上报即可。8 位机的性能和资源足够应付这类简单协议转换。我在实际操作中体会最深的一点是:好用的方案不一定要最先进,能把成熟可靠的芯片组合用好,解决现场的温差测控问题,就已经达成了项目目标。