stm32按键 长按 短按 函数 一

 

在stm32工程中,长按和短按的代码书写, 调用的读取按键状态的底层函数。封装成的按键函数代码。下面是函数的头文件,和.c文件的代码。使用定时器来扫描按键。

#define KEY_ON	1
#define KEY_OFF	0
#define KEY_NULL 0
#define KEY_SHORT 1
#define KEY_LONG  10
#define SHORT_TIME 200
uint8_t Key_state(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	 static uint8_t key_value = KEY_NULL;
	 static uint16_t longtime;
	 if( (longtime == 0) && (key_value != KEY_NULL))  //当按键状态为长按或者短按时,而longtime 不为零,则按键状态清零
	 { 
	     key_value = KEY_NULL;
	 }
	 if ( time == 5 ) /* 5 * 1 ms = 5ms 定时时间到 */
     {
        time = 0;
		if(KEY_PRESS(GPIOx,GPIO_Pin))  //按键按下
	    {
	         longtime++;
        }
        else  //按键松开
		{
		    if((longtime >= 3) && (longtime <= SHORT_TIME))  //短按
			{
				key_value = KEY_SHORT;
			}
			else if( longtime > SHORT_TIME ) //长按
			{
			    key_value = KEY_LONG;
			}
			else  //去抖动
			{
			    key_value = KEY_NULL;
			}
				longtime = 0; //清零
		}					
     }  
 return key_value;
}

上面的代码,是按键松开才能判断按键的状态,是长按还是短按。在实际项目中我需要,按键按下一段时间后,判断为按键长按,不用松开,返回按键长按。参考网上的代码,使用状态机写了如下代码

#define    KEY_PRESS(GPIOx,GPIO_Pin)      GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)
#define KEY_INPUT           KEY_PRESS(GPIOx,GPIO_Pin)    //读取按键状态

#define KEY_STATE_0         0       // 按键状态位
#define KEY_STATE_1         1
#define KEY_STATE_2         2
#define KEY_STATE_3         3

#define LONG_KEY_TIME       300     //长按的3秒时间
#define SINGLE_KEY_TIME     3       // 短按的消抖时间

#define N_KEY    0                  // 无状态
#define S_KEY    1                  // 单击
#define L_KEY    10                 // 长按

 

 

 

 

 

 

函数的主体部分,代码中按下按键读取到高电平。

unsigned char key_driver(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)) 
{     
    static unsigned char key_state = 0;         // 按键状态变量
    static unsigned int key_time = 0;           // 按键计时变量
    unsigned char key_press, key_return; 

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

    key_press = KEY_INPUT;                      // 读取当前键值

    switch (key_state)     
    {       
        case KEY_STATE_0:                       // 按键状态0:判断有无按键按下
            if (key_press == KEY_ON)                     // 有按键按下
            {
                key_time = 0;                   // 清零时间间隔计数
                key_state = KEY_STATE_1;        // 然后进入 按键状态1
            }        
            break;

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

        case KEY_STATE_2:                       // 按键状态2:判定按键有效的种类:是单击,还是长按
            if(key_press == KEY_OFF)                       // 如果按键在 设定的长按时间 内释放,则判定为单击
            { 
                 key_return = S_KEY;            // 返回 有效按键值:单击
                 key_state = KEY_STATE_0;       // 返回 按键状态0,继续等待按键
            } 
            else
            {
                key_time++;                     

                if(key_time >= LONG_KEY_TIME)   // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=200*10ms=2000ms), 则判定为 长按
                {
                    key_return = L_KEY;         // 返回 有效键值值:长按
                    key_state = KEY_STATE_3;    // 去状态3,等待按键释放
                }
            }
            break;

      case KEY_STATE_3:                         // 等待按键释放
          if (key_press == KEY_OFF) 
          {
              key_state = KEY_STATE_0;          // 按键释放后,进入 按键状态0 ,进行下一次按键的判定
          }         
          break; 

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

    return key_return;                          // 返回 按键值
} 
unsigned char key_handle(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
	unsigned char key_value;
  if ( time >= 10 ) /* 10 * 1 ms = 10ms 定时器 */
   {
        time = 0;
		    key_value = key_driver(GPIOx,GPIO_Pin); 
	 }
	 return key_value;
}

time 这个变量,定义在了定时器文件中

 在main.c中调用

int main(void)
{
	int8_t key_value;
	/* led 初始化*/ 
	LED_GPIO_Config();
	
	BASIC_TIM_Init();
	
	Key_GPIO_Config();
	
  while(1)
  {

//		key_value = Key_state(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
		key_value = key_handle(KEY1_GPIO_PORT,KEY1_GPIO_PIN);

		if(key_value == KEY_SHORT)
		{
			  
		    LED1_TOGGLE;
		}
		else if(key_value == KEY_LONG)
		{
		    LED2_TOGGLE; 
		}
		
  }
}

这样可以实现长按不松手,执行长按的代码。以后遇到好的思想会继续学习,总结下来。

代码风格不是特别好,很早之前写的了,放在这里了,仅供参考

链接    提取码:66zh

 

https://blog.csdn.net/xiaohu1996/article/details/103236089

这个是我写的按键二的博客,一些思想可以提供学习

你可能感兴趣的:(C,技术整理,stm32)