☰
基于PJ85718DM与STM32的双通道数字温度传感器设计
2026/10/22 6:45:40 网站建设 项目流程

做嵌入式控制板的朋友应该都有这种经历:一个系统里要同时测好几个温度点,而且这些点的位置往往不在同一块板子上。之前接手某 HVAC 控制器项目时,客户的要求其实很简单——控制板自身的环境温度要监控,风管里回风口的温度也要监控,两点之间大概隔了两米多的线距。我第一反应是老办法:两路 NTC 加 ADC,或者一根热电偶拉过去。但真正做起来才发现,NTC 要逐个标定,热电偶的信号又太弱,冷端补偿、放大、调理一套流程下来,工期和成本都压不住。后来换成 PJ85718DM 这颗带本地与远程双通道数字温度传感器,配一块 STM32L4S5ZI 做主控,一条 I2C 总线就同时拿下了本地和远端两个温度读数。这篇文章把硬件连接、固件读取、低功耗调度、校准方法以及调试过程中踩过的坑完整记录下来,给后面做类似嵌入式测温或 HVAC 项目的朋友做个参考。

1. 为什么要在 HVAC 里同时测“板子自身”和“远端风管”的温度

1.1 本地通道和远程通道分别盯的是什么

先说清楚“本地”和“远程”这两个概念。本地温度指的是传感器芯片所在 PCB 附近的温度,PJ85718DM 内部自带测温二极管,芯片通电后就能直接测出自身封装附近的温度。这个温度能反映控制板上电源模块、驱动器件、甚至 MCU 自身的发热情况,一旦板卡局部过热,最先报警的往往就是它。远程温度则完全不同,芯片通过 D+、D- 两个引脚外接一只二极管或三极管,利用 PN 结正向压降与温度的线性关系,把测温点延伸到传感器之外的地方。

在 HVAC 设备里,这种双通道结构非常实用。控制器主板一般装在电控盒里,而真正需要监测的是风口、盘管、压缩机回气管这些“冷源”或“热源”。例如回风温度可以用来判断过滤网是否堵塞,出风温度可以反映换热器工作状态,盘管温度则能直接看出制冷剂流量是否异常。这些点距离主控板常常有几米远,如果每个点都拉一根 NTC 回来,线缆成本和接插件数量都会翻倍;而用远程通道只需要一对信号线引到测温点附近的二极管上就行。

1.2 双通道数字测温方案对比热电偶和 NTC 的优势

很多工程师一看到“测温”就想到 NTC,因为便宜、常见、资料多。但 NTC 的问题是离散性大,批量生产时每个探头都要校准,而且长线传输时线路电阻会直接叠加到测量结果里,电源噪声也会通过分压网络进入 ADC,信号调理做起来相当啰嗦。热电偶虽然测温范围宽,但输出信号只有微伏到毫伏级别,需要精密放大器、冷端补偿和滤波电路,在小体积控制板里放这么一套模拟链路并不划算。

数字双通道温度传感器把这些麻烦都省掉了。PJ85718DM 内部完成电流激励、电压采样和 ADC 转换,直接通过 I2C 输出温度值,MCU 拿到的已经是数字量。远程通道虽然走的是二极管测温原理,但传感器内部对信号做了处理,线缆上的共模干扰大部分被滤掉。我把三条路线放在一张对比表里,优劣其实一眼就能看明白。

方案测温点位数长线抗干扰校准复杂度系统成本
NTC + ADC每点一路传感器差,线阻影响明显每个探头标定便宜但费工
热电偶 + 调理电路每点一路热电偶中等,需屏蔽需冷端补偿模拟链路成本高
PJ85718DM 双通道1 本地 + 1 远程较强,数字输出两点校准即可单颗芯片集成

对 HVAC 这种大量存在风机、继电器、变频压缩机的现场环境来说,数字输出本身就等于一层抗干扰能力。这也是我最后放弃 NTC 方案的根本原因。

2. PJ85718DM 与 STM32L4S5ZI 的硬件连接细节

2.1 最小系统与引脚分配

PJ85718DM 是一颗 I2C 接口的远程温度传感器,典型的引脚功能包括电源、地、SDA、SCL、地址引脚 A0/A1、报警输出 ALERT,以及远程测温用的 D+ 和 D-。我这次在主控板上用了 STM32L4S5ZI 的 I2C1 外设,SCL 和 SDA 分别接到 PB6、PB7,A0 和 A1 都接地,这样传感器的 7 位地址固定为 0x48,换算成 8 位写地址就是 0x90、读地址 0x91。如果你的板子上有多颗同型号传感器,可以用 A0/A1 的组合扩展出 4 个地址,具体以器件手册为准。

