ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

PIC18F86J10与PJ85718DM双链路温度监测系统设计

PIC18F86J10与PJ85718DM双链路温度监测系统设计

做嵌入式和HVAC相关项目的朋友,应该都绕不开温度监测这件事。嵌入式板卡要关心电源模块、驱动管、处理器附近有没有过热的风险;暖通空调系统则要盯住室内回风、送风管路、盘管进出口、室外换热器这些分散点位的温度变化。最近一套项目里,我用PJ85718DM配合PIC18F86J10做了双链路温度监测:本地通道直接采样,远程通道通过RS-485总线轮询多个温控节点。这套方案在实验室和现场都表现稳定,这篇我把从选型到固件的完整做法整理出来,想少走弯路的朋友可以直接参考。

1. 组合选型与方案定位:摸清需求再动手

1.1 先理清楚:你到底要测哪些温度

很多人拿到温度监测需求就直接选传感器、画板子,我建议先花一天时间把测温点位列清楚。嵌入式场景里,要测的是芯片表面、电源电感、MOS管、机箱内部空气这些“离控制板很近”的温度,特点是量程跨度大、空间紧凑、干扰因素多。HVAC场景则完全不同,要测的是分散在楼宇、机组、管道上的温度,一个点位跟另一个点位可能隔着几十米,供电环境、电磁干扰、安装位置都不一样。

标题里的“本地与远程温度”,本质上就是这两类场景的组合:本地温度指主控板附近的温度,用传感器直接接ADC就能解决;远程温度指分布在远处的传感器节点,必须走总线或网络把数据收回来。这套系统里的PJ85718DM承担传感采集,PIC18F86J10承担本地读取、远程组网和数据处理。把这个边界想清楚,后面所有硬件和固件设计都有明确目标。

1.2 主控选型:为什么是PIC18F86J10

PIC18F86J10是80引脚的高端8位单片机,我选的TQFP封装,Flash空间、RAM、外设资源应对这个项目很宽裕。具体来说,它内置16通道10位ADC、两路EUSART、两路MSSP(SPI/I2C)、5个定时器,还支持JTAG调试。这些资源里最关键的其实是ADC通道数和两路UART:一路UART给RS-485远程总线,另一路UART留给上位机或调试,各有各的用途,互不干扰。

有人会问,8位机做得了这些事吗?我的看法是,温度采集本身就是典型的低复杂度任务,用不着上32位平台。8位机开发工具链成熟、功耗可控、稳定性经过大量工业现场验证,成本还低。PIC18F86J10在3.3V下能跑到10 MIPS级别,轮询8个远程节点加上本地采样,CPU占用率很低。更重要的是,车规级或工业级的8位芯片在HVAC这种常年通电、环境复杂的场景里,故障率比想象中低得多。

1.3 传感器接入方式:一颗传感器,两种形态

PJ85718DM是一颗线性电压输出的温度传感器,供电范围宽,标准的10mV/℃灵敏度,输出电平与温度成线性关系。这种传感器的好处是接口极其简单——输出脚直接进ADC即可,不涉及复杂的时序协议。在本地链路上,我把它的输出经过一级RC滤波接到PIC的模拟输入通道;在远程链路上,每块远程采集板上同样用PJ85718DM测温度,但由板载MCU读ADC,再把换算好的温度数据通过RS-485发回主控。

也就是说,传感器本身没有变化,变的只是它“挂”在什么位置上。本地直连,省事、实时、成本低;远程数字化后走总线,抗干扰能力强、能带多个节点、传输距离上百米。这种设计让一套硬件方案同时覆盖嵌入式设备内部监测和HVAC分布式测温,后续维护只需要备一种传感器型号。

1.4 为什么不选单总线或无线方案

做远程温度采集时,常见方案有单总线数字传感器、无线模块、RS-485有线总线,我最终选了RS-485,原因是在HVAC现场它最省心。单总线(比如常见的18B20那一类)虽然便宜、接线少,但长线传输稳定性一般,时序敏感,节点多了容易受分布式电容影响,而且测温速度不快。无线方案免布线,但每个节点要解决供电问题,还要考虑同频干扰、电池更换、穿墙衰减,在机房和楼宇现场反而增加维护成本。

RS-485只在物理层上定义差分传输,主从问答、协议自己定。现场双绞线一拉,节点并联挂上去就行,距离足够长。配合屏蔽层和终端电阻,抗共模干扰能力比单端信号强得多。这套思路在楼宇自动化里跑了这么多年,属于最稳当的选择。

2. 硬件设计与关键连接:双链路怎么搭

2.1 本地温度通道:从传感器输出到ADC引脚

