PIC18F87J11与PJ85718DM的嵌入式HVAC双点测温方案

发布时间:2026/10/22 6:37:23
PIC18F87J11与PJ85718DM的嵌入式HVAC双点测温方案
做嵌入式设备或者暖通系统最绕不开的一个需求就是测温。尤其是项目既要看设备本身跑没跑过温又要看远端风道、机柜进风口或者被控介质里的实际温度本地和远程两组数据放在一起才能判断问题到底出在哪。这个项目围绕 PIC18F87J11 这颗 8 位单片机配合 PJ85718DM 温度传感器做本地温度采样再外接远程探头搭起一套适合嵌入式和 HVAC 场景的温度监测方案。全文会把选型逻辑、硬件连接、软件换算、联调排错完整过一遍给正准备做温控器、机柜监控或者设备状态监测的朋友做个参考。1. 项目整体设计与选型逻辑1.1 为什么用 PIC18F87J11 而不是 32 位单片机温度监测这件事本质上就是“采样、换算、显示、上报”对算力的要求其实很低。选处理器的关键不是跑多快而是外设够不够用、性价比够不够高、项目后期好不好维护。PIC18F87J11 是一颗 80 引脚的 8 位单片机IO 数量充足内部带多路 12 位 ADC还集成了 I2C、SPI、多个 UART一颗芯片就能把本地传感器、远程 NTC、显示屏和串口上报全部接完。如果用 32 位单片机来做不是不行但有点杀鸡用牛刀。32 位平台要处理启动文件、时钟树、外设库版本、Flash 加密这些额外复杂度对温度采集这个体量的应用来说开发成本不成比例。尤其很多产线维护人员习惯了 8 位单片机的裸机逻辑出了问题能直接拿仿真器看寄存器PIC18F87J11 这种成熟 8 位平台反而是最省心的选择。它的 12 位 ADC 对 NTC 测温来讲分辨率也足够0 到 100°C 范围内做到 0.1°C 级别的显示分辨率没有压力。这颗单片机的外设还有一个很实用的特点多个串口和 I2C 可以同时工作。项目中本地传感器走 I2C远程 NTC 走 ADC对外上报走 UART 转 RS-485三种数据通道互不干扰。实际调试时我一般把 I2C 速率设在 400kNTC 的 ADC 采样时间用软件拉到几十微秒以上整个系统跑起来占 CPU 资源非常低主循环里还能留出大量余量做按键扫描、LED 显示和异常判断。1.2 PJ85718DM 在系统里的角色PJ85718DM 在这套系统里负责本地温度采集。它是一颗数字输出的温度传感芯片通过 I2C 接口把温度数据直接送给单片机不再需要放大器、比较器和查表换算。这类芯片内部本质上是一个带隙基准加一个高精度模数转换器出厂前做了校准读出来的数值就是真实温度开发者省去了大量标定工作。从使用角度看这颗芯片最吸引人的是温度分辨率可以做到 0.0625°C 左右最大误差在 ±0.5°C 以内对嵌入式设备温升监测和 HVAC 舒适度控制来说完全够用。我拿到样品后做的第一件事是拿水银温度计做对照测试在 25°C 恒温环境下反复读了 100 次数据PJ85718DM 读数的重复性非常稳定跳动范围基本不超过一个字这说明内部 ADC 的噪声抑制做得不错。本地温度为什么要用数字传感器而不是也用 NTC原因是本地传感器就在单片机附近PCB 上难免有电源、功率器件带来的干扰。数字传感器在出厂时已经做了线性校准数据通过 I2C 传输也不受线长和接触电阻影响可靠性比直接采样模拟电压高一个档次。另外数字传感器还能直接报告故障状态比如总线短路、芯片内部自检失败这些信息对产品的现场维护非常有用。1.3 本地与远程分开测温是刚需很多刚接触温控项目的人会问测一个温度不就够了吗为什么要搞本地和远程两路实际项目里这两个温度代表的是完全不同的物理意义。以嵌入式机柜为例本地温度反映的是控制板本身、功率器件、电源模块的发热状态远程温度反映的是机柜进风口或者机柜内部的整体环境。如果只有本地温度你无法判断是设备自己过载了还是机房空调坏了导致环境温度升高。两组数据一对比温差突然拉大问题定位就非常清楚。HVAC 场景更是离不开双点测温。温控器的本地感温探头检测室内环境温度用来维持用户的舒适度设定远程探头埋在回风管、盘管或者冷水管上用来感知系统侧的冷热负载变化。室内温度响应慢回风温度响应快分开采集才能实现防冻保护、除霜启动、风机联动这些策略。比如冬天远程盘管温度低于 5°C系统必须立刻关风机或者打开加热否则盘管有冻裂风险。失效模式也是分开监测的一个重要理由。本地传感器坏了系统马上可以报警停机不会把错误温度当成控制依据远程探头断线脱落系统能识别出“传感器不在线”这个独立故障状态进入保护模式而不是拿一个跳变的假值去控制继电器。这种冗余设计看起来简单实际在产品现场能省下大量售后排查成本。2. 硬件连接与电路设计要点2.1 本地传感器接线与 I2C 上拉PJ85718DM 的硬件接线并不复杂核心是电源、I2C 两条信号线、地址引脚。VDD 接 3.3V 或者 5V对地放一个 0.1uF 陶瓷电容靠近芯片引脚布置有条件的话在靠近电源入口再放一个 10uF 电解电容防止电源线上其他负载突变影响采样精度。SCL 和 SDA 都需要接上拉电阻到同一个电源域阻值常规选 4.7kΩ如果 I2C 总线速度比较高或者线上设备比较多可以改成 2.2kΩ。地址引脚需要特别留意。如果电路板上只有一个 PJ85718DM很多芯片允许把地址引脚直接接地或者悬空但不同批次芯片的默认地址可能不完全一样。我习惯在初始化代码里先读一次芯片的 ID 寄存器或者设备地址确认总线上能正确应答再做温度读取。这样做了之后产线上换物料批次也不需要改代码。PCB 布局上本地传感器不要放在功率器件正下方也不要紧贴电感、变压器这类强磁元件。温度芯片测量的是自身封装附近的温度如果旁边就是发热的大功率 MOS 管读到的数值会被热辐射污染反映不了控制板整体的真实热状态。我见过一个项目把传感器放在开关电源电感旁边结果实测温度比实际环境高了 8°C怎么软件校正都救不回来最后只能改板子位置。2.2 远程温度探头的两种接入方式远程温度要根据实际线缆长度、精度要求和成本来做方案没有统一答案。第一种方式是 NTC 热敏电阻电路结构是 Vref 经过一个精密电阻后连到 NTC两者中间抽头接单片机的 ADC 通道。NTC 成本低、响应快探头可以做得很小适合放在风道、水管、机柜角落这些空间受限的地方。缺点是每一个 NTC 都有离散性需要用 B 值公式或者查表换算而且引线电阻会带来误差。第二种方式是 1-Wire 接口的数字温度探头。这类探头内部自带 ADC 和唯一序列号一根数据线就能挂多个探头最远传输距离可以到几米甚至更长非常适合 HVAC 里“一个主控器拖多个房间温度传感器”的架构。我用下来觉得它的优点是精度稳定、免标定缺点是对时序要求严格软件上做抗干扰要花点心思而且总线上任何一个探头的短路都可能把整条总线拉死。下面这张表是我在实际选型时经常用的对比思路远程测温方案成本精度线长能力软件复杂度适用场景NTC 热敏电阻低中等依赖标定1m 内可靠低需查表/公式单点近距离探头1-Wire 数字探头中高出厂校准数米支持多点中时序处理多房间/多风道热电偶高高需冷端补偿很长高需放大电路高温工业场景这个项目里远程温度我先按 NTC 方案来做因为单片机的 12 位 ADC 可以直接使用不需要额外增加驱动电路后面如果需要升级成多点数字探头软件上预留一个接口层就行。2.3 电源、滤波与 PCB 布局注意事项整个系统对电源最敏感的部分不是单片机而是 ADC 的参考电压。PIC18F87J11 的 ADC 参考电压如果直接用 VDD那么 VDD 上的纹波会直接折算成温度误差。我建议把 VREF 引脚单独走一段线并在这段线上放一个 100nF 和一个 1uF 的电容两个电容尽量靠近单片机引脚。远程 NTC 的电源端最好也从这个滤波后的参考电压点取这样 ADC 采样的比例关系更一致。模拟地和数字地不要大面积直接相连。这个项目里我采用了单点连接的方式所有传感器的模拟地、ADC 的地汇总到一点再和数字地汇合。如果 PCB 是双面板尽量保证模拟信号走线在底层有一整块的参考地避免信号跨分割区域否则 NTC 采样值会在某一个固定值上抖动。远程探头走线超过一米时我强烈建议用双绞屏蔽线。屏蔽层只在主控板一侧接地千万不能两端都接否则会形成地环路反而把更多干扰引进来。NTC 探头如果是两根引线超过一米后引线电阻的影响就必须考虑常用做法是改用三线制或者四线制或者干脆把 NTC 换成本地采集单元后走数字信号。这个细节很多初学者容易忽略远程温度在调试台上很准一到现场就乱跳往往就是走线太长加上屏蔽没做好。3. 软件实现与数据处理逻辑3.1 初始化流程和主循环结构软件部分我习惯先搭一个干净的主循环框架再往里填功能。系统上电后首先要配置时钟和 IO然后初始化 I2C 为 400k 主模式初始化 ADC 的通道、采样时间和 12 位分辨率最后初始化 UART 作为调试和上报出口。顺序上要把传感器的延时启动考虑进去很多温度传感器上电后需要几十毫秒才准备好第一次转换如果上电立刻去读容易拿到一个错误数据。主循环的逻辑是“读本地温度 → 读远程温度 → 换算与滤波 → 刷新显示/上报 → 处理按键和报警”整个循环跑一遍也就几毫秒。温度变化本身是慢变量不需要太高的采样频率我一般控制每秒采集 2 到 5 次就足够了剩下的时间让单片机处理其他任务。void main(void) { sys_clk_init(); gpio_init(); i2c_init(400000); adc_init(ADC_CH_NTC, ADC_RES_12BIT); uart_init(9600); delay_ms(100); // 等待传感器稳定 read_sensor_error i2c_probe(PJ85718DM_ADDR); while (1) { local_temp read_local_temp(); remote_temp read_remote_ntc(); smooth_filter(); limit_check(); refresh_display(); report_uart(); wdt_kick(); } }3.2 读取本地温度并拼接成实际温度值PJ85718DM 的温度结果一般存在两个连续寄存器里高字节在前低字节在后。读取过程就是主机发送器件地址加寄存器地址然后发起重复起始位以读模式读回两个字节。读回来之后要把两个字节拼成一个 16 位整数再根据芯片手册里的分辨率系数转换成温度值。以 12 位模式为例如果原始值算出来是 0x1A8也就是十进制的 424除以 16.0 就得到 26.5°C。负温度的情况要处理符号位一般温度寄存器的数值用补码表示检测到最高位为 1 时要用整个 16 位值减去 65536再去做除法。这个细节看起来简单实际很多人第一次接负温度传感器时读到的不是 -10°C 而是 65526就是因为忘了处理符号扩展。int16_t raw (uint16_t)(reg_high 8) | reg_low; if (raw 0x8000) { raw - 0x10000; } float temp_c raw / 16.0f;每次读回来的值还要做一个合理性检查比如温度值在 -55°C 到 125°C 之外就直接判定为传感器异常丢弃本次数据并置一个错误标志位。这个判断能挡掉很大一部分总线干扰产生的毛刺数据比单纯做滤波更有效。3.3 远程温度换算NTC 分压公式与查表远程 NTC 的换算核心是从 ADC 原始值反推热敏电阻的阻值。分压电路里NTC 一端接 GND另一端通过精密电阻 Rref 接参考电压 Vref中间抽头接 ADC。采样电压 Vov 等于 Vref × (Rntc / (Rref Rntc))所以反推 Rntc Rref × Vov / (Vref - Vov)。这里的 Vov 要用 ADC 原始值按比例计算避免直接用实际电压值因为参考电压和 Vref 是同一个来源比例关系可以抵消电源误差。拿到 Rntc 之后最常见的换算是 B 值公式。先取 25°C 下的标称阻值 R0 和器件手册给出的 B 值然后代入公式 T 1 / (1/T0 ln(Rntc/R0)/B) - 273.15。这个公式在 -20°C 到 80°C 范围内精度还不错HVAC 场景足够用。要求更高的话可以用 Steinhart-Hart 公式需要三个系数做出来的曲线在全温区更平滑。float calc_ntc_temp(uint16_t adc_val, uint16_t adc_max, float vref, float r_ref, float r0_25, float b_val) { float ratio (float)adc_val / (float)adc_max; float vout ratio * vref; float rntc r_ref * vout / (vref - vout); float t0_k 25.0f 273.15f; float t_k 1.0f / (1.0f / t0_k (1.0f / b_val) * logf(rntc / r0_25)); return t_k - 273.15f; }代码里要注意分母 vref - vout 可能接近零的情况比如 NTC 短路到电源这时候 rntc 会算出异常大的值。换算函数里要做除零保护ADC 原始值接近满量程时直接返回一个“探头故障”的特殊值不要傻傻算出一个离谱温度去参与控制。3.4 滤波、限幅和超温保护策略温度数据直接拿来用显示上会看到最后一位一直跳控制上还可能让继电器频繁吸合。我常用的办法是滑动平均窗口取 4 到 8 次采样每次采样进来先移除最旧的数据再求平均值。这个滤波对高频噪声抑制效果明显而且延迟很小不会像低通滤波那样造成明显的滞后。除了滤波限幅逻辑也很有用。相邻两次采样温度差超过设定值比如 10°C就判定为异常跳变本次值作废用上一次的有效值替代。这个策略能防止雷电干扰、通信毛刺、ADC 偶发错误把温度瞬间拉高导致误报警。超温保护要加回差。如果设定 80°C 报警、75°C 恢复那么任何时刻温度到达 80°C 就触发报警降到 75°C 以下才清除报警位。这样处理之后温度在临界点附近波动时不会出现继电器或蜂鸣器一开一关的“叫唤”现象。回差的具体值要看控制对象HVAC 里一般给 0.5°C 到 2°C嵌入式设备保护里给 5°C 左右都合理。4. 应用场景落地与系统联调4.1 嵌入式机柜温升监测的现场实测在机柜温升项目里我把 PJ85718DM 放在了主控板的电源模块旁边远程 NTC 探头固定在机柜进风格栅附近。这样一组数据可以判断如果本地温度和远程温度同时升高说明机房环境温度变了如果本地温度升高但远程温度不动说明机柜内部散热出了问题可能是风扇堵转或者风道被异物堵住。实测过程中我记录了待机、满载、满载加高温环境三组状态数据规律非常清楚。待机时本地温度比远程温度高 3°C 左右满载时这个差值会拉到 15°C 以上。通过这个差值软件里可以做一个风扇分级策略温差低于 8°C 风扇低速高于 12°C 风扇全速。相比直接测绝对温度这个“温差控制”逻辑对季节变化不敏感夏天和冬天不需要反复调整阈值。联调阶段最容易忽略的是上电顺序。如果系统上电后先让功率模块工作再初始化温度传感器传感器第一次读到的可能是被热风吹过的偏高的温度让控制系统误以为温度已经很高。所以我建议整个系统上电后先完成传感器初始化、读取并确认数据有效再解锁功率输出。软件上用一个“传感器就绪”标志位标志位没有置位前控制输出一律保持安全状态。4.2 HVAC 温控器的双点控制策略HVAC 温控器场景里本地传感器装在控制面板内部贴近面板进风口测量的是用户所在空间的空气温度远程探头装在回风管或者盘管上感知的是系统侧的冷热负载。控制策略上本地温度负责舒适度调节决定压缩机或加热器的工作状态远程温度负责安全保护比如盘管温度过低时启动防冻模式远程温度过高时自动降低输出功率。实际调试中我发现回风温度和本地温度之间存在明显的时间差。回风温度变化快本地温度变化慢如果只用本地温度做 PID 控制系统很容易振荡。比较实用的办法是本地温度做主控回风温度做前馈补偿远程温度突变时提前调整输出而不是等室内温度偏离了才反应。这样既保证舒适度又避免压缩机频繁启停。冬季防冻保护也需要双点配合。控制系统只在测温间隔内巡检一旦判定回风温度低于 5°C不等待本地温度变化直接强制开启加热或关闭新风阀。这个逻辑必须是最高优先级不能因为本地温度还正常就忽略远程探头的低温报警否则一个寒夜下来盘管就可能冻裂这是真金白银的教训。4.3 数据上报和现场校准数据上报在工程现场非常重要。我一般用 UART 转 RS-485走 Modbus RTU 协议这样温度数据可以直接进组态屏、PLC 或者物联网网关。寄存器映射保持简单直观一个寄存器放温度乘 10 的整数值既可以保留 0.1°C 分辨率又避免浮点数在 Modbus 总线上的传输麻烦。寄存器地址内容单位读写属性0x0000本地温度0.1°C只读0x0001远程温度0.1°C只读0x0010高温报警阈值0.1°C读写0x0011报警回差0.1°C读写0x0020传感器状态字位标志只读产线校准时每个设备可以在 EEPROM 里保存一个温度偏移量和一组 ADC 修正系数。同型号的温度传感器虽然出厂有标定但安装位置、外壳结构带来的固定偏差各不相同。我在项目里做了一个校准模式长按按键进入校准用标准温度计做对照操作人员直接把当前偏差写入 EEPROM设备重启后自动加在测量值上。这个功能看着简单却让产线良率提升了一大截省去了逐台人工调电阻匹配的工序。5. 常见问题与排查技巧实录5.1 温度读数跳变、抖动排除了原理问题还是不稳这种问题十有八九出在采样伺候环节。NTC 的 ADC 采样时间太短时采样电容还没充满就触发转换读数会随机跳动。我遇到过一块板子ADC 采样时间寄存器被默认配置成最短档结果温度值每隔几秒就跳一下后来把采样时间调大到几十微秒问题马上消失。接触不良也容易被忽略。NTC 引脚采用杜邦线连接时氧化层会导致接触电阻漂移温度越高阻值变化越明显。排查手法很简单拿稳定的电阻箱替代 NTC如果读数完全稳定那就是探头和线的问题与软件无关。现场处理上我给端子压接处套了热缩管并加了防松卡扣之后返修率明显下降。如果你用的是 1-Wire 数字探头跳变还可能是总线时序被中断引起的。1-Wire 对时序要求很苛刻如果主循环里有串口中断或者定时器中断长时间霸占 CPU复位时序就会被拉长。我建议把 1-Wire 的读时序放进临界区短时间关中断操作读完之后立刻恢复并且单次总线上只挂少量探头减少总线负载。5.2 远程探头线拉长之后读数漂移远程探头走线从 0.5 米加长到 3 米NTC 的读数普遍会偏高这是引线电阻在分压电路里叠加的结果。两根引线电阻各 0.5Ω 的话总共多出 1Ω对 10kΩ 的 NTC 来说常温附近就会造成约 0.2°C 到 0.3°C 的偏差温度越低偏差越明显。解决方法是把 NTC 从两线制改成三线制一根线专供激励电流另一根线单独采样电压引线电阻的影响被几乎完全消除。线缆如果靠近变频器、继电器触点或者开关电源输出还会引入共模干扰。我在一个现场亲眼见过远程温度在压缩机启动瞬间跳了 15°C后来在 ADC 输入端并联了 0.1uF 电容并把双绞屏蔽层单端接地跳动幅度立刻降到了 0.2°C 以内。排查这类问题时示波器探头夹在 ADC 引脚上看毛刺是最直观有效的方法。如果现场环境确实恶劣直接换 1-Wire 数字探头反而更省心。数字信号对干扰的容忍度高两根线其中一个还是地施工也简单信号质量比模拟 NTC 稳定得多。代价是软件复杂度高一点但这个复杂度换来的是现场调试时间的大幅缩减长期看是划算的。5.3 I2C 总线无应答、被拉死PIC18F87J11 和 PJ85718DM 通过 I2C 通信时最常见的现象是总线上读不到设备的 ACK。先检查地址对不对再看 SCL 和 SDA 的上拉电阻是否焊好。上拉电阻缺失时 SDA 在空闲状态是低电平设备永远不会应答因为它在总线非空闲时不会理会起始信号。I2C 总线一旦被某个从机拉死主机会一直等待。代码里必须给所有 I2C 操作加上超时机制比如等待 ACK 超过 10ms 就主动发送 9 个时钟脉冲把总线时钟恢复出来然后再重新初始化。我见过很多裸机代码在 I2C 读数据时没有超时判断一旦传感器被静电打坏整个主程序就死循环连看门狗都救不回来。这是非常严重的隐患。另外一点是电平域匹配。PJ85718DM 工作电压如果是 3.3VPIC18F87J11 的 IO 口如果配置成开漏模式两个器件之间不需要电平转换但如果 5V 器件和 3.3V 器件混接I2C 上拉电阻放在哪一侧就非常关键。稳妥的办法是直接用 3.3V 系统避免电平差异带来的隐患。5.4 读数偏高偏低算法再改也没用温度读数出现系统性偏差时先别怀疑公式去检查传感器的物理安装环境。传感器贴在功率电阻旁边中间没有气隙读到的就是电阻壳温而不是空气温度这不算“测错”而是测量点选择错了。如果你要测的是设备内部空气温度传感器就必须架高让它不接触发热元件外壳再开一些通风孔。导热介质也影响结果。用导热硅脂把传感器和被测物体紧密贴合可以降低接触热阻测量更准确但硅脂涂太厚反而形成隔热层读数比实际温度低。我做对比测试时发现同一颗传感器贴着散热器薄涂硅脂和不涂硅脂温差能达到 3°C。所以要么不涂要么涂薄而均匀的一层千万不要随手挤一大坨。环境辐射也是隐藏因素。在阳光直射或者靠近热源的 HVAC 现场传感器如果没有遮阳措施测温结果明显偏高。远程探头放进风管时会做一个金属护套护套本身被周边热管辐射加热如果护套和探头之间有空气层读数就会偏高。正确做法是探头直接压在套管内壁套管外部做保温让探头感应的是风温而不是管壁温度。5.5 问题速查表现象可能原因处理办法本地温度读数跳变I2C 干扰、供电纹波、传感器靠近强磁场加大去耦电容调整传感器位置NTC 远程温度偏高引线电阻、热辐射、硅脂过厚三线制接线加遮光罩控制导热介质I2C 无 ACK地址错误、上拉缺失、总线被拉死读设备 ID检查上拉电阻加超时恢复上电显示 -55°C传感器未就绪、总线断路延时启动检查接线远程温度跳变剧烈干扰、采样时间过短加滤波电容延长 ADC 采样时间本地和远程同时升高环境温度变化检查机房空调或通风最后聊点实际体会温度监测项目做久了我最大的体会是算法和滤波都只是辅助传感器装在哪里、怎么装才是决定成败的关键。同一个传感器贴在功率电阻上和悬空装在机箱角落读到的数据能差十几度这不是芯片的问题是测量方案的问题。每次现场返修我第一件事都是问探头是怎么固定的而不是急着改代码。另外一个值得养成的习惯是给传感器留校准入口。采集板出厂前做一次标准温度源校准把偏差写进 EEPROM后面维护时不需要动硬件就能微调。温度传感器本身会漂移产品用一两年后重新校准一下能避免很多莫名其妙的“温控不准”投诉。这套方案后续扩展空间也很大。多路传感器你已经有了接下来可以把 NTC 换成 1-Wire 数字探头做多房间温控数据上报已经走了 RS-485再往上接一个无线透传模块就能变成远程测温节点如果配合 SD 卡存储还能做温变记录仪。基础框架搭好之后剩下的都是往上面挂新功能整个项目的可复用性非常高。