1. 从一个温度采集需求说起为什么选这对组合嵌入式温度监测这件事看起来简单做起来坑不少。尤其是当你要同时盯着本地机箱内的温度和几十米外某个管道节点的温度时选型就变成了一道综合题本地测温要准、要稳远程测温要能拉远、要抗干扰主控还得有足够的算力和外设来同时处理两路数据、做逻辑判断、再通过某种方式把数据送出去。我最近在做一个 HVAC 相关的温控节点需求很明确板载一颗温度传感器监测设备自身工作环境同时通过远距离总线挂一颗远程温度传感器监测风道或水管的温度主控负责轮询两路数据、做阈值判断、驱动继电器并把数据汇总上报。选来选去最后落在PJ85718DM这颗温度传感器加PIC18LF47K40这颗低功耗 8 位 MCU 的组合上。为什么是这两颗先说 PJ85718DM。它是一颗本地加远程双通道的温度监测芯片本地通道用片上二极管或者内置传感结构测自身附近温度远程通道则支持外接晶体管通常是低成本的三极管接成二极管形式来测远端温度。这种一颗芯片管两路的设计直接省掉了一颗额外的远程测温芯片PCB 面积和 BOM 成本都下来了。更关键的是远程通道走的是电流模式信号对走线电阻和噪声不敏感这是它能拉远的核心原因。再说 PIC18LF47K40。这是 Microchip PIC18 家族里比较新的一代带 K40 后缀的型号在存储、外设和低功耗上都做了升级。选它的理由有三条第一它支持 1.8V 到 5.5V 的宽压供电LF 版本尤其适合电池或者低压轨场景第二它片上集成了 I2C、SPI、UART、ADC、比较器、PWM 等一堆外设跟 PJ85718DM 对接只需要 I2C 两根线剩下的引脚还能干别的第三它的低功耗模式做得比较细idle、sleep、doze 几档可以按需切换对于 HVAC 这种常年通电但大部分时间没事干的设备来说省电就是省寿命。提示PJ85718DM 的远程通道需要外接一个传感三极管常见做法是用 2N3904 或 MMBT3904 把基极和集电极短接用发射结当测温二极管。这个三极管要尽量靠近被测点引线越短越好。这套组合的定位很清楚中低复杂度、成本敏感、需要本地加远程双点测温、主控还要兼顾其他控制逻辑的嵌入式场景。HVAC 里的风机盘管控制器、地暖分集水器温控、机房环境监控节点都属于这个范畴。下面我把整个链路从硬件到固件拆开讲包括选型逻辑、寄存器配置、通信协议、校准方法和实际调试中踩过的坑。2. PJ85718DM 的双通道测温机制拆解2.1 本地通道与远程通道的本质差异很多人第一次用这类双通道温度芯片会默认两个通道只是位置不同配置应该差不多。实际上本地通道和远程通道在物理原理上就是两回事配置逻辑也完全不同。本地通道测的是芯片自身 die 的温度。PJ85718DM 内部有一个经过校准的传感结构输出跟绝对温度成正比的电信号片内 ADC 把它量化成数字量。这个通道的好处是简单、免外部元件、上电即用缺点是它测的是芯片自己的温度如果芯片旁边有发热元件比如 LDO、MOSFET读数会被带偏。所以本地通道的布局要点是芯片尽量远离热源如果实在避不开就要在固件里做偏移补偿。远程通道测的是外接三极管的发射结温度。原理是利用三极管发射结正向压降的负温度系数——温度每升高 1℃Vbe 大约下降 2mV。但单点测 Vbe 没法直接算出绝对温度因为 Vbe 还跟具体器件的工艺参数有关。所以这类芯片普遍采用双电流法用两个不同大小的激励电流比如 10μA 和 100μA比例 1:10分别流过传感三极管测两次 Vbe取差值 ΔVbe。这个 ΔVbe 只跟电流比和绝对温度有关跟器件工艺参数无关公式是ΔVbe (kT/q) × ln(N)其中 k 是玻尔兹曼常数T 是绝对温度q 是电子电荷N 是电流比。反解出 T就得到了远程温度。这就是为什么远程通道能做得准、能互换不同三极管的原因——它把工艺偏差消掉了。注意远程通道对传感三极管的型号有要求必须用低噪声、发射结特性一致的小信号三极管。功率管或者达林顿管不能用因为它们的发射结面积和串联电阻特性不适合双电流法。2.2 寄存器映射与关键配置项PJ85718DM 通过 I2C 跟主控通信内部有一组寄存器。虽然具体寄存器地址要查数据手册但功能分类是固定的大致分这么几类寄存器类别作用配置要点配置寄存器设置转换速率、通道使能、滤波决定功耗和响应速度的平衡本地温度结果本地通道最新读数高字节整数、低字节小数远程温度结果远程通道最新读数同上注意符号位处理状态寄存器报警、开路、超温标志远程通道开路检测靠它阈值寄存器高低温报警门限可设本地和远程各自的门限迟滞寄存器报警恢复的迟滞量防止门限附近抖动配置寄存器里最需要动脑子的是转换速率。PJ85718DM 一般支持从每秒几次到每几秒一次的转换率选择。转换率越高功耗越大但响应越快。HVAC 场景里温度变化本来就慢风道温度从 20℃ 升到 40℃ 可能要几分钟所以完全没必要每秒转好几次。我通常设成 1 秒一次或者 2 秒一次既够用又省电。另一个关键是远程通道的串联电阻补偿。传感三极管到芯片之间的走线有电阻如果走线长这个电阻会在双电流法里引入误差。PJ85718DM 支持通过配置寄存器设置一个补偿值抵消掉一部分串联电阻影响。走线越长补偿值要越大。这个值不是拍脑袋定的后面校准章节会讲怎么测。2.3 远程通道的开路与短路检测远程测温最怕的不是测不准而是传感三极管掉了或者线断了芯片还在那儿报一个看似正常的温度。PJ85718DM 内置了开路检测如果远程通道的输入引脚检测不到正常的二极管结压降状态寄存器里的开路标志会置位。这个功能在 HVAC 里特别重要。想象一下风道温度传感器装在吊顶里线被老鼠咬断了如果固件不检查开路标志控制器会拿着一个错误的温度继续调节可能导致风机一直转或者一直不转。所以固件里必须做两件事一是每次读温度前先读状态寄存器二是开路标志置位时把远程温度标记为无效并触发一个故障上报。短路检测同理。如果传感三极管被击穿短路远程通道读数会跑到极端值状态寄存器也会有对应标志。固件里对远程温度做一个合理性范围检查比如 -40℃ 到 125℃ 之外就认为异常能兜住大部分硬件故障。3. PIC18LF47K40 侧的 I2C 主机实现与资源分配3.1 为什么用硬件 MSSP 而不是软件模拟 I2CPIC18LF47K40 片上有一个 MSSP 模块可以配置成 I2C 主机模式。有人图省事用普通 IO 模拟 I2C觉得灵活。但在跟 PJ85718DM 这种温度芯片配合时我强烈建议用硬件 MSSP。原因有三。第一硬件 I2C 的时序由外设自己保证不会因为中断打断而拉长时钟高电平导致通信失败。温度采集往往跟其他任务并行软件模拟很容易在关键时刻被中断搅乱。第二硬件 I2C 支持时钟拉伸处理PJ85718DM 在转换期间如果被访问可能会拉伸时钟硬件模块能自动等待软件模拟就得自己写等待逻辑。第三硬件 I2C 省 CPU配置好之后一次传输只需要写几个寄存器、等标志位CPU 可以去干别的。配置 MSSP 成 I2C 主机的步骤大致是设置 SSPCON1 的 SSPM 位选主机模式设置 SSPADD 计算波特率配置 SDA 和 SCL 引脚的方向和输入输出模式。波特率方面PJ85718DM 支持标准模式 100kHz 和快速模式 400kHz。我一般用 100kHz因为温度数据量小100kHz 足够而且抗干扰余量更大走线长一点也稳。3.2 引脚分配与外围资源规划PIC18LF47K40 引脚数根据封装不同有 40 脚、44 脚等版本。做 HVAC 控制器引脚规划要提前想清楚因为后面加功能很容易发现引脚不够。我的分配思路是这样的I2C 两根线SDA、SCL固定给温度芯片留一路 UART 做调试和对外通信留两路 ADC 输入接其他模拟量比如湿度或者压力留几个 IO 驱动继电器或者光耦再留一个引脚做状态指示灯。这样算下来40 脚封装基本够用但如果还要加 LCD 或者更多继电器就得考虑 44 脚或者外扩 IO。有个细节容易被忽略PIC18LF47K40 的 I2C 引脚是复用引脚配置成 I2C 功能后就不能再当普通 IO 用。所以在画原理图阶段就要把复用关系理清楚别等到 PCB 打样回来才发现某个功能引脚被 I2C 占了。提示I2C 总线上一定要加上拉电阻典型值 4.7kΩ。如果总线走线较长或者挂的设备多可以降到 2.2kΩ。上拉电阻接到跟 MCU 和传感器相同的逻辑电平轨上别接错。3.3 低功耗模式下的温度采集节奏HVAC 设备很多是常年通电的功耗直接关系到电费和器件寿命。PIC18LF47K40 的低功耗模式配合 PJ85718DM 的间歇转换可以做到平均电流很低。我的做法是让 PJ85718DM 以 1 秒一次的速率连续转换MCU 平时处于 sleep 模式靠定时器或者外部中断唤醒。唤醒后读一次温度做判断如果需要动作就驱动输出然后继续睡。这样 MCU 大部分时间在睡只有读数据那一小段时间在跑。这里有个坑PIC18LF47K40 从 sleep 唤醒后I2C 模块需要重新初始化吗实测下来如果 sleep 期间 I2C 引脚状态保持唤醒后 MSSP 寄存器内容不丢可以直接用。但如果 sleep 前把 I2C 模块关了省电唤醒后就得重新配置。我倾向于不关 I2C 模块因为它的静态功耗很小关了再开反而增加代码复杂度和唤醒延迟。另一个坑是 PJ85718DM 的转换速率和 MCU 唤醒周期的匹配。如果 MCU 每 5 秒唤醒一次而传感器每 1 秒转换一次那读到的永远是最新值没问题。但如果 MCU 唤醒周期比转换周期还短就会读到重复值浪费总线时间。所以两者节奏要配合好一般让传感器转换周期小于等于 MCU 唤醒周期。4. 从寄存器到摄氏度数据换算与校准实操4.1 原始数据的格式与符号处理PJ85718DM 的温度结果寄存器通常是 16 位高字节是整数部分低字节是小数部分。但这里有个容易翻车的地方负温度的表示。正温度好办高字节直接就是摄氏度整数低字节按位权算小数。比如高字节 0x1925低字节 0x80如果低字节最高位权是 0.5℃那就是 25.5℃。但负温度就不一样了很多这类芯片用的是补码或者带符号的定点格式。如果直接按无符号数读-5℃ 可能被读成 251℃ 这种离谱值。我的处理方式是先把 16 位原始值当成有符号定点数高字节做符号扩展然后整体除以 256 得到摄氏度浮点值假设低字节是 8 位小数。具体代码大概这样int16_t raw (int16_t)((high_byte 8) | low_byte); float temp_c raw / 256.0f;这样不管正负都能正确换算。但要注意不同厂家的格式可能不同有的低字节只有高 4 位有效有的用 0.0625℃ 分辨率。所以第一步一定是查数据手册确认格式别想当然。4.2 本地通道的偏移校准本地通道测的是芯片 die 温度而 die 温度通常比环境温度高一点因为芯片自己在耗电。这个自热误差在低功耗间歇工作模式下很小可能只有 0.1℃ 到 0.5℃但在连续转换模式下会明显一些。校准方法很简单把设备放在一个已知温度的恒温环境里比如用校准过的温度计确认环境是 25.0℃等热平衡后读本地通道值差值就是偏移量。把这个偏移量写进固件每次读数减去它。但要注意这个偏移量跟工作模式有关。连续转换和间歇转换的自热不一样所以校准要在实际工作模式下做。我一般会在固件里留一个偏移常量方便后期根据实测调整。4.3 远程通道的串联电阻补偿实测远程通道的串联电阻补偿是这套方案里最需要动手测的部分。理论上的补偿值是走线电阻加上三极管串联电阻但实际走线电阻不好精确计算所以得实测。我的实测方法是先用一根很短的线连接传感三极管读一个温度值作为基准。然后换上实际长度的线再读一次。如果读数偏高说明串联电阻导致激励电流实际变小ΔVbe 偏大算出的温度偏高需要增加补偿值。反复调整补偿寄存器直到长线读数和短线读数一致。这个过程听起来麻烦但做一次就行因为走线长度固定后补偿值就固定了。我一般会在 PCB 设计阶段就把传感三极管的走线长度定下来然后在样机上做一次校准把补偿值固化到固件里。注意串联电阻补偿只在双电流法下有效而且补偿范围有限。如果走线太长超出补偿范围就得考虑用屏蔽线或者换用其他远程测温方案。一般几十米以内问题不大。4.4 温度数据的滤波与上报策略原始温度数据总会有抖动尤其是远程通道走线长、噪声大读数可能上下跳 0.5℃ 甚至更多。直接拿原始值做控制判断会导致继电器频繁动作。我的做法是加一个滑动平均滤波。维护一个长度为 8 的环形缓冲区每次读到的温度存进去取平均值作为有效值。这样既能平滑抖动又不会引入太大延迟。8 个样本在 1 秒转换率下就是 8 秒延迟对 HVAC 来说完全可以接受。如果抖动特别大可以在滑动平均之前先做限幅滤波如果本次读数和上次有效值差超过 2℃就认为这次是异常值丢弃不用。这个限幅阈值要根据实际场景定太小会误杀真实快速变化太大又起不到滤波作用。上报策略上我一般只在温度变化超过 0.5℃ 或者状态标志变化时才主动上报平时就静默采集。这样能减少通信负担尤其是用无线或者总线上报的场景。5. 联调阶段踩过的坑与排查链路5.1 I2C 通信时好时坏上拉电阻与走线的锅样机刚做出来的时候I2C 通信十次里有两三次失败读回来的温度是 0 或者 0xFF。一开始怀疑是芯片配置问题查了半天寄存器没发现异常。后来用示波器抓 SDA 和 SCL 波形发现 SCL 上升沿很缓明显是上拉太弱。原来我按习惯用了 10kΩ 上拉但这条总线走线比较长加上探头和杂散电容10kΩ 拉不起来。换成 4.7kΩ 后上升沿明显变陡通信成功率上去了。后来为了保险又降到 2.2kΩ彻底稳定。这个坑的教训是I2C 上拉电阻不是随便选个常用值就行要结合总线电容算。总线电容越大上拉电阻要越小但太小又增加功耗。经验公式是上升时间约等于 0.8 倍 RC标准模式 100kHz 要求上升时间小于 1000ns据此反推 R 值。5.2 远程温度读数偏高十几度补偿值没设远程通道第一次读数比实际温度高了差不多 15℃。一开始以为是三极管接错了检查发现基极和集电极确实短接了没问题。又怀疑是电流比配置错了查寄存器发现默认就是 1:10也没错。后来想到串联电阻补偿查数据手册发现补偿寄存器默认是 0。我的传感三极管走线大概 30 厘米串联电阻不小。把补偿值从 0 逐步往上调每调一档读一次温度调到某个值的时候读数跟实际温度对上了。最后固化下来的补偿值对应的等效电阻大概几十欧姆跟 30 厘米走线的电阻量级吻合。这个坑说明远程通道不校准直接用误差可能大到没法接受。而且不同板子走线长度不同补偿值不能照抄必须每块板子或者每种走线长度单独校准。5.3 负温度下读数乱跳符号处理写错了冬天测试的时候把设备放到室外温度降到零下。结果远程温度读数在 -5℃ 和 251℃ 之间乱跳。一看就是符号处理出了问题。原来我读温度结果时先读高字节再读低字节拼成 16 位后直接当无符号数处理。正温度没问题负温度时高字节是 0xFF 之类的值当无符号数就是 255减去偏移后变成 251。改成有符号数处理后-5℃ 就正常显示了。这个坑的教训是温度数据一定要确认符号格式是补码还是偏移二进制是 8 位还是 16 位。不同芯片格式不同甚至同一芯片不同寄存器格式都可能不同。读数据手册时要把这一节看仔细。5.4 低功耗模式下唤醒后第一次读数异常在做低功耗测试时发现MCU 从 sleep 唤醒后第一次读温度值总是偏高或者偏低第二次读就正常了。一开始以为是传感器需要稳定时间后来查资料发现是 I2C 总线在 sleep 期间状态不确定唤醒后第一次传输可能不完整。解决办法是在唤醒后先做一次 dummy 读读一个无关寄存器把 I2C 状态机理顺然后再读温度。或者更稳妥的做法是唤醒后重新初始化 I2C 模块虽然多花点时间但保证状态干净。这个坑比较隐蔽因为正常运行时不会出现只有低功耗场景才暴露。做低功耗产品时唤醒后的外设状态恢复一定要专门测试。6. 这套方案还能怎么扩展6.1 多路远程测温的复用思路PJ85718DM 只有一路远程通道如果 HVAC 系统需要同时监测多个点位比如回风、送风、盘管三个温度一颗芯片就不够了。这时候有两个思路一是挂多颗 PJ85718DM用 I2C 地址区分二是换用多通道的远程测温芯片。挂多颗的话I2C 地址要规划好别冲突。PJ85718DM 一般有地址选择引脚可以配出几个不同地址。总线负载也要考虑挂太多设备电容会上去上拉电阻要相应调整。如果点位特别多我会考虑用模拟开关切换传感三极管只用一颗芯片的远程通道分时测量。这样成本最低但切换后需要等稳定时间响应会慢一些。对 HVAC 这种慢过程来说慢一点无所谓。6.2 把温度数据接入上层系统的几种方式温度采回来之后怎么送出去也是个设计点。PIC18LF47K40 有 UART、SPI、I2C 可以选。如果设备是独立控制器可能只需要本地显示和继电器输出那就不用通信。如果要接入楼宇自控系统常见的是 Modbus RTU over UART或者通过无线模块上报。我一般会留一路 UART 做调试口同时兼容 Modbus 从站协议。这样既能用串口助手看数据又能接入标准系统。协议实现上Modbus 的保持寄存器映射温度值整数部分和小数部分各占一个寄存器上位机读两个寄存器拼起来就行。6.3 固件升级与参数存储的考虑HVAC 设备装到现场后改参数或者升级固件是常有的事。PIC18LF47K40 的 Flash 支持自写可以做 bootloader 通过 UART 升级。参数比如温度门限、补偿值、校准偏移存在 EEPROM 或者 Flash 的保留区掉电不丢。这里有个经验参数存储要做校验和读出来先校验校验不过就用默认值。现场干扰大EEPROM 偶尔会翻位没有校验的话可能拿着一个错误参数运行后果比用默认值严重。6.4 电磁兼容性方面的实际处理HVAC 环境里继电器、风机、变频器一大堆电磁干扰不小。温度信号本身是低频慢信号抗干扰主要靠硬件。我的做法是传感三极管的走线尽量短用双绞线或者屏蔽线I2C 走线远离功率走线电源加去耦电容继电器线圈加续流二极管。软件上也能做一点事温度读数做合理性检查突变超过阈值就丢弃通信失败重试几次再报错关键参数写 EEPROM 时先擦后写再回读校验。这些措施加起来现场稳定性会好很多。我在实际项目里用这套 PJ85718DM 加 PIC18LF47K40 的组合做过几版温控节点从样机到小批量整体表现比较稳。最深的体会是远程测温的校准不能省串联电阻补偿和符号处理这两个点最容易翻车低功耗场景下唤醒后的外设状态恢复要专门测。把这几个地方盯住剩下的就是常规的嵌入式开发工作了。
阅读完成 · 觉得有帮助?