本地链路的核心电路不复杂,但细节决定精度。PJ85718DM的供电我从3.3V主电源上单独引了一路,中间加磁珠和10μF+0.1μF去耦电容,避免电源噪声耦合进输出。传感器输出脚先串联一个1kΩ电阻,再接0.1μF对地电容形成低通滤波,最后进PIC的AN0通道。这个RC的截止频率大约是1.6kHz,足以滤掉绝大多数开关电源的纹波噪声,又不会让温度信号有明显延迟。

ADC参考电压这里我用了外部基准,没有直接用VDD。原因很直接:3.3V主电源纹波虽然经过稳压,但负载变化时还是有几毫伏的波动,这会直接变成ADC误差。外部基准芯片输出2.5V稳定电压,10位ADC在2.5V参考下,一个LSB对应约2.44mV,按PJ85718DM的10mV/℃灵敏度换算,理论上温度分辨率能到0.244℃。如果直接用VDD当参考,等于把电源的波动一并算进温度误差里,这个钱不能省。

2.2 远程节点硬件与RS-485总线拓扑

远程节点板的组成是:PJ85718DM加一颗小封装MCU,再加一颗RS-485收发器。MCU负责把本地传感器输出电压换算成温度,然后等主控轮询时把数据发出去。每块节点板用拨码开关设置1~8的节点地址,拨码的意义在于现场改地址不用重新烧程序,直接拨到位、重启即可,这个细节对工程维护非常友好。

总线上,所有节点的收发器A/B脚并联到同一对双绞线上,主控侧同样接一颗RS-485收发器,连接到PIC的UART1。物理层的几个关键点:总线两端各接一个120Ω终端电阻,匹配差分阻抗、抑制反射;屏蔽层在主机侧单端接地,避免形成地环路;分支线尽量短,不能超过1米。这些规则我在第一版样板里偷懒过,后面现场通信不稳,老老实实按规范改完就再没出过问题。

2.3 主控最小系统与电源布局注意事项

PIC18F86J10工作电压范围窄一些,我统一用3.3V系统。主控板电源入口是宽压DC-DC先降到5V,再由低噪声LDO降到3.3V,给MCU、基准、传感器和RS-485收发器供电。数字部分和模拟部分的地采用单点连接,ADC参考和PJ85718DM尽量靠近模拟地走线,不要跟RS-485收发器的地混在一起。

晶振我选16MHz被动晶振,两个22pF负载电容,布局上紧贴MCU的OSC引脚。复位用带手动按钮的RC复位电路,调试接口预留JTAG。这些看似常规的设计,其实直接决定了系统在现场的稳定性。特别是去耦电容,每个电源引脚旁边必须放一个0.1μF,这是很多人画板时最容易省掉、最后又回来补的东西。

3. 固件实现:ADC换算、RS-485轮询与任务调度

3.1 开发环境与初始化注意点

固件开发我在原厂IDE环境下用C语言完成,配合官方编译器,调试器用通用的调试工具即可。开发初期有几个配置位必须确认:一是外部16MHz晶振的振荡模式要选对HS模式;二是在原型阶段把看门狗关掉,等程序稳定后再打开;三是JTAG默认使能会占用部分IO,如果不用调试功能,建议关闭以释放引脚。

ADC初始化代码比较简单,核心是选通道、配置参考电压、设置转换时钟。采样时钟不能太快,PIC的ADC采样保持电容需要在规定时间内充满,转换时钟太快会导致高阻抗源下读数偏低。我按照数据手册建议,把转换时钟配置为Fosc/16,保证在外部RC滤波的阻抗条件下有足够的采样时间。

