按键功能拓展--单击、双击、长按、组合按等

按键功能拓展--单击、双击、长按等

将无自锁功能的按键通过对其单击,双击,长按等状态,进行分配相应的功能,扩展按键功能,调用相关函数即可。

1.轮询方式

key.c

#include "firmware.h"
#include "key.h"

u8 Key1_Lock_Flag = 0;
u16 Key1_Cnt = 0;//u8 0-255;u16 0-65535
u8 KeyNum = 0;
u8 Key_Short_Flag = 0;
u8 Key1_Cnt2 = 0;
u8 Key1_Times = 0;
u8 Key1_Cnt3 = 0;
u8 Key_Couple_Flag = 0;
u8 Key12_Lock_Flag = 0;
u16 Key12_Cnt = 0;
u8 Key2_Lock_Flag = 0;
u16 Key2_Cnt = 0;

按键单击消抖

void Key_Scan1(void)
{
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
}

按键短按与长按

void Key_Scan2(void)
{
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
		if(Key_Short_Flag == 1)
		{
			Key_Short_Flag = 0;
			KeyNum = 1;//赋短按键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key_Short_Flag = 1;//大于消抖时间,有可能是长按也有可能是短按
		}
		if(Key1_Cnt > Key_Long_Time)
		{
			Key_Short_Flag = 0;//进入长按,取消短按标志位
			Key1_Cnt = 0;
			KeyNum = 2;//赋长按键值编码。
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
		}
	}
}

按键短按与连按

void Key_Scan3(void)
{
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
	else if(Key1_Cnt < Key_Long_Time)//按键持续按下自锁标志为1,不可进入上述步骤
		{
			Key1_Cnt ++;//连按超过一定时限,进入连按
		}
		else
		{
			Key1_Cnt2 ++;//连击时间间隔计数
			if(Key1_Cnt2 > Key_Long_Time2)//每超过连击时间间隔
			{
				Key1_Cnt2 = 0;//连击时间间隔计数器清零
				KeyNum = 1;//与单击相同实现连续单击效果
			}
		}
}

按键单击、双击与连击

void Key_Scan4(void)
{
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
		if(Key1_Times > 0)
		{
			Key1_Cnt3 ++;//当前距离前一次按下间隔时间
			if(Key1_Cnt3 > Key_Double_Time)//超过双击有效间隔时间
			{
				Key1_Cnt3 = 0;
				Key1_Times = 0;
			}
		}
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
			Key1_Times ++;//统计按键按下次数
			Key1_Cnt3 = 0;
			if(Key1_Times == 1)
			{
				KeyNum = 1;//按键单击
			}
			else if(Key1_Times == 2)
			{
				KeyNum = 2;//按键双击
			}
			else if(Key1_Times == 3)
			{
				KeyNum = 3;//按键三击
			}
		}
	}
	else if(Key1_Cnt < Key_Long_Time)//按键持续按下自锁标志为1,不可进入上述步骤
		{
			Key1_Cnt ++;//连按超过一定时限,进入连按
		}
		else
		{
			Key1_Cnt2 ++;//连击时间间隔计数
			if(Key1_Cnt2 > Key_Long_Time2)//每超过连击时间间隔
			{
				Key1_Cnt2 = 0;//连击时间间隔计数器清零
				KeyNum = 1;//与单击相同实现连续单击效果
			}
		}
}

组合按键(不区分先后顺序)

