非阻塞式按键检测(长按、短按)
本文介绍了一种非阻塞式按键检测的实现方法,通过状态机在定时器中断中处理按键状态,支持单击和长按检测。系统采用结构体数组存储各按键状态,通过定时器中断(1ms周期)轮询检测GPIO状态,使用状态机实现消抖处理。代码分为按键检测和事件处理两个部分,通过标志位区分短按(100ms以下)和长按(100ms以上)。实践证明该方案检测精准可靠,适用于嵌入式系统的按键处理场景。
·
非阻塞式按键检测的核心思想是在不中断主程序执行的情况下检测按键状态。
我采用以下方法实现:
1、使用状态机处理按键状态
2、在定时器中断中处理按键状态和消抖(非阻塞)
3、分离按键检测与事件处理
4、支持单击、长按检测
实现过程非常简单,首先开启任意一个定时器,设置计数器自增时间为1ms。
以下是具体代码,以两个按键为例,如果想要增加个数,只需要更改结构体数组长度就可以。
这套代码没有滤波,但是经过我的检测,还是很精准好用的。
.h文件
#ifndef __KEY_H_
#define __KEY_H_
#include "main.h"
//按键状态结构体
struct keys{
char key_num; //按键状态
char key_cnt; //按键状态机
int key_time; //长按短按时间判断
char key_short_flag; //短按标志位
char key_long_flag; //长按标志位
} ;
#endif
.c文件
#include "key.h"
struct keys key[2]={0,0}; //为每个按键创建结构体
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim->Instance==TIM2){
key[0].key_num=HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7); //获取每个按键状态
key[1].key_num=HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); //获取每个按键状态
for( char i=0;i<2;i++){ //按键个数增加,更改for循环长度
switch(key[i].key_cnt){
case 0:{
if(key[i].key_num==0){key[i].key_cnt=1;} //状态1:按键按下进入下一状态
}
break;
case 1:{
if(key[i].key_num==0){key[i].key_cnt=2;} //进入第二状态,消抖检测
else{key[i].key_cnt=0;}
}
break;
case 2:{
if(key[i].key_num==1){key[i].key_cnt=3;} //第三状态,长按检测
else{key[i].key_time++;}
}
break;
case 3:{
if(key[i].key_time>=100){ //判断按键时间,超100ms过则为长按
key[i].key_long_flag=1; //设置标志位
}
else{key[i].key_short_flag=1;} //否则为短按
//设置标志位
key[i].key_time=0;
key[i].key_cnt=0;
}
break;
}
}
}
}
主程序查询标志位就可以检测按键了,注意将结构体声明为外部可调用的,或者再写一个返回按键值的小函数转变一下。
更多推荐



所有评论(0)