非阻塞式按键检测的核心思想是在不中断主程序执行的情况下检测按键状态。

我采用以下方法实现:

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;
			}
		}
	}
}

主程序查询标志位就可以检测按键了,注意将结构体声明为外部可调用的,或者再写一个返回按键值的小函数转变一下。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