最近在调试一块基于 PJ85718DM 和 STM32F745VG 的双通道测温板场景是嵌入式设备自身的发热监控加上 HVAC 系统里的风管和回风温度采集。这个组合实际跑下来之后我发现最难处理的并不是“把温度读出来”而是“本地温度和远程温度放在同一套系统里怎么保证两边都测得准、跑得稳”。PJ85718DM 负责把温度信号变成数字量STM32F745VG 负责把这些数字量变成控制逻辑和上报数据两个器件各管一段分工很明确。这篇文章我尽量把整套方案讲完整从需求拆解到硬件连接再到固件实现和现场调试踩坑适合正在做嵌入式测温、HVAC 控制器或者想了解本地/远程双通道测温方案的朋友参考。1. 先把需求聊清楚本地温度和远程温度到底差在哪1.1 一个芯片管两个温度是怎么做到的很多人第一次看到“本地温度”和“远程温度”这对说法会觉得是不是一个传感器在设备里面、一个在设备外面这么简单。实际上在 PJ85718DM 这类温度采集前端的设计里概念要更具体本地温度指的是芯片自己所在位置的温度通常是 PCB 板级环境温度远程温度则是芯片通过外部引脚连接到一个远端测温元件后测量到的那个元件所在位置的温度。远程测温元件最常见的是二极管或者三极管的 PN 结因为 PN 结正向压降和温度之间有稳定的对应关系大约在 -2mV/°C 左右。PJ85718DM 内部会有一个恒流源把这个电流加到外部 PN 结上然后通过测量压降变化换算温度。这个方案的优点是远端元件非常便宜、体积小、响应快可以用很细的引线拉到几十厘米甚至几米外的地方特别适合 HVAC 里测风管温度、盘管表面温度这类场景。本地和远程两个通道放在同一个芯片里好处是显而易见的成本低、校准简单、时序统一。系统只需要通过 I2C/SMBus 接口访问 PJ85718DM就能同时拿到两个温度读数不用额外挂两块独立的传感器芯片。实际做产品的时候这能省掉不少布板面积和物料成本。1.2 嵌入式和 HVAC 对测温到底提了什么要求嵌入式设备里的温度监测核心是保护和工作点补偿。比如 STM32F745VG 跑在 216MHz 的时候芯片自身发热不小如果机箱散热做不好内部温度一路飙升虽然芯片有热保护但等你触发热保护的时候系统已经处于异常状态了。因此本地温度要能提前预警比如 85°C 报警、95°C 强制降频这种阶梯式策略在电源类产品里非常常见。HVAC 场景则完全是另一个路数。空调箱、新风机组、冷冻水管路温度变化不是一蹴而就的系统更关注的是稳定性和绝对精度。回风温度、送风温度、盘管出风温度这些点位的读数要能长期稳定误差控制在 ±0.5°C 以内并且要能及时反映温度趋势供 PID 或者滞回控制逻辑使用。远程温度通道在这里的价值就是能做多点布测让控制逻辑真正基于“现场温度”而不是“控制板温度”。说到这里你会发现两个场景对温度数据的要求其实略有冲突嵌入式保护看重响应速度和绝对阈值HVAC 看重长期稳定和平滑趋势。而本地/远程双通道方案刚好能同时覆盖这两类需求这也是我选这套芯片组合的原因之一。2. 硬件方案PJ85718DM 和 STM32F745VG 怎么搭2.1 板级最小系统与供电细节STM32F745VG 是 STM32F7 系列里很有代表性的一颗料ARM Cortex-M7 内核主频最高 216MHz带双精度硬件浮点Flash 和 SRAM 的容量对这类中大型嵌入式应用非常充足。选它而不选价格更低的 F1/F4主要是两个原因一是 F7 的硬件浮点让滤波和 PID 运算非常轻松Cortex-M4 虽然也有 FPU但 F7 在双精度和总线上更强二是 F7 系列的 I2C 外设对 SMBus 支持更完整和 PJ85718DM 这类 SMBus 风格的芯片对接更省心。最小系统的连接很简单STM32F745VG 的 PB8/PB9 可以复用为 I2C1接到 PJ85718DM 的 SCL/SDA配好 8MHz 外部晶振和 3.3V 供电SWD 调试口拉出来。PJ85718DM 的电源最好单独用一颗 LDO 或者磁珠加电容隔离不要直接裸挂在 24V 转 3.3V 的电源输出上。原因是 HVAC 设备里常有变频器、风机、电磁阀等干扰源电源线上的毛刺很容易通过传感器串进温度读数里。芯片的地址引脚要仔细处理。PJ85718DM 一般会有 AD0 之类的地址选择脚如果不接默认地址也可能被内部下拉固定住最好按参考设计接一个 10kΩ 电阻到地让地址状态确定。我习惯把地址脚用 0Ω 电阻接到 VCC 或者 GND这样量产后还能通过改电阻换地址方便同一条 I2C 总线上挂多颗芯片。2.2 远端传感器接口的接线规则远程温度通道是最容易翻车的部分。PJ85718DM 的远程测温引脚通常是两根线一根接二极管的阳极/三极管的发射极另一根接阴极/基极。很多人以为远程测温就跟量一个普通电阻一样随便拉两根杜邦线就完事结果读数要么跳得厉害要么偏移好几度。接线时要记住三个要点远程引线必须双绞最好带屏蔽。双绞能抑制共模干扰屏蔽层单端接地不要把屏蔽层接在传感器引脚上。引线长度要看芯片手册的推荐值一般一两米以内问题不大超过三米就要额外考虑电容补偿。线缆电容会影响恒流源的建立时间和压降采样精度导致远端读数偏慢、偏小。传感器引脚上可以并联一个小电容典型值是 100pF 到 1nF用来滤高频干扰。但电容不能太大否则测量稳定时间会变长。还有一个经常被忽略的点远程二极管的漏电流。如果用了便宜的二极 SST 管三极管接成二极管它的漏电流在高温下会明显增大导致 PJ85718DM 测出来的温度偏低。我一般宁可多花几毛钱选低漏电流的型号也不愿意在高温标定环节为了非线性补偿头疼。3. 固件开发从初始化到稳定读到温度3.1 用 CubeMX 把外设配完STM32 开发用 STM32CubeMX 生成初始化代码已经是常规操作了这里重点说几个容易配错的地方。I2C1 的模式选择 I2C速度可以选 Fast Mode即 400kHz。PJ85718DM 这类芯片的 SMBus 时序要求里通常会有最小的 SCL 低电平时间和建立保持时间要求而 STM32 的 I2C 外设自己会处理大部分时序细节我们只需要把 clock speed 设置正确就行。打开 I2C 中断并配置一个定时器用于周期轮询。PJ85718DM 是主从结构所有测温动作都由主机发起所以我不建议用忙等阻塞方式读温度在实时性要求比较高的工程里配合定时器和状态机来读取会更稳。代码框架大致是这样// 每 500ms 由定时器触发一次温度采样请求 void TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM6) { temperature_poll_flag 1; } } void TemperatureTask(void) { static uint8_t step 0; if (!temperature_poll_flag) return; temperature_poll_flag 0; switch (step) { case 0: PJ85718DM_ReadLocalTemp(); // 启动读本地温度 step 1; break; case 1: PJ85718DM_ReadRemoteTemp(); // 启动读远程温度 step 0; break; } }配置 UART 的时候记得把 DMA 加上。HVAC 系统里温度数据要往触摸屏或者上位机上报如果每帧都用阻塞发送主循环的实时性会被拖得很差。DMA 发送加空闲中断接收是省心组合。3.2 驱动层读写流程PJ85718DM 的操作本质上就是 I2C 地址加寄存器读写但不同厂商的芯片在寄存器定义上有差异我写驱动的时候习惯先读一下芯片的 ID 寄存器确认 I2C 通信正常再去操作后面的配置寄存器。这是很基础但很有效的自检步骤能直接避开“软件看半天结果硬件没焊接好”的低级问题。固件里建议按这种层次来组织typedef struct { float local_temp; // 本地温度单位 °C float remote_temp; // 远程温度单位 °C uint8_t fault_flags; // 故障标志 } TempData; TempData g_temp;每次读取之前先写配置寄存器设置转换分辨率。PJ85718DM 这类芯片通常提供 9 到 12 位分辨率可选我一般选 12 位因为 HVAC 应用对瞬时响应要求不高多出来的转换时间可以接受。转换完成后从温度数据寄存器读出原始值再根据分辨率换算成实际温度。温度原始值一般是 16 位有符号数最高位是符号位。如果不处理负数冬季在北方现场测试的时候零下温度会变成很大的正数控制逻辑会直接乱套。换算公式类似float ConvertRawToCelsius(int16_t raw, float resolution) { return raw * resolution; }分辨率等于每个 LSB 对应的摄氏度数12 位模式通常是 0.0625°C/LSB。3.3 温度换算与滤波滤波这块我要多说几句因为很多嵌入式工程师容易走极端。一种是完全不过滤读数毛刺多到没法看另一种是滤波过度温度变化七八分钟都反映不出来HVAC 的 PID 根本没法用。对于 HVAC 这种时间常数很大的对象我推荐两级滤波第一级是中值滤波窗口取 5 个点用来剔除偶发的尖峰干扰。尖峰通常来自继电器吸合、变频器启动这些瞬态事件中值滤波能在保留温度突变的前提下把尖峰干掉。第二级是一阶低通滤波时间常数 10 到 30 秒之间用来平滑传感器本身和 ADC 量化带来的小抖动。代码很简单float LowPassFilter(float input, float prev_output, float tau, float dt) { float alpha dt / (tau dt); return prev_output alpha * (input - prev_output); }这里面 tau 的选择很有讲究。如果这套系统用在精密空调控制上30 秒的 tau 会让曲线非常光滑但送风温度有阶跃变化时反馈速度会明显变慢。如果用在设备过热保护上我反而建议把 tau 调小因为保护逻辑需要尽快看到真实温度。我的做法是本地温度通道用短时间常数远程温度通道用较长时间常数两套滤波参数分开配。3.4 校准不校准的温度值只能算参考温度传感器出厂精度有限加上 PCB 布局、走线电阻、远程引线长短这些因素直接读出来的温度可能和真实值差 1°C 到 2°C。如果只是做保护逻辑可能够用但 HVAC 客户多数会要求 ±0.5°C 以内的偏差这就必须做校准。校准分两步第一步是单点偏移校准。把测温探头和参考温度计放在同一环境里等读数稳定后算出一个固定的 offset。这个 offset 主要纠正传感器本身的初始偏差和 PCB 走线误差。第二步是两点增益校准。分别在低温点和高温点做记录比如 10°C 和 50°C然后算比例关系。这一步主要纠正远端引线电阻带来的误差因为引线电阻对测量值的影响会随温度变化而变化。校准参数我建议存放在 STM32F745VG 的内部 Flash 或者外部 EEPROM 里做成一个校准结构体每台设备出厂时执行一次自动校准流程把参数写进去。这样即使同一批次的传感器个体差异较大固件也能通过校准参数把偏差拉回来。4. 把温度用起来HVAC 控制逻辑与远程上报4.1 基于本地/远程温度的 HVAC 控制框架温度读出来之后放哪都行但要做好就需要一套合理的控制框架。HVAC 里最常见的控制是回风温度或者送风温度控制用的是 PI/PID 或者滞回控制。滞回控制适合启停式的风机和电动阀逻辑简单可靠性高。写起来大概是#define HYSTERESIS_ON 24.0f // 目标温度上限°C #define HYSTERESIS_OFF 22.0f // 目标温度下限°C void HvacControl(float remote_temp) { if (remote_temp HYSTERESIS_ON) { CompressorOn(); } else if (remote_temp HYSTERESIS_OFF) { CompressorOff(); } }滞回控制的优点是抗抖但温度在目标值附近缓慢爬行的时候会看到很规律的开-停-开-停。如果项目要求舒适度更高就要上 PI 控制器。这里的 P 值要参考系统的热惯性来调HVAC 系统的滞后通常很大ideal值可能只有 1 到 3I 值要小否则系统会周期性震荡。本地温度在这个框架里扮演的角色更多是安全联锁。比如本地温度超过 90°C强制关掉加热器和变频器超过 80°C 的时候降低风机转速避免控制板过热。这两个逻辑要和 HVAC 温度控制完全独立防止控制逻辑死机之后安全逻辑也跟着失灵。4.2 远程上报Modbus 与 MQTT 的取舍HVAC 项目里远程上报通常有两种路线。一种是传统的楼宇自控协议比如 Modbus RTU 走 RS485另一种是物联网化上报比如 MQTT 走以太网/Wi-Fi。Modbus 路线适合直接接入现有楼宇管理系统现场工程师用触摸屏或者上位机组态软件就能看到温度值。STM32F745VG 有多个 UART挂一个 RS485 收发器把地址映射到 Modbus 保持寄存器里就行。映射方式建议做成 16 位整数温度值乘以 100 来保留两位小数这是自控领域最基本的约定上位机组态时不需要你额外解释。MQTT 路线则更现代适合做远程云监控。STM32F745VG 本身集成了以太网 MAC外部接一个 PHY 芯片就可以跑轻量级 IP 协议栈。温度数据以 JSON 格式发布到 MQTT Broker 上云端的图表和大屏直接订阅主题刷新。这里要注意的是 QoS 等级选择温度数据属于周期性状态量不是命令和控制用 QoS 0 就够了不需要重试机制否则在网络抖动时会产生大量积压数据。我实际做过一个设备本地温度和远程温度各占两个 Modbus 寄存器另加一个状态字寄存器里面放着传感器断线标志、转换失败标志、上下限越界标志。这样上位机可以在同一帧里同时拿到数值和健康状态不用等固件里慢慢对故障码。5. 调试实录10 个最常踩的坑5.1 常见问题速查表现象可能原因解决办法I2C 通信偶发失败上拉电阻太小或太大检查上拉值常用 2.2kΩ/4.7kΩ总线上只有一个主机时不要超过 10kΩ远程温度读数跳几度引线太长且没有双绞换屏蔽双绞线线径不小于 0.2mm²屏蔽层单端接地远程温度整体偏低 2°C远程引线电阻高补偿或缩短引线必要时做两点校准本地温度正常远程读数固定为负远程传感器未接或者接反检查 D/D- 极性未接时有的芯片会报负温度温度读数总是零I2C 寄存器没写对加读 ID 寄存器的自检确认驱动在正确的从机地址上通电瞬间温度异常电源不稳芯片供电上加 0.1µF 10µF 去耦避免共用模拟电源数值有周期性波动滤波不足或者靠近变频器加中值滤波检查传感器走线是否和功率线捆扎在一起低温段误差大于高温段未做两点校准用恒温槽分别标定低温点和高温点STM32 死机后 I2C 挂死总线低电平锁定主循环里做总线恢复或选用支持 SMBus 超时的外设配置和上位机值对不上数据格式不统一统一用 int16 或 float明确小数点位置和上位机工程师对齐协议表5.2 印象最深的一次现场问题有一次设备在现场调试远程温度读数总是每十几分钟跳一下幅度有七八度但本地温度始终正常。刚开始怀疑是 PJ85718DM 芯片本身的问题后来把远程引线换成屏蔽双绞线暂时好了结果第二天客户反馈还是跳。排查到最后发现现场有一条 220V 的电磁阀控制线和远程温度线走在同一个线槽里电磁阀是双向可控硅触发控制线里的电流变化率很高对温度线产生了严重的耦合干扰。哪怕把传感器引线换了屏蔽线屏蔽层如果没有专门接到保护地上高频干扰照样从芯线耦合进来。最后我让现场把所有温度线单独走槽和动力线至少离开 20cm问题才彻底消失。这件事给我的教训是现场干扰问题软件上只能缓解硬件抗干扰设计从一开始就要按最恶劣工况来做。等你到了现场再发现读数乱跳最棘手的往往不是代码而是已经排好的线。还有一个小技巧可以分享给经常调 I2C 的人如果发现总线上设备偶尔失联不要急着加延时或者 /ACK 重试先检查时钟拉伸和超时恢复逻辑。STM32 的 I2C 外设不是万能的把 SCL/SDA 配成开漏同时在主循环里定期检查总线状态一旦发现总线被拉死不释放就主动翻转 SCL 发送几个时钟脉冲让从机释放 SDA。这个“伪恢复”方法在机房现场救了我很多次比断电重启更快更稳。最后再提一句实际项目中的心得不要迷信高精度传感器就一定能测准温度PJ85718DM 加 STM32F745VG 这套方案本身就具备很好的精度潜力真正决定系统精度的往往是远端引线布线、电源噪声和软件滤波策略。把这三样处理好了±0.5°C 并不难处理不好换再贵的芯片也无济于事。