void adc_init(void) { // 使能ADC,选择AN0通道 ADCON0 = 0b00000101; // 参考电压选择:VREF+引脚,VREF-接VSS // 转换时钟配置为Fosc/16 ADCON1 = 0b00110000; // 结果右对齐,采集时间配置为2TAD ADCON2 = 0b10100010; // AN0设为输入方向 TRISAbits.TRISA0 = 1; }

3.2 本地温度计算:从ADC码值到实际温度

温度换算公式不复杂,但容易在细节上栽跟头。ADC输出的是10位码值,和输入电压的关系是:Vin = ADC码值 × Vref / 1024。假设Vref为2.5V,PJ85718DM灵敏度为10mV/℃,那么一台理论上零点为0V的器件,温度就是Vin除以0.01。

实际在固件里我用浮点计算,虽然8位机跑浮点慢一点,但温度采集本身频率不高,200ms采一次完全够用。为了减少偶发噪声,我做了软件滤波:连续读12次,去掉最大值和最小值,对剩下的10次取平均。这样做下来,常温下读数稳定在±0.1℃以内,偶尔有毛刺也会被剔除掉。

uint16_t adc_read_average(uint8_t channel) { uint16_t sum = 0; // 连续采集12次,剔除最大最小后求平均 for (int i = 0; i < 12; i++) { ADCON0bits.CHS = channel; ADCON0bits.GO = 1; while (ADCON0bits.GO); sum += ADRES; } return sum / 12; } float read_local_temp(void) { uint16_t adc = adc_read_average(0); float volt = (float)adc * 2.5f / 1024.0f; float temp = volt * 100.0f; // 10mV/℃ return temp; }

需要特别提醒:PJ85718DM的实际零点可能存在微小偏移,不同批次之间会有差别。我在项目里抽测过同批次传感器,零点偏移普遍在正负20mV以内,换算成温度就是正负2℃左右。所以标定程序里必须预留一个温度偏移量,不能假设零点就是0V。

3.3 RS-485帧协议与半双工收发切换

RS-485是半双工总线,同一时刻只能有一个设备发送。我的主从协议很简单:主控发送查询命令,被查询的节点返回数据,其他节点保持静默。帧结构用了固定长度,发送帧是6字节,接收帧是7字节,校验用累加和——把所有字节相加,取低8位作为CRC字节。工业现场如果协议要更严谨,可以直接换成Modbus RTU,但在这个项目里自定的简化协议足够可靠。

// 发送帧:AA 55 地址 功能码 保留 CRC uint8_t tx_frame[6]; tx_frame[0] = 0xAA; tx_frame[1] = 0x55; tx_frame[2] = node_addr; tx_frame[3] = 0x01; tx_frame[4] = 0x00; tx_frame[5] = crc8(tx_frame, 5);

半双工方向切换是个容易踩坑的点。RS-485收发器的发送使能脚(DE)和接收使能脚(RE)通常接在一起,由单片机一个IO控制:拉高进入发送模式,拉低进入接收模式。发送完成后不能立刻拉低切换,因为UART移位寄存器可能还在输出最后一位。我实测下来,查发送完成标志后,最好再延时几个微秒再切换方向,否则最后一个字节的停止位会被截断,节点收不到完整命令。

接收端也有类似问题:主控发送命令后,总线还处于发送模式,这时候收发器的接收器是关闭的。必须等方向切换回接收后,再开始监听节点的回复。我在代码里用了一个简单的状态机:发送命令、延时、切换方向、开启超时等待接收。超时时间设成30ms,超过就算该节点离线。

3.4 主循环轮询与离线节点处理

主程序结构非常直接:读本地温度,轮询8个远程节点,汇总数据,通过第二路UART发给上位机,最后延时200ms进入下一轮。

while (1) { local_temp = read_local_temp(); for (uint8_t i = 0; i < 8; i++) { if (poll_node(i + 1, &remote_temp[i])) { node_status[i] = NODE_ONLINE; } else { node_status[i] = NODE_OFFLINE; } } report_to_host(local_temp, remote_temp, node_status); __delay_ms(200); }

轮询8个节点,每个节点即使超时也要等30ms,最坏情况一轮要240ms,加上延时200ms,数据刷新周期约440ms。对温度监测来说这个刷新率完全够用,人也感知不到延迟。离线节点我会连续查3次,3次都超时才标记离线,避免偶发干扰导致误报。这样处理后,现场只要不是物理断线,节点状态基本不会闪断。

4. 调试过程与故障排查实录

4.1 ADC读数跳动:先从参考电压找问题

第一版板子调试时,本地温度读数在稳定环境下跳了将近正负3个LSB,常温下温度显示忽高忽低。我一开始怀疑是RC滤波不够,加大电容之后改善不明显。后来用示波器看3.3V电源,发现纹波有将近30mV,负载切换时还有毛刺。问题根源就是我用VDD做ADC参考电压,电源噪声全被算进了转换结果。

换成外部2.5V基准后,读数立刻稳定下来。这个教训说明一个原则:ADC的参考电压干净程度,直接决定整个测量链路的精度。如果你手头项目里ADC读数总在跳,先别急着加软件滤波,拿示波器量一下参考电压,可能有意外收获。

4.2 RS-485偶发丢帧:方向切换时序和端接电阻

远程通信最开始有个很奇怪的现象:单个节点单独测试一切正常,两个节点挂上总线后,偶尔会有一个节点回复收不到。我先是怀疑地址配置冲突,查了拨码没问题。然后用示波器抓A/B线波形,发现帧尾有明显振铃,反射波叠加到正常电平上,导致接收端误码。

原因有两个。第一个是我把120Ω终端电阻焊在了主控板内,而不是总线的物理末端。总线长了之后,主控板不在一端,端接电阻等于接在中间,反射根本没被吸收。第二个原因是发送切接收的时序太急,发送完后立刻拉低DE,最后一位还没发完。修正方法很简单:端接电阻按实际布线挪到总线两端,切换时序里加一点裕量。改完后再抓波形,干净很多。

4.3 传感器标定:两点法加上软件偏移

PJ85718DM的线性度不需要怀疑,但零点偏移是必须处理的。我的标定方案是两点法:把传感器探头放到冰水混合物中,稳定后记录显示温度,另一个点用高精度水浴或恒温槽设在50℃,同样记录读数。然后根据这两个点算出一阶线性补偿系数:实际温度 = 测量温度 × 增益 + 偏移。

标定的代码实现不复杂,就是给换算公式加两个可配置参数。我在固件里留了一段配置区,通过串口命令字可以临时写入新的增益和偏移,不用重新烧录程序。这个设计在现场特别实用,传感器换批次或者探头换了位置后,直接用上位机校准工具调一下就行。很多人觉得传感器出厂已经校准过就不需要动,实际上系统级误差还包括ADC误差、参考电压误差和探头安装热阻,上电后跑一次两点校准很值得。

4.4 HVAC现场环境的特殊坑

HVAC场景比实验室多两个麻烦:一是冷凝水,二是高低温循环。远程节点如果装在回风口或盘管附近,夏天表面温度低于露点,探头和板卡上会结露。PJ85718DM的封装本身密封性尚可,但PCB走线暴露在外,结露后绝缘电阻下降,会导致读数漂移。我后来的方案是给传感器探头加防水套管,节点板灌封三防漆,接线端子做朝下安装,让水滴自然流走。

另外,室外换热器附近的节点在冬天和夏天的温差非常大,塑料外壳在低温下变脆,电缆接头热胀冷缩后容易松动。处理办法是选用宽温级外壳,所有接线端子用带锁扣的插拔端子,固定点加弹簧垫片。这些看起来跟“温度监测”没直接关系的小事,恰恰是现场项目能不能长期稳定运行的关键。

这里把常见问题整理成速查表,方便现场对照:

现象可能原因处理方法
本地温度读数跳动大参考电压不稳、滤波不足换外部基准,加大RC滤波
远程节点偶发丢帧端接电阻位置不对、收发切换太快端接电阻移到总线末端,切换加延时
所有节点都不回应A/B线接反、收发器方向脚悬空对照线序检查,确认DE/RE默认接收
单节点读数明显偏大传感器附近有热源、自热探头远离发热器件,降低传感器供电电流
低温段读数漂移结露、端子松动探头防水套、板卡三防漆、锁扣端子

5. 测试效果与后续扩展方向

5.1 现场实测数据整理

系统稳定后,我在一个模拟的暖通机组环境里做了48小时连续运行测试。主控板放在设备间内,本地温度测的是柜内空气温度;远程节点分别放在模拟回风口、供水管表面和室外机旁边。48小时内本地读数保持在25.1到25.4℃之间,波动范围很小;远程节点数据传输成功率在正常布线下达到99.9%以上,偶发超时在重试后都能恢复。

采集到的数据由主控第二路UART上传到触摸屏显示。触摸屏上同一时刻能看到本地温度和8个远程节点的温度,哪个节点离线会直接显示故障状态,不需要去现场用万用表一个个量。这套人机交互思路对HVAC运维来说很实用,操作员看到的是“哪个点位温度异常”,而不是一堆原始电压值和寄存器数据。

5.2 后续还可以这样扩展

这套系统的架构留足了扩展空间。首先,远程节点上限可以超过8个,只要协议里的地址字段扩一个字节,轮询表加长就能带几十个点。其次,如果现场需要接入触摸屏或PLC做集中控制,可以把第二路UART改成Modbus RTU从站,让上位机来读PIC里缓存好的温度表,这样就跟主流楼宇自控协议对接上了。

功耗方面,PIC18F86J10本身支持低功耗模式,远程节点如果靠电池供电,可以在非轮询时间段进入休眠,由定时器定时唤醒响应查询。不过HVAC现场大多数节点都能就近取电,我暂时没有启用休眠,把重点放在可靠性和抗干扰上。如果是做便携式嵌入式设备,倒是值得把低功耗这块认真做起来。

5.3 再分享一个探头安装的小经验

最后说一个实际项目中反复踩过坑的点:探头安装方式对测量结果的影响,很多人会忽略。温度传感器测出来的其实是它自己的温度,不是空气温度,也不是管壁温度。如果探头直接贴在金属管壁上,测到的接近管壁温度;如果架空在风管中间,测的才是气流温度。我习惯在安装时用导热硅脂填充探头与接触面之间的缝隙,再用夹具固定,这样热阻最小,响应也最快。要是条件允许,管道测温最好插入热套管,这样检修时探头可以直接抽出来,不需要停机放水。

传感器引线也要注意,超过一定长度的屏蔽线最好单端接地,避免形成地环路干扰。PJ85718DM的输出阻抗本身不高,但长线传输环境复杂,有条件就把远程部分全部数字化走RS-485,别用模拟量长距离拉线,这是最容易省事也最容易出问题的分界线。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进