
1. 从一个真实需求说起为什么本地与远程温度要同时盯做嵌入式温控项目的人迟早会碰到一个绕不开的场景设备本身的温度要测设备外部的环境温度也要测而且这两路数据得同时进系统还得能远程看。比如一套 HVAC 控制板板载的功率器件温度决定了风扇要不要提速而房间里的环境温度决定了压缩机要不要启停。这两路温度如果只测一路系统要么反应迟钝要么频繁误动作。我最早接触这类需求是在一个恒温箱控制项目上当时只用了 MCU 内部温度传感器结果发现读数跟实际环境差了七八度原因是芯片自发热严重干扰了测量。后来换成外置数字温度传感器本地和远程各挂一路问题才解决。这个经历让我意识到本地温度监测和远程温度监测在硬件选型、通信协议、数据处理上完全是两套逻辑不能混为一谈。这篇内容围绕 PJ85718DM 和 STM32L4A6RG 这套组合展开讲清楚怎么把本地温度板载、靠近热源和远程温度通过传感器延伸出去同时采回来怎么处理数据怎么保证精度以及在实际布线和代码层面容易踩的坑。适合正在做 HVAC 控制、工业数据采集、嵌入式环境监测的开发者参考也适合刚接触 STM32 外设驱动、想找一个完整温度监测案例练手的朋友。核心思路不复杂STM32L4A6RG 作为主控负责采集、处理、上报PJ85718DM 作为远程温度传感前端通过数字接口把远端温度传回来本地温度则用 MCU 自带传感器或板载数字传感器获取。难点在于两路数据的同步、校准、抗干扰以及低功耗场景下的采样策略。2. PJ85718DM 与 STM32L4A6RG 的角色分工2.1 PJ85718DM 在温度链路里到底干什么PJ85718DM 是一颗远程温度传感器接口芯片它的核心能力是把远端测温器件通常是二极管接法的三极管或专用热敏元件的微弱模拟信号转换成数字量。远端测温的原理基于半导体 PN 结的电压与温度呈线性关系芯片内部通过切换不同电流源、测量两次正向压降差来消除串联电阻带来的误差。这个“电流切换差分测量”的机制是远程测温精度的关键也是它比普通热敏电阻方案更稳的原因。在实际接线中PJ85718DM 的远程测温通道通常接一个低成本的三极管比如 MMBT3904把基极和集电极短接用发射结作为测温元件。这个三极管可以贴在离主控很远的发热点上比如 HVAC 系统的风道内壁、压缩机外壳、换热器表面。芯片和测温点之间用双绞线连接长度可以做到几米甚至十几米这是本地传感器做不到的。注意远程测温三极管的走线必须用双绞线且尽量远离功率开关节点。我见过一个案例测温线跟电机驱动线捆在一起走读数跳变超过 5 度分开走线后立刻稳定。2.2 STM32L4A6RG 为什么适合做这个主控STM32L4A6RG 是 STM32L4 系列里的高配型号Cortex-M4 内核带 FPU主频 80MHz1MB Flash、320KB SRAM外设资源对温度监测来说绰绰有余。选它主要看中三点一是低功耗模式丰富Stop 2 模式下电流只有微安级适合电池供电或能量收集场景二是 I2C、SPI、UART 接口齐全跟 PJ85718DM 对接灵活三是内部温度传感器精度虽然一般但经过出厂校准后可以做到正负 1.5 度以内做本地温度参考够用。更重要的是L4A6RG 带硬件 I2C 滤波和模拟看门狗在 HVAC 这种电磁环境复杂的场合能减少通信误码。我实测过同样走线条件下带滤波的硬件 I2C 比软件模拟 I2C 的误码率低一个数量级。2.3 两路温度的分工与数据流整个系统的数据流是这样的远程测温三极管 - PJ85718DM 模拟前端 - 数字接口 - STM32L4A6RG本地温度 - MCU 内部传感器或板载数字传感器 - STM32L4A6RG。MCU 把两路数据做校准、滤波、单位换算然后通过 UART 或无线模块上报给上位机。这里有个设计取舍PJ85718DM 和 MCU 之间用 I2C 还是 SPII2C 省引脚但速率低、抗干扰弱SPI 速率高、全双工但占引脚多。对于温度这种慢变量I2C 的 100kHz 或 400kHz 完全够用所以我一般优先选 I2C把 SPI 留给显示屏或高速 ADC。3. 硬件连接从原理图到 PCB 的实操细节3.1 远程测温通道的元件选型与计算远程测温三极管的选择有讲究。MMBT3904 是最常见的便宜、好买但它的发射结压降随温度变化的斜率约 -2mV/度PJ85718DM 内部 ADC 的分辨率要能分辨这个变化。假设芯片的远程测温分辨率是 0.125 度对应电压分辨率就是 0.25mV这对 ADC 的噪声要求很高。所以 PCB 布局时测温三极管的走线要尽量短且远离 DC-DC 开关节点。串联电阻的选择也影响精度。远程测温通道通常需要串联一个电阻来限制电流典型值在 1k 到 10k 之间。电阻太大会引入热噪声太小则功耗增加。我一般用 2.2k配合双绞线分布电容形成的时间常数在微秒级对温度这种慢信号没有影响。3.2 I2C 总线的上拉电阻与滤波电容I2C 总线的上拉电阻取值直接决定通信稳定性。STM32L4A6RG 的 I2C 引脚在 3.3V 供电下上拉电阻一般取 4.7k。如果总线电容较大走线长、挂载设备多要减小到 2.2k 甚至 1.5k。我遇到过一块板子上拉用了 10k结果 400kHz 下波形上升沿太缓通信时好时坏换成 2.2k 后彻底稳定。滤波电容方面I2C 的 SDA 和 SCL 对地各接一个 100pF 电容能有效抑制高频干扰。但电容不能太大否则会拖慢上升沿。100pF 是个折中值实测对 400kHz 通信没有明显影响但能滤掉几十兆赫兹的毛刺。3.3 电源与地去耦的实战经验PJ85718DM 的供电质量直接影响测温精度。它的模拟部分对电源纹波很敏感所以 VDD 引脚旁边必须放一个 0.1uF 陶瓷电容再并一个 10uF 钽电容。这两个电容要尽量靠近芯片引脚回路面积越小越好。地平面处理上模拟地和数字地要分开铺最后在芯片下方单点连接。我见过一个设计模拟地和数字地混在一起结果远程测温读数每隔几秒跳一次查了半天才发现是数字开关噪声串进了模拟通道。分开铺地后跳变消失。提示如果 PCB 空间允许在 PJ85718DM 的远程测温输入引脚旁边再放一个 1nF 到 10nF 的电容到地能进一步滤除射频干扰。这个电容对测温精度没有影响因为温度信号带宽极低。4. 固件实现初始化、采样与数据融合4.1 STM32L4A6RG 的 I2C 外设初始化STM32L4A6RG 的 I2C 初始化用 HAL 库比较省事但要注意几个关键参数。时钟速度设为 400kHz占空比用 2:1模拟滤波器使能数字滤波器系数设为 0 到 15 之间的值。我一般设 8能滤掉大部分尖峰噪声。hi2c1.Instance I2C1; hi2c1.Init.Timing 0x10909CEC; // 400kHz, 3.3V hi2c1.Init.OwnAddress1 0; hi2c1.Init.AddressingMode I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 0; hi2c1.Init.OwnAddress2Masks I2C_OA2_NOMASK; hi2c1.Init.GeneralCallMode I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(hi2c1);Timing 寄存器的值不是随便填的它跟 I2C 时钟源频率、上升时间、下降时间都有关。STM32CubeMX 能自动算但如果你手动改时钟树记得重新生成。我习惯用 CubeMX 配好后再把代码抠出来避免手算出错。4.2 PJ85718DM 的寄存器配置与读取PJ85718DM 内部有一组配置寄存器和数据寄存器。上电后先写配置寄存器设置测温通道、分辨率、采样速率。然后启动转换等待转换完成标志再读数据寄存器。数据通常是 16 位高字节在前低字节在后需要拼成有符号整数再乘以分辨率。uint8_t cfg[2] {0x01, 0x60}; // 配置远程通道12位分辨率 HAL_I2C_Master_Transmit(hi2c1, PJ85718DM_ADDR1, cfg, 2, 100); uint8_t raw[2]; HAL_I2C_Master_Receive(hi2c1, (PJ85718DM_ADDR1)|1, raw, 2, 100); int16_t temp_raw (int16_t)((raw[0]8) | raw[1]); float remote_temp temp_raw * 0.0625f; // 假设分辨率0.0625度这里的分辨率系数要根据实际配置来定不同分辨率对应的 LSB 权重不同。12 位时通常是 0.0625 度9 位时是 0.5 度。配置错了温度会差好几倍。4.3 本地温度传感器的校准与补偿STM32L4A6RG 内部温度传感器的出厂校准值存在系统存储区读取后按公式换算。但出厂校准是在特定条件下做的实际使用中芯片自发热会导致读数偏高。我的做法是在系统空闲、功耗最低时采一次内部温度跟一个已知环境温度对比算出一个偏移量后续测量都减去这个偏移。// 读取出厂校准值 uint16_t ts_cal1 *(uint16_t*)0x1FFF75A8; uint16_t ts_cal2 *(uint16_t*)0x1FFF75CA; float vsense (float)ADC1-DR * 3.3f / 4095.0f; float local_temp (vsense - ts_cal1) / (ts_cal2 - ts_cal1) * 80.0f 30.0f;这个公式里的 30 和 80 是校准点对应的温度值不同型号可能不同一定要查对应型号的参考手册。我见过有人直接抄别的型号的公式结果温度差了二十度。4.4 两路数据的融合与上报策略两路温度采回来后不能直接上报原始值。我的做法是先做滑动平均滤波窗口大小取 8 到 16既能平滑噪声又不至于响应太慢。然后判断两路温度的差值如果差值超过阈值比如 10 度说明可能有一路传感器故障触发报警。最后按固定周期通过 UART 上报格式用简单的 ASCII 或二进制协议。#define FILTER_WINDOW 8 float remote_buf[FILTER_WINDOW]; float local_buf[FILTER_WINDOW]; // 滑动平均 float remote_avg 0, local_avg 0; for(int i0; iFILTER_WINDOW; i){ remote_avg remote_buf[i]; local_avg local_buf[i]; } remote_avg / FILTER_WINDOW; local_avg / FILTER_WINDOW;上报周期根据应用定。HVAC 里温度变化慢1 秒上报一次足够。如果是快速保护场景可以缩短到 100ms但功耗会增加。5. 精度与抗干扰那些文档里不会写的坑5.1 远程测温三极管的布局陷阱三极管的放置位置比选型更重要。我做过一个对比实验同样一颗 MMBT3904贴在发热体表面用导热硅胶固定跟悬空在旁边 5mm 处读数差了 12 度。所以测温元件必须跟被测表面紧密接触最好用导热胶或金属夹片固定。另外三极管的引脚不能太长。引脚越长引入的热阻越大响应越慢。如果必须延长用铜箔包裹引脚并接地能减少电磁干扰。5.2 I2C 通信误码的排查链路I2C 误码是这类项目最常见的故障。排查顺序我一般这样走先用示波器看 SDA 和 SCL 波形确认上升沿是否够陡、电平是否干净然后查上拉电阻和总线电容再查地址是否冲突最后查电源纹波。有一次我遇到通信随机失败查了两天最后发现是 PJ85718DM 的供电引脚虚焊补焊后一切正常。注意如果 I2C 总线上挂了多个设备地址冲突会导致通信完全失败。PJ85718DM 的地址通常可以通过引脚配置布线时要把地址引脚拉高或拉低不要悬空。5.3 低功耗模式下的采样时序STM32L4A6RG 在 Stop 2 模式下I2C 外设会停止工作。如果要用低功耗必须用定时器唤醒唤醒后重新初始化 I2C采样再进低功耗。这个过程的时间开销在毫秒级对温度监测来说可以接受。我实测过用 RTC 每 10 秒唤醒一次采样两路温度然后继续睡平均电流不到 10uA。如果用 2000mAh 电池供电理论续航超过 20 年当然实际受电池自放电限制。5.4 温度跳变的软件滤波技巧除了滑动平均还可以用中值滤波剔除突发尖峰。具体做法是连续采 5 次排序后取中间值。这个方法对脉冲干扰特别有效但会增加采样时间。我一般把中值滤波和滑动平均结合先中值滤波去尖峰再滑动平均平滑。float median_filter(float *buf, int n){ // 简单冒泡排序 for(int i0; in-1; i) for(int j0; jn-1-i; j) if(buf[j] buf[j1]){ float t buf[j]; buf[j] buf[j1]; buf[j1] t; } return buf[n/2]; }这个函数虽然简单但在资源紧张的 MCU 上够用。如果采样频率高可以考虑更高效的排序算法。6. 远程监测的扩展从本地串口到网络上报6.1 串口协议的设计与解析本地和远程温度数据最终要送到上位机或云端。最直接的方式是用 UART 转 USB接到电脑上。协议我一般用简单的帧格式帧头 0xAA 0x55长度字节命令字数据区校验和。校验和用累加和或 CRC8能过滤掉大部分传输错误。void send_temp_frame(float local, float remote){ uint8_t frame[12]; frame[0] 0xAA; frame[1] 0x55; frame[2] 8; // 长度 frame[3] 0x01; // 温度数据命令 memcpy(frame[4], local, 4); memcpy(frame[8], remote, 4); uint8_t sum 0; for(int i0; i12; i) sum frame[i]; frame[12] sum; // 实际帧长13这里示意 HAL_UART_Transmit(huart1, frame, 13, 100); }上位机收到后按同样格式解析就能拿到两路温度。如果要做远程监测把 UART 换成无线模块或以太网模块协议不变。6.2 无线模块的选型与对接无线上报可选方案很多短距离用蓝牙或 Zigbee长距离用 LoRa 或 NB-IoT。选型主要看距离、功耗、数据量。温度数据量极小每秒几十字节所以低速率方案完全够用。LoRa 在空旷环境能传几公里功耗也低适合 HVAC 设备分散部署的场景。对接时注意电平匹配。STM32L4A6RG 是 3.3V 电平有些无线模块是 5V tolerant但反过来不一定。如果模块是 5V 供电TX 输出 5V 电平直接接 MCU 的 RX 可能损坏引脚必须加电平转换。6.3 数据上云的轻量级方案如果要把数据传到云端最轻量的方式是 MQTT。STM32L4A6RG 跑 MQTT 客户端有点吃力但配合 ESP32 或类似模块做透传MCU 只管发串口数据模块负责联网和协议封装这样分工最合理。我一般让 MCU 每 10 秒发一帧温度数据模块收到后转发到 MQTT 主题云端订阅后存数据库或展示曲线。提示MQTT 的 QoS 等级选 0 就行温度数据丢一两帧无所谓选 1 或 2 会增加开销和延迟。7. 实测数据与长期运行观察7.1 精度对比PJ85718DM 与板载传感器我在一个恒温箱里做了对比测试温度从 10 度升到 60 度每隔 10 度记录一次。PJ85718DM 配 MMBT3904 的远程读数与标准温度计偏差在正负 0.5 度以内STM32 内部传感器偏差在正负 2 度左右。这个结果符合预期也说明远程测温方案在精度上确实有优势。温度点标准值PJ85718DM 读数STM32 内部读数10 度10.010.312.120 度20.020.221.830 度30.029.831.540 度40.040.141.950 度50.049.751.660 度60.060.262.3从表里能看出内部传感器在高温段偏差更大因为芯片自发热更明显。如果应用对本地温度精度要求高建议还是外挂一颗数字温度传感器比如常见的 I2C 接口型号精度能到正负 0.5 度。7.2 长期运行中的漂移与维护连续跑了三个月PJ85718DM 的远程读数漂移小于 0.3 度基本可以忽略。但三极管的导热胶老化会导致接触热阻变大响应变慢。如果设备工作在振动环境建议用金属夹片固定比胶水可靠。另外I2C 总线的上拉电阻长期工作在高温下会阻值漂移虽然影响不大但如果是高可靠性场景选低温漂的电阻更稳妥。7.3 故障模式与恢复策略最常见的故障是 I2C 通信超时。我的处理策略是连续 3 次读取失败后重新初始化 I2C 外设再试。如果还失败上报故障标志让上位机决定是否重启设备。这个策略在实际运行中救过好几次场有一次是总线被静电干扰锁死重新初始化后恢复。if(HAL_I2C_Master_Receive(hi2c1, addr, raw, 2, 100) ! HAL_OK){ i2c_error_count; if(i2c_error_count 3){ HAL_I2C_DeInit(hi2c1); HAL_I2C_Init(hi2c1); i2c_error_count 0; } }这个简单的恢复逻辑比看门狗复位更温和不会丢失系统状态。8. 一些个人体会这套方案我从原型到量产改了三版最大的感受是远程测温的精度瓶颈不在芯片而在传感器安装和走线。PJ85718DM 本身的性能足够好但如果你把三极管随便一贴或者跟功率线捆在一起走再好的芯片也救不回来。另一个体会是低功耗和实时性要平衡。如果应用允许尽量把采样周期拉长既能省电又能减少噪声。温度是慢变量没必要每秒采几十次。最后I2C 的调试工具很重要。一个便宜的逻辑分析仪能省下大量猜测时间。我早期靠示波器看 I2C 波形效率很低后来用逻辑分析仪抓包一眼就能看出是地址错了还是数据错了。这个投入值得。