精华内容
下载资源
问答
  • STM32按键(单击、双击、长按)操作
  • STM32F103按键控制 按键双击,长按有效,单击取消 在学习过程中需要完成稍微复杂一点的功能,按键又不想设计太多(主要节省成本) 在工程中主要有以下几个步骤 一、按键初始化 1、初始化按键IO引脚,这里配置的是...

    STM32F103按键控制
    按键双击,长按有效,单击取消
    在学习过程中需要完成稍微复杂一点的功能,按键又不想设计太多(主要节省成本)


    在工程中主要有以下几个步骤
    一、按键初始化
    1、初始化按键IO引脚,这里配置的是上拉输入
    2、编写单个按键检测程序(加延时消抖)
    3、宏定义每个按键的状态值Key_State
    4、编写判断是否有按键按下函数,并确定此按键的状态值
    5、编写按键功能函数
    二、定时器初始化
    1、选择通用定时器
    2、配置定时器时间,并开启中断
    3、编写中断服务函数
     

    //宏定义每个按键的状态值Key_State
    #define KEY1_STATE_VALUE	(0x0001)
    #define KEY2_STATE_VALUE	(0x0002)
    #define KEY3_STATE_VALUE	(0x0004)
    #define KEY4_STATE_VALUE	(0x0008)
    
    #define KEY5_STATE_VALUE	(0x0010)
    #define KEY6_STATE_VALUE	(0x0020)
    #define KEY7_STATE_VALUE	(0x0040)
    #define KEY8_STATE_VALUE	(0x0080)
    
    #define KEY9_STATE_VALUE	(0x0100)
    #define KEY10_STATE_VALUE	(0x0200)
    #define KEY11_STATE_VALUE	(0x0400)
    #define KEY12_STATE_VALUE	(0x0800)
    
    //按键延时超时值
    #define Key_Two_Click_Time		200 //200以内双击有效输出
    #define Key_Long_Click_Time		300 //长按300及以上有效输出
    
    
    uint16_t Key_State = 0; 		//按键状态值
    
    uint8_t Key_Value = 0;			//按键按下去的值
    uint8_t Old_Key_Value = 0;		//上一次按键按下去的值
    
    uint8_t Key_Ture_Value = 0;		//最终输出的值
    uint8_t Old_Key_Ture_Value = 0;	//上一次最终输出的值
    
    uint8_t Key_Down_Count_Flag = 0;//按键按下次数的值,用于判断是单击还是双击
    
    uint8_t Key_Down_Flag = 0;		//按键按下标志位,防止一直按着导致按键次数一直增加
    
    uint16_t Key_Click_Time = 0;	//按键次数为1时开始计时,其他状态为0
    
    
    
    void Key_Init(void) //初始化12个按键引脚
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
    		
    	GPIO_InitStructure.GPIO_Pin = KYE10_GPIO_PIN|
    								  KYE8_GPIO_PIN|
    								  KYE7_GPIO_PIN|
    								  KYE6_GPIO_PIN|
    								  KYE5_GPIO_PIN|
    								  KYE4_GPIO_PIN|
    								  KYE3_GPIO_PIN|
    								  KYE1_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA,&GPIO_InitStructure);	
    	
    	GPIO_InitStructure.GPIO_Pin = KYE2_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB,&GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Pin = KYE9_GPIO_PIN|
    																KYE11_GPIO_PIN|
    																KYE12_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_Init(GPIOC,&GPIO_InitStructure);	
    }
    
    /*
    * 描述:  返回key1控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key1_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY1_GPIO,KYE1_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY1_GPIO,KYE1_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    
    /*
    * 描述:  返回key2控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key2_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY2_GPIO,KYE2_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY2_GPIO,KYE2_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    
    /*
    * 描述:  返回key3控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key3_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY3_GPIO,KYE3_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY3_GPIO,KYE3_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    
    /*
    * 描述:  返回key4控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key4_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY4_GPIO,KYE4_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY4_GPIO,KYE4_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    
    /*
    * 描述:  返回key5控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key5_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY5_GPIO,KYE5_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY5_GPIO,KYE5_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    /*
    * 描述:  返回key6控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key6_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY6_GPIO,KYE6_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY6_GPIO,KYE6_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    /*
    * 描述:  返回key7控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key7_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY7_GPIO,KYE7_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY7_GPIO,KYE7_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    
    /*
    * 描述:  返回key8控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key8_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY8_GPIO,KYE8_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY8_GPIO,KYE8_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    
    
    /*
    * 描述:  返回key9控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key9_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY9_GPIO,KYE9_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY9_GPIO,KYE9_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    /*
    * 描述:  返回key10控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key10_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY10_GPIO,KYE10_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY10_GPIO,KYE10_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    /*
    * 描述:  返回key11控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key11_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY11_GPIO,KYE11_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY11_GPIO,KYE11_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    /*
    * 描述:  返回key12控制键的状态  
    * 参数:  无
    * 返回值:0按下 1没按下
    */
    uint8_t Get_Key12_State(void)
    {
    	if(GPIO_ReadInputDataBit(KEY12_GPIO,KYE12_GPIO_PIN) == RESET)
    	{
    		Delay_Ms(10);
    		if(GPIO_ReadInputDataBit(KEY12_GPIO,KYE12_GPIO_PIN) == RESET)
    		{
    			return 0;
    		}	
    	}
    	return 1;
    }
    /*
    *描述:		判断只有一个按键按下
    *参数:		无
    *返回值:	1:有按键按下,0:无按键按下
    */
    uint8_t Key_Down_Num(void)
    {
    	if(0 == Get_Key1_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key1_State())
    		{
    			Key_State |= KEY1_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY1_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key2_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key2_State())
    		{
    			Key_State |= KEY2_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY2_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key3_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key3_State())
    		{
    			Key_State |= KEY3_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY3_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key4_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key4_State())
    		{
    			Key_State |= KEY4_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY4_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key5_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key5_State())
    		{
    			Key_State |= KEY5_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY5_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key6_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key6_State())
    		{
    			Key_State |= KEY6_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY6_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key7_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key7_State())
    		{
    			Key_State |= KEY7_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY7_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key8_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key8_State())
    		{
    			Key_State |= KEY8_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY8_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key9_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key9_State())
    		{
    			Key_State |= KEY9_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY9_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key10_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key10_State())
    		{
    			Key_State |= KEY10_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY10_STATE_VALUE;
    	}
    
    ///
    	if(0 == Get_Key11_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key11_State())
    		{
    			Key_State |= KEY11_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY11_STATE_VALUE;
    	}	
    	
    ///
    	if(0 == Get_Key12_State())
    	{
    		Delay_Ms(10);
    		if(0 == Get_Key12_State())
    		{
    			Key_State |= KEY12_STATE_VALUE;
    		}
    	}
    	else
    	{
    		Key_State &= ~KEY12_STATE_VALUE;
    	}	
    ///	
    	Key_State &= 0x0fff;
    	if(Key_State != 0)
    	{
    		return 1;
    	}
    	return 0;	
    }
    
    /*
    *描述:		按键检测
    *参数:		无
    *返回值:	无
    */
    void Key_Scanf(void)
    {
    	if(1 == Key_Down_Num())//判断是否有按键按下
    	{
    		Old_Key_Value = Key_Value; //每一次按下记录上一次按键的值
    		switch(Key_State) //判断按键状态值
    		{
    			case KEY1_STATE_VALUE:Key_Value = 1;break;
    			case KEY2_STATE_VALUE:Key_Value = 2;break;
    			case KEY3_STATE_VALUE:Key_Value = 3;break;
    			case KEY4_STATE_VALUE:Key_Value = 4;break;
    			case KEY5_STATE_VALUE:Key_Value = 5;break;
    			case KEY6_STATE_VALUE:Key_Value = 6;break;
    			case KEY7_STATE_VALUE:Key_Value = 7;break;
    			case KEY8_STATE_VALUE:Key_Value = 8;break;						
    			case KEY9_STATE_VALUE:Key_Value = 9;break;		
    			case KEY10_STATE_VALUE:Key_Value = 10;break;
    			case KEY11_STATE_VALUE:Key_Value = 11;break;
    			case KEY12_STATE_VALUE:Key_Value = 12;break;			
    			default:Key_Value = 0;break;			
    		}		
    		if(Key_Down_Flag == 1)
    		{
    			Key_Down_Count_Flag++; //记录按键按下去的次数			
    		}
    		Key_Down_Flag = 0;		
    	}
    	else
    	{
    		Key_Down_Flag = 1;
    	}
    	
    }
    
    /*
    *描述:判断是否是有效键值
    *参数:无
    *返回值:无
    */
    void GetKey_True_Touch(void)
    {
    	if(Key_Down_Count_Flag == 1) //按下1次
    	{
    		if(Key_Down_Flag == 0) //按键按下
    		{
    			//定时器超过长按规定时间
    			if(Key_Click_Time >= Key_Long_Click_Time)
    			{
    				Key_Ture_Value = Key_Value;
    			}
    			else
    			{
    				Key_Ture_Value = 0;
    			}			
    		}
    		else	///按键松开
    		{
    			//判断定时器时间是否超过规定时间
    			//如果超过规定时间,清零变量
    			if(Key_Click_Time > Key_Two_Click_Time)
    			{
    				Key_Ture_Value = 0;				//输出值清零				
    				Key_Click_Time = 0;				//定时器时间清零
    				Key_Down_Count_Flag = 0;	//按键次数清零
    			}
    		}	
    	}
    	else if(Key_Down_Count_Flag == 2)//按下2次
     	{
    		//如果两次按键值相等,说明双击的是同一个按键
    		//如果两次按键值不相等,输出0;
    		if(Old_Key_Value == Key_Value)
    		{
    			Key_Ture_Value = Key_Value;
    		}
    		else
    		{
    			Key_Ture_Value = 0;				//输出值清零	
    		}
    		Key_Click_Time = 0;				//定时器时间清零
    		Key_Down_Count_Flag = 0;	//按键次数清零
    		while(Key_Down_Num());    //等待按键松开
    	}
    	
    }
    
    //定时器配置//
    
    void TIM2_Init(void)
    {
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;	
    	NVIC_InitTypeDef 				NVIC_InitStructure;
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
    	
    	
    	//配置周期为5ms
    	TIM_TimeBaseInitStructure.TIM_Period = 4999;
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;
    	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
    	
    	TIM_ARRPreloadConfig(TIM2,ENABLE);//在ARR上启用或禁用TIMx外设预加载寄存器。
    	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
    	TIM_Cmd(TIM2,ENABLE);
    	
    	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
    	
    	NVIC_Init(&NVIC_InitStructure);
    }	
    //中断服务函数
    void TIM2_IRQHandler(void)
    {
    	while(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update))
    	{
    		//按键单击,双击,长按监测
    		if(Key_Down_Count_Flag == 1)
    		{
    			Key_Click_Time++;
    			if(Key_Click_Time > Key_Long_Click_Time)
    			{
    				Key_Click_Time = Key_Long_Click_Time;
    			}			
    		}
    		else
    		{
    				Key_Click_Time = 0;
    		}
    		TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
    	}	
    }

     

    展开全文
  • STM32按键处理机制 文章目录STM32按键处理机制一、按键处理原理按键中断代码段:按键计时定时器中断代码:按键消息判断代码:二、代码汇总"myKey.c""myKey.h" 一、按键处理原理     通过定时器...

    STM32按键处理机制

    一、按键处理原理

        通过定时器的按键状态计时,实现短按、长按、双击、处于长按状态等状态的判断。

    首先头文件中定义一下枚举变量和结构体,用来储存每个按键的消息状态。

    //定义按键物理状态枚举
    typedef enum 
    {
    	KEY_UNPRESSED = 0,
    	KEY_PRESSED = ~KEY_UNPRESSED,
    }keyState_enum;
    
    //定义按键消息结构体
    typedef struct 
    {
    	//按键消息
    	unsigned char longPressed ;
    	unsigned char shortPressed ;
    	unsigned char doublePressed ;
    	unsigned char isLongPressing ;
    	//按键物理状态变量
    	keyState_enum keyState ;
    	//按键消息触发计时
    	unsigned int pressedTime5ms ;
    	unsigned char pressedTime1s;
    }myKey_ValueTypedef;
    

        按键通过中断检测,如果被有按键被按下就将 按键被按下的标志置位 (myKey_IsPressed_Flag = 1;)
    然后再进行进一步的按键消息判断。被按下的按键则在定时器中断中开始计时按下的时长,等待按键弹起,则确定按键是长按还是短按。当按下时间大于2S并且还没有弹起,则将isLongPressing (处于正在长按状态)置位。

    按键中断代码段:

    void EXTI0_IRQHandler(void)
    {
    	delay_EXTI0_delayTime5ms = 0;
    	while(delay_EXTI0_delayTime5ms > 2);
    	if(!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))
    	{
    		myKey_IsPressed_Flag = 1;
    	}
    	
    	EXTI_ClearITPendingBit(KEY_RST_EXTI_LINE);
    }
    
    
    void EXTI15_10_IRQHandler(void)
    {
    	if(EXTI_GetITStatus(KEY_UP_EXTI_LINE)!=RESET)
    	{
    		delay_EXTI15_10_delayTime5ms = 0;
    		while(delay_EXTI15_10_delayTime5ms > 2);
    		if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15))
    		{
    			myKey_IsPressed_Flag = 1;
    	
    		}
    	}
    	if(EXTI_GetITStatus(KEY_DOWN_EXTI_LINE)!=RESET)
    	{
    		delay_EXTI15_10_delayTime5ms = 0;
    		while(delay_EXTI15_10_delayTime5ms > 2);
    		if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14))
    		{
    			myKey_IsPressed_Flag = 1;
    		
    		}
    	}
    	if(EXTI_GetITStatus(KEY_LEFT_EXTI_LINE)!=RESET)
    	{
    		delay_EXTI15_10_delayTime5ms = 0;
    		while(delay_EXTI15_10_delayTime5ms > 2);
    		if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13))
    		{
    			myKey_IsPressed_Flag = 1;
    			
    		}
    	}
    	if(EXTI_GetITStatus(KEY_RIGHT_EXTI_LINE)!=RESET)
    	{
    		delay_EXTI15_10_delayTime5ms = 0;
    		while(delay_EXTI15_10_delayTime5ms > 2);
    		if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12))
    		{
    			myKey_IsPressed_Flag = 1;
    		
    		}
    	}
    	
    	EXTI_ClearITPendingBit(KEY_UP_EXTI_LINE);
    	EXTI_ClearITPendingBit(KEY_DOWN_EXTI_LINE);
    	EXTI_ClearITPendingBit(KEY_LEFT_EXTI_LINE);
    	EXTI_ClearITPendingBit(KEY_RIGHT_EXTI_LINE);
    
    }
    

    按键计时定时器中断代码:

    //按键计时中断
    //定时器3中断服务程序 5ms一次
    void TIM3_IRQHandler(void)   //TIM3中断
    {
    	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
    		{
    			TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
    			
    			delay_Time5ms++;
    			if(delay_Time5ms == 200)//1S
    			{
    				delay_Time5ms = 0;
    			}
    			
    			if(key_RST_Value.keyState == KEY_PRESSED)
    			{
    				key_RST_Value.pressedTime5ms++;
    			}
    			
    			if(key_UP_Value.keyState == KEY_PRESSED)
    			{
    				key_UP_Value.pressedTime5ms++;
    			}
    			if(key_DOWN_Value.keyState == KEY_PRESSED)
    			{
    				key_DOWN_Value.pressedTime5ms++;
    			}
    			if(key_LEFT_Value.keyState == KEY_PRESSED)
    			{
    				key_LEFT_Value.pressedTime5ms++;
    			}
    			if(key_RIGHT_Value.keyState == KEY_PRESSED)
    			{
    				key_RIGHT_Value.pressedTime5ms++;
    			}
    			
    			delay_EXTI0_delayTime5ms++;
    			delay_EXTI15_10_delayTime5ms++;
    			myKey_GetKeyValue_delayTime5ms++;
    		
    		}
    }
    
    

    按键消息判断代码:

    void judge_KeyValue(GPIO_TypeDef * keyGPIO, uint16_t keyGPIO_Pin, myKey_ValueTypedef * keyValue)
    {
    	//键处理
    	if(!GPIO_ReadInputDataBit(keyGPIO, keyGPIO_Pin))//如果按键处于按下状态
    	{
    		if(keyValue->keyState == KEY_UNPRESSED)
    		{
    			keyValue->keyState = KEY_PRESSED;
    			keyValue->pressedTime5ms = 0;
    		}
    		else if(keyValue->keyState == KEY_PRESSED && keyValue->pressedTime5ms >= 200)
    		{
    			keyValue->isLongPressing = 1;	
    		}
    	}
    	
    	//如果按键处于弹起状态状态并且之前有被按下,则将根据按下时间确定键值
    	else if(GPIO_ReadInputDataBit(keyGPIO, keyGPIO_Pin) && keyValue->keyState == KEY_PRESSED)
    	{
    		keyValue->keyState = KEY_UNPRESSED;
    		keyValue->isLongPressing = 0;	
    		if(keyValue->pressedTime5ms >= 200)
    		{
    			keyValue->longPressed = 1;
    			keyValue->shortPressed = 0;
    		}
    		else
    		{
    			keyValue->longPressed = 0;
    			keyValue->shortPressed = 1;
    		}
    		myKey_IsPressed_Flag = 0;	
    		myKey_ValueChangedFlag = 1;
    	}
    }
    

    二、代码汇总

    以下是总体代码:

    “myKey.c”

    /************************************************************************************
    *  Copyright (c), 2019, LXG.
    *
    * FileName		:myKey.c
    * Author		:firestaradmin
    * Version		:1.0
    * Date			:2019.12.11
    * Description	:中断按键键值处理
    * History		:
    *
    *
    *************************************************************************************/
    
    #include "myKey.h"
    #include "delay.h"
    #include "OLED_I2C_Buffer.h"
    #include "myShaoBingApp.h"
    #include "DS18B20.h"
    
    #define KEY_RST_GPIO_PortSource		GPIO_PortSourceGPIOA
    #define KEY_UP_GPIO_PortSource 		GPIO_PortSourceGPIOB
    #define KEY_DOWN_GPIO_PortSource	GPIO_PortSourceGPIOB
    #define KEY_LEFT_GPIO_PortSource 	GPIO_PortSourceGPIOB
    #define KEY_RIGHT_GPIO_PortSource 	GPIO_PortSourceGPIOB
    
    #define KEY_RST_GPIO_PinSource		GPIO_PinSource0
    #define KEY_UP_GPIO_PinSource		GPIO_PinSource15
    #define KEY_DOWN_GPIO_PinSource 	GPIO_PinSource14
    #define KEY_LEFT_GPIO_PinSource 	GPIO_PinSource13
    #define KEY_RIGHT_GPIO_PinSource 	GPIO_PinSource12
    
    
    #define KEY_RST_GPIO_PORT		GPIOA
    #define KEY_UP_GPIO_PORT 		GPIOB
    #define KEY_DOWN_GPIO_PORT		GPIOB
    #define KEY_LEFT_GPIO_PORT 		GPIOB
    #define KEY_RIGHT_GPIO_PORT 	GPIOB
    
    #define KEY_RST_GPIO_PIN		GPIO_Pin_0
    #define KEY_UP_GPIO_PIN 		GPIO_Pin_15
    #define KEY_DOWN_GPIO_PIN 		GPIO_Pin_14
    #define KEY_LEFT_GPIO_PIN 		GPIO_Pin_13
    #define KEY_RIGHT_GPIO_PIN 		GPIO_Pin_12
    
    #define KEY_RST_EXTI_LINE 		EXTI_Line0
    #define KEY_UP_EXTI_LINE 		EXTI_Line15
    #define KEY_DOWN_EXTI_LINE 		EXTI_Line14
    #define KEY_LEFT_EXTI_LINE 		EXTI_Line13
    #define KEY_RIGHT_EXTI_LINE 	EXTI_Line12
    //5ms计数器
    unsigned short delay_Time5ms = 0;
    //按键被按下标志
    unsigned char myKey_IsPressed_Flag = 0;
    //按键扫描延时周期
    unsigned char myKey_GetKeyValue_delayTime5ms;
    
    unsigned char delay_EXTI0_delayTime5ms;
    
    unsigned char delay_EXTI15_10_delayTime5ms;
    
    
    myKey_ValueTypedef key_RST_Value;
    myKey_ValueTypedef key_UP_Value;
    myKey_ValueTypedef key_DOWN_Value;
    myKey_ValueTypedef key_LEFT_Value;
    myKey_ValueTypedef key_RIGHT_Value;
    u8 myKey_ValueChangedFlag = 0;;
    
    
    void TIM3_IRQHandler(void);   //TIM3中断
    void TIM3_Int_Init(u16 arr,u16 psc);
    
    
    
    void myKey_Init()
    {
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA, ENABLE);
    		/* EXTI的时钟要设置AFIO寄存器 */
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE) ;
    	
    	GPIO_InitTypeDef GPIO_InitStructure;
    	EXTI_InitTypeDef EXTI_InitStruct;
    	NVIC_InitTypeDef NVIC_InitStructure;
    	
    	
    	
    	GPIO_InitStructure.GPIO_Pin =  KEY_RST_GPIO_PIN;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//上拉输入
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Pin =  KEY_UP_GPIO_PIN | KEY_DOWN_GPIO_PIN | KEY_LEFT_GPIO_PIN | KEY_RIGHT_GPIO_PIN;
    	GPIO_Init(GPIOB, &GPIO_InitStructure);
    	
    	/* 初始化EXTI外设 */
    	/* 选择作为EXTI线的GPIO引脚 */
    	GPIO_EXTILineConfig( KEY_RST_GPIO_PortSource , KEY_RST_GPIO_PinSource) ;
    	/* 配置中断or事件线 */
    	EXTI_InitStruct.EXTI_Line = KEY_RST_EXTI_LINE ;
    	/* 配置模式:中断or事件 */
    	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
    	/* 配置边沿触发 上升or下降 */
    	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
    	/* 使能EXTI线 */
    	EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
    	EXTI_Init(&EXTI_InitStruct) ;
    	
    	GPIO_EXTILineConfig( KEY_UP_GPIO_PortSource ,  KEY_UP_GPIO_PinSource) ;
    	EXTI_InitStruct.EXTI_Line = KEY_UP_EXTI_LINE;
    	EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
    	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
    	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
    	EXTI_Init(&EXTI_InitStruct);
    	
    	GPIO_EXTILineConfig( KEY_DOWN_GPIO_PortSource ,  KEY_DOWN_GPIO_PinSource) ;
    	EXTI_InitStruct.EXTI_Line = KEY_DOWN_EXTI_LINE;
    	EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
    	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
    	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
    	EXTI_Init(&EXTI_InitStruct);
    	
    	GPIO_EXTILineConfig( KEY_LEFT_GPIO_PortSource ,  KEY_LEFT_GPIO_PinSource) ;
    	EXTI_InitStruct.EXTI_Line = KEY_LEFT_EXTI_LINE;
    	EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
    	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
    	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
    	EXTI_Init(&EXTI_InitStruct);
    	
    	GPIO_EXTILineConfig( KEY_RIGHT_GPIO_PortSource ,  KEY_RIGHT_GPIO_PinSource) ;
    	EXTI_InitStruct.EXTI_Line = KEY_RIGHT_EXTI_LINE;
    	EXTI_InitStruct.EXTI_LineCmd = ENABLE ;
    	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt ;
    	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling ;
    	EXTI_Init(&EXTI_InitStruct);
    	
    	
    	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;  //
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  //先占优先级2级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  //从优先级2级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器
    	
    	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;  //
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  //先占优先级2级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级2级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 
    	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器
    
    
    	//中断的时间为t:t = (arr * psc / APB1*2) * 1000 ms
    	TIM3_Int_Init(1000,360); //5ms
    }
    
      
    
    
    void EXTI0_IRQHandler(void)
    {
    	delay_EXTI0_delayTime5ms = 0;
    	while(delay_EXTI0_delayTime5ms > 2);
    	if(!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0))
    	{
    		myKey_IsPressed_Flag = 1;
    	}
    	
    	EXTI_ClearITPendingBit(KEY_RST_EXTI_LINE);
    	
    }
    
    
    void EXTI15_10_IRQHandler(void)
    {
    	if(EXTI_GetITStatus(KEY_UP_EXTI_LINE)!=RESET)
    	{
    		delay_EXTI15_10_delayTime5ms = 0;
    		while(delay_EXTI15_10_delayTime5ms > 2);
    		if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15))
    		{
    			myKey_IsPressed_Flag = 1;
    	
    		}
    	}
    	if(EXTI_GetITStatus(KEY_DOWN_EXTI_LINE)!=RESET)
    	{
    		delay_EXTI15_10_delayTime5ms = 0;
    		while(delay_EXTI15_10_delayTime5ms > 2);
    		if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14))
    		{
    			myKey_IsPressed_Flag = 1;
    		
    		}
    	}
    	if(EXTI_GetITStatus(KEY_LEFT_EXTI_LINE)!=RESET)
    	{
    		delay_EXTI15_10_delayTime5ms = 0;
    		while(delay_EXTI15_10_delayTime5ms > 2);
    		if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13))
    		{
    			myKey_IsPressed_Flag = 1;
    			
    		}
    	}
    	if(EXTI_GetITStatus(KEY_RIGHT_EXTI_LINE)!=RESET)
    	{
    		delay_EXTI15_10_delayTime5ms = 0;
    		while(delay_EXTI15_10_delayTime5ms > 2);
    		if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12))
    		{
    			myKey_IsPressed_Flag = 1;
    		
    		}
    	}
    	
    		
    	EXTI_ClearITPendingBit(KEY_UP_EXTI_LINE);
    	EXTI_ClearITPendingBit(KEY_DOWN_EXTI_LINE);
    	EXTI_ClearITPendingBit(KEY_LEFT_EXTI_LINE);
    	EXTI_ClearITPendingBit(KEY_RIGHT_EXTI_LINE);
    
    }
    
    
    void judge_KeyValue(GPIO_TypeDef * keyGPIO, uint16_t keyGPIO_Pin, myKey_ValueTypedef * keyValue)
    {
    	//键处理
    	if(!GPIO_ReadInputDataBit(keyGPIO, keyGPIO_Pin))//如果按键处于按下状态
    	{
    		if(keyValue->keyState == KEY_UNPRESSED)
    		{
    			keyValue->keyState = KEY_PRESSED;
    			keyValue->pressedTime5ms = 0;
    		}
    		else if(keyValue->keyState == KEY_PRESSED && keyValue->pressedTime5ms >= 200)
    		{
    			keyValue->isLongPressing = 1;	
    		}
    	}
    	
    	//如果按键处于弹起状态状态并且之前有被按下,则将根据按下时间确定键值
    	else if(GPIO_ReadInputDataBit(keyGPIO, keyGPIO_Pin) && keyValue->keyState == KEY_PRESSED)
    	{
    		keyValue->keyState = KEY_UNPRESSED;
    		keyValue->isLongPressing = 0;	
    		if(keyValue->pressedTime5ms >= 200)
    		{
    			keyValue->longPressed = 1;
    			keyValue->shortPressed = 0;
    		}
    		else
    		{
    			keyValue->longPressed = 0;
    			keyValue->shortPressed = 1;
    		}
    		myKey_IsPressed_Flag = 0;	
    		myKey_ValueChangedFlag = 1;
    	}
    }
    
    //扫描按键消息进程
    void myKey_GetKeyValue()
    {
    	if(myKey_IsPressed_Flag == 1 && myKey_GetKeyValue_delayTime5ms > 10) //判断如果有按键被按下了 ,并且按键扫描周期到达相应时间了则开始扫描按键
    	{
    		
    		
    		judge_KeyValue(KEY_RST_GPIO_PORT, KEY_RST_GPIO_PIN, &key_RST_Value);
    		judge_KeyValue(KEY_UP_GPIO_PORT, KEY_UP_GPIO_PIN, &key_UP_Value);
    		judge_KeyValue(KEY_DOWN_GPIO_PORT, KEY_DOWN_GPIO_PIN, &key_DOWN_Value);
    		judge_KeyValue(KEY_LEFT_GPIO_PORT, KEY_LEFT_GPIO_PIN, &key_LEFT_Value);
    		judge_KeyValue(KEY_RIGHT_GPIO_PORT, KEY_RIGHT_GPIO_PIN, &key_RIGHT_Value);
    
    		
    		myKey_GetKeyValue_delayTime5ms = 0;//清楚按键扫描周期计数
    		
    	}
    	
    }
    
    
    //按键计时中断
    //定时器3中断服务程序 5ms一次
    void TIM3_IRQHandler(void)   //TIM3中断
    {
    	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
    		{
    			TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中断标志 
    			
    			delay_Time5ms++;
    			if(delay_Time5ms == 200)//1S
    			{
    				delay_Time5ms = 0;
    				//testDynamicNum ++;
    				
    				
    			}
    			
    			if(key_RST_Value.keyState == KEY_PRESSED)
    			{
    				key_RST_Value.pressedTime5ms++;
    			}
    			
    			if(key_UP_Value.keyState == KEY_PRESSED)
    			{
    				key_UP_Value.pressedTime5ms++;
    			}
    			if(key_DOWN_Value.keyState == KEY_PRESSED)
    			{
    				key_DOWN_Value.pressedTime5ms++;
    			}
    			if(key_LEFT_Value.keyState == KEY_PRESSED)
    			{
    				key_LEFT_Value.pressedTime5ms++;
    			}
    			if(key_RIGHT_Value.keyState == KEY_PRESSED)
    			{
    				key_RIGHT_Value.pressedTime5ms++;
    			}
    			
    			delay_EXTI0_delayTime5ms++;
    			delay_EXTI15_10_delayTime5ms++;
    			myKey_GetKeyValue_delayTime5ms++;
    			
    //			if(delay_EXTI0_delayTime5ms > 200)delay_EXTI0_delayTime5ms = 0;
    //			if(delay_EXTI15_10_delayTime5ms > 200)delay_EXTI15_10_delayTime5ms = 0;
    //			if(myKey_GetKeyValue_delayTime5ms > 200)myKey_GetKeyValue_delayTime5ms = 0;
    		}
    }
    
    
    //这里时钟选择为APB1的2倍,而APB1为36M
    //arr:自动重装值。
    //psc:时钟预分频数
    //一次中断的时间为t:t = (arr * psc / APB1*2) * 1000 ms
    void TIM3_Int_Init(u16 arr,u16 psc)
    {
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
     
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
    	
    	//定时器TIM3初始化
    	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
     
    	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
     
    	//中断优先级NVIC设置
    	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  //先占优先级0级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器
     
     
    	TIM_Cmd(TIM3, ENABLE);  //使能TIM3					 
    }
    
    
    
    

    “myKey.h”

    #ifndef __MYKEY_H_
    #define __MYKEY_H_
    #include <stm32f10x.h>
    
    
    //定义按键物理状态枚举
    typedef enum 
    {
    	KEY_UNPRESSED = 0,
    	KEY_PRESSED = ~KEY_UNPRESSED,
    }keyState_enum;
    
    //定义按键消息结构体
    typedef struct 
    {
    	//按键消息
    	unsigned char longPressed ;
    	unsigned char shortPressed ;
    	unsigned char doublePressed ;
    	unsigned char isLongPressing ;
    	//按键物理状态变量
    	keyState_enum keyState ;
    	//按键消息触发计时
    	unsigned int pressedTime5ms ;
    	unsigned char pressedTime1s;
    }myKey_ValueTypedef;
    
    //定义5个按键结构体
    extern myKey_ValueTypedef 			key_RST_Value;
    extern myKey_ValueTypedef 			key_UP_Value;
    extern myKey_ValueTypedef 			key_DOWN_Value;
    extern myKey_ValueTypedef 			key_LEFT_Value;
    extern myKey_ValueTypedef 			key_RIGHT_Value;
    
    extern u8 myKey_ValueChangedFlag;//按键消息改变标志位
    extern u8 testNum;
    
    
    void myKey_Init(void);//按键初始化
    void myKey_GetKeyValue(void);//更新按键消息
    void TIM3_Int_Init(u16 arr,u16 psc);//按键触发计时定时器初始化
    
    #endif
    
    
    
    

        如果有什么宝贵的建议请留言或私信,谢谢

    展开全文
  • 利用定时器,外部中断,串口,GPIO完成的一个stm32小项目。
  • STM32按键的短按/长按/双击

    万次阅读 2018-06-06 15:54:26
    上一篇文章已经写好了定时器,并且实现了按键长按。 现在狭隘的用一下: ...//⑥外部中断 2 服务程序 按键效果!!! void EXTI2_IRQHandler(void) { if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2) == 0) //按键 KEY2 ...

    上一篇文章已经写好了定时器,并且实现了按键长按。

    现在狭隘的用一下:

    https://mp.weixin.qq.com/s?__biz=MzUyOTM0NDkyMA==&mid=2247484014&idx=1&sn=b07bde8a1d5b15467b2c80dfd7ae3547&chksm=fa633299cd14bb8f8e9334282059930bafabf44dfcf502b0a39b7f30326268f8574acc0b0ccf&mpshare=1&scene=23&srcid=0606fxjOEkyOf9zu21GHV78G#rd

    //⑥外部中断 2 服务程序  按键效果!!!
    void EXTI2_IRQHandler(void)
    {
        if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2) == 0) //按键 KEY2
        {
            key_fall_flag = 1;//生成按键按下标志
        }
        EXTI_ClearITPendingBit(EXTI_Line2); //清除 LINE2 上的中断标志位
    }
    
    
    
    //中断效果
    void TIM3_IRQHandler(void) //TIM3 中断
    {
      static u16 keyupCnt = 0;//按键弹起后计数值
      static u16 key_holdon_ms = 0;//按下的时长
      u16 keyUpFlag = TRUE;//按键弹起标志
    	
      if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //检查 TIM3 更新中断发生与否
        {
    	TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除 TIM3 更新中断标志
            if(key_fall_flag == 1) //发生按键按下事件(按键中断发生,在按键中断中设置为1)
            {
                if(GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2) == 0) //按键还是按下的
                {			
                    if(key_holdon_ms <= 2000)
                    {
                        key_holdon_ms++;
                    }
    		else if(key_holdon_ms > 2000) //按键按下到2000ms就判断长按时间成立,生成长按标志
                    {
                        key_holdon_ms = 0;	//清除时间单位
                        short_key_flag = 0; //清短按键标志
                        key_long_down = 1;  //长按键标志置位!!!OK
                        key_fall_flag = 0;  //清按键按下标志
    										keyUpFlag = FALSE;  //标记按下
    										keyupCnt = 0;
    										LED1 = ~LED1;
                    }
    								//距离上次单击时间在100~500ms之间,则认为发生连击事件
    								if((keyupCnt > 300) && (keyupCnt < 500))
    								{
    									keyupCnt = 0;
    									doubleClick = 1;	//标记发生了连击事件!!OK
    									BEEP = ~BEEP;
    								}
    			
                }
                else //当时是按下去的,此时已经释放按键了
                {			
    								keyupCnt = 0;
                    if(key_holdon_ms > 50) //按下时间大于50ms,生成单击标志
                    {
                        key_holdon_ms = 0;
                        short_key_flag = 1;	//标记短按标志!!OK
                        key_long_down = 0;	//清除长按标志
                        key_fall_flag = 0;
    										LED0 = ~LED0;
    										keyupCnt = 0;
                    
    										//距离上次单击时间在100~500ms之间,则认为发生连击事件
    										if(keyupCnt>100 && keyupCnt<500)
    										{ 
    											 doubleClick = TRUE;
    											 short_key_flag=0;
    										} 
    										keyUpFlag = TRUE;//单击抬起按键后,生成按键抬起标志 
    								}
                    else  //按键持续时间小于50ms,忽略
                    {
                        key_holdon_ms = 0;//按键按下时间的位
                        short_key_flag = 0;//短按
                        key_long_down = 0;//长按标志
                        key_fall_flag = 0;//按键按下标志
    										keyupCnt = 0;
                    }
    				
                }
    
    
            }
    
    
            if(keyUpFlag)//单击抬起后,启动计数,计数到500ms
                keyupCnt++;
    
    
            if(keyupCnt > 500)
            {
                keyupCnt = 0;
                keyUpFlag = FALSE;//标记为弹起
            }
    
    
        }
    }
    

    结合第一个文章  看看按键的单 双 长 按的代码

    https://pan.baidu.com/s/1gg-1zcC9gRY1CY67qOJpfQ



    展开全文
  • STM32按键识别 状态机( 单击 双击 长按)可以根据情况自己在添加多击 长按 在做嵌入式产品时按键是最常用的输入信号了,按键多的时候我们可以实现很多的功能,有时候资源不够,但又需要实现较多的功能时,这就需要...

    STM32按键识别 状态机( 单击 双击 长按)可以根据情况自己在添加多击 长按

    在做嵌入式产品时按键是最常用的输入信号了,按键多的时候我们可以实现很多的功能,有时候资源不够,但又需要实现较多的功能时,这就需要按键复用了,常常一个按键包含短按,长按,或者双击,N击,赋予不同的功能,这和具体项目有关。我们通常做的方法是识别I/O引脚电平,然后加以适当防抖处理,那么简单的按键单击功能就可以实现了。

    先明确自己需要实现的功能

    用户基本操作定义:
    1。短按操作:按键按下,按下时间<1s,属于一次短按操作
    2。长按操作:按键按下,按下时间>1.5s,属于一次长按操作
    在正常0.5s内无按键操作为启始按键扫描条件下,扫描按键将产生以下3种按键事件:
    1。长按事件:任何1次出现的长按操作都属于长按事件
    2。单击事件:1次短按操作后,间隔0.5内没有短按操作
    3。双击事件:2次短按操作间隔时间<0.5s,则2次短按操作为1次双击事件,且2次短按都取消

    对按键操作者的建议:
    由于按键的多功能性质,建议操作者每次在单击/长按/双击按键事件发生后,隔0.5s后再进行下一次的按键操作。因为在特别操作情况下,程序是保证按定义进行判断和处理的,主要是怕操作者自己记不清楚导致操作失误。

    STM32的IO初始化代码 和 定时器初始化代码这方面的代码,很多大佬理解的比我还好,我就不献丑了

    读取按键的状态

    /****************************************************************************

    • 名 称: GetKEY(void)
    • 功 能:取得按键GPIO的值
    • 入口参数:无
    • 出口参数:返回按键值
    • 说 明:如果读到低电平则说明有按键按下,不同的CPU只要更改if里面的读取方式即可
    • 调用方法:key_driver 函数调用 用于判断是否有按键按下
      增加按键或者删除按键 需要对应增加或者删除
      ***************************************************************************/
      uint8_t GetKEY(void)
      {
      if(GPIO_ReadInputDataBit(GPIO_PORT_K1, GPIO_PIN_K1) == PRESS) /
      读取按键 2 的状态 /
      {
      return KEY_K1;//按键被按下 返回1
      }
      if(GPIO_ReadInputDataBit(GPIO_PORT_K2, GPIO_PIN_K2) == PRESS) /
      读取按键 2 的状态 /
      {
      return KEY_K2;//按键被按下 返回2
      }
      if(GPIO_ReadInputDataBit(GPIO_PORT_K3, GPIO_PIN_K3) == PRESS) /
      读取按键 2 的状态 */
      {
      return KEY_K3;//按键被按下 返回3
      }
      return KEY_NO_DOWN;
      }

    实现 单击 和 长按

    /****************************************************************************

    • 名 称:unsigned char key_driver(void)

    • 功 能:状态机检测按键

    • 入口参数:无

    • 出口参数:返回按键值

    • 调用方法:该函数实现按键的单击长按和没有按键按下的检测
      添加或者删除独立按键不需要更改此处
      ****************************************************************************/
      unsigned char key_driver(void)
      {
      static unsigned char key_state = 0; // 按键状态变量
      static unsigned int key_time = 0; // 按键计时变量
      static unsigned char Key_LaetgValue = 0;//上一次扫描的键值
      unsigned char Key_LaetPress,key_press, key_return;//当前按键键值

      key_return = N_KEY; // 清除 返回按键值

      Key_LaetPress = key_press = GetKEY(); // 读取当前键值

      if( Key_LaetPress ) //保存按键的的键值只在非 0 的状态才改变其按键值
      {
      Key_LaetgValue = key_press;
      }

      switch (key_state)
      {
      case KEY_STATE_A: // 按键状态A:判断有无按键按下
      if ( ( key_press != 0 ) & (key_press == Key_LaetPress) ) // 有按键按下
      {
      key_time = 0; // 清零时间间隔计数
      key_state = KEY_STATE_B; // 然后进入 按键状态B
      }
      break;

      case KEY_STATE_B: // 按键状态B:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
      if (key_press == Key_LaetPress)
      {
      key_time++; // 一次10ms
      if(key_time>=SINGLE_KEY_TIME) // 消抖时间为:SINGLE_KEY_TIME*10ms;
      {
      key_state = KEY_STATE_C; // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
      }
      }
      else
      {
      key_state = KEY_STATE_A; // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
      }
      break;

      case KEY_STATE_C: // 按键状态C:判定按键有效的种类:是单击,还是长按
      if( key_press == 0 ) // 如果按键在 设定的长按时间 内释放,则判定为单击
      {
      key_return = (Key_LaetgValue | KEY_STATE_C ); // 返回 有效按键值:单击
      key_state = KEY_STATE_A; // 返回 按键状态A,继续等待按键
      }
      else
      {
      key_time++;
      if(key_time >= LONG_KEY_TIME) // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME10ms=20010ms=2000ms), 则判定为 长按
      {
      key_return = (Key_LaetgValue | KEY_STATE_E ); // 返回 有效键值值:长按
      key_state = KEY_STATE_F; // 去等待释放状态
      }
      }
      break;

      case KEY_STATE_F: // 按键状态C:按键释放
      if ( key_press == 0 )
      {
      key_state = KEY_STATE_A; // 按键释放后,进入 按键状态A ,进行下一次按键的判定
      }
      break;

      default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
      key_state = KEY_STATE_A;
      break;
      }

      return key_return; // 返回 按键值
      }

    单击 双击 检测

    /****************************************************************************

    • 名 称:char key_read(void)

    • 功 能:状态机检测按键

    • 入口参数:无

    • 出口参数:返回按键值

    • 调用方法:该函数是对 key_driver 函数的调用 用于实现按键的 双击 和 单击 检测
      ****************************************************************************/
      unsigned char key_read(void)
      {
      static unsigned char KeyState = 0; // 初始化状态机的状态
      static unsigned int KeyTime = 0; // 按键计时变量
      static unsigned char LaetgKeyValue = 0;//上一次扫描的键值
      unsigned char KeyValue,KeyReturnValue;//当前按键键值

      KeyReturnValue = N_KEY; // 清除 返回按键值

      KeyValue = key_driver(); // 读取当前键值的状态

      if( KeyValue ) //保存按键的的键值只在非 0 的状态才改变其按键值
      {
      LaetgKeyValue = KeyValue & VALUE; //取出按键值 去掉按键的状态编号
      }

      switch (KeyState)
      {
      case KEY_STATE_A: // 按键状态0:判断有无按键按下
      if ( ( KeyValue & STATE ) == KEY_STATE_C ) // 判断是否有单击按键
      {
      KeyTime = 0; // 清零时间间隔计数
      KeyState = KEY_STATE_D; // 然后进入 按键状态D
      }
      else // 对于无键、长键,返回原事件
      {
      KeyReturnValue = KeyValue;
      }
      break;

      case KEY_STATE_D: // 按键状态D:双击状态
      if ( ( KeyValue & STATE ) == KEY_STATE_C )
      {
      KeyReturnValue = (LaetgKeyValue | KEY_STATE_D ); // 返回 有效按键值:双击
      KeyState = KEY_STATE_F; // 然后进入 按键状态F
      }
      else if ( ++KeyTime >= DOUBLE_KEY_TIME ) //DOUBLE_KEY_TIME*10ms时间内没有再次单击 视为单击
      {
      KeyReturnValue = (LaetgKeyValue | KEY_STATE_C ); //返回 有效按键值:单击
      KeyState = KEY_STATE_A; // 然后进入 按键状态F
      }
      break;

      case KEY_STATE_F: // 等待按键释放
      if ( KeyValue == 0 )
      {
      KeyState = KEY_STATE_A; // 按键释放后,进入 按键状态0 ,进行下一次按键的判定
      }
      break;

      default: // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
      KeyState = KEY_STATE_A;
      break;
      }

      return KeyReturnValue; // 返回 按键值
      }

    定时器调用函数

    /*


    • 函 数 名: GENERAL_TIM3_IRQHandler
    • 功能说明: 定时器 的中断处理函数
    • 形 参: 无
    • 返 回 值: 无

    /
    uint16_t Number;
    extern uint8_t g_u8_KeyValue;
    void GENERAL_TIM3_IRQHandler (void)
    {
    if ( TIM_GetITStatus( GENERAL_TIM3_TIM, TIM_IT_Update) != RESET )
    {
    TIM_ClearITPendingBit(GENERAL_TIM3_TIM, TIM_IT_Update);
    /
    中断任务执行*/
    g_u8_KeyValue = key_read();
    switch(g_u8_KeyValue)
    {
    case Key1_S:
    printf(" This is 11 SINGLE key ! \r\n" );
    break;
    case Key1_D:
    printf(" This is 11 DOUBLE key ! \r\n" );
    break;
    case Key1_L:
    printf(" This is 11 LONG key ! \r\n" );
    break;
    case Key2_S:
    printf(" This is 22 SINGLE key ! \r\n" );
    break;
    case Key2_D:
    printf(" This is 22 DOUBLE key ! \r\n" );
    break;
    case Key2_L:
    printf(" This is 22 LONG key ! \r\n" );
    break;
    case Key3_S:
    printf(" This is 33 SINGLE key ! \r\n" );
    break;
    case Key3_D:
    printf(" This is 33 DOUBLE key ! \r\n" );
    break;
    case Key3_L:
    printf(" This is 33 LONG key ! \r\n" );
    break;
    default:
    break;
    }
    }
    }

    变量定义

    //按键状态
    #define KEY_STATE_A 0xA0 // 无
    #define KEY_STATE_B 0xB0 // 软件消抖
    #define KEY_STATE_C 0xC0 // 单击
    #define KEY_STATE_D 0xD0 // 双击
    #define KEY_STATE_E 0xE0 // 长按
    #define KEY_STATE_F 0xF0 // 等待按键释放

    //用于识别按键的状态 用它与按键的状态相与即可区分
    #define STATE 0xF0 // 等待按键释放
    #define VALUE 0x0F // 存放按键值

    //用于识别按键按下的状态识别
    #define PRESS RESET //低电平识别

    //按键时间调整
    #define SINGLE_KEY_TIME 3 // 消抖时间为 SINGLE_KEY_TIME10MS
    #define DOUBLE_KEY_TIME 50 /
    双击间隔时间 DOUBLE_KEY_TIME10MS 改变这个数值可以增加按键的灵敏度 数值越小 灵敏度越高
    此数值
    定时器定时时间要大于消抖时间 小于长按按键的时间 /
    #define LONG_KEY_TIME 150 // 长按时间 LONG_KEY_TIME
    10MS

    // 按键值 增加按键或者删除按键 需要对应增加或者删除
    #define KEY_NO_DOWN 0x00 //无按键按下
    #define KEY_K1 0x01 // 第一个按键按下
    #define KEY_K2 0x02 // 第二个按键按下
    #define KEY_K3 0x03 // 第三个按键按下

    //按键返回值 增加按键或者删除按键 需要对应增加或者删除
    #define N_KEY 0 // no click
    #define Key1_S (KEY_STATE_C | KEY_K1 ) // single click
    #define Key1_D (KEY_STATE_D | KEY_K1 ) // double press
    #define Key1_L (KEY_STATE_E | KEY_K1 ) // long press

    #define Key2_S (KEY_STATE_C | KEY_K2 ) // single click
    #define Key2_D (KEY_STATE_D | KEY_K2 ) // double press
    #define Key2_L (KEY_STATE_E | KEY_K2 ) // long press

    #define Key3_S (KEY_STATE_C | KEY_K3 ) // single click
    #define Key3_D (KEY_STATE_D | KEY_K3 ) // double press
    #define Key3_L (KEY_STATE_E | KEY_K3 ) // long press

    完整工程链接
    参考教程
    参考博客 https://blog.csdn.net/u010360138/article/details/79148966
    FSM状态机按键功能解析 http://www.doc88.com/p-8252759803281.html

    展开全文
  • 给arm初学者一个比较实用的多功能按键,实现单击,双击,长按。声明一下:这是我修改的例程。 key.h #define key_5 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5) key.c //在函数之外定义全局变量,这个几个标志位...
  • STM32CUEB关于KEIL5、stm32f103c8t6的单次、双击、长按三种按键程序代码实现 .
  • STM32使用HAL库实现按键的单击、双击、长按 目录STM32使用HAL库实现按键的单击、双击、长按前言具体思路工程配置代码实现实验效果 前言 编程开发环境:STM32CubeIDE        &...
  • 1、mcu:stm32f103zet6 2、实现功能: 长按实现:亮/灭LED7,并且data++;亮/灭LED8 短按:亮/灭LED6; 双击:亮/灭LED8 3、实现步骤: 利用外部中断监测按键是否被按下,按下标志位设为1; 定时器(20Ms)监测标志位、...
  • 由于项目产品的需要,只能设置一个按键,但是需要实现短按(即单击)切换工作模式、长按开关机、双击暂停等复用功能。下图是三种情况下的按键波形。按键未按下时是高电平,按下去是低电平。按键单击时,判断时间门槛...
  • 目录- 单击、双击、长按原理解析 - 程序源码 - 思考总结引言:在很多项目开发过程中我们通常会涉及到按键的使用,为了使按键的功能更多远化我们通常会区别按键的单击、双击、长按等操作过程从而实现更多的功能。...
  • stm32F4, 按键模块:用一个按键,KEY0=PG3, LED灯:LED0==PF7,LED1=PF8,共阳接法 内部资源 定时器3定时5ms作为基准(这个需要实际测量,看下是否正确,怎么测量?定时5ms,然后在定时器中断函数里面,让LED0取反...
  • 由于项目产品的需要,只能设置一个按键,但是需要实现短按(即单击)切换工作模式、长按开关机、双击暂停等复用功能。下图是三种情况下的按键波形。按键未按下时是高电平,按下去是低电平。按键单击时,判断时间门槛...
  • STM32-蓝桥杯嵌入式之三行按键检测 目录STM32-蓝桥杯嵌入式之三行按键检测一、检测按键下降沿分析二、检测按键上升沿分析三、按键检测程序的核心代码 首先先说说异或,异或即相同为0不同为1,可以通过使用异或来判断...
  • 由于项目产品的需要,只能设置一个按键,但是需要实现短按(即单击)切换工作模式、长按开关机、双击暂停等复用功能。下图是三种情况下的按键波形。按键未按下时是高电平,按下去是低电平。按键单击时,判断时间门槛...
  • stm32cubeMX学习二、按键点灯与灭灯

    千次阅读 2019-06-29 21:30:31
    上一节入门了stm32cubeMX,这节我们来学习下编写一个按键的程序。 本程序编写基于秉火霸道STM32F103ZET6开发板进行。 一、打开stm32cubeMX软件 二、选择芯片型号 首先点击File,然后选择New Project,在弹...

空空如也

空空如也

1 2 3 4
收藏数 75
精华内容 30
关键字:

stm32按键双击