ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于PIC18F86J15与PJ85718DM的双点温度采集系统设计

基于PIC18F86J15与PJ85718DM的双点温度采集系统设计

做嵌入式测温的项目做了这么多年,我越来越觉得,真正考验水平的往往不是把传感器接上单片机那么简单,而是把信号在复杂的现场环境里稳定地采回来。这次要聊的方案,是围绕 PJ85718DM 温度传感模块和 PIC18F86J15 单片机展开的一套双点测温系统,专为嵌入式设备机柜和 HVAC(供热通风与空调)场景设计:一个测温点装在控制器本地,另一个测点在远端风道或室外机,两路温度通过同一颗单片机完成采集、换算、滤波,最终经 Modbus RTU 上报给上位机。整套方案从选型、画板到固件调到实测,踩过的坑不算少,写出来给正在做类似项目的朋友做个参考。

1. 项目需求拆解与总体设计思路

1.1 本地测温与远程测温的根本差异

很多刚入门的朋友容易把"多路温度采集"想简单了,觉得无非是多接几根线、多开几个 ADC 通道的事。但一旦把"本地"和"远程"放到一起,问题就完全不一样了。

本地测温点通常就在主控板旁边,走线短,可能只有几厘米到几十厘米,信号衰减和干扰都相对可控,直接分压采样问题不大。远程测温点就麻烦了:现场部署的时候,传感器到主控板的线缆动不动就是十几米甚至几十米。距离一旦拉长,线缆电阻、分布电容、电机和继电器产生的电磁干扰全部会叠加进来。我在现场见过最夸张的情况,是远端温度读数在压缩机启动的瞬间整体跳高了接近 3℃,这就是典型的干扰耦合进模拟链路的结果。

所以设计一开始就要明确两个测温点的物理需求差异,不能只用同一套接口电路硬套。

1.2 HVAC 场景里的真实约束

HVAC 行业的温度监测,有几个指标是绕不开的:

第一是量程。设备机柜内部温度通常在 -10℃ 到 +70℃,风道温度、室外环境温度则在 -40℃ 到 +50℃ 之间都有可能。传感器的量程必须覆盖这个范围,并且在整个量程内都不能出现明显非线性畸变。

第二是精度。舒适性空调的控制回路一般要求 ±0.5℃,用于能效监测和故障诊断的场景可以放宽到 ±1℃,但采暖计费、温控阀调节这类用途会更严格。不要觉得 ±0.5℃ 很简单,传感器自身误差、分压电阻温漂、ADC 参考电压漂移、自热误差全部叠加上去之后,想把最终的测量误差压进这个范围,还是需要花点功夫的。

第三是响应速度。风道温度传感器要能跟得上气流温度的变化,不能滞后太多,否则温控环路很容易振荡。

第四是环境。HVAC 现场往往有振动、冷凝水、灰尘和大量的电力电子设备,这在嵌入式项目里不算友好。

1.3 方案架构的选定

整个系统的架构定为:两路 PJ85718DM 模拟温度传感模块分别布置在本地和远端,通过屏蔽双绞线引入主控板;PIC18F86J15 片上集成了 12 位 ADC,直接完成两路模拟信号的采样;固件里做滤波、线性化、校准补偿,再通过 EUSART 走 Modbus RTU 协议上报。这样做的好处一是 BOM 简单,不用外扩 ADC 芯片;二是一颗单片机就把采样、运算、通信全包了,后期维护也方便。

2. 核心器件选型:两块关键芯片的组合逻辑

2.1 PJ85718DM 传感模块的定位分析

PJ85718DM 在实际项目中是一个非常典型的模拟温度传感方案,内部主要由高精度 NTC 热敏电阻和预置的分压网络组成,对外输出一个与温度相关的模拟电压信号。这类模块在 HVAC 行业用得极多,原因很实在:便宜、成熟、替换方便,现场工程师基本不需要专门培训就能接线维护。

NTC 热敏电阻的典型规格是 25℃ 时标称阻值 10kΩ,B 值 3950。这个参数组合在 -20℃ 到 +85℃ 区间内有不错的灵敏度,尤其是 0℃ 到 50℃ 这个 HVAC 最关心的范围内,阻值变化曲线足够陡峭,配合高分辨率 ADC 可以获得很好的分辨力。

