做嵌入式的朋友应该都有过这种体会:凡是跟 HVAC 沾边的项目,第一件事永远是摸清“温度”到底从哪儿来。控制器本体旁边要测回风温度或者机箱内环境温度,管道深处又要测送风温度,室外机或者远端还要挂一路远程探头。这套需求用两个词概括就是“本地+远程”。我最近完成的一个项目正好围绕这个核心展开,主控用的是 PIC18F46K40 这颗 8 位 MCU,测温前端则采用一块型号为 PJ85718DM 的温度监测模块,配合一路本地传感器与一路远程传感器,把嵌入式和 HVAC 场景中常见的多点温度监测问题完整地走了一遍。这篇文章就把整个设计思路、硬件接口、固件逻辑、调试标定以及现场经验原原本本整理出来,希望能给正在做类似温度采集方案的读者提供一条可复用的路径。
这个项目最大的价值在于:它不是简单地把温度传感器接到单片机的 ADC 上,而是把“传感器前端模块”和“主控运算”分离,变成一个可复用的温度监测子板。PJ85718DM 负责把模拟信号转换为数字量,并且对外提供成熟的通信接口,主控只负责读取、换算、逻辑判断和对外上报。这样做的直接好处是系统更整洁,产品在 HVCA 整机里也更容易做认证。接下来我会按设计思路、硬件电路、固件实现、调试方法、现场问题五个大块展开,全是实际操作记录,没有一句空话。
1. 项目整体设计与思路拆解
1.1 为什么拆成本地与远程两路测温
先看应用场景。嵌入式与 HVAC 设备里,温度从来不是一个单一变量。以一台常见的空气处理机组为例,控制器所在的控制箱内部温度可以看作“本地温度”,它决定了主控板自身的工作环境,也影响到器件寿命;机组送风管内的风温则是“远程温度”,它直接关系到空调效果和风机转速控制。更典型的情况还包括:回风温度、盘管进出口温度、室外补偿温度。传统做法是给每一路都配一个传感器并接到主控板上,但传感器一多,线路复杂,线缆压降、干扰、接线顺序都会成为问题。
所以这次设计我一开始就定下目标:主控上只保留两路物理温度输入。一路是本地温度,传感器直接做得小型化,贴近控制器安装;另一路是远程温度,通过屏蔽线或者两线制探头延伸到几十米外的管道或室外。目标场景覆盖 HVAC 的控制面板、风柜控制器、还有部分需要环境温度补偿的嵌入式设备。PIC18F46K40 负责采样、标定和决策,PJ85718DM 模块则把两路测温的模拟前端收拢在一起。
1.2 PJ85718DM 模块的定位与选型考量
PJ85718DM 不是一个传统意义上的单芯片温度传感器,它更像一个完成度很高的温度监测前端模块。在这套方案里,模块承担了几个关键功能:给本地和远程传感器提供稳定的激励与调理电路、完成模拟到数字的转换、输出隔离后的数字信号。对开发者来说,这就省去了自行设计恒流源、放大器和滤波电路的麻烦,也把复杂度最高的模拟部分提前固定下来,后面改板、升级固件都更容易。
选它还有一层考虑:模块的输出接口兼容常见的 I2C 总线。PIC18F46K40 作为一款带增强型核心的 8 位 MCU,硬件 I2C 模块完全可以直接对接。整机里如果还有别的数字设备,比如 EEPROM、温湿度传感器、LCD 驱动,全部挂在同一条 I2C 总线上即可,主控无需额外增加引脚资源。项目现场如果需要替换方案,也可以很快平移到其他带硬件 I2C 的主控平台上,从 MCU 角度看,几乎不需要改动应用层逻辑。
1.3 功能边界与整体架构
在固件层面,我并没有让主控承担太多数学运算。PJ85718DM 测量出来的原始数据通过 I2C 交给 PIC18F46K40,主控负责完成温度换算、滤波和量程判断。最终温度值按照 0.1℃ 分辨率保存在内部寄存器里,同时根据预设阈值输出状态位,方便上位机或者逻辑控制器直接判断。
整个系统的温度采集范围设定在 -40℃ 到 +125℃ 之间。本地通道常工作在 0℃ 到 60℃,远程通道会因为户外或管道环境覆盖更大的范围。这个量程覆盖了绝大多数 HVAC 控制场景,也保留了嵌入式设备机箱监控的余地。从主控的引脚分配来看,I2C 占用两个引脚,一个引脚做模块复位或报警读取,其余引脚全部留给对外通信和继电器控制,资源非常宽裕。
2. 硬件原理与接口设计
2.1 PJ85718DM 的接口定义与接法
拿到 PJ85718DM 模块后,第一件事是核对接口定义。从模块丝印和手册来看,核心引脚无非是电源、地、时钟、数据以及报警输出。这里特别提醒一点:I2C 地址引脚和报警输出引脚一定要直接确认清楚,很多模块出厂后地址引脚是悬空的,默认地址只在特定电平组合下有效。我在这块板子上把地址引脚固定接到了 GND,实际地址读出来为 0x50 系列,在 7 位地址模式下对应 0x28。
与 PIC18F46K40 连接时,需要在 SCL 和 SDA 上分别接 4.7kΩ 上拉电阻。虽然模块内部有时会带上拉,但不同批次差异很大,主控侧按标准值加上不会出错。如果总线上还有其他设备,上拉电阻总值需要重新核算。我实测在 400kHz 快速模式下面,波形上升沿干净,没有出现数据错位。
报警输出脚建议通过一个 10kΩ 电阻上拉到 3.3V,然后再进主控的普通 IO。这样设计的好处是报警输出作为开漏信号时,主控可以直接读到低电平触发;如果模块自身是推挽输出,串电阻也能起到简单的电平隔离作用。这个引脚在调试阶段特别有用,因为模块内部的告警逻辑可以先独立验证。
2.2 PIC18F46K40 的资源配置
PIC18F46K40 的资源分配是整个 BOM 里最灵活的部分。这款 MCU 在 44 引脚封装下提供了多个串口、ADC、定时器以及 CIP 智能外设。按照 2.1 的接法,我分配给温度监测的最小资源如下:MSSP 模块配置为 I2C 主模式,时钟选择 FOSC/4,400kHz;一个普通 IO 用于读取模块报警状态;如果后续需要模拟量备份校验,还可以复用 AN0 通道作为对比输入。
这里要特别提一下 PIC18F46K40 的上电时序。模块和 MCU 共用同一个 3.3V 电源轨时,如果 MCU 已经启动并在 I2C 总线上发起通信,而模块尚处于上电复位状态,容易产生总线冲突。我的解决方法是:主控启动后延时 50ms 再初始化 I2C 外设,同时首次通信做一个“软复位脉冲”。具体做法是将 SCL 连续翻转 9 个周期,确保模块状态机恢复到默认位,再开始正常的寻址读取。这个技巧对很多 I2C 从机都通用。
2.3 电源与抗干扰处理
HVAC 环境里最大的敌人是强电启停带来的干扰。接触器、风机、压缩机的启停瞬间,电流变化率很大,电源线上的毛刺和地线上的电位跳变很常见。温度采集板如果直接噪声耦合进模拟测量,整个控温逻辑都会变得神经质。
所以电源部分我采用了 LDO 独立供电子板的方式,而不是直接吃开关电源的输出。输入 12V 或 24V 经一级降压得到 5V,再经 LDO 降到 3.3V 供给 PJ85718DM 与 MCU。LDO 的电源抑制比在低频段表现明显优于开关电源,能把大多数电机换向产生的低频纹波挡在外面。每个电源引脚旁边都放置了 0.1μF 陶瓷电容和 10μF 钽电容,形成低阻抗回路。
PJ85718DM 的本地温度部分对布线敏感度稍低,但远程温度输入是真正的重点。远程探头走线长,容易拾取空间辐射。我在接口处增加了由 100Ω 电阻与 1nF 电容组成的 π 型滤波,同时把传感器的屏蔽层在子板单点接地。实测在变频器旁边运行时,远程通道读数的波动从 ±2℃ 降到了 ±0.2℃ 以内。
3. 固件逻辑与核心步骤实现
3.1 初始化顺序与 I2C 时序
固件方面我一贯的原则是:先让硬件跑通,再上复杂逻辑。初始化顺序固定为:系统时钟配置、IO 方向设置、I2C 外设初始化、延时等待、软复位总线、检测 PJ85718DM 应答、读取模块 ID 或状态寄存器。这种顺序能保证后续调试时只要在串口打印最后一步的状态,就能立刻判断前面哪一环没就绪。
下面是一段简化后的初始化示例,采用类 C 语法,具体寄存器地址以实际模块和 MCU 为准:
void temp_sensor_init(void) { // 1. 配置 I2C 主模式,400 kHz // 2. 将 SDA/SCL 设为开漏输出 // 3. 发送 START + STOP,形成一个 dummy 周期 // 4. 发送满 9 个 SCL 时钟,恢复从机总线状态 // 5. 轮询从机地址,连续 3 次失败则报警指示灯闪烁 // 6. 读取模块状态寄存器,清除上电标志位 }这段代码看上去不难,但第 4 步常常被忽略。实际项目里我发现,模块在 MCU 调试器反复复位时,偶尔会卡在一个半通信状态。通过对 SCL 手动翻转 9 个时钟,等于强制把从机状态机“洗”回空闲态,比单纯重新上电或改代码逻辑高效得多。
3.2 温度值换算与数据格式处理
PJ85718DM 返回的原始数据是 16 位有符号数,并且带有符号位和扩展位。手册给出的方式通常是“原始值除以固定系数,再乘以分辨率”,但实际使用中我发现不同批次的模块基准稍有差异,最好的方式是在固件里做两点标定补偿,而不是完全信任出厂系数。
温度换算的基本公式如下:
float temp_value_calc(int16_t raw) { // 假设模块输出分辨率为 0.01℃/LSB float temp = (float)raw * 0.01f; // 出厂偏移量,依据标定结果写入Flash temp += calibration_offset_eeprom; return temp; }在 PIC18F46K40 上我尽量用定点数处理,避免浮点库占用太多 ROM。温度值乘以 10 后拿整数运算,只有在外送显示时才转成小数。这样单次转换耗时可以控制在几微秒内,对定时器中断的压力很小。
分辨率 0.01℃ 在现场其实有点过度设计。HVAC 控制器本身温度控制精度多数在 ±0.5℃ 就够了。所以我并没有直接输出原始分辨率,而是在内存里先做一轮滑动平均滤波,把 16 次采样结果求和再取平均,最终输出以 0.1℃ 为单位的整形值。这样既保证了读数稳定,又让后端的 PID 控制器看到的变化曲线平滑许多。
3.3 本地与远程通道的采样调度
两个通道不能在同一时刻读,原因在于模块内部模拟多路开关的切换需要稳定时间。如果上一次读远程通道刚结束,立刻切到本地通道读取,内部滤波电容上的残余电压会影响头几个采样点。稳妥的做法是:每次切换通道后至少延迟 10ms,再连续读取 3 次,取中间值作为该轮结果。
整个采样周期里,我的调度顺序是:读取远程通道 -> 延时 -> 读取本地通道 -> 更新状态标志 -> 处理阈值判断。采样周期固定为 500ms。这个周期对 HVAC 应用足够了,同时也不会给 I2C 总线增加多余负载。
主循环里的逻辑相当于一个有限状态机:
typedef enum { SENSOR_IDLE, SENSOR_READ_REMOTE, SENSOR_SETTLE, SENSOR_READ_LOCAL, SENSOR_UPDATE, } sensor_state_t;有人可能会问,为什么远程通道要放在前面读。这是因为远程探头线长、信号建立时间更长,同样 10ms 延时下,远程通道先读可以保证后面本地通道读取时模块内部已经彻底稳定。这个细节是我对比过数据后发现的:远程先读、本地后读,比反过来读到的本地数据更稳定,原因是内部参考电压不会因为长线电容而波动。
3.4 超时保护与异常数据过滤
任何 I2C 设备都可能在极端干扰下丢应答。针对 PIC18F46K40,我在 MSSP 中断服务程序里维护了一个超时计数,如果一次通信超过 5ms 没有完成,立即强制复位 I2C 外设并重新初始化总线。这样做的好处是即使总线真正被拉死,也不会阻塞主循环。
温度数据过滤则包括三个层次。第一层是范围检查,超出 -50℃~+130℃ 的数据直接丢弃。第二层是跳变检查,相邻两次读数的差值超过 8℃ 时,先不更新当前值,而是重新采样一次,如果仍然偏差过大再认为探头异常。第三层是持续失败计数,连续 10 个周期读取失败就恢复默认温度值,并置位故障标志。这样后端即使没有收到正确数据,也知道当前处于故障态,而不是拿到一个误导输出的温度值。
4. 调试方法与标定校准
4.1 先用串口把原始值全部吐出来
调试 PID、搞联动逻辑之前,最基础也最重要的手段就是串口日志。我这里在调试阶段会直接通过 MCU 的 UART 向外发送一行调试数据,内容包含本地原始值、本地换算值、远程原始值、远程换算值、I2C 错误计数。有了这五个数据,几乎所有异常都能定位到是“传感器部分”还是“主控部分”。
实际调试时,我会左手拿一个冰水混合物,右手拿一个加热台,盯着串口监视器看数值变化。这里有个小经验:冰水混合物温度会缓慢回升,所以不要把两边都盯死。我通常把远程探头放进冰水混合物,本地探头放在室温环境,然后观察两条曲线是否平滑交叉。如果有一路曲线出现毛刺,优先检查接触端子,而不是改软件滤波器。
4.2 两点标定的具体操作步骤
PJ85718DM 模块出厂时做过基本校准,但为了匹配 PCB 布局和线缆长度,整个系统还需要一次整机两点标定。我选的标准温度点是 0℃ 和 60℃。0℃ 点用冰水混合物实现,60℃ 点用精密恒温槽,没有恒温槽的话至少也要用经过校准的工业温度计进行参考对照。
标定公式非常直接:
offset = (temp_100_ref_high * raw_low - temp_100_ref_low * raw_high) / (raw_high - raw_low); scale = (raw_high - raw_low) / (temp_100_ref_high - temp_100_ref_low);在实际产品里,我把这两个参数存放在 PIC18F46K40 的数据 EEPROM 中,出厂前由产线工装写入。这样做比把参数硬编码在源码里灵活得多:同一版固件可以对应不同精度的传感器批次,现场更换模块也不需要重新烧录整个程序。
4.3 常见问题一页速查
调试期间最容易碰到的问题基本集中在通信和供电上,我把它们整理成一张表放在项目文档里,顺手分享出来:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| I2C 一直无应答 | SDA/SCL 上拉电阻缺失 | 检查总线波形,确认上拉到 3.3V |
| 远程读数整体偏高 | 线缆屏蔽层浮空 | 将屏蔽层单点可靠接地 |
| 本地读数跳动 | 模块电源纹波过大 | 在 LDO 后增加 10μF 钽电容 |
| 上电后读数为 0 | 软复位脉冲未执行 | 初始化时发送 9 个 SCL 时钟 |
| 读数偶尔跳变 10℃ | 探头接线端子氧化 | 更换镀金端子,检查扭矩 |
| 高温下误差变大 | 基准电压受温度影响 | 增加软件两点补偿,提升标定频次 |
这张表的作用不仅是排查问题,更重要的是在项目交接时告诉现场工程师“先看总线波形,再查供电,最后才怀疑传感器”,省掉许多无效返工。
5. 量产与现场运行经验总结
5.1 注意 MCU 资源余量与烧录保护
PIC18F46K40 本身程序空间充足,我在完成这套逻辑后只占用了不到 30% 的 Flash,剩余空间全部留给后续扩展。但我想提醒一点:空间充裕不代表可以把所有调试代码塞进去。正式版本里,串口调试输出务必用条件编译关掉,否则 printf 和浮点转字符串会消耗大量 ROM 和 RAM,也可能拖慢实时性。
烧录保护方面,我在最终版本中把代码保护位打开,同时将配置位里的调试模式关闭。HVAC 设备到了现场基本不会有人去在线调试,打开调试模式反而会增加被误操作的风险。如果后续要升级固件,直接通过预留的 UART Bootloader 接口即可,没必要保留 ICSP 调试口。
5.2 现场安装时的接地与布线习惯
整套系统在现场稳定运行后,我总结出几个特别值得注意的地方。第一,温度探头线不要和 220V 动力线走同一个线槽,间距至少保持 10cm 以上,否则感应电压会直接叠加到模块前端。第二,远程探头线预留长度宁长勿短,但多出来的线一定要盘起来固定好,不能让它像天线一样在旁边颤。第三,如果现场有多个机组,各机组的地之间可能存在电位差,传感器屏蔽层只能在子板端单点接地,不要两端都接。
这些经验在实验室里不容易遇到,但到了现场几乎是必踩的坑。尤其是多设备共用大楼主地时,地环路上的低频电流会让温度读数产生无法解释的偏移。单端接地后,这类问题会立刻消失。
5.3 长期稳定性与保养建议
因为 PJ85718DM 模块本身功耗很低,整套子板在 3.3V 供电下功耗大约只有 20mA 左右,所以控制箱内的温升基本可以忽略。但长期运行时,控制箱内部灰尘和湿气仍然是最大隐患。我建议终端设备每年维护时,对连接端子进行一次重新紧固,并检查模块针脚是否有氧化变色。出现接触不良的早期迹象是远程通道偶尔闪断,但本地通道一切正常。这时不要急着改软件,先把端子清洁处理再说。
如果产品需要进一步提升环境适应性,可以在模块表面喷涂一层三防漆,但这属于产线工艺范畴,必须提前验证对 I2C 时序的影响。我在小批量样品上做过一次喷涂测试,结果完全没有影响时序,只是表面留了一个涂层厚度需要控制的工艺参数。
这个项目做下来,我最大的体会是:温度监测在 HVAC 系统里看着简单,但真正稳定可靠地做出来,需要把传感器选型、接口设计、固件容错、现场布线这四件事一起考虑进去。PJ85718DM 配合 PIC18F46K40 的组合,正好把模拟前端和主控逻辑之间的边界切得很干净,让我可以把精力集中在业务逻辑而不是反复地和噪声搏斗。最后分享一个小技巧:把每个通道的标定参数和故障标志统一做成结构体,调试上用起来非常顺手,后面不管接上位机还是接 HMI,所有数据都能通过同一套接口访问,不用东一块西一块地找全局变量。希望这些记录对你做类似的温度监测方案有实际帮助。