STHS34PF80红外传感器实现静态人体存在检测的实战指南
2026/9/5 12:28:50 网站建设 项目流程

简介:本资源是一套面向嵌入式开发工程师与物联网硬件开发者的技术实践包,聚焦STHS34PF80高灵敏度红外存在感应检测方案,解决传统TMOS传感器在宽温区下因环境温度漂移导致的人体/物体存在判断不准、温度测量失真等核心痛点。资源包含225个文件,总计4.21MB,涵盖90个头文件(h)、36个C源码(c)及37个目标文件(o),完整集成InfraredPD自研算法库、STM32H5系列HAL驱动(如tim、i2c、uart、rtc等)、工程配置文件(uvprojx、ioc、sct)及编译输出产物(axf、hex、map),支持直接部署于STM32H503CB平台。已有224人学习下载,提供可替代传感器内置智能算法的线性/非线性环境温度补偿实现,显著提升低增益模式下的存在识别鲁棒性,并附带配套CSDN图文教程与B站实操视频,便于理解算法原理、调试流程与实际部署要点。

1. 项目缘起:从“动”到“静”的感知挑战

在智能家居、办公节能和安防监控这些领域,我们常常需要判断一个空间里是否“有人”。传统的解决方案,比如基于热释电(PIR)的人体感应模块,大家应该都很熟悉了。它们成本低、功耗也还行,但有个硬伤:只能检测“移动”的人。一旦你坐在工位上一动不动,或者躺在沙发上睡着了,PIR传感器就“看”不到你了。于是,灯会熄灭,空调会关闭,这种体验非常糟糕。

为了解决“静态存在检测”这个痛点,行业里出现了更高级的方案,比如毫米波雷达和基于红外热成像的传感器。毫米波雷达精度高,但成本也高,部署复杂,在消费级产品里用起来有点“杀鸡用牛刀”。而红外热成像方案,过去往往需要阵列式传感器,体积和功耗都不太友好。

直到我接触到STMicroelectronics的STHS34PF80,才发现原来用一颗小小的单点红外传感器,也能实现相当可靠的静态存在检测。它不像PIR那样只对温度变化敏感,而是直接测量目标物体发出的绝对红外辐射强度。这个思路的转变,让“检测静止人体”成为了可能。最近我在一个智能办公桌灯的项目里深度用了一把这颗传感器,整个过程踩了不少坑,也总结了一些非常实用的经验,今天就来和大家详细聊聊,如何用STHS34PF80的InfraredPD(红外光电二极管)模式,来实现高精度的存在感应。

2. STHS34PF80核心原理:不止于“热释电”

要玩转一个传感器,第一步永远是吃透它的数据手册。STHS34PF80被官方定义为“高灵敏度红外存在检测传感器”,这个定位本身就很有意思。它内部其实包含了两套独立的检测系统,这也是它能实现静态检测的关键。

2.1 双通道探测机制解析

第一套系统,是大家熟悉的“热释电(Pyroelectric)”通道。这个通道内部有一个对红外辐射敏感的热电材料。当有红外辐射(比如人体发出的热量)照射到材料上,其表面温度会发生变化,从而产生一个微弱的电压信号。关键在于,这个电压信号的大小与温度变化的速率成正比。也就是说,只有当红外辐射源在移动,导致传感器接收到的辐射强度快速变化时,这个通道才会有显著的输出。对于静止的目标,辐射强度恒定,输出就基本为零。这就是传统PIR的局限性。

第二套系统,也是本篇的重点,叫做“红外光电二极管(Infrared Photodiode)”通道,简称IR PD。这个通道的原理完全不同。它本质上是一个对特定波长红外光(大约在5μm到20μm之间,这正是人体热辐射的主要波段)敏感的光电二极管。它不检测温度变化率,而是直接检测入射红外辐射的绝对强度。无论目标是静止还是移动,只要它持续发出红外辐射,IR PD通道就会持续产生一个与辐射强度成正比的电流信号。这个特性,正是实现静态存在检测的物理基础。

2.2 寄存器配置的核心:启用IR PD模式

STHS34PF80默认上电后,两个通道都是可用的,但我们需要通过配置寄存器来告诉传感器我们主要关心哪个通道的输出,以及如何进行处理。

这里有一个非常重要的细节:STHS34PF80的IR PD通道输出的是非常微弱的电流信号(通常在pA到nA级别)。传感器内部集成了一个跨阻放大器(TIA),将这个电流信号转换为我们MCU可以读取的电压信号。相关的配置主要在CTRL1CTRL2寄存器中。

