最近在折腾一套双路温度采集方案:PJ85718DM 配 STM32L432KC,专门用来做嵌入式控制柜和 HVAC 设备的本地与远程温度监测。以前现场系统里测温这活儿比较粗糙——一块板子上放一颗热敏电阻,用 ADC 读个大概,够用就行。但这两年设备密度上来了,风管机、多联机、储能柜里的控制器全都开始要求严格温度上报,而且既要测设备本体温度,又要测远端关键点的温度,数据还要组网送上去做联动报警。这篇就把我从选型、画板到写驱动、调协议踩过的坑梳理一下,希望能帮到正在做同类项目的朋友。
1. 项目背景:为什么双路测温在嵌入式与 HVAC 中越来越刚需
1.1 两类场景的测温需求与共同痛点
嵌入式场景里,温度监测的对象往往很具体。比如控制柜里的开关电源、功率 MOS 管、电机驱动板,甚至 MCU 本身,都会在工作时持续发热。我们需要测的"本地温度",就是靠近这些热点区域的板级温度,用来做风扇转速调节、热降额保护和异常报警。而"远程温度"则是电池包极耳、充电口、箱体外壁这些分散位置的温度,这些点通常离主控板有一定距离,一根信号线拉过去是最常见的做法。
HVAC 场景的结构有点类似,但逻辑更偏向系统控制。空调外机既要测电控盒内变频模块附近的温升,保证功率器件不超温,也要测回风温度、送风温度、盘管进出口温度,用来算过热度、做防冻保护或者除霜判断。后者的探头位置离主控板经常隔着风道、管路,距离三五米很常见。
两个领域的核心痛点其实是一模一样的:单点测温只能反映局部,覆盖不了多个关键工况点;如果每个点位都独立用一颗传感器,BOM 成本和布板面积都会翻倍,尤其是 HVAC 外机的电控盒,空间紧张到多放一颗 0603 电阻都要琢磨半天。这种情况下,一颗带本地加远程双通道的传感器就成了很自然的选择。
1.2 本地温度与远程温度的技术区分
本地温度和远程温度看上去只是测量位置不一样,实际上信号链差别很大。本地通道的感应元件就在芯片内部,几乎不受外部干扰影响,精度稳定,响应也快;远程通道的信号要经过芯片引脚、PCB 走线、接插件、线缆,最后才到外接感温元件,这一段路里的每一个环节都会引入误差和噪声。
所以设计的时候要把它们当两套问题来处理:本地通道要关心的是芯片供电质量和 PCB 热布局,远程通道要关心的则是线缆屏蔽、线阻、接触电阻和感温元件的安装工艺。响应速度上也有差异,远程感温元件本身有热质量,再加上线缆电容,整个通道的时间常数通常比本地慢好几倍。写软件的时候如果对两个通道用同样的滤波窗口,大概率会出现本地温度已经稳定了,远程温度还在慢慢爬的情况。
2. 选型思路:STM32L432KC 与 PJ85718DM 的搭配逻辑
2.1 主控选型:为什么用低功耗 Cortex-M4F
STM32L432KC 这颗料我在几个项目里都用过,它的定位很明确:低功耗、带 DSP 和 FPU 的 Cortex-M4F 核、80MHz 主频、256KB Flash 和 64KB SRAM。做温度采集这种活儿,性能绰绰有余,但好处是滤波算法、Modbus 协议栈、PID 控制这类代码都能跑得动,后续想扩展边缘计算也不至于要换平台。
低功耗能力是我选它的一个关键点。不少温度采集节点是电池供电的,尤其嵌入式的无线传感器,一节纽扣电池或者锂电池要用几个月甚至一年。L432KC 的 STOP2 模式电流可以做到 1µA 左右,动态运行功耗也非常低,做周期性的采样任务非常合适。另外一个加分项是它的通信外设很齐全,三路 UART、两路 I2C、两路 SPI,还有低功耗定时器 LPTIM,做定时唤醒不需要额外加芯片。
2.2 传感器选型:PJ85718DM 的双通道设计怎么用
PJ85718DM 是一颗数字温度传感器,I2C/SMBus 接口,最大的特点是同一颗芯片内集成了本地测温通道和远程测温通道。本地通道直接测量芯片自身温度,远程通道则通过引脚外接感温元件。
这种"一芯双通道"的设计理念其实源于服务器内存和 CPU 的温度监控,用来同时测主板环境温度和 CPU 内部温度。放到嵌入式板和 HVAC 主控板上,正好对应设备本体温度和远端关键点温度这两个需求。
使用上需要注意几点。首先,远程感温元件通常是一只二极管结构的东西,可能是 PNP 三极管的 BC 结,也可能是专用的温度二极管。芯片会给这个元件施加一个恒流激励,然后通过测量正向压降随温度的变化来换算温度。其次,PJ85718DM 的分辨率和转换周期是可配置的,HVAC 这种温度变化慢的场景不需要开最高分辨率,反而可以降低转换频率来省电。另外,芯片一般还带温度报警阈值寄存器,可以在芯片层面做高温报警,不用主控一直轮询。
2.3 三种测温方案横向对比
为了说明这套组合的价值,拿它跟两个常见方案对比比较直观:
| 方案 | 本地测温实现 | 远程测温实现 | 通信接口占用 | 模拟调理电路 | 整体复杂度 |
|---|---|---|---|---|---|
| 双通道数字传感器 | 芯片内置 | 外接感温元件 | 1 路 I2C | 不需要 | 低 |
| 两颗单点数字传感器 | 一颗传感器 | 另一颗传感器 | 2 路 1-Wire/I2C | 不需要 | 中 |
| MCU ADC 采集 NTC | ADC 通道加基准 | 另一路 NTC 加调理 | 2 路 ADC | 需要运放、偏置、校准 | 高 |
用两颗单点传感器最大的问题不是成本,而是两个通道的测量时刻不同步,软件要多花心思对齐;用 ADC 直接采 NTC 的麻烦在于校准,热敏电阻的 B 值离散性大,批量生产时每个探头都要单独标定。双通道数字传感器把这些都省掉了,接线少、软件统一、校准简单,很适合产品化。
3. 硬件电路实现:电源、I2C 与远程探头的实战细节
3.1 供电去耦与抗干扰设计
硬件设计第一步是电源。PJ85718DM 和 STM32L432KC 都工作在 3.3V,可以直接共用一个电源域,但 HVAC 设备里的大电机启动冲击、继电器通断,都会让 3.3V 电压出现跌落和毛刺,这种噪声对温度采集的影响非常大。
我的做法是:输入端先放一个 TVS 管做浪涌吸收,然后接 LC 滤波,比如 10µH 电感加 10µF 电容,把高频噪声挡在外面。TVS 的钳位电压选 5V 左右,不能选太紧的,否则继电器动作时的负压尖峰可能把 TVS 打穿。传感器电源引脚旁边放 100nF 和 1µF 两个去耦电容,远程通道引脚附近加 10nF 电容滤除高频干扰。这里要提醒一句,远程通道的滤波电容不能放太大,否则芯片给感温元件施加激励电流时,电容充电时间过长,转换结果会偏慢甚至不稳。
PCB 布局上,传感器不要放在 MOS 管、电感、变压器的正下方,这些器件工作时会产生磁场和热量,直接影响测量精度。如果板子空间实在紧张,可以在传感器下面挖掉一部分铜皮,减少热传导。
3.2 I2C 总线连接与多设备地址规划
I2C 总线连接是最容易踩坑的地方。PJ85718DM 的 I2C 地址通过 A0、A1 引脚配置,一般可以有四个可选地址,具体怎么编要看手册的地址表。设计的时候一定要列出全板的 I2C 设备地址表,防止传感器、存储器、IO 扩展芯片之间地址冲突。很多工程师画原理图的时候不查地址,样板回来才发现挂两个器件的地址一样,焊上去之后一个都读不到。
上拉电阻的选择跟总线上挂的设备数量和总线长度有关。我实测下来,3.3V 电平、总线只挂一两颗设备、线长小于 10cm 时,用 4.7kΩ 没问题;挂到四颗以上,或者走线较长,要换成 2.7kΩ 或者 2.2kΩ。忘了改上拉电阻的后果是总线上升沿变缓,400kHz 模式下通信不稳定,偶尔出现首字节错误,很难排查。
我习惯在 SDA 和 SCL 上各串一个 22Ω 的小电阻,位置靠近 MCU 引脚,这个电阻配合上拉可以抑止走线反射产生的振铃。调试时拿示波器看 SDA 波形,如果发现有过冲毛刺,优先调大这个串联电阻,而不是去改上拉,效果会更明显。
3.3 远程感温探头的接线与布线规范
远程探头是这套方案里最影响精度的部分。我的经验是第一版就按双绞屏蔽线设计,屏蔽层在主机侧单点接地。电缆长度在 1 米以内,直接接传感器引脚问题不大;超过 2 米,就必须考虑屏蔽和线阻了。
线缆线阻会造成温度偏高。因为芯片激励电流在线阻上会产生压降,芯片会把这一部分压降也当成感温元件的正向压降来处理,所以测出来的温度会偏高。应对办法有两个:一是选低阻的线材,二是软件上做补偿,在批量校准的时候把线阻的影响算进标定系数里。另外,实际项目中如果感温元件和传感器之间要经过接插件,接插件要用镀金脚,氧化严重的接插件会产生接触电阻,导致读数漂移,而且这种漂移是间歇性的,非常难查。
探头的安装方式同样不能马虎。感温元件测的是元件本身的温度,而不是环境温度,所以安装时要用导热硅脂加金属卡簧,把它压贴在测点表面,不能只用普通胶带一粘了事。胶带的热阻太大,探头测出来的温度会比实际温度慢好几拍,尤其在风管送风温度控制这种对实时性有要求的场景里,这个问题会被完全暴露出来。
4. 软件架构:驱动、滤波、上报与低功耗四步走
4.1 初始化与 I2C 读取驱动
软件流程不复杂,但每一步都有讲究。第一步,配置时钟和 I2C 外设。在 STM32L432KC 上,我用 MSI 时钟配合 PLL 将系统时钟拉到 80MHz,然后初始化 I2C1,目标速率 400kHz。
hi2c1.Instance = I2C1; hi2c1.Init.Timing = 0x20404768; hi2c1.Init.OwnAddress = 0x00; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0x00; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; HAL_I2C_Init(&hi2c1);第二步,初始化传感器。上电后先延时 10ms 以上,让芯片内部振荡器稳定,然后写配置寄存器,选择连续转换模式和合适的分辨率。对于默认情况,我建议先读一次状态寄存器,确认芯片能正常响应,再往下走。
uint8_t config = 0x00; HAL_I2C_Mem_Write(&hi2c1, PJ85718DM_ADDR << 1, REG_CONFIG, I2C_MEMADD_SIZE_8BIT, &config, 1, 100);第三步,读取本地和远程温度。注意这类芯片的寄存器数据一般是高字节在前,把两个字节拼成 int16_t 之后,再乘上对应的分辨率值,就得到摄氏温度。
HAL_StatusTypeDef PJ85718DM_ReadBoth(float *local, float *remote) { uint8_t regs[4]; int16_t raw; if (HAL_I2C_Mem_Read(&hi2c1, PJ85718DM_ADDR << 1, REG_LOCAL_TEMP, I2C_MEMADD_SIZE_8BIT, regs, 4, 100) != HAL_OK) return HAL_ERROR; raw = (int16_t)((regs[0] << 8) | regs[1]); *local = raw * 0.0625f; raw = (int16_t)((regs[2] << 8) | regs[3]); *remote = raw * 0.0625f; return HAL_OK; }4.2 温度数据换算、滤波与校准
数据换算本身很简单,乘一个常数就行,但真正让数据可信的是后面的处理和校准。
滤波是第一个要考虑的。HVAC 风管里的温度本身就在缓慢波动,用滑动平均滤波就很合适,取 4 次平均,既能平滑气流扰动,又不会造成太大滞后。而工业现场有继电器、变频器等强干扰源,温度读数偶尔会出现一个明显的脉冲跳变,这种情况滑动平均压不住,要改用 3 点中值滤波,把最大值和最小值丢掉,取中间值。我一般会把两种滤波都实现出来,通过配置项切换。
校准是很多工程师容易跳过的一步。PJ85718DM 本地通道精度还不错,但远程通道经过线缆和感温元件之后,误差来源更多。批量生产时建议做两个温度点的标定,比如在 0℃ 和 50℃ 恒温槽里各测一次,算出偏移和增益系数,然后存进 Flash 或 EEPROM。注意一点,如果产品工作范围横跨制冷和制热两种工况,标定范围要覆盖整个量程,不要只在一个温度附近校准然后外推,外推的误差会成倍放大。
4.3 Modbus RTU 上报与报警逻辑
数据采集到之后要送出去。工业组网最通用、最不容易出问题的方案是 Modbus RTU,走 RS485 总线,一台主机可以挂几十个温度节点。温度值建议放到保持寄存器区,用 03 功能码来读,方便 PLC 和组态软件直接采集。
一个典型的 Modbus RTU 温度响应帧构造方式是这样的:
void Modbus_RTU_Temperature(uint8_t slave_addr, float local, float remote) { uint8_t frame[9]; uint16_t reg_loc = (uint16_t)((local + 40.0f) * 10.0f); uint16_t reg_rem = (uint16_t)((remote + 40.0f) * 10.0f); frame[0] = slave_addr; frame[1] = 0x03; frame[2] = 4; frame[3] = reg_loc >> 8; frame[4] = reg_loc & 0xFF; frame[5] = reg_rem >> 8; frame[6] = reg_rem & 0xFF; uint16_t crc = CRC16_Modbus(frame, 7); frame[7] = crc & 0xFF; frame[8] = crc >> 8; UART_Send(frame, 9); }这里把温度扩大 10 倍传输,避免浮点数在 Modbus 报文里传输的麻烦。报警逻辑我建议做两层:芯片内部有阈值寄存器,可以在硬件层面做第一级报警;主控再根据业务逻辑做一个迟滞比较,比如温度超过 75℃ 报警,降到 65℃ 才恢复,避免临界点反复抖动。
4.4 低功耗唤醒与外设恢复
如果这个节点是用电池供电的,低功耗策略就非常重要。我的设计思路是:LPTIM 每 10 秒唤醒一次 MCU,唤醒后做一次单次温度转换,读取数据后立刻回到 STOP2 模式。这样系统平均电流可以压到很低。
void Enter_LowPower(void) { while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY); HAL_SuspendTick(); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); SystemClockConfig_STOP(); HAL_ResumeTick(); MX_I2C1_Init(); }这段代码里有几个细节容易踩坑。首先是 STOP2 模式唤醒之后,系统时钟和 I2C 外设的时钟都丢了,必须重新配置时钟,然后重新初始化 I2C,否则第一次通信必然超时。其次是进入睡眠前要确认 I2C 没有正在传输的数据,不然总线会卡在忙状态。还有,如果传感器在睡眠期间还在上电工作,它的 SDA 引脚可能正拉着总线,唤醒之后要先释放总线再初始化,否则通信仍然起不来。
5. 现场问题排查与心得:几个典型的翻车点
5.1 I2C 地址配错与总线无响应
这是最常见的低级错误。现象是 HAL_I2C_Mem_Read 一直返回超时,示波器抓 SDA 能看到波形,但就是没有 ACK。
排查思路我整理成一个清单:
- 确认传感器地址有没有左移一位。HAL 库要求传 7 位地址左移后的 8 位地址,很多人直接把 0x48 传进去,结果读写位占错了位。
- 确认 A0、A1 引脚实际接法。芯片上拉、下拉接反了,地址就对不上。
- 量一下传感器供电引脚电压。有些芯片带使能引脚,忘了拉高就是完全没响应。
- 检查上拉电阻。如果是低温环境出问题,优先怀疑焊接不良或者电阻值挑得太大。
另外,如果 MCU 和传感器是分开供电的,一定要处理上电时序。传感器上电比 MCU 慢,MCU 启动后立刻去读传感器,大概率失败。解决方法是初始化前加一个 200ms 延时,或者在驱动里做两次重试,第二次基本就成功了。
5.2 远程温度跳变与漂移
远程温度读出来不稳定,甚至明显偏离实际值,这通常是现场返修率最高的一个问题。
我碰到过几种具体情况。第一种是读数周期性跳变,幅度有零点几度甚至一度,这种绝大多数是远程线缆和动力线走了同一个线槽,耦合了共模干扰。解决办法是把屏蔽层单端接地,并且尽量让信号线和动力线分开走。第二种是读数整体偏高,这种多半是线阻和接触电阻造成的,尤其是经过了氧化了的接插件。第三种是温度上不去也下不来,响应特别慢,这种基本就是探头的安装工艺问题了,热阻太大,感温元件没能跟测点形成良好热接触。
调试的时候有一个很实用的小技巧:在传感器远程引脚附近并联一个 1nF 电容,先看读数噪声是否下降。能降下来,说明是高频干扰,加强屏蔽即可;如果噪声没变化,那就要检查电源纹波和探头接触了。
5.3 低功耗唤醒后通信失效
低功耗模式下的 I2C 恢复问题,我在前文提到过,这里再展开说。现象是设备跑一段时间后,温度数据就不更新了,看门狗复位之后又能正常工作一段时间,然后再次卡死。
根因几乎都在于 STOP 模式唤醒后没有把 I2C 外设重新初始化干净。有些人只调用 HAL_I2C_Init,但忘了先 DeInit,外设状态机还停留在之前的状态,通信就一直失败。
我的建议是唤醒之后按这个顺序做:重新配置系统时钟,调用 HAL_I2C_DeInit,再调用 HAL_I2C_Init,然后读一次传感器状态寄存器做自检。如果读不到,就再用 GPIO 模拟一个 I2C 停止条件释放总线。把这个流程做成一个独立的"外设恢复函数",所有睡眠唤醒路径都统一走它,会比在每个地方手工初始化可靠得多。
5.4 批量安装时的地址冲突与探头布局
批量生产时最容易出现的是地址冲突问题。如果一台设备上有多个 PJ85718DM,设计时没有规划好 A0、A1 的跳线设置,产线装配时稍微接错一根线,整机就有一路温度读不到或者读到同一个数值。
我的经验是方案阶段就定死地址分配表,每个传感器模块出场前把地址写清楚,整机装配后做一次 I2C 总线扫描,确认挂载数量和地址列表跟设计一致再往下走。
探头布局方面,批量安装时还要注意探头的固定方式是否统一。同一个型号的设备,如果有的探头用卡簧,有的用胶带绑,实测温度能差出好几度。所以探头安装工艺一定要写进作业指导书,用什么样的导热介质、用多大的力矩拧卡簧,都要标准化。
一套方案落地后的几点实在体会
这套 PJ85718DM 加 STM32L432KC 的方案,我从最小系统飞线验证,一路做到带 RS485 和无线模块的完整采集节点,中间改了三版硬件。最大的体会是:数字传感器确实把模拟调理电路省掉了,但远程通道的线缆和接插件,还是得当成模拟信号来做,屏蔽、线阻、滤波一个都不能省。另外一个容易被低估的点就是低功耗唤醒后的外设恢复,软件上多写几行恢复逻辑,能省掉现场大量返修工作量。如果你正在做类似的双路测温项目,第一版就把 I2C 地址规划、远程线缆屏蔽和上电时序这三件事定死,后面的开发会顺利很多。