【按键】三行核心代码解决按键按下、松开、长按。代码高效移植快(附源码)

介绍

  1. 硬件平台 :stm32f103c8t6(都一样,有定时器的就行)
  2. 消抖方式:定时器消抖
  3. 按键触发方式:对地触发(ad触发也一样)

核心代码分析

先贴个结构体做全局变量

typedef struct
{
     
  uint8_t now:1;         //当前键值
  uint8_t press:1;       //按下flag
  uint8_t release:1;     //释放flag
  uint8_t continued:1;   //持续按下flag
  uint16_t duration;    //持续按下时间
}Key;

typedef struct
{
      
	Key    		   key[KEY_COUNT]; 
}KeyData;	

正片内容:

 

/*  该代码段放在定时器里面扫描,
	返回值为按键值
    本人习惯20ms刷新一次
 */
 #define KEY_COUNT 1 //按键数量
 KeyData   keys; 
uint16_t KeyScan(void)
{
     
	uint16_t key_num = 0;
	uint8_t i; 
	for (i=0;i<KEY_COUNT;i++)
	{
     
		keys.key[i].now=0x00;
	} 
	if(!HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_10))//按键按下
	{
     
		keys.key[KEY_1].now=KEY_DOWN; 
	}
	for (i=0;i<KEY_COUNT;i++)// 此按键程序的心脏,具体得细品。
	{
     	 
		keys.key[i].press=keys.key[i].now & (keys.key[i].now^keys.key[i].continued);//按下判断
		keys.key[i].release=keys.key[i].now ^ keys.key[i].press ^ keys.key[i].continued;//松开判断
		keys.key[i].continued=keys.key[i].now;//长按判断
		if (keys.key[i].continued==0x00)
		  keys.key[i].duration =0;//长按时间清零
	}
	key_num = KeyPress(); //按下判断返回
	if(key_num) 
		return key_num; 
	key_num = KeyRelease();//松开判断返回
	if(key_num) 
		return key_num; 
	key_num = KeyContinued();//长按判断返回
	if(key_num) 
		return key_num; 
	
	return 0;  
}

按下、松开、长按处理判断程序,各自建立一个函数体,不然按键多的时候代码很啰嗦。这里按下返回值为1,松开返回值为11,长按返回值为111,若无任务,都返回0.

  uint16_t KeyPress(void)
{
     
	if (keys.key[KEY_1].press)//电源 
		return 1; 
	return 0;
}

  uint16_t KeyRelease(void)
{
      
	if (keys.key[KEY_1].release)//  
		return 11; 
	return 0;//
}
// keys.key[KEY_1].duration为长按时间,实际时间是你定时器刷新时间
 
  uint16_t KeyContinued(void) 
{
       
	if (keys.key[KEY_1].continued)//电源
	{
     
		if (keys.key[KEY_1].duration<50 * 10)//乘上10是为了使代码更具拓展性。
		  keys.key[KEY_1].duration++;
		if (keys.key[KEY_1].duration==50)  	
		return 111; 
	}
	return 0;
}


//假如 定时器20ms刷新一次,那么keys.key[KEY_1].duration==50时也就是1s后所返回的值
if (keys.key[KEY_1].duration<50 * 10)
*10是为了使你代码更具有拓展性,比如说duration为100时,你可以返回其他值,为300时返回另外的值

实际应用起来也很简单,比如我stm32c8为例子:
定义一个全局变量key_num,获取键值。这儿定时器我使用1ms溢出,所以按键20ms刷新一次。
【按键】三行核心代码解决按键按下、松开、长按。代码高效移植快(附源码)_第1张图片

然后在while直接使用

int main(void)
{
     
	SysCLKConfig();
	while (1)
	{
      
		switch(key_num)
		{
     
			case 1:
				ShowNumber(1);//任务1
				break;
			case 11:
				ShowNumber(11);//任务2
				break;
			case 111:
				ShowNumber(111);//任务3
				break;
		} 
	} 
}

总结

该按键程序是我在工作以来一直使用,现在分享给大家,使用的时候要把按键扫描KeyScan()的定时器优先级提高,保证实时性。如果要深入了解,可以看一下那段for循环的心脏(只可意会不可言传)。

该代码只实现了按键的 按下、松开、长按时间判断。没有进行组合按键和双击判断。
因为组合键和双击的应用会和按下松开长按的判断重合,所以需要拓展的话组合键,双击的话要在指定的按键任务功能做些判断。
比如说你需要组合键的时候你要牺牲该按键的按下功能,然后在松开任务做个判断条件即可。

你可能感兴趣的:(单片机,c语言,按键事件)