首先,我们需要在CTRL1寄存器中设置传感器的操作模式和数据输出速率(ODR)。对于存在检测应用,目标通常是静止或缓慢移动的,因此不需要很高的数据刷新率。设置ODR为1Hz或2Hz通常就足够了,这能有效降低平均功耗。例如,设置CTRL1.ODR[3:0] = 0010代表1Hz。

其次,最关键的一步是配置CTRL2寄存器。这个寄存器里有一个位叫做IR_PD_MODE这个位必须被设置为‘1’,才能将传感器的工作模式切换到以IR PD通道为主的状态。在这个模式下,传感器内部的模拟前端和数字滤波器会针对IR PD信号的特点进行优化,同时,Pyroelectric通道的输出可能会被抑制或用于辅助判断。

注意:数据手册里可能会提到“同时模式”,即两个通道都启用。但在实际调试静态存在检测时,我强烈建议先专注于IR PD模式。因为Pyroelectric通道的信号(即使是噪声)可能会干扰你对IR PD信号阈值的判断。先单独调通IR PD,再考虑融合双通道数据做更复杂的算法(比如区分人和宠物),这是一个更稳妥的路径。

配置完成后,我们就可以通过I2C接口,从STATUS寄存器读取数据就绪标志,然后从DATA_IR_PD_LDATA_IR_PD_H这两个寄存器中读取16位的IR PD原始数据了。

3. 硬件设计要点与常见“坑位”

电路设计是传感器稳定工作的基石。STHS34PF80虽然集成度高,但外围电路设计上的一些细节,直接决定了最终信号的稳定性和抗干扰能力。

3.1 电源与去耦:给传感器一个安静的环境

STHS34PF80通常使用3.3V供电。电源噪声是红外传感器的大敌,尤其是IR PD通道处理的是极其微弱的信号。数据手册明确要求,电源引脚(VDD)必须紧挨着放置一个容值至少为100nF的陶瓷电容,并且这个电容要尽可能靠近VDD引脚,接地回路要短。我一般会再并联一个10μF的钽电容或电解电容,用于滤除更低频率的电源纹波。

在实际布线时,传感器的地(VSS)必须连接到系统数字地的“安静”区域,最好是通过一个独立的走线连接到主地平面,避免数字电路(特别是MCU、开关电源)的噪声通过地线耦合进来。如果电路板空间和层数允许,在传感器下方做一个局部的接地铜箔,效果会更好。

3.2 红外窗口与菲涅尔透镜的选择

这是影响探测距离和视场角(FOV)的关键因素。STHS34PF80的感光区域很小,需要外部光学器件来收集红外辐射。

  • 红外窗口材料:传感器正上方必须使用能透过长波红外(LWIR)的材料。普通的玻璃或亚克力对5-20μm的红外线几乎是不透明的。必须使用特殊材料,如锗(Ge)、硫化锌(ZnS)或聚乙烯(PE)。锗的透过率最高但成本也高;聚乙烯薄膜成本低廉,常用于一次性或低成本设备。这个窗口的作用是只让有用的红外辐射进入,同时阻挡可见光和其他干扰。
  • 菲涅尔透镜:这是提升灵敏度的神器。它是一个由一系列同心圆环纹路构成的塑料透镜,每个环纹都是一个独立的小透镜,能够将大角度范围内的红外辐射聚焦到传感器的小感光点上。透镜的焦距(f)和传感器到透镜的距离,决定了系统的视场角和探测距离。选择一个FOV适合你应用场景的透镜至关重要。例如,桌面存在检测可能需要一个较窄的FOV(如30°)来避免检测到相邻工位的人;而房间存在检测可能需要一个较宽的FOV(如90°或120°)。

实操心得:透镜和传感器之间的对准必须非常精确。哪怕微小的偏移,都会导致聚焦不良,灵敏度急剧下降。建议使用带定位柱的透镜支架,并在打样PCB时,将传感器开口和支架定位孔做精准匹配。在组装时,可以用一点热熔胶或UV胶固定透镜支架,防止其松动。

3.3 I2C上拉电阻与布线

STHS34PF80通过I2C通信。SCL和SDA线需要上拉电阻,阻值通常在2.2kΩ到10kΩ之间,具体取决于总线速度和总线电容。对于1米以内的短距离通信,4.7kΩ是个通用值。

布线时,I2C信号线应尽量短,并远离模拟电源、高频信号线(如Wi-Fi天线)以及电机的驱动线。如果无法避开,可以考虑在信号线旁边走一条地线进行屏蔽。

4. 固件驱动与数据读取流程

