【单片机】人体感应模块

前言

大家好,我是林白柏;

希望你看完之后,能有所收获,不足请指正!

PS:本文提到的模块都使用正点原子的stm32开发板战舰驱动,模块用的某宝现成的模块。


模块介绍(可跳过)

模块由菲涅尔透镜、热释电红外探头、放大电路组成。

菲涅尔透镜用于提高探头灵敏度。

透镜在探头前方产生交替变化的“盲区”和“高灵敏区”,这样当人体走过时,人体发射的红外线就会不断交替经过“盲区”和“高灵敏区”,便于探头产生脉冲信号。

热释电红外探头检测到人体发出的红外线时,发出一个脉冲信号(脉冲宽度固定);有人时,人体产生的红外线会交替出现在“盲区”和“高灵敏区”,就一直有脉冲信号输出(实测人静止不动时好像不会输出)。

在通过放大器是BISS0001将脉冲信号转化为更直观的高低电平输出,有人输出高,无人输出低。并在放大电路上设置电位器,调节输出信号的灵敏度(比如探头产生n个脉冲,模块才输出高电平),调节高电平持续时间。

image-20220419210118203

模块使用

模块接口只有三个脚,地、电源、数据线;分别计为GND、VCC、OUT

探头检测到有人移动时,OUT=1;没人移动时,OUT=0;

因此我们可以把它当成一个独立按键,按下时(有人移动)为1,松开时(没人移动)为0。

image-20220419215448737

我们将IO口初始化为外部中断、跳变沿触发,当产生中断时,在中断服务函数中读取IO状态,IO=1则为上升沿——有人移动,IO=0则为下降沿——无人移动。(见头文件human_body_induction.c部分)

将事件返回给事件回调函数。(见头文件human_body_induction.h部分)

代码:h文件

头文件*(为了一个“按键”封装两个文件确实点过于仪式感了哈哈哈哈)*中定义了两种事件,用于返回给事件回调函数。

typedef enum {
    HBI_NOBODY,//无人移动
    HBI_PEOPLE_MOVING,//有人移动
}hbi_evt_t;

typedef void ( * hbi_evt_handle_t )( hbi_evt_t * event );//事件回调函数类型

void hbi_init( hbi_evt_handle_t event_handle);//初始化函数声明

代码:c文件

源文件中分为两部分:初始化,中断服务函数。

初始函数,初始化io、中断,并保存回调函数指针。

static hbi_evt_handle_t m_event_handle;	//保存用户传进来的回调函数指针
void hbi_init( hbi_evt_handle_t event_handle) {
 	GPIO_InitTypeDef GPIO_InitStructure;
 	EXTI_InitTypeDef EXTI_InitStructure;
 	NVIC_InitTypeDef NVIC_InitStructure;
    
    //[ 与硬件相关 ]
	//使能外设时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);  //使能PORTG口时钟 
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	   //使能复用功能时钟
    
	//将IO初始化为下拉输入(上拉下拉好像都行)
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;				
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; 		  
 	GPIO_Init(GPIOG, &GPIO_InitStructure);
    
    //配置GPIOG.8为中断线EXTI_Line8的中断源(这部分需要去了解stm32中断相关知识)
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOG,GPIO_PinSource8);
	//EXTI_Line8初始化为跳变沿触发
    EXTI_InitStructure.EXTI_Line = EXTI_Line8;    
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);     //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
    
	//初始化中断分组
  	NVIC_InitStructure.NVIC_IRQChannel = HBI_EXTI_IRQ_CHANNEL;		
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;			//子优先级3
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure); 

    //[ 与硬件无关 ]
    //保存用户传进来的回调函数指针,中断服务函数中使用
    m_event_handle = event_handle;
}

中断服务函数中,根据中断类型返回相应的事件给用户

void EXTI9_5_IRQHandler(void)//stm32中,中断线5-9公用一个中断服务函数
{
	if(EXTI_GetITStatus( EXTI_Line8 ) != RESET)
	{
		hbi_evt_t evt = HBI_NOBODY;
		EXTI_ClearFlag( EXTI_Line8 );    //清除中断标志位
		EXTI_ClearITPendingBit( EXTI_Line8 ); //清除EXTI线路挂起位
        

        if( GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_8) ) {//上升沿
            evt = HBI_PEOPLE_MOVING;
        }
        else {//下降沿
            evt = HBI_NOBODY;
        }
        m_event_handle( &evt );
	}
}

代码使用方法

初始化时,应用程序注册一个回调函数,后续就只需要在回调函数中判断事件并执行相应操作即可

//以下使用演示
static void bi_evt_cb( hbi_evt_t * event ) {//定义事件回调函数
    switch ( *event ) {
        case HBI_NOBODY        : _LOG_DEBUG("[hbi] nobody\n\n"); break;
        case HBI_PEOPLE_MOVING : _LOG_DEBUG("[hbi] people moving\n\n");; break;        
    }
}

int main(void){
    hbi_init( hbi_evt_cb );//将回调函数指针传给初始化函数
    while(1);
}

补充介绍(可/不可重复触发)

模块还有一个重复触发不重复触发的概念,由BISS0001实现(具体实现方式查看BISS0001规格书),两者的区别如下图红色方框

image-20220419220844072

不可重复触发,探头产生脉冲时,模块out脚输出高电平,时长Tx;在Tx结束前,探头产生的脉冲都无效。

可重复触发,探头产生脉冲时,模块out脚输出高电平,时长Tx;在Tx结束前,探头产生新的脉冲,则从新的脉冲处开始重新计时Tx。只要Tx结束前一直有脉冲产生,则模块高电平会一直持续下去。

可通过模块上跳线帽进行设置,L(不可重复触发)和H(可重复触发)

image-20220419224252959

代码获取

共用代码:https://gitee.com/sumoting1629/mcu-practice/tree/master/common

驱动代码:https://gitee.com/sumoting1629/mcu-practice/tree/master/component

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值