按键加定时器实现按键单击、双击、多击与长按等经验分享

本次使用stm32作示范,并且出于某些原因,我身边没有实物stm32,使用的是Proteus 8 Professional仿真,可以会有些许误差或者问题。

一.按键消抖

按键消抖使用的是常见的定时器消抖,可以说是许多前辈的代码,以下是借鉴的代码出处。

42独立按键定时器扫描实现编程_哔哩哔哩_bilibili

零基础入门(二)_哔哩哔哩_bilibili

int Key_GetNum(void)
{
	int KeyNum=0;
	if(Key1==0)	KeyNum=1;
	else if(Key2==0)KeyNum=2;
	else if(Key3==0)KeyNum=3;
	else if(Key4==0)KeyNum=4;
	return KeyNum;
}

void Key_Run(void)
{
	uint8_t Key_New,Key_Down,Key_Up;
	if(Key_Time<10) return;//10毫秒后进入按键判断,实现消抖
	Key_Time=0;

	Key_New=Key_GetNum();
	Key_Down=Key_New&(Key_New^Key_Old);
	Key_Up=~Key_New&(Key_New^Key_Old);
	Key_Old=Key_New;

    switch(Key_Down)
    {
        case 1:
            break;
        case 2:
            break;
        case 3:
            break;
        case 4:
            break;
    }
}

单次按下按键,Key_Down会进行一次识别,即会有一次有值,但一直按着的话只有Key_Old有值,Key_Down为0。

将key_run();放在主函数,Key_Time放在1ms定时器里自增。

int main(void)
{
	Timer2_Init(72,1000);//72-1的分频,1000-1的计数,1ms
	Key_Init();//按键初始化引脚
	while(1)
	{
		Key_Run();
	}
}

void TIM2_IRQHandler()
{
	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
	{
		Key_Time++;//自增
		TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
	}
}

注意:使用该代码时,主函数不宜使用长时间的delay延时。中断服务函数中代码不多时 Key_Run();可放在中断里。

以上代码可以实现简单的按键单击消抖,下面我进行一些扩展。

二.单击+松手+长按

松手很简单,就是对Key_Up进行判断就行。

长按就是一直按住不放,当按住时进行一个变量的自增,当到一定值时,就可以判断为长按,此次我再定义一个32位的变量Key_long_Time自增,便实现一个简单的长按函数了。

void Key_Run(void)
{
	uint16_t Key_New,Key_Down,Key_Up;
	if(Key_Time<10) return;
	Key_Time=0;
	
	Key_New=Key_GetNum();
	Key_Down=Key_New&(Key_New^Key_Old);
	Key_Up=~Key_New&(Key_New^Key_Old);
	Key_Old=Key_New;

	if(Key_Down)//一直按着时,不会进入这里
	{
		Key_long_Time=0;//此处清空,防止计数到长按规定的值
		switch(Key_Down)
		{
			
			case 1: 

			break;
			
			case 2:
				
			break;
		}
	}
	if(Key_long_Time>1000&&Key_Old)//长按
	{
		switch(Key_Old)
		{
			case 1:
				
			break;
			
			case 2:
				
			break;
		}
	}
	if(Key_Up)//松手
	{
        Key_long_Time=0;//松手清空长按数据
		switch(Key_Up)
		{
			case 1:
				
			break;
			
			case 2:
				
			break;
		}
	}
	
}

值得注意的是:长按时,短按也会执行一次,并且一直按时,会不断进入长按执行代码。

例如:定义一个num,短按一次num加1,长按num会快速增加。

        如果你是希望一个按键短按自增1次,长按快速自增,这个函数应该还能用,但是我感觉还有提升空间,希望有能力的网友能完善。

void TIM2_IRQHandler()//1ms的中断服务函数
{
	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
	{
		Key_Time++;
		Key_long_Time++;
		TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
	}
}

三.单击+多击+长按

此时看似多加了一个功能,但代码要变更许多。

if(Key_Down)//单击加上多击
{
		Key_long_Time=0;
		switch(Key_Down)
		{
			
			case 1: 
					if(Key_Down_Time==0)//判断没有按过一次
					{
						Key_Down_Count++;//加一次按下次数
						Key_Down_Flag = 1;//开始计时标志位,在定时器中使Key_Down_Time自增
					}
					else if(Key_Down_Time>0&&Key_Down_Time<600)//600ms内判断按键按下次数,如果手速更快可以适当减少判断时间
					{
						Key_Down_Count++;//在规定的600ms时间内按下,按下次数自增。
					}//此为识别按键次数
			break;
			
			case 2:
				
			break;
}

if(Key_Down_Time>=600&&!Key_Old)//超过按下的规定时间,并且没有一直按住按键,开始执行按键代码
{
		Key_Down_Flag = 0;//清空计数标志位
		Key_Down_Time=0;//清空计数
		switch(Key_Down_Count)//开始判断
		{
            //按下一次,即单击
			case 1:
            led[2]^=1;
			Key_Down_Count=0;//执行完后,清空按下次数,以下亦如此
				break;
            //按下两次,即双击
			case 2:
            led[3]^=1;
			Key_Down_Count=0;
				break;
            //按下三次,即三击
			case 3:
            led[1]^=1;
			Key_Down_Count=0;
				break;
            //按下n次,即多击
            //多击要适当延长判断时间
			case n:
            
			Key_Down_Count=0;
				break;
		}
}
else if(Key_Down_Time>=1000&&Key_Old)//超出长按时间,并且按键一直按着,执行长按代码
{
		Key_Down_Flag = 0;//清空计数标志位
		Key_Down_Time=0;//清空计数
		led[0]^=1;
		Key_Down_Count=0;//执行完后,清空按下次数,以下亦如此
}

如果你只使用单击双击和长按,且由于各按键的不同,你可以将判断的600ms时间缩短到你觉得适合的时间 

void TIM2_IRQHandler()//1毫秒的中断服务函数
{
	if(TIM_GetFlagStatus(TIM2,TIM_FLAG_Update)==SET)
	{
		Key_Time++;
		if(Key_Down_Flag==1)
		{
			Key_Down_Time++;
		}
		TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
	}
}

        此代码仍有瑕疵,无论是单击,双击,三击亦或者多击,都要等到判断时间结束才能执行按键代码,并且使用多按键时,各变量可能会相互影响(目前我还没研究完,看看情况),建议在使用多按键时,不要同时按其他按键。长按时不会影响单击,并且只能执行一次,一直按下去不会进行多次执行。好处也很明显,各功能不会相互影响,把握好就能让一个按键实现多种功能

最后,本人新人,如果有什么不足之处,希望大佬们能指点一二。 

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值