硬件搞定后,我们来写代码。驱动STHS34PF80本质上就是通过I2C读写它的寄存器。以下是一个基于STM32 HAL库的示例流程,涵盖了初始化、配置和读取数据的核心步骤。

4.1 传感器初始化与寄存器配置

首先,我们需要定义一些常用的寄存器地址和配置值。

// STHS34PF80 常用寄存器地址 (7位地址,假设ADDR引脚接地为0x5A) #define STHS34PF80_I2C_ADDR (0x5A << 1) // HAL库要求左移一位 #define STHS34PF80_WHO_AM_I 0x0F #define STHS34PF80_CTRL1 0x20 #define STHS34PF80_CTRL2 0x21 #define STHS34PF80_STATUS 0x27 #define STHS34PF80_DATA_IR_PD_L 0x2A #define STHS34PF80_DATA_IR_PD_H 0x2B // 配置值 #define ODR_1HZ 0x02 // CTRL1[3:0]: 0010 = 1 Hz #define IR_PD_MODE_ENABLE 0x01 // CTRL2[0]: 1 = Enable IR PD mode

初始化函数需要完成以下几件事:

  1. 检查设备ID (WHO_AM_I),确保通信正常。
  2. 软件复位(如果需要)。
  3. 配置CTRL1设置ODR。
  4. 配置CTRL2启用IR PD模式。
