【STM32】基于蓝桥杯嵌入式开发板实现按键单击、双击、长按(通用模板)

前言

基于蓝桥杯嵌入式开发板实现按键的单击,双击,长按检测与处理,使用定时器后台检测,防止占用前台资源,可以随便移植到任何单片机上。

一、硬件原理图

在这里插入图片描述

  • CubeMX配置,使用定时器3来检测按键
    在这里插入图片描述

二、构造按键结构体

  • 看注释
#define KEY_B1 HAL_GPIO_ReadPin(KEY_B1_GPIO_Port, KEY_B1_Pin)
#define KEY_B2 HAL_GPIO_ReadPin(KEY_B2_GPIO_Port, KEY_B2_Pin)
#define KEY_B3 HAL_GPIO_ReadPin(KEY_B3_GPIO_Port, KEY_B3_Pin)
#define KEY_B4 HAL_GPIO_ReadPin(KEY_B4_GPIO_Port, KEY_B4_Pin)

/* 按键长按检测时间(单位:次数) 一次为定时器扫描一次的时间 */
#define KEY_LONG_PRESS_TIME 80

/* 按键双击间隔时间(单位:次数) 一次为定时器扫描一次的时间 */
#define KEY_DOUBLE_GAP_TIME 40

enum KEY_STATE
{
    
    
	key_state_0 = 0,
	key_state_1 = 1,
	key_state_2 = 2,
	key_state_3 = 3
};

enum KEY_EVENT
{
    
    
	key_no     = 0,		/* 无按键按下 */
	key_click  = 1,		/* 单击 */
	key_double = 2,		/* 双击 */
	key_long   = 3		/* 长按 */
};


struct key{
    
    
	bool key_input_val;
	enum KEY_STATE key_state_buff1;	/* 按键执行状态1 */
	enum KEY_STATE key_state_buff2;	/* 按键执行状态2 */
	enum KEY_EVENT key_real_result;	/* 最终判断结果 */
	unsigned char key_time_cnt1;	/* 定时器1 */
	unsigned char key_time_cnt2;	/* 定时器2 */
};

三、在定时器中断回调函数中检测

  • 我的按键是检测到0为有效,1为无效
  • 看注释
static enum KEY_EVENT key_driver(int key_num)
{
    
    
	enum KEY_EVENT key_result = key_no;
	switch (key[key_num].key_state_buff1)
	{
    
    
		case key_state_0:
			if (key[key_num].key_input_val ==  0)
			{
    
    
				key[key_num].key_state_buff1 = key_state_1;
				/* 如果按键被按下,状态切换到按键消抖和确认状态 */
			}
			break;
		case key_state_1:
			if (key[key_num].key_input_val ==  0)
			{
    
    
				key[key_num].key_time_cnt1 = 0;
				key[key_num].key_state_buff1 = key_state_2;
				/* 按键仍处于按下状态 */
				/* 消抖完成,计时器key_time_cnt1 开始计时 */
				/* 状态切换到计时状态 */
			}
			else
				key[key_num].key_state_buff1 = key_state_0;
			break;
		case key_state_2:
			if (key[key_num].key_input_val == 1)
			{
    
    
				key_result = key_click;		/* 按键抬起,产生一次click操作 */		
				key[key_num].key_state_buff1 = key_state_0;						
			}
			else if (++key[key_num].key_time_cnt1 >= KEY_LONG_PRESS_TIME)
			{
    
    	/* 按键继续按下超过1000ms */
				key_result = key_long;		/* 返回长按操作 */
				key[key_num].key_state_buff1 = key_state_3;	/* 状态切换到按键释放状态 */
			}
			
			break;	
		case key_state_3:
			if (key[key_num].key_input_val == 1)
			/* 没按键按下了,回正常状态,防止按一次检测出两次单击 */
				key[key_num].key_state_buff1 = key_state_0;
			break;	
	}
	
	return key_result;
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    
    
	
	if (htim->Instance == TIM3)
	{
    
    
		enum KEY_EVENT key_result;
		key[0].key_input_val = KEY_B1;/* 读取按键值 */
		key[1].key_input_val = KEY_B2;
		key[2].key_input_val = KEY_B3;
		key[3].key_input_val = KEY_B4;
		
		for (int i = 0; i < 4; i++)
		{
    
    
			key_result = key_driver(i);
			
			switch (key[i].key_state_buff2)
			{
    
    
				case key_state_0:
					if (key_result == key_click)
					{
    
    
						key[i].key_time_cnt2 = 0;	
						key[i].key_state_buff2 = key_state_1;
						/* 第一次单击,不返回,到下一个状态判断是否有双击 */
					}
					else
						key[i].key_real_result = key_result;
						/* 对于无键,长按,返回原事件 */
					break;
				case key_state_1:
					if (key_result == key_click) /* 又一次单击,时间间隔小于500ms */      
					{
    
    
						key[i].key_real_result = key_double; /* 返回双击事件 */
						key[i].key_state_buff2 = key_state_0;
					}
					else if (++key[i].key_time_cnt2 >= KEY_DOUBLE_GAP_TIME)
					{
    
    
						key[i].key_real_result = key_click;		
						/* 500ms内没有再次出现单击事件,返回单击事件 */
						key[i].key_state_buff2 = key_state_0;	
					}
					break;
			}	
		}	
	}
}

四、按键处理函数

  • 记得处理完按键后清除按键事件,置为无键事件
  • 记得开定时器3
void key_proc()
{
    
    
		if (key[0].key_real_result == key_click)
		{
    
    
			LCD_ClearLine(Line1);
			LCD_DisplayStringLine(Line1, (uint8_t *)"     key0_click    ");
			key[0].key_real_result = key_no;/* 清除按键事件,置为无键事件 */		
		}
		else if (key[0].key_real_result == key_double)
		{
    
    
			LCD_ClearLine(Line1);
			LCD_DisplayStringLine(Line1, (uint8_t *)"     key0_double   ");
			key[0].key_real_result = key_no;			
		}
		else if (key[0].key_real_result == key_long)
		{
    
    
			LCD_ClearLine(Line1);
			LCD_DisplayStringLine(Line1, (uint8_t *)"     key0_long     ");
			key[0].key_real_result = key_no;			
		}
		
		if (key[1].key_real_result == key_click)
		{
    
    
			LCD_ClearLine(Line2);
			LCD_DisplayStringLine(Line2, (uint8_t *)"     key1_click    ");
			key[1].key_real_result = key_no;			
		}
		else if (key[1].key_real_result == key_double)
		{
    
    
			LCD_ClearLine(Line2);
			LCD_DisplayStringLine(Line2, (uint8_t *)"     key1_double   ");
			key[1].key_real_result = key_no;	
		}
		else if (key[1].key_real_result == key_long)
		{
    
    
			LCD_ClearLine(Line2);
			LCD_DisplayStringLine(Line2, (uint8_t *)"     key1_long      ");
			key[1].key_real_result = key_no;	
		}
}

五、现象

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_61737429/article/details/129993354