void Key_Scan5(void)
{
	if((KEY1 || KEY2) == 1)//按键没有按下
	{
		Key_Couple_Flag = 0;
		Key12_Lock_Flag = 0;//清零自锁标志
		Key12_Cnt = 0;//清零计数标志
	}
	else if(Key12_Lock_Flag == 0)
	{
		Key12_Cnt ++;//累计按键消抖延时次数
		Key_Couple_Flag = 1;//组合按键按下
		if(Key12_Cnt > Key_Delay_Time)
		{
			Key12_Cnt = 0;//清零计数变量
			Key12_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 12;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
	
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
	}
	else if((Key1_Lock_Flag == 0) && (Key_Couple_Flag == 0))
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 1;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
	
	if(KEY2 == 1)//按键没有按下
	{
		Key2_Lock_Flag = 0;//清零自锁标志
		Key2_Cnt = 0;//清零计数标志
	}
	else if((Key2_Lock_Flag == 0) && (Key_Couple_Flag == 0))
	{
		Key2_Cnt ++;//累计按键消抖延时次数
		if(Key2_Cnt > Key_Delay_Time)
		{
			Key2_Cnt = 0;//清零计数变量
			Key2_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 2;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
}

组合按键(区分先后顺序)

void Key_Scan6(void)
{	
	if(KEY1 == 1)//按键没有按下
	{
		Key1_Lock_Flag = 0;//清零自锁标志
		Key1_Cnt = 0;//清零计数标志
	}
	else if(Key1_Lock_Flag == 0)
	{
		Key1_Cnt ++;//累计按键消抖延时次数
		if(Key1_Cnt > Key_Delay_Time)
		{
			Key1_Cnt = 0;//清零计数变量
			if(KEY2 == 0)
			{
				Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
				KeyNum = 3;//赋键值编码。
			}
			else
			{
				Key1_Lock_Flag = 1;//自锁标志,防止按键多次触发
				KeyNum = 1;//赋键值编码。
			}
		}
	}
	
	if(KEY2 == 1)//按键没有按下
	{
		Key2_Lock_Flag = 0;//清零自锁标志
		Key2_Cnt = 0;//清零计数标志
	}
	else if(Key2_Lock_Flag == 0)
	{
		Key2_Cnt ++;//累计按键消抖延时次数
		if(Key2_Cnt > Key_Delay_Time)
		{
			Key2_Cnt = 0;//清零计数变量
			Key2_Lock_Flag = 1;//自锁标志,防止按键多次触发
			KeyNum = 2;//赋键值编码。外部函数调用结束需将此变量清零,否则一直认为按下
		}
	}
}

key.h

#ifndef __KEY_H
#define __KEY_H

#include "firmware.h"  //IO define
#define Key_Delay_Time  100 //按实际调整
#define Key_Long_Time   500 //长按持续时间
#define Key_Long_Time2  500 //长按每次变化间隔时间
#define Key_Double_Time 200 //双击有效间隔时间

void Key_Scan1(void)
void Key_Scan2(void)
void Key_Scan3(void)
void Key_Scan4(void);
void Key_Scan5(void);
void Key_Scan6(void);

#define KEY1 IN1 //单片机IO
#define KEY2 IN2 //单片机IO
#endif

2.定时器检测

开启定时器中断,将计时时间设置为50ms,即50ms扫描一次按键,实现检测按键是否按下和连按。

struct Key
{
  char KeyStaute;//是否按下
  char Continuous;//是否连按
  int KeyNumberContinuous;//连按统计
};
struct Key key1,key2,key3,key4;//定义结构体变量,代表四个按键

void Key_Scan(struct Key * key,GPIO_TypeDef* GPIO_Port,uint16_t GPIO_Pin)
{
  if(!HAL_GPIO_ReadPin(GPIO_Port,GPIO_Pin))//按键按下被拉低
  {
    if(key->KeyStaute)
    {
      key->KeyContinueNumber++;
      if(key->KeyContinueNumber>20)//长按超过1s
      {
        key->Continuous = 1;
      }
    }
    else
    {
      key->KeyStaute = 1;
    }
  }
  else
  {
    key->KeyStaute = 0;
    key->KeyContinueNumber = 0;
    key->Continuous = 0;
  }
}

按键自锁

u16 z_count = 0;
u8 z_en = 0;
u8 z_flag = 0;
void z_key(void)
{
	if(IN3 == 0)
	{
		z_count ++;
		if(z_count >= 300)//调试更改
		{
			z_count = 300;
		}
	}
	if((IN3 == 1) && (z_count >= 300))
	{
		z_en^=1;//异或,相同为0,不同为1
		z_count = 0;
	}
	if(z_en == 1)
	{
		  OUT11 = 1;//按单次
		  z_flag = 1;
	}
	else if(z_en == 0)
	{   
		  OUT11 = 0;//按双次
		  z_flag = 0;
	}	
}
  • 2
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值