电源和上拉处理有几个细节值得注意。VCC 用 3.3V,旁边放 100nF 和 1µF 两颗电容并联去耦,电容尽量贴近芯片引脚。I2C 总线是开漏结构,必须外部上拉,STM32 内部虽然也能配置上拉,但阻值偏大,总线上挂了两颗芯片以后边沿变缓,所以外部加 4.7kΩ 上拉到 3.3V 更稳妥。ALERT 报警输出是开漏引脚,不使用时可以直接悬空或者接上拉;我习惯把它接到 STM32 的一个 GPIO 并配置成 EXTI 外部中断,这样温度超限时 MCU 能第一时间被唤醒,不用靠轮询。

I2C_HandleTypeDef hi2c1; void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.Timing = 0x20404768; /* 需要按实际 APB 时钟调整 */ hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } }

Timing 参数在 CubeMX 里配置 I2C 时钟时可以直接生成,手动填 0x20404768 的前提是 APB1 时钟是 80MHz、目标速率 400kHz。如果通信不稳定,优先检查这个参数,因为它直接决定了 SCL 高低电平时间,配错的表现往往是从机没有任何 ACK。

2.2 远程二极管的布线处理与抗干扰设计

远程通道的硬件连接是整个方案里最容易出问题的地方。二极管可以选用小信号三极管 2N3904,把集电极和基极短接当二极管用,基极集电极端接 D+,发射极接 D-,这样比直接用二极管电流能力更稳,β 参数也相对可控。注意晶体管的极性一定不能接反,否则远程通道读出来就是异常值。

布线方面,D+、D- 是所有信号线里抗干扰优先级最高的两条。我在这两条线上预留了 RC 滤波位置:D+ 串一只 4.7kΩ 电阻,D+/D- 之间并一颗 2200pF 电容,既能限制高频噪声电流,又能滤掉差分噪声。实际布线时让这两根线尽量贴在一起走,最好双绞或平行包地,不要穿过继电器、变压器、开关电源的功率回路。这个原则看起来简单,但在 PCB 布局紧凑时特别容易被忽略,后面调试跳变问题时有近一半的根因都出在这里。

3. 固件第一步:I2C 寄存器操作与温度计算

3.1 寄存器映射与 I2C 初始化

不同厂家的远程温度传感器寄存器地址不完全一样,但总体风格非常接近。PJ85718DM 上电后默认工作在连续转换模式,核心寄存器包括本地温度寄存器、远程温度寄存器、状态寄存器、配置寄存器、上限报警阈值 TOS 和回差阈值 THYST。基本操作流程就是先配置工作模式,然后周期读取两个温度寄存器。下面这张表是我按常见寄存器风格整理的,具体地址偏移量以器件手册为准。

寄存器典型地址说明
Local Temperature0x00本地温度,16 位左对齐
Remote Temperature0x01远程温度,16 位左对齐
Status0x02状态位,指示远程断路/短路
Configuration0x03转换模式、报警极性等
TOS0x06上限报警阈值
THYST0x07回差阈值

I2C 初始化完成后,建议先读一次状态寄存器确认芯片在线,再读取温度。这一步看起来多余,但批量生产时可以避免“板子焊完才发现传感器虚焊”的麻烦,也能在调试初期快速区分通信问题和器件问题。

3.2 本地/远程温度读取代码与转换公式

读取温度我用的是 HAL 库的HAL_I2C_Mem_Read,先指定要读的寄存器地址,再读两个字节。PJ85718DM 的温度数据格式是 16 位左对齐,低 4 位为无效位,实际有效数据是高 12 位,分辨率为 0.0625°C。把原始数据右移 4 位后得到有符号整数,再乘以 0.0625 就是浮点温度值。

float read_temperature(uint8_t reg_addr) { uint8_t buf[2]; if (HAL_I2C_Mem_Read(&hi2c1, 0x48 << 1, reg_addr, I2C_MEMADD_SIZE_8BIT, buf, 2, 100) != HAL_OK) { return NAN; } int16_t raw = (int16_t)((buf[0] << 8) | buf[1]); raw >>= 4; return (float)raw * 0.0625f; }

这里最容易被坑的是带符号数的处理。如果只把寄存器值当成无符号数,负温度时读出来的值会变成一个很大的正数,计算出的温度完全错误。HVAC 系统里不仅有夏天制冷,还有冷库、冬季新风预热等场景,远程测温点完全可能低于 0°C,所以必须用int16_t做符号扩展。如果手册标注的数据格式是右对齐的 13 位,那就不能右移 4 位,而是直接按比例换算。格式问题一定要以手册为准,我在这个细节上吃过亏。

