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

    五、现象

    作者:ssq不是上上签

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【STM32】蓝桥杯嵌入式开发板实现按键单击、双击、长按(通用模板)

    发表回复