去年做一套HVAC控制器的时候我遇到一个很典型的需求机柜里要测板卡自身温度现场还要测风管、冷水管这些远端位置的温度。板卡的温度直接关系到主控芯片的稳定性和散热风扇策略远端温度则决定了压缩机、水阀怎么动作。一开始我想偷懒用两个NTC加ADC去读后来发现线一拉长误差和标定问题全来了。最终换成了PIC18F67K40做主控搭配PJ85718DM数字温度传感器把“本地温度”和“远程温度”两路一起解决了。这篇文章就把这套方案从选型、硬件、固件到现场调试的经验整理出来给同样在做嵌入式热管理、HVAC控制器的朋友一个参考。1. 方案选型这一对组合到底解决了什么1.1 需求拆解为什么HVAC控制里要同时盯住本地和远程两路温度做暖通控制的同行都有体会温度从来不是“一个点”的事。控制器装在电柜里板子上的器件温度会随着负载、阳光照射、通风条件变化如果板温过高对外通信和模拟采样都会不稳定。另一边被控对象——比如风管、冷冻水管、盘管进出口——的温度才是逻辑判断的依据。这两路温度如果只取一路要么保护失效要么控制滞后。“本地远程”在实际项目里对应两个问题本地温度用来做控制器自身的过热保护、风扇调速、采样补偿。远程温度用来参与PID调节、露点判断、防冻保护和设备联锁。这两路温度往往不在同一个物理位置但都需要交给同一个MCU做逻辑处理。PIC18F67K40在这个位置上是比较稳妥的中间层它本身有足够的外设资源既能跑I2C总线跟传感器通信又能同时处理阀门、风机、继电器这些控制输出不必要再额外挂一片MCU。1.2 PJ85718DM与PIC18F67K40的分工PJ85718DM是一颗数字温度测量芯片I2C接口能直接读回本地节点温度也支持通过外部二极管或者三极管测量远端温度。这个特性很关键等于用一颗芯片同时覆盖了两路测温点省掉了第二颗传感器和一路I2C地址。PIC18F67K40在系统里的角色是“主脑”它通过I2C周期性读取PJ85718DM的本地温度寄存器和远程温度寄存器把原始值换算成实际温度再做滤波、超限判断输出给继电器控制逻辑或者上位机通信。我选用PIC18F67K40还看重一点它的外设引脚可以选择映射PPSI2C引脚不一定锁死在默认位置。这样在PCB布局时可以把I2C信号挪到远离强电干扰的引脚上对于HVAC这种强弱电混在一起的板子来说布线能轻松不少。1.3 为什么不用传统的NTC加ADC方案曾经有一版设计用的是MCU内置ADC加两个NTC热敏电阻。原理上没毛病但实际制造和现场维护时吃了不少亏。对比项NTC ADC方案PJ85718DM数字方案精度一致性依赖1%电阻分压和查表标定传感器自带校准读回即温度长线传输NTC引线电阻会引入偏差需要三线/四线补偿数字信号通过I2C传输抗干扰能力明显更好本地与远程需要两路ADC通道、两组分压电阻一颗芯片原生支持本地和远程故障识别开路/短路表现为满量程判断不太精确状态位和超范围值可以做掉线识别软件开销要查表和做线性校正右移加乘法开销小当然NTC也不是不能做特别是成本敏感的高温场景。但HVAC控制器通常要求长期稳定和现场可维护性数字传感器把大量“标定”工作放到出厂前做掉了给我们省了非常多生产校准时间。2. 硬件接线PJ85718DM与PIC18F67K40的电路设计2.1 PJ85718DM的供电与地址配置PJ85718DM大部分应用场景供电电压在3.3V刚好和PIC18F67K40主供电统一。我们板子上没有额外为传感器升压直接用3.3V平面供给这样I2C电平也省去了转换芯片。地址设置在硬件上很关键。PJ85718DM一般会有地址选择引脚比如A0、A1通过上拉或下拉接地来设定7位I2C地址。一个I2C总线上可以挂多颗PJ85718DM但在我们这个方案里一颗芯片就同时包含本地和远程所以总线上只需要一颗地址设成默认即可。注意如果板上还有别的I2C器件比如EEPROM、RTC先把它们的地址列出来避免和传感器冲突。我习惯画一个地址分配表让硬件和固件都照着这张表做省得后面调试时对着示波器猜地址。2.2 远程温度测量点的接法远程测量不是直接接热电偶或者NTC而是接一个外部二极管或者把三极管的基极和集电极短接后当成二极管使用。我这边用的是小信号三极管比如常见型号的2N3904或者2N3906基极和集电极短接发射极和基极作为两线输出。实际接线时需要注意远程测温的两根线必须区分正负方向接反了读出来的温度完全不对两根线尽量双绞减少磁场耦合如果现场是电柜到风管这么长的距离走线要避开变频器输出电缆这类强干扰源。PJ85718DM内部会给远程传感器提供恒定偏置电流通过测量二极管压降来推算温度。这个特性意味着引线电阻会被一定程度上消除但引线之间的电容和漏电流仍然会影响稳定时间。为了现场方便我把远程传感器接口做成一个两针端子线标用“D/D-”接线上看不出方向的人就少了。PCB丝印上直接标注“接三极管传感器长引脚为正”这样生产装配的人不用对着原理图猜。2.3 PIC18F67K40的I2C引脚分配与PPS重映射PIC18F67K40有多个可复用引脚。IO配置上我把I2C的SDA和SCL通过PPS设置到两个带输入施密特触发的引脚上并且在引脚附近预留串联电阻的位置。I2C在正常通信时靠上拉电阻把线路拉到高电平。上拉电阻取值与总线电容有关我这边SDA、SCL各用一颗4.7kΩ的上拉到3.3V总线速率跑100kHz。如果项目要提速到400kHz电阻可以降到2.2kΩ但前提是总线总电容小走线短。这里有一个实际操作经验不要只依赖MCU内部上拉。PIC18F67K40内部上拉对I2C来说通常太弱尤其在远程传感器线很长的时候上升沿会变得很慢导致通信误码。外部上拉电阻几乎是必须的。2.4 供电去耦和强电干扰处理HVAC板子上经常有继电器、接触器动作瞬间电流很大电源轨上很容易出现毛刺。PJ85718DM电源引脚我放了0.1μF和10μF两级电容并且在传感器电源入口串了磁珠。这样继电器打火时传感器不会复位温度数据不会出现瞬时跳变。MCU的电源同样要做处理特别是ADC如果还要顺带检测NTC或者其他模拟量的话VDD上的纹波会直接反映到采样结果里。我的习惯是数字部分和功率驱动部分分开走线单点接地I2C信号线尽量远离继电器驱动线和220V强电走线。如果现场电磁环境比较恶劣可以在I2C两根线上各加一小颗串联电阻比如100Ω再在传感器端加TVS管。这个组合能扛不少浪涌代价是信号沿稍微变缓通信速率不能太高。3. 固件实现I2C轮询与温度换算3.1 先定通信速率100kHz还是400kHzPJ85718DM支持标准I2C和快速模式本地距离短时跑400kHz没问题。但如果远程传感器走线超过一定长度比如现场布置了1米以上的双绞线我建议把I2C速率降到100kHz。实际上远程测温的转换过程是有时间常数的读频率不需要特别高。我们控制器的轮询周期是500ms完全够HVAC系统的响应要求。I2C速率低一点总线上反射和振铃的影响也会小很多系统更稳定。用PIC18F67K40的MSSP外设做主模式我一般先配置主时钟分频再设置引脚重映射最后开启中断。下面是裁剪后的初始化片段// 假设系统时钟为64MHz目标I2C为100kHz void i2c_init(void) { // 引脚重映射到指定IO PPSLOCKED 0; // 将SCL、SDA对应的PPS寄存器配置为MSSP模块功能 // 具体寄存器名以芯片头文件为准 PPSLOCKED 1; SSP1CON1 0x08; // I2C主机模式 SSP1CON2 0x00; SSP1ADD 159; // 分频值得到约100kHz SSP1STAT 0x80; // 使能SMBus信号规范 }不同编译环境、不同时钟频率下分频值要重新算。公式大概是主时钟除以4倍目标频率后再减1比如64MHz跑100kHz计算出来就是159附近。实际用示波器量一下SCL频率最靠谱。3.2 读取本地温度和远程温度寄存器PJ85718DM的温度寄存器一般会返回两个字节。读完之后需要把原始数据转换成带符号的实际温度。我这里读回的是16位原始值取高字节和低字节组成一个int16_t然后右移4位乘以0.0625。下面是读取远程温度的基本流程本地温度只是寄存器地址不同函数逻辑完全一样int16_t read_temperature(uint8_t reg_addr) { int16_t raw 0; uint8_t high, low; i2c_start(); i2c_write(PJ85718DM_ADDR 1); // 写地址 i2c_write(reg_addr); // 指向目标寄存器 i2c_stop(); i2c_start(); i2c_write((PJ85718DM_ADDR 1) | 1); // 读地址 high i2c_read_ack(); low i2c_read_nack(); i2c_stop(); raw (int16_t)((high 8) | low); // 根据数据手册右移4位后乘以最低位权重0.0625 return (raw 4) * 625 / 10000; }返回值的单位是摄氏度。这样处理之后-55.0和125.0这类温度范围都能正常表达不用额外判断符号位。注意右移针对的是带符号数C语言里int16_t右移是算术右移负数最高位补1正好能正确处理负温度。3.3 轮询、滤波与缓存设计传感器本身会有一定测量噪声尤其是远程通道现场干扰大时读数偶尔会跳。我的做法不是在应用层简单取一次值而是维护两个环形缓冲区本地温度缓存长度8远程温度缓存长度8。每次读回数据后存到环形缓冲然后计算平均值。这相当于一个简单的FIR低通滤波代码量小、实时性也能保证。HVAC系统的热惯性很大温度不会在几十毫秒内突变8次平均带来的延迟完全可接受。轮询状态机我建议放在定时器中断里比如每500ms触发一次读任务。不要在main函数的while循环里用delay等I2C操作否则温度读取会阻塞控制逻辑PIC18F67K40的效率也发挥不出来。void timer_task(void) { static int flag 0; flag !flag; if (flag) { loc_temp read_temperature(REG_LOCAL_TEMP); push_to_buffer(loc_buf, loc_temp); } else { rem_temp read_temperature(REG_REMOTE_TEMP); push_to_buffer(rem_buf, rem_temp); } }这样交替读取两个通道都维持在稳定刷新率上。过滤后的值再参与上层逻辑判断比如风扇档位、防冻报警等。4. HVAC工况下的本地与远程温度调试4.1 远程传感器走线对测量结果的影响远程测温通道有过不少调试翻车现场。最常见的问题是“温度读数比实际高好几度”。第一次遇到时我以为芯片坏了后来排查发现是远程传感器线束太长平行走线引入了共模噪声再加上电机启停瞬间的干扰被传感器偏置源捕获导致二极管压降异常。处理办法分几步将两根远程测温线换成双绞线双绞能抵消大部分磁耦合在传感器端并联一小颗电容这个电容不能太大否则稳定时间变长让线缆远离变频器输出端子和强电继电器线束提高I2C读取的稳定时间比如寄存器配置里增加滤波选项或者降低转换速率。如果用示波器观察远程通道的数字输出你会发现读数往往不是线性漂移而是等间隔的抖动。这种抖动多半来自外部干扰。排除干扰后读数会稳定下来。4.2 负温度处理和零点偏移HVAC里冷冻水管道、冬季新风温度都可能低于0°C。这时传感器的负温度换算很容易出错。我的经验是统一用int16_t而不是uint16_t去读原始值右移和乘法都在有符号整数域内完成显示层不要立即转成无符号整数否则负数会变成65535之类的大数。除了负温度现场校准也很重要。PJ85718DM出厂已经校准过但远程二极管本身可能有离散性所以批量生产时最好在“0°C冰水浴”和“55°C恒温箱”各测一个点把修正偏移量写到PIC的Flash配置区。比如远程通道在0°C时读到0.4°C偏移就是0.4°C在55°C时读到55.3°C增益误差也不大。因为HVAC控制逻辑很多是看阈值和温差偏移1°C可能会让防冻保护提前或者延后这个校准的功夫不能省。4.3 掉线、短路等异常识别传感器和远程探头的连接是现场最容易损坏的部分。线头松了、端子进水、线缆被老鼠咬断都会导致远程温度变成离谱的数值。我在固件里做了这样一套判断逻辑读回的温度如果高于150°C或者低于-60°C视为无效连续3次无效就上报远程传感器故障故障期间用最后一次有效值做控制避免控制逻辑产生突变故障恢复后自动清除报警不需要人工复位。本地温度通道相对稳定但也要做类似保护。PIC18F67K40可以在检测到传感器故障后把风机强制切换到中速挡保证柜内至少有基础的散热能力。有人问过为什么不做成故障时直接把设备停机HVAC系统里有些设备不能轻易停比如制冷机组频繁启停反而更容易损耗。所以我的默认策略是“降级运行报警提示”只有温度超过第二层保护阈值时才停机。5. 常见故障排查与经验速查5.1 I2C总线发地址后无ACK这是最常见的通信故障。用示波器挂上SDA和SCL确认启动条件满足再确认地址字节是不是和硬件配置一致。我踩过的一个坑是引脚重映射只配了SDA没配SCL总线时钟一直拉低通信直接卡死。排查清单地址选择引脚是否悬空PJ85718DM地址配置有没有和代码一致上拉电阻是否焊上阻值是否过大传感器电源是否正常3.3V是否出现在VDD引脚SDA和SCL是否接反。5.2 远程温度读数反复横跳频繁跳变基本指向两个原因一是采样时间太短噪声还没稳定下来二是远程传感器引脚接触不良。我建议先用示波器看SDA线上的波形如果数据位边沿有过冲或者振铃就检查探头线是不是太长、有没有和动力线并行走线。如果波形正常但数据还是跳可以适当增加平均次数。把环形缓冲区从8次改成16次抖动会明显变小。代价是响应变慢但对HVAC控制来说根本不是问题。5.3 I2C总线被拉死总线卡死多半是某个从设备异常拉低SDA。PIC18F67K40的MSSP模块有总线超时检测机制但默认不一定打开。我在固件里加了一个软件看门狗每次I2C操作如果超过一定时间没有收到ACK就主动发送停止条件然后重新初始化MSSP。实际测试下来这个“软复位I2C”的效果立竿见影。尤其是传感器在强电浪涌下偶然进入异常状态时让它重新上电或重新初始化远比直接改代码有效。5.4 功耗和待机工作状态如果控制器需要满足低功耗待机PJ85718DM也有待机模式。我在待机前先把传感器配置寄存器设为待机PIC18F67K40进入休眠前把I2C外设关闭并把SDA、SCL引脚设置为普通输入。唤醒后重新初始化I2C和传感器然后再读温度。这里有一个非常容易忽略的细节I2C上拉电阻在待机时会形成一个从VDD到GND的直流通路虽然电流很小但在电池供电设备上积少成多。可以考虑用一个MOS管在待机时断开传感器和上拉电阻的电源彻底阻断漏电流。下面是一个经验速查表基本覆盖我调试过程中遇到的主要问题现象可能原因检查方向通信完全无响应地址不对、电源没上、SCL/SDA接反示波器看启动条件万用表量VDD本地温度正常远程异常远程探头接线反了、线缆干扰检查D/D-方向换双绞线远程温度偏高且抖动长线共模干扰、偏置电流不稳加滤波电容降低I2C速率温度读数固定为某个大值传感器寄存器读错、总线位干扰抓波形确认读地址和寄存器地址待机后唤醒温度不准上电稳定时间不足唤醒后延时10ms再初始化I2C偶尔卡死强电浪涌导致从设备异常开启总线超时复位增加TVS写在最后的实战体会这套PJ85718DM加PIC18F67K40的组合我在高速风机控制板和冷水机组控制器上都用过。真正让我觉得“选对了”的点不是省了一颗芯片而是把“本地保护”和“远程控制”这两个温度域理清楚了。远程探头放风管里本地传感器盯板温两路数据在同一套代码逻辑里处理调试时不用对着两套不同协议反复切换。最后分享一个小技巧批量生产时我会在出厂测试里强制把远程探头放到0°C冰水混合液里读取一次原始值再把探头放到50°C恒温箱里读取一次原始值。这两组数据不仅能校准传感器还能顺便检验远程线缆焊接质量——如果连线虚焊或者线序错了温度值一定会对不上。这个测试成本很低但能在现场真正省下大量售后时间。
阅读完成 · 觉得有帮助?