3.3 报警阈值设置与 HVAC 中的回差设计

报警功能对 HVAC 设备来说不是可选项而是刚需,比如盘管温度过高可能意味着冷媒泄漏,电机温度过低可能意味着气流不足。设置超限报警的思路是:先写 TOS 上限,再写 THYST 回差。两者的差值决定了温度回落到多少度才解除报警。假如我把 TOS 设为 75°C、THYST 设为 70°C,那么温度升到 75°C 触发报警后,要回落到 70°C 以下报警才会解除。

void set_alarm_threshold(float tos_degc, float thyst_degc) { int16_t tos_raw = (int16_t)(tos_degc * 16.0f) << 4; int16_t thyst_raw = (int16_t)(thyst_degc * 16.0f) << 4; uint8_t tos_buf[2] = { (uint8_t)(tos_raw >> 8), (uint8_t)(tos_raw & 0xFF) }; uint8_t thys_buf[2] = { (uint8_t)(thyst_raw >> 8), (uint8_t)(thyst_raw & 0xFF) }; HAL_I2C_Mem_Write(&hi2c1, 0x48 << 1, 0x06, I2C_MEMADD_SIZE_8BIT, tos_buf, 2, 100); HAL_I2C_Mem_Write(&hi2c1, 0x48 << 1, 0x07, I2C_MEMADD_SIZE_8BIT, thys_buf, 2, 100); }

回差的意义在于防抖。如果阈值是 75°C、回差为 0,温度在 74.9°C 和 75.1°C 之间波动时,报警输出会不停翻转,带动外部继电器频繁吸合释放,触点寿命急剧下降。设置 5°C 左右的回差,不仅对继电器友好,也给控制系统留出了响应时间。

4. 低功耗采样与调度:让温度监测真正适合嵌入式设备

4.1 连续转换模式的功耗账

如果做的是 24V 供电的 HVAC 控制器,功耗压力不大,传感器一直开着连续转换完全没问题。但如果是电池供电的温控面板、无线传感器节点,或者需要满足待机功耗要求的设备,功耗账就得仔细算。PJ85718DM 在连续转换模式下,典型工作电流在数百微安这个量级。单独看确实不大,但在一个总电流预算只有几十微安的待机系统里,这部分占比会非常扎眼。

改用单次转换模式可以把平均功耗降一个数量级。原理很简单:平时传感器处于关断或空闲状态,MCU 需要读数时写一个启动位,等待转换完成后读走结果,然后继续休眠。采样周期越长,平均电流越低。对 HVAC 应用来说,回风温度和盘管温度的变化原本就很缓慢,1 秒采样一次已经绰绰有余,完全没有必要让传感器全速跑。

4.2 STM32L4S5ZI 的 STOP2 模式与 RTC 定时唤醒

STM32L4S5ZI 本身就是低功耗定位,带多路 RTC 闹钟和多种 STOP 模式。我采用的调度方案是:主循环平时进入 STOP2 模式,RTC 闹钟每 1 秒唤醒一次,唤醒后读取温度和报警状态,然后再次进入睡眠。这样整机功耗完全由唤醒频率决定。

void enter_sleep_and_wait(void) { HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_ALARM_A); __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); /* 唤醒后系统时钟会切换到低速源,必须重新配置 */ SystemClock_Config(); read_temperature_and_process(); }

唤醒后最容易被忽略的一步是重新配置系统时钟。STM32 从 STOP2 模式唤醒后,系统时钟会自动变成 MSI 低速时钟,如果直接接着跑 I2C,通信时序完全不对,表现就是读到的数据全是 0xFF 或者 HAL 超时。我最初做这个方案时踩过这个坑,后来在每次唤醒后的第一件事就放SystemClock_Config(),问题立刻消失。

4.3 读数滤波与异常值识别

远程通道温度读取偶尔会混入毛刺,比如风机启动瞬间的电磁干扰在某些场景下可以穿透滤波电容。轮询程序里加一个简单的滑动中值滤波,效果非常明显:每轮采集 5 次温度,排序后取中间值,能同时滤掉正向和负向的尖峰。

float median_filter(float samples[], int len) { /* 简单的选择排序,只排 5 个点即可 */ for (int i = 0; i < len - 1; i++) { for (int j = i + 1; j < len; j++) { if (samples[j] < samples[i]) { float tmp = samples[i]; samples[i] = samples[j]; samples[j] = tmp; } } } return samples[len / 2]; }