但它也不是没有缺点。NTC 的"阻值-温度"曲线是强非线性的,低温端变化剧烈、高温端变得平缓,必须做线性化处理。另外 NTC 的一致性受制造工艺影响,同一批次不同个体的阻值偏差可能有 ±1% 到 ±3%,折合温度误差就是 0.3℃ 到 1℃ 的量级。所以量产项目必须留标定环节,这个后面细说。

2.2 PIC18F86J15 为什么够用

PIC18F86J15 是 Microchip 高集成度 8 位单片机家族里的一个典型型号,选择它主要看中四点。

第一是 ADC。这颗芯片内部的 ADC 是 12 位分辨率,这在 8 位机里是比较难得的配置。很多同类产品只有 10 位 ADC,1 LSB 对应的电压是 5V/1024≈4.88mV,用来测 NTC 分压可能只能分辨 0.1℃ 左右。而 12 位 ADC 配合 2.048V 参考电压,1 LSB 正好是 0.5mV,同样的温度区间分辨力能到 0.01℃ 级别,这对精度和稳定性都有质的提升。

第二是存储和外设。64KB Flash、3936 字节 SRAM、1KB 数据 EEPROM,对双路温度采集加 Modbus 协议栈来说绰绰有余。EEPROM 还能用来保存标定系数和故障历史,不用额外挂存储芯片。

第三是通信接口。EUSART 硬件串口的波特率误差控制得不错,跑 9600bps 和 19200bps 的 Modbus RTU 都很稳,而且支持自动波特率检测,调试的时候好说话。

第四是功耗。J 系列带 nanoWatt 技术,休眠电流能做到 1µA 以下,在电池供电的无线室内温控器场景里也能撑得住。我这次虽然是主供电方案,但低功耗能力给后续产品迭代留了余地。

2.3 对比其他方案的取舍逻辑

做方案的时候也考虑过外扩 ADS1115 这颗 16 位 ADC,以及直接上数字温度传感器。对比了一圈之后还是决定用内部 ADC。

先说 ADS1115:16 位分辨力确实诱人,但它需要 I2C 通信,采样率只有 860SPS,而且要额外占 PCB 面积和 BOM 成本。双路温度采集的刷新率要求本来就只有 1Hz 到 10Hz,12 位分辨率完全够用,没必要为 16 位去买单。更重要的是,当现场干扰大的时候,16 位 ADC 的低位数据基本都被噪声淹没,实际有效位数可能还不如 12 位 ADC 加合理的滤波和保护。

再说 DS18B20 这类 1-Wire 数字传感器。数字传输的抗干扰理论上更好,但实际部署有几个麻烦:1-Wire 总线上每个传感器都有唯一 ROM 码,多颗挂同一根总线时要处理寻址,协议时序对延时极其敏感,远程走线一旦线缆过长、寄生电容过大,时序就乱了。而且数字传感器出厂标定参数是固定的,后期想做现场二次标定反而麻烦。对于 HVAC 的远程测温点,屏蔽双绞线加模拟信号传输,配合主控端做滤波,是工程上被验证过无数次的稳妥做法。

3. 硬件电路与信号链路设计

3.1 本地测温点的直接采样电路

本地测温点离主控板近,电路可以做得很干净。PJ85718DM 模块输出的模拟电压直接经过一级 RC 低通滤波进入 ADC 引脚。

关键参数:参考电压用 2.048V,模块内部等效的 NTC 分压网络,在 25℃ 时输出大概 1.024V,0℃ 时升高到 1.5V 以上,50℃ 时回落到 0.55V 左右。整个动态范围都落在 2.048V 参考电压之内,不需要额外做电平搬移。

RC 滤波器的截止频率我建议压在 1kHz 左右,也就是串联 1kΩ 电阻、并联 100nF 电容。这样既能滤掉高频辐射干扰,又不影响温度的缓慢变化。注意必须使用 C0G/NP0 型电容,X5R/X7R 陶瓷电容在直流偏压下容值会下降,滤波效果会打折扣。

