首页 / 资讯中心 / 文章详情

双通道数字温度传感器与PIC18F45K80的暖通测温实战

双通道数字温度传感器与PIC18F45K80的暖通测温实战 ★ FEATURED ARTICLE
最近做暖通控制板的项目时碰到一个很典型的测温需求单片机既要知道自己这块控制板附近的温度用于过热保护又要知道两三米外风道深处的送风温度用来参与调节和报警。如果用两根 NTC 热敏电阻拉过去引线电阻和现场干扰会让人很头疼。最后定下的方案是 PJ85718DM 加 PIC18F45K80一颗双通道数字温度传感器负责本地和远程两路温度一颗带 CAN 接口的 8 位单片机负责读取、联动和上报。调完以后整体非常稳今天把方案逻辑、硬件接线、固件流程和调试中踩过的坑完整复盘一遍。先说明白这颗 PJ85718DM 是什么定位。它是一颗本地测温 远程二极管测温二合一的数字温度传感器本地通道测芯片自身结温远程通道通过 DXP/DXN 两个引脚外接一枚普通的三极管利用三极管 PN 结导通压降随温度变化的特性反推远端温度。真正放到被测现场的是一枚几毛钱的小三极管而不是体积不小的热敏电阻探头导线影响小、抗干扰能力强比传统阻性测温方式更适合长线传输。PIC18F45K80 则是很经典的工业级 8 位单片机内部集成 ECAN 控制器正好适合后面接楼宇自控总线。这篇东西适合正在做嵌入式温度采集的工程师也适合暖通设备选型阶段的技术人员参考下面进入正题。1. 方案整体设计为什么本地和远程温度要分开测1.1 HVAC 场景里的温度测点从来不只是“一个”做过暖通的人都知道一套风柜或风机盘管系统里参与控制的温度测点少则两三个多则七八个。回风温度、送风温度、盘管进出口水温、新风温度、混合温度每个测点服务的控制目标都不一样。送风温度参与风机转速和冷热水阀开度计算回风温度反映房间实际负荷盘管温度还关系到防冻保护。这些测点分散在不同的物理位置不可能全部挤在控制板上所以“传感器在被测现场、主控在控制盒里”是常态。测点和控制器之间只要有距离就必然有导线。导线短的时候什么传感器都好用一长就露馅。这个项目里送风温度测点离控制盒大约两米五中间还要在桥架上绕一段。如果用 NTC常见的 10kΩ 热敏电阻引线电阻哪怕只有 2Ω温度误差就能到 0.2°C 左右再加上附近变频器感应进来的噪声ADC 采样结果会非常乱。PJ85718DM 的远程通道恰恰绕开了这两个问题它传输的不是一个随温度变化的电阻值而是恒流源驱动二极管产生的电压。这个电压信号的抗干扰能力比阻性测量强很多而且传感器内部做了 β 补偿和串联电阻抵消线缆电阻带来的误差可以被算法补掉一部分。实测下来在不算干净的工业现场远程温度读数也能稳定在 ±1°C 以内。1.2 嵌入式控制器自身的本地温度也有大用本地温度很多人容易忽略觉得“不就是芯片自己的温度嘛”。实际上控制板上有功率 MOS、继电器、开关电源这些发热源板温往往比环境温度高出不少。如果板温持续越过阈值一般意味着散热通道堵了或者输出负载异常应该提前报警甚至降额运行。PJ85718DM 的本地通道正好承担这个板级过热保护任务。本地温度还有第二个用途就是给远程温度提供参考点。虽然远程测温芯片内部会做自动补偿但在极端温差场景下比如现场环境 -20°C、控制盒里却因为功率器件发热到了 80°C多一个本地温度信息做校验总是更放心。上位机看到“环境 30°C、盘管水温 11°C”这样一组数据也更容易判断整个温度链路是否正常。所以这颗传感器“双通道”的意义就在这里一颗芯片同时覆盖控制器自身状态监控和外部测点监控比用两颗传感器省事布线也更干净。1.3 选型时为什么排除了 NTC、PT100 和红外测温有人在选型时问过我测温方式这么多为什么偏偏用一颗数字双通道传感器。我逐个对比过一遍NTC价格便宜但要 ADC 采样、查表、线性化长线传输需要恒流源或三线制配置才能稳住精度工程调试成本不低。PT100精度确实高但需要恒流源激励和仪放电路外围元件一圈成本一下子就上去了小批量产品上不划算。红外测温非接触是优点但发射率参数要设置而且没办法测管道内部或者风道深处的空气温度。数字传感器直接输出数字量单片机 I2C 读回来就是温度而且 PJ85718DM 这种双通道型号把远端和本地需求一次包圆了。单片机这一侧选择 PIC18F45K80理由也很直接。第一是 HVAC 设备现在普遍要挂楼宇自控总线CAN 在工业现场很常见这颗芯片内置 ECAN 控制器不用外挂 CAN 控制器芯片硬件和驱动工作都省了。第二是它的工作电压范围 2.0~5.5V对控制盒这种电源波动比较大的场合很友好。第三是 Flash 和 RAM 余量足以后想加风阀控制逻辑或者水泵联锁不用换主控。2. 硬件设计要点接线、去耦和安装细节2.1 主控的资源分配与引脚预留做硬件分配的时候我的原则是“先把扩展空间留出来”。PIC18F45K80 的资源分配思路如下功能模块使用的外设说明温度传感器接口MSSP/I2C Master接 PJ85718DM100kHz报警输入外部中断引脚接传感器 ALERT 引脚远程通信ECAN 模块对接楼宇自控总线调试输出UART接 USB 转串口看日志本地状态2 个 GPIO报警灯、运行指示灯这样把外设分开规划后续如果再扩展第二路温度传感器I2C 地址可以用 A0/A1 引脚切换同一棵总线上最多挂四颗。做多测点控制器的时候这个余量非常重要。这里有个经验I2C 的 SCL 和 SDA 一定要选支持开漏输出的引脚并加上拉电阻。上拉电阻值我是根据传感器工作电压选的3.3V 供电时用 4.7kΩ总线如果比较长绞合线电容会让沿变缓就换成 2.2kΩ。太高的上拉电阻会让总线上升沿不够快特别是在现场线缆长了以后容易出偶发通信错误。2.2 传感器的供电与 I2C 接线PJ85718DM 本次按 3.3V 供电设计SCL、SDA 各接一颗上拉电阻到 3.3V。因为单片机也工作在 3.3V省掉了电平转换那一步。如果控制板整体用 5V 电源需要确认传感器型号是否支持 5V 供电否则要在 I2C 线上加电平移位别硬接。传感器 VDD 和 GND 之间我放了 0.1μF 陶瓷电容和 10μF 钽电容并联。很多工程师习惯只放一颗 0.1μF但在温度传感器附近尤其是远程测温通道对电源毛刺很敏感的场合加大电容有实际效果。曾经碰到过一次本地温度读数偶尔跳 3~4°C 的情况排查到最后就是电源纹波问题补了钽电容以后就正常了。ALERT 引脚直接连到单片机的外部中断引脚。这颗传感器也有 SMBus 超时功能但实际项目中用硬件中断比轮询状态寄存器更及时。ALERT 是开漏输出也要加上拉我用的也是 4.7kΩ。2.3 远程三极管的接法和安装远程测温的本质是把一个二极管放在远端。工程上最稳妥的做法是用普通三极管我选的是 2N3906 这类 PNP 管。接法很固定PNP 三极管的发射极接 DXP基极和集电极短接后接 DXN。这里最容易犯的错误是方向接反接反以后读数通常会指向一个明显不合理的极端值比如 -50°C 或者 150°C。安装方式直接决定测量质量测风道温度把三极管扁平外壳贴在翅片或者铜块上涂导热硅脂再用高温胶带固定。测水管温度用抱箍把三极管压在管壁上外面包保温棉防止环境温度干扰。绝对不能直接把三极管悬在空中测空气那样测到的是周围环境混合温度而不是被测对象的温度。远程通道走线超过一米我强烈建议用屏蔽双绞线。DXP 和 DXN 作为差分对走双绞线屏蔽层单端接控制器的 GND。另外在传感器端DXP 和 DXN 之间并联一颗 1nF 陶瓷电容DXP、DXN 各串联一颗 100Ω 电阻这个 RC 结构能明显衰减空间耦合噪声。我第一次调试没加滤波读数在变频器动作时会跳加了以后干净很多。2.4 长线测温的抗干扰布局提到抗干扰布局不是只考虑传感器那一段。控制板上的开关电源、继电器线圈如果离传感器太近干扰也会耦合进去。我在布板的时候把 PJ85718DM 放在离电源模块尽量远的位置传感器接口区域不走功率线模拟地和控制地单点连接。还有一个容易被忽略的点CAN 总线本身是差分结构抗干扰能力不错但 CAN 收发器和微控制器之间也要注意隔离。如果现场有变频器或大功率接触器建议用光耦隔离或者集成隔离式收发器否则温度数据偶尔会被干扰成错误帧。说实话温度监测项目里的 CAN 功率不强求隔离但为了后期省心能隔就隔。3. 固件实现从初始化到双路温度稳定读取3.1 系统初始化先把时钟和通信口理清楚固件用标准 C 语言编写基于寄存器操作方便之后移植。第一步是配置时钟。PIC18F45K80 内部振荡器经 PLL 后跑到 32MHz不需要外部晶振省了两个引脚。然后把 I2C 配置成主模式目标速率 100kHz。void system_init(void) { // 配置内部振荡器开 PLL等待时钟稳定 OSCCON 0x72; // 内部 8MHz 振荡器 while (!OSCCONbits.PLLRDY); // 等待 PLL 锁定 // I2C 主模式100kHz SSPCON1 0x28; // I2C 使能主模式 SSPCON2 0x00; SSPADD (unsigned char)((32000000UL / 4 / 100000UL) - 1); // 外部中断引脚配置用于响应传感器 ALERT TRISBbits.TRISB0 1; // RD0 设为输入 INT0CON 0x90; // 下降沿触发使能外部中断 // 调试串口 uart_init(9600); // CAN 初始化 can_init(500); }SSPADD 的计算公式是 Fosc / (4 × 目标频率) - 1。32MHz 下 100kHz 算出来是 79代码里直接算出写进去。如果想跑 400kHz就拿 64MHz 或者更高的输入时钟重新算但我的建议是温度采集应用别追求高速100kHz 足够。有一点要特别说明PJ85718DM 的实际寄存器地址和配置位请一定以你手上的数据手册为准。我在这里用的寄存器宏定义是这个项目里整理出来的不同批次或型号后缀可能有差异。3.2 I2C 读取函数和温度换算I2C 读温度的流程是启动 → 写器件地址和写方向 → 写寄存器地址 → 重启 → 写器件地址和读方向 → 连续读两个字节 → 停止。器件地址按 0x48 左移一位写方向是 0x90读方向是 0x91。unsigned int read_temp_register(unsigned char reg_addr) { unsigned int value 0; i2c_start(); i2c_write_byte(0x90); // 地址 0x48写 i2c_write_byte(reg_addr); // 寄存器指针 i2c_restart(); i2c_write_byte(0x91); // 地址 0x48读 value i2c_read_byte(1); // 高字节回 ACK value (value 8); value | i2c_read_byte(0); // 低字节回 NACK i2c_stop(); return value; }温度寄存器的数据格式是 16 位有效精度 12 位最低位代表 0.0625°C。换算函数要小心负数温度不能直接当成无符号数算。float raw_to_celsius(unsigned int raw) { unsigned int sign raw 0x8000; if (sign) { raw | 0xF000; // 扩展符号位 } signed int val (signed int)raw; val 4; // 去掉低 4 位扩展位 return val * 0.0625f; }这里的坑在于如果直接把 raw 当成有符号数右移在部分编译器上可能是逻辑右移而非算术右移负温度就会算成很大的正数。我刚开始用了一句(signed short)raw 4结果 -5°C 读出来成了 600 多度排查了老半天。后来老老实实做符号扩展再移位问题才解决。3.3 报警中断和主循环逻辑报警处理我用了中断加轮询双重保险。PJ85718DM 的 ALERT 引脚会在温度越限时拉低接在单片机外部中断引脚上中断服务程序里读状态寄存器判断是哪一路报警然后置标志位主循环根据标志位执行降额或者发送故障帧。void __interrupt() isr(void) { if (INT0IF) { INT0IF 0; unsigned char status read_temp_register(REG_STATUS); if (status 0x02) // 远程温度越限 alarm_flags | ALARM_REMOTE_HIGH; if (status 0x04) // 本地温度越限 alarm_flags | ALARM_LOCAL_HIGH; } }主循环的节奏控制在 500ms 周期。对暖通场景来说这个采样周期足够支持风机启停和阀门的调节。不要贪快让周期低于传感器的转换时间否则读到的可能还是上一次的数据而且白白增加总线和单片机的负载。void main_loop(void) { while (1) { float t_local read_local_temp(); float t_remote read_remote_temp(); if (t_remote 80.0f) { alarm_flags | ALARM_REMOTE_HIGH; } if (t_local 85.0f) { alarm_flags | ALARM_LOCAL_HIGH; } can_send_temp_report(t_local, t_remote); __delay_ms(500); } }报警阈值可以做成配置项写在 EEPROM 里这样现场不需要烧程序就能调整风机的保护温度。我这个项目里默认远程送风温度 80°C 报警、本地板温 85°C 降额都是根据设备长期运行数据定的不同机型会略有差异。3.4 通过 CAN 上报温度帧PIC18F45K80 内置的 ECAN 模块带多个报文缓冲器发送逻辑比早期 CAN 模块好用。我把两路温度、一个状态字节打包成 5 字节数据帧标准标识符 0x1A0 上传。温度值乘以 16 后取整用整型传输分辨率 0.0625°C既不丢精度又方便上位机解析。void can_send_temp_report(float t_local, float t_remote) { unsigned char msg[8]; signed short tl (signed short)(t_local * 16.0f); signed short tr (signed short)(t_remote * 16.0f); msg[0] (unsigned char)(tl 8); msg[1] (unsigned char)(tl 0xFF); msg[2] (unsigned char)(tr 8); msg[3] (unsigned char)(tr 0xFF); msg[4] 0; can_send_standard_frame(0x1A0, msg, 5); }上位机拿到数据后除以 16转成十进制显示和传感器端的分辨率完全对应。如果需要数据带时间戳可以扩展成 8 字节多放一个毫秒级时间戳方便排查历史记录。4. 现场实测与问题排查实录4.1 现象一远程温度读数跳变像心电图这是长线远程测温最典型的故障。症状是远程温度在正常值附近快速大幅跳变有时候还能跳成负值。排查顺序我建议从硬件到软件先看 DXP/DXN 有没有接反。再看线缆是否双绞这个项目最开始用的普通平行线干扰明显。检查线路长度超过三米建议加 RC 滤波DXP/DXN 之间并 1nF 电容。用示波器看 DXP/DXN 波形如果叠了明显的高频噪声基本锁定干扰源。我这边的最终原因是变频器启停瞬间的空间电磁干扰。换成屏蔽双绞线、屏蔽层单端接地后读数立刻稳定。软件里我又加了一层一阶低通滤波取 16 次平均波动幅度从之前的 ±3°C 压缩到 ±0.3°C 以内。4.2 现象二温度整体偏高怀疑传感器坏了有一路远程温度读出来总是比实测环境高 1.5°C 左右。先做恒温槽校准把远程三极管和标准温度计同时放进 25°C 恒温槽里对比发现确实偏高但偏移值稳定。排查下来是线缆的串联电阻问题。这根远程线比较细来回两米五等效串联电阻大约 3Ω相当于给二极管叠了一个不小的串联电阻导致测量结果偏高。解决办法有两个一是换更粗的导线把串联电阻压到 1Ω 以下二是看传感器是否支持串联电阻抵消功能如果支持在配置寄存器里打开能从算法层面消掉这部分误差。实际产品里两个手段我都用了效果最好的是开内部抵消功能粗线反而成了冗余保险。4.3 现象三本地温度正常远程读数为零远程通道读数一直是 0°C 附近甚至报错但本地温度完全正常。这类问题大概率出在 DXP/DXN 短路或者三极管接反。用万用表二极管档直接在传感器引脚处测量室温下 DXP-DXN 之间应该有 0.5V 左右的结压降。如果量到 0V说明远端短路如果量到反向不通说明三极管方向不对。我遇到过一次是现场工人把传感器线缆的两个端子压接到同一个接线端子上相当于直接把 DXP 和 DXN 短了。拆开重做端子以后恢复正常。这个问题的排查速度很快但很多人会先怀疑程序代码查半天其实万用表一量就知道。4.4 现象四I2C 偶发通信失败调速率后消失设备在实验室跑得好好的现场偶尔报找不到传感器。用逻辑分析仪看波形发现总线电平上升沿比较缓偶发出现一个不完整的应答位。原因有两层一是 I2C 上拉电阻太大总线电容导致沿太缓二是我最初为赶进度把速率设在 400kHz现场线缆稍长一点边缘时间就超规格了。最后把速率降到 100kHz上拉电阻从 10kΩ 换成 4.7kΩ问题彻底消失。对于暖通这种实时性要求并不极端的应用I2C 通信速率追求的是稳定而不是速度温度数据每 500ms 上报一次100kHz 的总线毫无压力。4.5 常见问题速查表故障现象可能原因处理办法远程温度跳变干扰、线缆过长、DXP/DXN 接反改屏蔽双绞线、加 RC 滤波、检查方向远程读数偏高线缆串联电阻过大换粗线、开串联电阻抵消远程读数为零远端短路、三极管接反万用表测二极管压降本地温度异常电源去耦不足、纹波过大补 0.1μF 10μF 电容I2C 读不到设备地址错误、上拉过大、速率过高检查 A0/A1 地址线、换 2.2~4.7kΩ 上拉、降到 100kHz温度数据偶发错误帧干扰串入 CAN 总线CAN 收发器隔离、屏蔽层单端接地排查问题的时候有个习惯先量再猜。硬件上的坑万用表、示波器一量就知道别急着怀疑固件。固件出问题的比例远没有想象中那么高。最后再说一个实际体会。做这种本地和远程温度监测项目很多人把工夫全花在选高精度传感器上可真正决定成败的往往是布线和后端逻辑。PJ85718DM 用一枚外接三极管解决远程测点思路很巧妙但对于远程线缆的抗干扰设计、电源去耦、报警逻辑每一个环节都不能偷懒。如果你现在也在做类似控制器建议在样板阶段就把传感器线和动力线分开敷设远程线用双绞线做好屏蔽I2C 速率定在 100kHz后面调试能省下大量时间。这个方案后续还可以扩展成多路远程测温换一颗支持多通道的传感器型号或者用一颗 PJ85718DM 加模拟开关轮流切入配合 PIC18F45K80 的 Flash 余量代码结构基本不用大改。
阅读完成 · 觉得有帮助?
咨询建站