uint8_t STHS34PF80_Init(I2C_HandleTypeDef *hi2c) { uint8_t who_am_i = 0; uint8_t tx_data[2]; // 1. 检查WHO_AM_I if(HAL_I2C_Mem_Read(hi2c, STHS34PF80_I2C_ADDR, STHS34PF80_WHO_AM_I, I2C_MEMADD_SIZE_8BIT, &who_am_i, 1, 100) != HAL_OK) { return 0; // 通信失败 } if(who_am_i != 0xD3) // STHS34PF80的WHO_AM_I固定值 { return 0; // 设备ID不匹配 } // 2. 可选:软件复位 (CTRL3寄存器,BIT3) // tx_data[0] = 0x08; // HAL_I2C_Mem_Write(hi2c, STHS34PF80_I2C_ADDR, 0x22, I2C_MEMADD_SIZE_8BIT, tx_data, 1, 100); // HAL_Delay(10); // 3. 配置CTRL1: 设置ODR为1Hz,并确保传感器处于连续模式(默认) tx_data[0] = ODR_1HZ; // 低功耗模式可考虑设为0x00(单次模式),由MCU触发 if(HAL_I2C_Mem_Write(hi2c, STHS34PF80_I2C_ADDR, STHS34PF80_CTRL1, I2C_MEMADD_SIZE_8BIT, tx_data, 1, 100) != HAL_OK) { return 0; } // 4. 配置CTRL2: 启用IR PD模式 tx_data[0] = IR_PD_MODE_ENABLE; if(HAL_I2C_Mem_Write(hi2c, STHS34PF80_I2C_ADDR, STHS34PF80_CTRL2, I2C_MEMADD_SIZE_8BIT, tx_data, 1, 100) != HAL_OK) { return 0; } // 等待传感器稳定(根据ODR,可能需要等待一个数据输出周期) HAL_Delay(1100); // 略大于1秒 return 1; }

4.2 数据就绪轮询与读取

配置完成后,传感器会按照设定的ODR(1Hz)持续进行测量。我们需要轮询STATUS寄存器的DRDY_IR_PD位(通常是bit 1),来判断新的IR PD数据是否就绪。

int16_t STHS34PF80_Read_IR_PD_Data(I2C_HandleTypeDef *hi2c) { uint8_t status = 0; uint8_t data[2]; int16_t ir_pd_raw = 0; // 1. 读取STATUS寄存器 if(HAL_I2C_Mem_Read(hi2c, STHS34PF80_I2C_ADDR, STHS34PF80_STATUS, I2C_MEMADD_SIZE_8BIT, &status, 1, 100) != HAL_OK) { return 0x7FFF; // 返回一个错误值 } // 2. 检查IR PD数据是否就绪 if((status & 0x02) == 0) // 假设DRDY_IR_PD是bit 1 { return 0x7FFE; // 数据未就绪 } // 3. 读取IR PD数据(先低字节,后高字节) if(HAL_I2C_Mem_Read(hi2c, STHS34PF80_I2C_ADDR, STHS34PF80_DATA_IR_PD_L, I2C_MEMADD_SIZE_8BIT, &data[0], 1, 100) != HAL_OK) { return 0x7FFF; } if(HAL_I2C_Mem_Read(hi2c, STHS34PF80_I2C_ADDR, STHS34PF80_DATA_IR_PD_H, I2C_MEMADD_SIZE_8BIT, &data[1], 1, 100) != HAL_OK) { return 0x7FFF; } // 4. 组合成16位有符号整数 ir_pd_raw = (int16_t)((data[1] << 8) | data[0]); return ir_pd_raw; }

在主循环中,你可以定期(比如每秒一次)调用这个函数来获取原始数据。这个原始数据是一个16位有符号整数,其数值大小直接反映了传感器接收到的红外辐射强度。

5. 从原始数据到存在判断:算法与阈值调试

拿到原始数据只是第一步,如何将它转化为可靠的“有人/无人”状态,才是真正的挑战。这个过程没有放之四海而皆准的阈值,必须根据你的具体应用场景进行调试。

5.1 建立环境基线

传感器上电后,在确保探测区域内没有任何人的情况下,连续读取一段时间(比如5分钟)的IR PD数据。计算这些数据的平均值,这个值就是“无人状态基线”。环境温度、传感器自身温度、周围墙壁和家具的辐射都会影响这个基线值。

// 伪代码:计算基线 int32_t sum = 0; for(int i=0; i<300; i++) // 假设1Hz ODR,采集5分钟 { raw_data = STHS34PF80_Read_IR_PD_Data(&hi2c1); if(is_valid_data(raw_data)) // 过滤错误码 { sum += raw_data; HAL_Delay(1000); // 等待1秒 } } int16_t baseline = sum / 300;

将这个基线值存储到非易失性存储器(如Flash)中,以后每次上电都可以直接使用,无需重新校准。

5.2 动态阈值与滞回比较

直接使用一个固定阈值与当前读数比较,很容易因为环境温度的缓慢漂移或微小干扰而产生误触发。更稳健的方法是使用“动态阈值”和“滞回比较”。

  • 动态阈值:阈值不是固定的,而是在基线基础上加上一个偏移量。阈值 = 基线 + OFFSET。这个OFFSET就是你需要调试的核心参数。它代表了“需要多强的红外信号才被认为有人”。这个值需要通过实验来确定。
  • 滞回比较:为了避免在阈值附近频繁切换状态,需要引入滞回区间。
    • 当前状态为“无人”:只有当读数 >(基线 + OFFSET)时,才切换到“有人”状态。
    • 当前状态为“有人”:只有当读数 <(基线 + OFFSET - HYSTERESIS)时,才切换回“无人”状态。HYSTERESIS是滞回值,通常设为OFFSET的20%-50%。
#define OFFSET 150 // 需要调试的关键值 #define HYSTERESIS 50 // 滞回值 int16_t current_baseline = get_stored_baseline(); uint8_t presence_state = 0; // 0:无人, 1:有人 int16_t current_raw_data; void check_presence() { current_raw_data = STHS34PF80_Read_IR_PD_Data(&hi2c1); if(!presence_state) { // 当前无人状态 if(current_raw_data > (current_baseline + OFFSET)) { presence_state = 1; printf("检测到有人!\r\n"); // 触发开灯、开启空调等动作 } } else { // 当前有人状态 if(current_raw_data < (current_baseline + OFFSET - HYSTERESIS)) { presence_state = 0; printf("人已离开。\r\n"); // 触发关灯、节能等动作 // 可选:在无人状态下,缓慢更新基线,以跟踪环境温度漂移 // current_baseline = current_baseline * 0.99 + current_raw_data * 0.01; } } }

5.3 调试OFFSET值的实战方法

这是整个项目中最“玄学”也最关键的一步。你需要准备一个热源(最好是真人,因为热水袋、暖宝宝的辐射谱和人体有差异),在预期的探测距离内,进行静止和移动测试。

  1. 打印数据:在调试初期,务必通过串口连续打印出IR PD的原始数据、计算出的阈值以及当前状态。将数据导入到Excel或Python(如Matplotlib)中绘制曲线图,直观无比。
  2. 无人状态观察:记录下稳定的基线值范围。观察数据是否有周期性波动(可能是空调出风口导致的),波动幅度有多大。
  3. 有人状态测试
    • 静止测试:让人坐在探测区域内,保持不动5分钟。观察数据曲线,会看到一个明显的阶跃上升,然后稳定在一个新的平台值。这个“平台值”与“基线值”的差值,就是理想的OFFSET参考值。注意,这个差值会随着距离增加而急剧减小
    • 移动测试:让人在区域内走动。数据曲线会出现更大的脉冲。此时OFFSET应该设置得比静止差值略高一些,以避免过于敏感。
  4. 确定OFFSET:从静止测试的差值开始,作为一个初始值。然后进行反复的“进入-离开”测试。如果OFFSET设得太低,容易误报(比如阳光扫过、暖气片开启);设得太高,则可能对远处或侧面的人检测不到。一个实用的技巧是,将OFFSET设置为“静止差值”的70%-80%,再结合一个适中的HYSTERESIS。这样能在灵敏度和抗干扰之间取得较好的平衡。

6. 进阶优化与抗干扰策略

调通基本功能后,还可以通过一些策略让检测更可靠。

6.1 温度补偿

STHS34PF80内部有温度传感器。环境温度变化会影响红外辐射的强度和传感器本身的灵敏度。虽然IR PD模式对绝对辐射敏感,但进行温度补偿可以进一步提升稳定性。你可以读取温度数据,建立一个简单的补偿模型(例如,温度每升高1度,基线预期增加N个LSB),动态调整你的基线或阈值。

6.2 数据滤波

即使配置了IR PD模式,原始数据仍可能包含高频噪声。在软件端添加一个简单的数字滤波器能有效平滑数据。一个一阶低通滤波器(IIR)就足够,且计算量小:

float alpha = 0.1; // 滤波系数,越小越平滑,响应越慢 int16_t filtered_data = 0; filtered_data = (int16_t)(alpha * current_raw_data + (1 - alpha) * filtered_data);

之后用filtered_data去进行阈值比较。注意,滤波会引入延迟,需要根据你的ODR和应用对响应速度的要求来调整alpha

6.3 多条件判决与状态保持

对于需要高可靠性的应用(如智能开关),可以引入多条件判决和状态保持计时器。

  • 多条件判决:不要仅凭一次超阈值就判定有人。可以改为“连续M次采样超阈值,才判定有人”。同样,“连续N次采样低于阈值,才判定无人”。这能滤除瞬间干扰。
  • 状态保持:一旦判定为“有人”,启动一个计时器(比如5分钟)。在计时器超时前,即使数据偶尔低于阈值,也维持“有人”状态。这可以应对人坐在桌前轻微活动(如低头看手机)导致信号短暂减弱的情况,避免灯光频繁闪烁。

6.4 应对典型干扰源

  • 阳光/白炽灯:强烈的近红外光源是主要干扰。确保红外窗口能有效阻挡短波红外。此外,可以通过算法检测异常快速的信号跳变(阳光扫过)并将其忽略。
  • 暖气片/空调出风口:这些是动态热源。它们的温度可能变化缓慢,但仍可能导致基线漂移。动态基线更新算法(在无人状态下,用当前读数缓慢修正基线)可以帮助应对。
  • 小型宠物:猫狗的红外辐射特征与人不同,且通常移动较快。结合Pyroelectric通道的数据(对移动敏感)可能有助于区分。例如,如果IR PD信号中等强度但Pyroelectric信号持续活跃,可能提示是宠物而非静止的人。

7. 实测案例:智能办公桌灯

最后,分享一个我的实测案例。我将STHS34PF80(搭配一个60° FOV的菲涅尔透镜)安装在办公桌显示器的顶部,朝向座椅方向。

  • 场景:检测用户是否在工位,自动控制桌面屏幕挂灯和显示器电源。
  • 挑战:办公室环境复杂,有中央空调、同事走动、窗外阳光变化。
  • 参数调试
    1. 无人时,基线值约在 -200 LSB 左右(原始数据有正负)。
    2. 人坐在椅子上(距离传感器约0.8米),数据稳定在 180 LSB 左右。
    3. 差值约380 LSB。我将OFFSET设为 300,HYSTERESIS设为 100。
    4. 采用“连续3次超阈值判定有人,连续10次低于阈值判定无人”的判决逻辑。
    5. 有人状态下,设置15分钟的状态保持计时器。
  • 效果:可以实现稳定的存在检测。坐下后约3秒开灯,起身离开后约10-15分钟关灯(取决于状态保持计时)。偶尔有同事快速经过桌旁不会触发,阳光从侧面窗户照射的影响也被有效滤除。

整个调试过程花了不少时间,主要耗在光学组件的对准和阈值的精细调整上。但一旦调通,STHS34PF80提供的是一种低成本、低功耗、高集成度的静态存在检测方案,非常适合集成到各种IoT设备中。希望这篇超详细的拆解和实战记录,能帮你绕过我踩过的那些坑,更快地让这颗传感器在你的项目里可靠地工作起来。

本文还有配套的精品资源,点击获取

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

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

立即咨询