
1. 项目缘起与整体设计思路温度监测这件事看起来简单真要做到本地看得见、远程收得到、长期跑得稳里面门道不少。我最近刚交付一个暖通空调控制柜的温度采集模块用的就是 PJ85718DM 这颗 I2C 数字温度传感器主控选的是 STM32F767ZG。整套方案从选型到落地大概花了三周中间踩了几个不大不小的坑这里把完整思路和实操过程整理出来给做嵌入式温度采集、尤其是 HVAC 方向的朋友做个参考。先说这个项目要解决什么问题。暖通空调设备里温度采集点通常分两类一类是本地温度比如控制板附近的进风温度、回风温度传感器就焊在板子上或者用短线连出来另一类是远程温度比如风管里、水箱里、室外机上的测点传感器离主控可能有好几米甚至十几米。传统做法是用模拟传感器加长线但长线一走压降、干扰、温漂全来了读数飘得没法看。所以这次我直接上数字温度传感器I2C 总线本地挂一颗远程用差分或者屏蔽线延长 I2C配合合理的上拉和滤波把本地和远程两路温度都稳稳采回来。主控为什么选 STM32F767ZG这颗芯片是 Cortex-M7 内核主频能跑到 216MHz带 FPU 和 DSP 指令I2C 外设资源丰富最多能挂好几路 I2C。有人会说采个温度用得着这么猛的芯片吗单看温度采集确实用不着但这个板子同时还跑着风机控制、阀门调节、Modbus 通信和一块小液晶屏温度采集只是其中一个任务。F767ZG 的算力和外设余量足够后面加算法、加通道都不用换板子这是从产品迭代角度做的取舍。如果只是单纯做个温度采集 DemoF103 甚至 F0 系列都够用这点后面我会细说。整个系统的设计目标我列一下方便你对照自己的项目本地温度采集精度做到 ±0.5℃ 以内远程温度在 10 米线长下误差不超过 ±1℃采集周期 1 秒一次支持多通道轮询数据本地显示同时通过串口或 Modbus 上传给上位机长期运行不丢数据传感器掉线能自动恢复硬件成本可控不堆料这套目标定下来之后选型和电路设计的方向就清晰了。下面我按传感器选型—硬件设计—软件实现—问题排查的顺序展开每一步都说说为什么这么选、怎么算、怎么调。2. 温度传感器选型与 PJ85718DM 核心特性解析2.1 为什么是数字温度传感器而不是热敏电阻做温度采集第一反应往往是 NTC 热敏电阻或者 PT100。这两种我都用过NTC 便宜、电路简单但线性度差需要查表或者拟合而且长线传输时引线电阻直接影响分压结果10 米线走下来误差能到好几度。PT100 精度好、线性度好但需要恒流源激励、需要仪表放大器电路复杂度和成本都上去了而且模拟小信号在 HVAC 这种强电环境里特别容易被干扰。数字温度传感器把 ADC 和信号调理都集成在芯片内部输出的是数字量I2C 传输的是高低电平只要时序对了线长带来的压降基本不影响数据正确性。这是我在这个项目里选数字方案的核心原因。PJ85718DM 就是这类器件里比较典型的一颗I2C 接口出厂校准直接读寄存器就能拿到温度值省掉了大量模拟电路调试工作。2.2 PJ85718DM 的关键参数与寄存器结构PJ85718DM 是一颗高精度数字温度传感器我把它几个关键参数列出来这些直接决定了电路和软件怎么写参数项典型值说明供电电压1.8V ~ 3.6V和 STM32 的 3.3V 电平天然兼容温度范围-40℃ ~ 125℃覆盖 HVAC 全部工况本地精度±0.5℃-20~85℃常温段精度最好分辨率可配置 9~12 位12 位对应 0.0625℃接口I2C最高 400kHz标准/快速模式都支持地址由 ADDR 引脚决定支持多颗挂同一条总线寄存器方面核心就几个温度结果寄存器只读16 位高 12 位有效、配置寄存器设置分辨率、工作模式、报警阈值、以及高低限报警寄存器。读温度的标准流程是写指针寄存器指向温度结果寄存器地址然后连续读两个字节高字节在前低字节的高 4 位有效拼起来右移 4 位再乘 0.0625 就是摄氏度。这个换算过程后面代码里会写清楚。注意PJ85718DM 的温度数据是 12 位有效低 4 位是保留位读出来是 0。如果你直接拿 16 位整数当温度用会得到 16 倍于真实值的数这是新手最容易犯的错。2.3 本地与远程采集的差异化设计本地和远程虽然用的是同一颗传感器但电路处理上要区别对待。本地传感器离主控近I2C 走线短上拉电阻用 4.7kΩ 就行走线尽量短、尽量远离功率器件。远程传感器就麻烦了线一长总线电容增大上升沿变缓400kHz 可能跑不动得降到 100kHz 甚至更低上拉电阻也要相应减小到 2.2kΩ 甚至 1.5kΩ用来加快上升沿。我实测过一组数据用普通杜邦线延长 I2C线长和可用最高速率的关系大致是这样线长上拉电阻可用最高速率读数稳定性1 米4.7kΩ400kHz稳定5 米2.2kΩ100kHz稳定10 米1.5kΩ100kHz偶发 NACK15 米1.5kΩ50kHz需加屏蔽这张表是我自己拿示波器看波形、反复试出来的不是手册数据你实际用的时候线材不同结果会有差异。远程那一路我最后用的是屏蔽双绞线SCL 和 SDA 各走一对屏蔽层单端接地速率降到 100kHz连续跑了一周没出现丢包。3. 硬件电路设计与关键参数计算3.1 主控最小系统与 I2C 外设分配STM32F767ZG 是 LQFP144 封装I2C 外设有 I2C1、I2C2、I2C3、I2C4 四路。我把本地传感器挂在 I2C1PB6/PB7远程那一路挂在 I2C2PB10/PB11这样两路互不干扰本地采集出问题不影响远程。电源部分用 3.3V LDO 从 5V 降压传感器和主控共用同一路 3.3V保证电平一致。这里有个细节F767 的 I2C 引脚是复用开漏输出必须外接上拉电阻不能依赖内部上拉内部上拉太弱只有几十 kΩ带不动总线电容。上拉电阻接到 3.3V不要接到 5V否则会通过 I2C 引脚往芯片里灌电流。3.2 上拉电阻的计算过程上拉电阻不是随便选的它由总线电容和上升时间要求决定。I2C 标准规定上升时间 tr 最大 1000ns标准模式或 300ns快速模式。上升时间公式是tr ≈ 0.847 × R × C其中 R 是上拉电阻C 是总线总电容。总线电容包括走线电容约 1~3pF/cm、引脚电容每颗约 10pF和线缆电容双绞线约 50pF/m。本地这一路走线 10cm两颗器件主控传感器总线电容约 10cm×2pF 2×10pF 40pF。要满足快速模式 300nsR ≤ 300ns / (0.847 × 40pF) ≈ 8.8kΩ。取 4.7kΩ 有充足余量。远程这一路10 米双绞线电容约 500pF加器件电容约 520pF。要满足标准模式 1000nsR ≤ 1000ns / (0.847 × 520pF) ≈ 2.27kΩ。所以我选了 2.2kΩ。但电阻也不能太小否则灌电流超过 3mA 会损坏器件2.2kΩ 在 3.3V 下灌电流约 1.5mA安全。实操心得远程 I2C 我建议先用示波器看 SCL/SDA 波形如果上升沿有明显的 RC 充电曲线、顶部圆钝说明上拉偏大或电容偏大要么减小电阻要么降速。别凭感觉波形不会骗人。3.3 电源去耦与抗干扰布局HVAC 环境里继电器、接触器、风机一堆电磁干扰很凶。传感器电源引脚旁边必须放 0.1μF 陶瓷电容紧贴引脚再并一个 1μF 的做低频滤波。远程传感器的供电我单独走一对线不和 I2C 信号线绞在一起避免电源噪声耦合到信号上。PCB 布局上I2C 走线尽量短、尽量平行等长SCL 和 SDA 之间不要夹其他信号线。远程接口处我加了 TVS 管做浪涌保护因为风管里的传感器线可能感应到雷击浪涌或者电机启停的尖峰。这个 TVS 选的是低电容型号结电容小于 5pF不影响 I2C 波形。4. 软件实现与核心代码拆解4.1 I2C 底层驱动配置STM32F767 的 HAL 库配置 I2C 比较直接但有几个参数必须配对。我用 CubeMX 生成初始化代码时钟配置成 100kHz远程和 400kHz本地占空比用默认的 2:1。关键配置项hi2c1.Instance I2C1; hi2c1.Init.ClockSpeed 400000; hi2c1.Init.DutyCycle I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 0; hi2c1.Init.AddressingMode I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode I2C_DUALADDRESS_DISABLE; hi2c1.Init.GeneralCallMode I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode I2C_NOSTRETCH_DISABLE;NoStretchMode一定要关掉让从机可以拉低 SCL 做时钟拉伸。PJ85718DM 在转换期间会拉伸时钟如果主控不允许拉伸读出来的数据就是错的。这个坑我踩过现象是读数偶尔跳变查了半天才发现是时钟拉伸被禁了。4.2 温度读取函数与数据换算读温度的核心函数我封装成这样带超时和重试#define PJ85718_ADDR_LOCAL 0x48 #define PJ85718_ADDR_REMOTE 0x49 #define PJ85718_REG_TEMP 0x00 float PJ85718_ReadTemp(I2C_HandleTypeDef *hi2c, uint8_t addr) { uint8_t buf[2]; uint8_t reg PJ85718_REG_TEMP; float temp; if (HAL_I2C_Master_Transmit(hi2c, addr 1, reg, 1, 100) ! HAL_OK) return -999.0f; if (HAL_I2C_Master_Receive(hi2c, (addr 1) | 1, buf, 2, 100) ! HAL_OK) return -999.0f; int16_t raw (int16_t)((buf[0] 8) | buf[1]); raw 4; temp raw * 0.0625f; return temp; }换算逻辑说明一下两个字节拼成 16 位右移 4 位丢掉保留位剩下的 12 位是有符号数乘 0.0625 得到摄氏度。返回 -999 表示读取失败上层根据这个值判断传感器是否掉线。4.3 多通道轮询与本地显示主循环里我用一个 1 秒的软定时器触发采集本地和远程各读一次读到的值存进数组同时刷新液晶屏。屏幕用的是 SPI 接口的小尺寸 TFT显示两行温度值加状态标志。如果某一路返回 -999屏幕上对应位置显示 ERR同时点亮一个告警 LED。轮询顺序上我先读本地再读远程中间隔 50ms避免两条总线同时活动带来的电源波动。这个间隔不是必须的但实测下来加上之后读数更稳尤其是远程那一路。4.4 数据上传与 Modbus 从机实现上位机通信用的是 Modbus RTUSTM32 做从机波特率 96008 数据位无校验。温度值放大 10 倍存进保持寄存器比如 25.3℃ 存成 253上位机读出来除以 10 就行。这样避免浮点数在 Modbus 里传输的兼容问题。Modbus 帧的解析我用的是状态机方式在串口中断里逐字节接收收到完整帧后置标志位主循环处理。这种方式比阻塞式接收可靠不会因为等一帧数据卡住整个采集流程。寄存器映射表我列一下寄存器地址内容说明0x0000本地温度×10有符号 16 位0x0001远程温度×10有符号 16 位0x0002状态字bit0 本地在线bit1 远程在线0x0003报警阈值可写单位 0.1℃5. 常见问题与排查技巧实录5.1 读数跳变与 NACK 问题排查调试阶段最头疼的是远程那一路偶尔 NACK读数跳变。我按这个顺序排查的先看波形。示波器夹在远程传感器的 SDA 上发现上升沿有明显台阶说明上拉不够或者电容太大。把 4.7kΩ 换成 2.2kΩ台阶改善但没完全消失。降速。从 400kHz 降到 100kHz波形干净了NACK 频率大幅下降。换线。把普通杜邦线换成屏蔽双绞线屏蔽层接主板地NACK 基本消失。加软件重试。在读取函数里加 3 次重试每次间隔 10ms彻底解决偶发失败。这个排查过程说明一个问题I2C 长线传输是电气问题软件重试只能兜底根子还在硬件。顺序不能反先解决电气再上软件容错。5.2 温度值偏差与自热效应有段时间发现本地温度总比参考温度计高 0.8℃ 左右。查了半天是传感器自热。PJ85718DM 工作电流不大但如果采集太频繁芯片自身发热会累积。我把采集周期从 100ms 改成 1 秒偏差降到 0.2℃ 以内。另外传感器布局上远离 LDO 和主控这些发热源也能减少偏差。注意温度传感器测的是它自己的温度不是环境的温度。任何靠近它的热源都会影响读数这是物理规律软件补偿只能修一部分布局才是根本。5.3 常见问题速查表现象可能原因解决方法读数为 0 或固定值地址错误、器件没供电查 ADDR 引脚、量电源读数跳变大上拉不当、干扰调电阻、降速、加屏蔽偶发 NACK总线电容大、时序紧减小上拉、降速、加重试温度偏高自热、靠近热源降采集频率、改布局通信完全无响应SDA/SCL 接反、无上拉查线序、补上拉电阻5.4 长期运行稳定性验证产品交付前我做了 72 小时连续运行测试每秒采集一次记录丢包率和温度漂移。结果是本地丢包 0远程丢包 3 次都在电机启停瞬间重试后全部恢复。温度漂移在 ±0.3℃ 以内。这个结果满足设计要求但我还是把远程的重试次数从 3 次加到 5 次进一步降低丢包影响。6. 方案扩展与个人经验总结这套方案跑通之后我做了几个扩展尝试也一并说说。第一个是多点组网PJ85718DM 的地址由 ADDR 引脚决定理论上一条总线能挂多颗我把远程那一路扩到 3 颗传感器分别测风管三段温度地址用 0x49、0x4A、0x4B轮询读取工作正常。第二个是加报警功能用传感器自带的高低温报警寄存器和 ALERT 引脚超限直接硬件中断比软件轮询响应快。如果让我重新做一遍有两点会调整。一是远程 I2C 我会考虑换成 I2C 缓冲器或者差分 I2C 收发器虽然成本高一点但 10 米以上的线长会更稳不用在速率上妥协。二是主控其实可以降一档如果只做温度采集加 ModbusF767 有点浪费F407 甚至 F103 都能胜任省下的成本可以投到更好的传感器和线材上。最后分享一个我调试时的小技巧读温度之前先读一次配置寄存器确认器件在线且配置正确再读温度。多这一次读操作能提前发现器件掉线避免拿到无效数据。这个习惯让我在后期维护时省了不少事上位机报上来的数据从来没出现过假在线的情况。这套本地加远程的温度监测方案核心就三件事选对数字传感器、把 I2C 电气特性调好、软件上做好容错。把这三点做到位HVAC 这种恶劣环境也能稳定跑。