中值滤波比滑动平均更适合温度采样,因为温度本身是慢变量,滑动平均会让阶跃响应变钝,而中值滤波对真实台阶的响应几乎没有延迟。同时还要识别异常值:远程二极管开路或短路时,温度寄存器会读到接近满量程的极端值,程序里要判断读数是否超出物理范围,超了就直接丢弃并置一个通道故障标志,而不是把错误温度拿去控制风机阀门。

5. 精度校准:把远程通道的误差追回来

5.1 误差来源拆解:偏置电流、串联电阻与 β

任何远程温度传感器都有系统误差,只是大小不同。PJ85718DM 的远程测温原理是:芯片向 D+ 注入一个已知大小的偏置电流,流过外部二极管后测量正向压降 Vbe,再根据 PN 结电压与温度的近似线性关系反推温度。这个过程中存在三处主要误差:偏置电流本身的绝对值偏差、外部串联电阻产生的欧姆压降、以及外部晶体管 β 值引起的等效串联电阻变化。

串联电阻误差最典型。如果 D+/D- 走线很长,或者测温二极管本身带有较大的体电阻,芯片测到的电压就包含电阻压降,导致读数偏高。很多传感器为此提供了串联电阻补偿寄存器,通过一个偏移量修正这部分误差。有些芯片还支持 β 补偿和温度系数补偿,PJ85718DM 的具体特性以手册为准。但原理都是通用的:误差不是随机噪声,而是系统性偏移,可以通过校准消除。

5.2 两点校准操作流程

要校准远程通道,需要两个稳定且已知的参考温度点。最省事的做法是冰水混合物提供 0°C,恒温箱或精密恒温水槽提供 50°C。校准前先把远程测温二极管放入参考环境,等传感器读数稳定后记录下数值,得到两组数据:传感器读数 x_low/x_high,参考真实值 y_low/y_high。然后按两点式直线校准公式计算斜率和截距:

k = (y_high - y_low) / (x_high - x_low) b = y_low - k * x_low 校正值 = k * 传感器原始读数 + b

我实测过一批样机,校准前在 0°C 时偏差约 +2.1°C,50°C 时偏差约 +1.6°C,用两点校准后残余误差可以压到 ±0.3°C 以内。不过要说明的是,这一套流程主要适用于远程通道,本地通道本身精度已经够高,通常不需要额外校准。如果批量生产对精度要求不苛刻,比如只要求 ±1°C,完全可以省略校准流程,出厂测试中做一次抽样验证就好。

5.3 校准系数如何在固件里生效

校准得到的 k 和 b 不能写死在代码里,这样换一批板子又要改程序重编译。我建议把校准系数存储到内部 Flash 的最后一个扇区,或者外部 EEPROM,产品校准工装在校验完成后把系数写入,固件启动时读取并应用到所有远程温度读数上。

typedef struct { float k; float b; uint16_t crc; } cal_param_t; float apply_remote_calibration(float raw_temp) { cal_param_t cal; read_cal_param_from_flash(&cal); if (cal.crc == valid_crc) { return cal.k * raw_temp + cal.b; } return raw_temp; /* 没有校准数据时退回原始值 */ }

注意 Flash 擦写寿命有限,不要每次开机都写一次,一般只在出厂校准工装烧录时写。EEPROM 方案更灵活些,但产品成本会略微增加。我在实际项目中用的是内部 Flash,配合 CRC 校验,只要校验失败就自动忽略系数,避免因为 Flash 异常导致温度出现离谱偏移。

6. 调试实录:三个典型案例的完整排查链路

6.1 远程温度读数周期性跳变:噪声耦合

项目联调第一天,功能基本正常,但远程通道在风机启动后开始抽风:温度从 26°C 跳到 47°C,来回摆动,幅度夸张。一开始我怀疑是软件读寄存器时序问题,但把本地通道同时打印出来,本地完全稳定,说明 I2C 通信本身没问题,问题出在远程通道和外部环境的交互上。

接下来用示波器抓 D+/D- 的信号,发现风机一启动,线上就叠加了几百毫伏的高频共模脉冲。顺着 PCB 布线一查,D+/D- 有大概五厘米的走线从继电器输出线旁边经过,继电器触点动作时把噪声耦合了进来。处理方案做了两步:把 D+/D- 走线换到远离功率器件的位置,并给 PCB 增加了屏蔽地;同时在 D+/D- 之间加上 2200pF 差分电容,D+ 串联 4.7kΩ 电阻。改完后复试,风机启停和继电器反复动作的场景下,远程温度读数都不再跳动。这个案例给我的教训是:远程通道的滤波不是可选项,而是干扰环境下的必选项。