ADC 引脚前还要加一级输入保护:串联一个 330Ω 到 1kΩ 的电阻,并在 ADC 引脚对地放一个 1nF 电容,必要时加一小对肖特基二极管做钳位,防止传感器线缆意外碰到高压时打坏 MCU。

3.2 远程测温点的长线传输处理

远程测温就得上点手段了。几十米的线缆,主要问题有三个:线阻带来的分压误差、共模干扰、以及线缆电感在高频噪声下的拾取。

我的做法是给远端传感器单独准备一个恒流激励或者至少是低阻抗的驱动,让信号以更高的电平幅度往主控端传。如果 PJ85718DM 模块是纯电阻输出,建议在模块端就加一级电压跟随/缓冲,降低输出阻抗。如果模块不自带缓冲,那就改用三线制接法:两根线给传感器供电和采样,一根线单独用来反馈参考电位,然后在主控端用仪表放大器做差分采样,这样可以抵消掉线上压降。

如果传输距离超过 50 米,最靠谱的方案是 4-20mA 电流环。把温度换算成电流,电缆电阻对电流信号几乎没有影响,而且抗干扰能力极强。PIC18F86J15 那边只需要用一只精密采样电阻把电流还原成电压再进 ADC。这个方案要额外加一颗变送器芯片,成本会高一些,但对工业 HVAC 项目来说,可靠性优先,这点成本花得值。

屏蔽双绞线的屏蔽层必须单端接地,而且只在主控端接地。如果两端都接地,屏蔽层就会变成地环路的一部分,反而把干扰送进来。

3.3 参考电压、供电与 PCB 布局细节

PIC18F86J15 的 ADC 参考电压可以直接用芯片内部的固定电压参考(FVR)模块输出 2.048V。内部参考的好处是稳定、不占引脚,坏处是驱动能力有限,只能给 ADC 和分压网络提供参考,不能同时给外部负载供电。

供电上,模拟地和数字地要分开,最后在芯片下方的焊盘处单点汇合。ADC 的 AVdd 引脚必须单独加 LC 滤波,用一个 10µH 电感和 1µF 电容组成一小段干净的模拟电源岛。我实测过,不做这个滤波的话,板上 DC-DC 的开关噪声会直接耦合进 ADC 读数,表现为十几到几十个 LSB 的随机跳动。

PCB 布局还有一个小细节:两条传感器信号线尽量平行走,中间用地线隔离,不要让它们和继电器驱动线、通信线并行走很长距离。如果实在避不开,就要在信号层下面挖出完整的参考地平面,靠地平面来屏蔽。

4. 固件实现与温度换算

4.1 12 位 ADC 的通道管理与采样策略

ADC 驱动我用的是顺序轮询加自动转换的模式,代码结构比较清晰。以下代码基于 XC8 编译器,寄存器名以 PIC18F86J15 数据手册为准。

// 内部固定电压参考:输出 2.048V FVRCON = 0x81; // FVREN=1, FVRS[1:0]=01 // 使能 AN0、AN1 为模拟输入 ANCON0 = 0x03; // ADC 配置:12 位分辨率,时钟 = FOSC/32 ADCON1 = 0x40; ADCON2 = 0x00; ADCON0 = 0x01; // 开启 ADC 模块

ADC 采样要注意一个关键点:每次切换通道之后,必须给采样电容足够的时间充电。12 位 ADC 的采样时间如果太短,高档位的阻性源会影响测量精度。我一般手动设置采样时间和转换时钟,不依赖默认值。

4.2 从电压到温度:NTC 线性化与查表插值

ADC 拿到的是 12 位数字量,要变成温度,中间有两步换算。

第一步,把数字量还原成电压。12 位分辨率下,2.048V 参考电压的 1 LSB 正好是 0.5mV,这个整数的换算关系特别舒服:

float voltage = (float)adc_raw * 2.048f / 4096.0f;

第二步,把电压还原成 NTC 阻值,再用温度-阻值关系算温度。分压网络的关系是 Vout = Vref * Rntc / (Rseries + Rntc),反解出 Rntc:

float NTC_Resistance(float vref, float series_r, float vout) { if (vout >= vref) return 0.0f; // 防除零 return series_r * vout / (vref - vout); }

第三步,阻值换算温度。推荐用 B 值方程,工程上足够准确:

float NTC_ToCelsius(float resistance) { const float T0_K = 298.15f; // 25℃ const float R0 = 10000.0f; // 25℃ 标称阻值 const float B = 3950.0f; // 传感器 B 值 float t_inv = 1.0f / T0_K + logf(resistance / R0) / B; return (1.0f / t_inv) - 273.15f; }

如果对精度要求更高,可以用 Steinhart-Hart 方程,B 值方程在宽量程下的拟合误差会被放大,而 S-H 方程用三个系数拟合,在 -20℃ 到 +85℃ 全程都能控制在 0.1℃ 以内:

#define A_COEF 1.1293e-3f #define B_COEF 2.3410e-4f #define C_COEF 8.7674e-8f float NTC_ToCelsius_SH(float resistance) { float lnr = logf(resistance); float inv = A_COEF + B_COEF * lnr + C_COEF * lnr * lnr * lnr; return (1.0f / inv) - 273.15f; }

B 值方程适合开发阶段快速验证,量产固件里我建议直接把 S-H 系数做进查表逻辑,再把整条"阻值-温度"曲线固化成 256 项查表加线性插值,这样 MCU 上可以不用浮点库跑对数运算,速度也快得多。

4.3 抗干扰滤波与通信上报

固件层面不做事后滤波的话,前面硬件做的防护就白费了。我的滤波策略是"中值滤波 + 滑动平均"两层组合。每次采集 16 个样本,去掉最大值和最小值,剩下的取平均。这样既能干掉脉冲性干扰,又能平滑掉传感器自身的热噪声。

#define SAMPLE_COUNT 16 uint16_t filtered_sample(void) { uint16_t buf[SAMPLE_COUNT]; uint8_t i, min_i = 0, max_i = 0; for (i = 0; i < SAMPLE_COUNT; i++) { buf[i] = read_adc(); __delay_us(200); } for (i = 1; i < SAMPLE_COUNT; i++) { if (buf[i] < buf[min_i]) min_i = i; if (buf[i] > buf[max_i]) max_i = i; } uint32_t sum = 0; for (i = 0; i < SAMPLE_COUNT; i++) { if (i == min_i || i == max_i) continue; sum += buf[i]; } return (uint16_t)(sum / (SAMPLE_COUNT - 2)); }

通信方面用 Modbus RTU 比较省心,寄存器表定义如下:

寄存器地址内容数据类型说明
40001本地温度int16温度×100,2350 表示 23.50℃
40002远端温度int16温度×100
40003状态字uint16bit0=传感器断线,bit1=传感器短路
40004固件版本uint16低字节为主版本,高字节为次版本

刷新周期我设成 500ms 一次,Modbus 响应超时 200ms。不要设太快,否则上位机的轮询和现场总线的实时性都会有问题。

5. 标定流程与实测验证

5.1 两点标定法及系数存储

NTC 的一致性偏差决定了成品必须标定。工程上最实用的是两点标定:在 0℃ 和 50℃ 两个标准温度点分别记录 ADC 原始值,计算出增益修正系数和偏移修正系数,存进 EEPROM。

0℃ 可以用冰水混合物实现,标准大气压下稳定在 0.0℃;50℃ 用恒温水浴或者高精度的干体炉。标定时先让传感器浸入标准温度,等待读数稳定(至少 5 分钟),记录原始计算温度 t1 和 t2,然后计算:

k = (50.0 - 0.0) / (t2 - t1) b = 0.0 - k * t1 最终温度 = k * 原始温度 + b

标定系数用浮点存进 EEPROM 后,固件每次上电读取,加载到换算链路尾部。

5.2 实测数据比对

标定完成后的实测数据,拿标准的铂电阻温度计做参照,结果如下:

铂电阻参考值标定前读数标定后读数标定后误差
0.00℃0.83℃0.05℃+0.05℃
15.00℃15.70℃14.97℃-0.03℃
25.00℃25.58℃24.98℃-0.02℃
35.00℃35.49℃35.03℃+0.03℃
50.00℃51.10℃49.96℃-0.04℃

整个 0℃ 到 50℃ 区间内,标定后的最大偏差在 ±0.05℃ 以内,这个结果对于 HVAC 应用来说已经相当优秀了。注意这个结果是在实验室条件下得到的,现场环境还有干扰和温漂,实际整机精度能做到 ±0.3℃ 就已经非常够用。

5.3 长期稳定性观察

连续跑了 72 小时,两路温度读数都很稳定,没有出现漂移超过 0.1℃ 的情况。其中有一个值得记录的现象:远程测温点在压缩机启停的瞬间,读数偶尔会有 0.2℃ 左右的波动,但滤波后很快恢复,不影响控制逻辑。

标定系数在 EEPROM 里保存得很稳,断电重启后读数恢复一致,没有出现参数丢失的问题。

6. 现场问题排查与避坑实录

6.1 读数跳变与共地噪声

现场遇到最多的现象是温度值无规律跳变,尤其柜内有变频器或继电器动作时。排查顺序:先用示波器看 ADC 引脚波形,再用万用表确认电源纹波,最后检查地线。

多数情况下都是共地不良导致的。解决办法是把传感器信号线的屏蔽层只接主控地,把模拟地和数字地在 ADC 附近单点汇合,再检查所有接插件的接地端子是否牢固。还有一个容易被忽略的坑:传感器线缆和动力线走同一个线槽,一旦长期摩擦磨损,绝缘破损后就会出现间歇性短路,读数直接掉到满量程。现场布线时物理隔离千万不能省。

6.2 远程线缆压降和干扰

一开始远程测温直接用两线制分压,结果 30 米线缆带来了差不多 0.8℃ 的误差——线阻参与了分压。把 PJ85718DM 模块改成三线制接法、差分采样之后,这个误差降到了 0.05℃ 以下。

判断是不是线阻问题有个土办法:在传感器端接一只精密电阻代替传感器,如果主控端读数与理论计算值不一致,偏差部分就是线阻造成的。算出等效线阻后,可以在固件里做补偿,但最根本的解法还是三线制或 4-20mA 电流环。

6.3 传感器自热误差

NTC 是靠自身流过电流来测量的,电流会在传感器上产生焦耳热,导致读数偏高。对于 10kΩ NTC,持续 1mA 激励电流时自热可能造成 0.1℃ 到 0.5℃ 的误差,具体取决于传感器的封装和散热条件。

降低自热最有效的方法是降低激励电流和功耗,或者用间歇采样:只在采样的几十毫秒内给传感器供电,其余时间断开,这样平均功耗大幅下降。我实测把激励电流从 1mA 降到 0.2mA 后,静止空气中的自热误差从 0.4℃ 降到了 0.1℃ 以内。

6.4 标定漂移与老化处理

NTC 在长期高温高湿环境下会缓慢老化,阻值可能漂移。所以批量产品建议在出厂前做一次高温老化筛选(比如 85℃ 保持 48 小时),然后重新标定。现场使用一两年后,如果发现两个测温点在相同环境下的读数差逐渐拉大,多半是某一颗 NTC 老化了,这时候重新做一次两点标定,或者直接换传感器模块,成本都不高。

量产时还要注意传感器模块的批次一致性。不同批次采购的 PJ85718DM,B 值和标称阻值可能略有差异,固件里预留的标定系数结构最好支持一字节的"批次号"字段,这样现场维护时能快速判断两台设备的标定参数是否来自同一批次。

最后补充一点个人体会

这套方案做完之后给我的最大感触是:温度采集这种看起来基础到不行的功能,真正想在 HVAC 现场环境里做稳,比想象中要费心思得多。选型时多看一眼 ADC 的位数和参考电压,画板时多花十分钟处理模拟地的走线,固件里多写二十行滤波逻辑,现场就能少跑好几趟。

后续如果要扩展,可以在这套架构上直接加无线模块,把两路温度数据通过低功耗蓝牙或者 Sub-1G 上传到云平台,实现远程监控和预警。再进一步,可以引入多点测温,用同样一颗 PIC18F86J15 把 8 路甚至更多路的 NTC 接进来,固件里的通道管理改成自动扫描模式就行。这个方向留给下一个项目继续折腾了。

返回列表