按键多种触发方式

常用的按键触发方式采用延时消抖策略,比如如下:

u8 Key_Scan(void){
    static u8 key_sta=1;
    if(!key && key_sta){
        delay_ms(10);
        if(!key){
            key_sta=0;
            return 1;
        }
    }
    if(key)    key_sta=1;
    return 0;
}

这种方式是轮询检测的,也是最简单的按键触发,不过按键触发采用了10ms的延时消抖,这部分时间对于要求系统高响应来说是比较大影响的。按键触发方式还有另外一种,就是外部中断触发,响应速度快,不占用太大的时间,我采用stm32的hal库设计如下:

GPIO_InitTypeDef GPIO_InitStruct;

void Key_Init(void){
	__HAL_RCC_GPIOA_CLK_ENABLE();
	
	GPIO_InitStruct.Mode=GPIO_MODE_IT_RISING;
	GPIO_InitStruct.Pin=GPIO_PIN_0;
	GPIO_InitStruct.Pull=GPIO_PULLDOWN;
	GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
}

void EXTI0_IRQHandler(void){
	HAL_GPIO_EXTI_IRQHandler(GPIO_InitStruct.Pin);
}

void HAL_GPIO_EXTI_Callback(u16 GPIO_Pin){
	if(GPIO_Pin==GPIO_PIN_0){
		//代码实现
	}
}

不过在代码实现区域有的时候也得加上一定的延时来防止重复触发,因此这种方法也占用了一定的系统时间。还有一种方法,就是使用计时代替延时,需要另外再初始化一个定时器,在其内部对按键触发的延时值做计时处理,如下:

u8 Key_Flag;                            //按键标记
u8 Key_DelayCnt;                        //按键延时值

#define		C_Key_Delay		0x01        //延时状态
#define		C_Key_Disable	0x02        //按键失效标记

#define		key				PAin(0)     //按键GPIO口

​
//按键初始化,采用GPIOA的下拉输入
void Key_Init(void){
	GPIO_InitTypeDef GPIO_InitStruct;
	__HAL_RCC_GPIOA_CLK_ENABLE();
	
	GPIO_InitStruct.Mode=GPIO_MODE_INPUT;
	GPIO_InitStruct.Pin=GPIO_PIN_0;
	GPIO_InitStruct.Pull=GPIO_PULLDOWN;
	HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);
	Key_DelayCnt=0;
	Key_Flag=0;
}

//按键扫描,放在主函数中,有按键触发时返回1
u8 Key_Scan(void){
	if(Key_Flag & C_Key_Delay){                         //判断按键是否进入延时状态
		if(!Key_DelayCnt){                              //判断按键延时值是否为0,即按键延时是否结束
			Key_Flag &= ~C_Key_Delay;                   //按键延时结束,取消延时状态
			if(key){                                    //按键仍然按下中,说明按键有效
				Key_Flag |= C_Key_Disable;              //按键标记失效
				return 1;
			}
		}
		else if(!key){                                  //如果按键延时未结束,且此时按键抬起,则按键无触发,清除所有标记(初始化按键)
			Key_Flag=0;
		}
	}
	else{                                                //按键未进入延时状态
		if((Key_Flag & C_Key_Disable)==0){               //按键未失效,说明在此之前没有任何按键按下
			if(key){                                     //如果此时按键被按下
				Key_Flag |= C_Key_Delay;                 //按键进入延时状态
				Key_DelayCnt=10;                         //按键延时值赋值
			}
		}else if(!key){                                  //按键在失效情况下检测到按键已经抬起,则清楚按键所有标记,初始化按键
			Key_Flag=0;
		}
	}
	return 0;
}

//按键1ms延时函数,必须将此函数放在1ms中断定时器中
void Key_1MS_IRQ(void){
	if(Key_Flag & C_Key_Delay){                           //按键已经进入延时状态
		if(Key_DelayCnt)	Key_DelayCnt--;               //对延时值自减
	}
}

​

采用Key_Flag的两位来做按键的标志,轮询的方式实时监测按键,其中Key_1MS_IRQ函数必须放在一个1ms的定时器中,也可以直接放在滴答定时器中断里面。该功能不采用delay函数进行延时,可以释放部分系统资源,对资源分配也比较友好。

如果系统采用RTOS多任务,则可以采用第一种延时方法,代码量小,在延时过程中进入阻塞状态,将系统资源分配给其他任务。

第一次写博文,内容有什么不对请指教,谢谢啦!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值