6.2 远程通道读数固定不变:二极管接线反了

第二块样机焊完后,本地温度正常,远程通道始终读到 0xFFFF 附近的极端值,而且完全不变。第一反应是芯片损坏,但换芯片后故障依旧,于是开始读状态寄存器,排错信息明确提示远程通路异常开路。

用万用表二极管档测 D+/D-,正反测量压降都不对,再对照 PCB 原理图检查,才发现某个批次贴片时把远程二极管的 D+ 和 D- 接反了。PN 结反接之后,传感器注入的偏置电流无法形成正常压降,通道就表现为开路。修正焊接后,远程温度恢复稳定。这个案例提醒我两点:第一,远程二极管极性在原理图和封装库阶段就要做防呆设计,比如引脚命名尽量直观;第二,批量生产时出厂测试一定要跑远程温度通道的自检,别只读本地温度,否则这类焊接问题很容易漏过去。

6.3 继电器动作瞬间 I2C 通信失败:地弹与走线干扰

第三个坑比较隐蔽。程序跑起来后大部分时间正常,但只要外部继电器吸合,I2C 通信就会偶发失败,故障灯闪一下,多试几次还会进入 HAL 超时。刚开始以为是 I2C 时序被长线拖慢,把速率从 400kHz 降到 100kHz 有所缓解,但没有根治。

用示波器同时抓 3.3V 电源轨和 SDA 信号,发现继电器吸合瞬间,3.3V 上出现幅度不小的跌落和毛刺,这就是典型的地弹效应。继电器线圈断电时产生反电动势,如果线圈两端没有续流二极管,反电动势会通过地回路干扰控制板电源,进而影响数字信号电平。检查原理图发现继电器驱动电路确实漏了续流二极管。补上 1N4007 之后,3.3V 电源毛刺明显消失,I2C 通信恢复稳定。作为加固,我又把 I2C 两条信号线包地处理,并将上拉电阻从 4.7kΩ 调整为 2.2kΩ,提高总线抗干扰裕量。

这类问题在 HVAc 设备里非常典型,因为继电器、接触器、压缩机是系统标配,功率回路和控制回路天然存在耦合路径。排查的时候不要一上来就怀疑芯片或代码,先看电源和地,再看走线布局,顺序对了,问题基本上都能快速锁定。

7. 这套方案的适用边界和我的一些补充建议

7.1 什么时候适合用,什么时候不适合

PJ85718DM 搭配 STM32L4S5ZI 的双通道测温方案,最合适的场景是:需要同时监控控制板自身温度和几个较近处的远端温度点,距离在几米以内,温度范围没有超出传感器覆盖区间,而且系统本身已经有 MCU 和 I2C 总线。这时候双通道传感器的优势最大,一颗芯片解决两个点,数字输出省掉模拟调理,开发周期明显缩短。

如果测温点数量很多,比如一台大型风柜要同时测十几个点的温度,双通道方案就不合适了。I2C 地址有限,地址线最多组合出几个地址,就算加 I2C 多路选择器,也需要额外代码管理。这种场景不如直接用多路数字传感器或者 1-Wire 总线的方案,一条总线挂几十个节点,系统结构更简单。如果测温距离超过几十米,数字 I2C 信号本身的传输距离上限就不够,可以考虑转成差分或无线方式,把数据先就地处理再上传。理解边界之后再做选型,才不会把路走窄。

7.2 如果重新做一遍,我在选型和设计中会改什么

回头复盘这个项目,有几件事如果再给我一次机会,我肯定会提前做。原理图阶段就把远程通道的滤波电阻电容、ESD 保护器件全部预留好位置,而不是等到调试时再飞线补;ALERT 中断引脚从一开始就接入 MCU,而不是先轮询、后续再优化;远程测温点的封装选择上优先用三极管,因为它比裸二极管更好焊接,极性辨识也更清楚。

数据上报的接口值得提前留一个。HVAC 设备最终往往要接入楼宇自控系统或者运维平台,温度数据只有变成 Modbus 寄存器或者上层网关能读的东西,才算真正发挥价值。我这次在固件里预留了一个简单的数据缓冲区,把本地温度、远程温度、报警状态打包成结构体,后续接网关或者通信模块时只需增加一个透传入口,不需要改动采集逻辑。这些改进都不复杂,但每一条都能节省实际项目里少则半天、多则数天的调试时间。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询