Skip to content

mojinpan/key

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 

Repository files navigation

key: 一个精简但功能强大的按键驱动

version build build

1. 介绍

这是一个通过位操作实现状态机转换的按键驱动,通过独特的算法,在非常非常小的资源消耗下实现短按键/shift键/长按连发,长按单发等多种复杂的按键功能。

2. 原理介绍

2.1 键值码

  • 本按键驱动键值码的方式返回按键输入状态,键值码中每一个位表示一个按键。
  • 键值码根据配置长度从8位到~64位(即最多支持64个按键)。
  • 键值码根据实际情况分成短按键值码shift键值码,长按键值码
    短按键值码  = 键值码
    shift键值码 = shift键值码 | 键值码.
    长按键值码  = ~键值码

3.算法说明

//PreKey:前次按键值
//NowKey:当前按键值
//PreScanKey:前次采样值 
//NowReadKey:当前采样值 
  a.按键获取算法
    1).NowKey & PreKey                                : 电平触发 
    2).NowKey ^ PreKey                                : 边缘触发 
    3).NowKey & (NowKey ^ PreKey)或(~PreKey) & NowKey : 上升沿触发
    4).PreKey & (NowKey ^ PreKey)或PreKey & (~NowKey) : 下降沿触发
  b.滤波算法
    1).PreScanKey & NowScanKey                        : 电平触发
    2).PreReadKey & (PreScanKey ^ NowScanKey)         : 采样保持
    3).NowReadKey = 1) | 2)                           : 带采样保持的电平触发
//以上算法可通过列真值表推导

4.功能说明

  • 支持最大64个按键(数量可配置)。
  • 支持按键消抖处理(可滤掉小于2个扫描周期的毛刺)。
  • 支持按键环形缓冲区(长度可配置)。
  • 支持4种不同按键模式:A:短按键 B:shift键 C:长按单发 D:长按连发。
  • 短按键 :短按直接输出键值。
  • shift键 :点击后除了输出一次shift键的键值码外,还将后续所有其他按键的键值改为shift键值码
  • 长按连发 :长按一定时间后连续输出按键键值。
  • 长按单发 :长按一定时间后反码输出键值(仅一次)
  • 4种不同按键模式可相互叠加使用,所有按键功能都能并发输出。

5. 移植说明

  • 使用宏或枚举定义按键键值码。(长按单发使用反码表示)
typedef enum
{
    //短按键键值码
    KEY_UP    = 0x0001,
    KEY_DN    = 0x0002,
    KEY_LT    = 0x0004,
    KEY_RT    = 0x0008,  
    KEY_ENT   = 0x0010,
    KEY_ESC   = 0x0020,
    KEY_INC   = 0x0040,
    KEY_DEC   = 0x0080,
    KEY_FUN   = 0x0100,
    //长按键键值码
    KEY_UP_L 	 = 0xFFFE,	
    KEY_DN_L 	 = 0xFFFD,
    //shift按键键值码
    KEY_UP_SF    = 0x0101,
    KEY_DN_SF    = 0x0102,
    KEY_LT_SF    = 0x0104,
    KEY_RT_SF    = 0x0108,  
    KEY_ENT_SF   = 0x0110,
    KEY_ESC_SF   = 0x0120,
    KEY_INC_SF   = 0x0140,
    KEY_DEC_SF   = 0x0180
} KEY_value;
  • 根据具体硬件环境编写按键初始化函数KeyInit()。
  • 根据编写按键读取函数KeyIOread(),注意所有按键均需定义为高电平有效。
__weak static KEY_TYPE  KeyIOread( void )
{
    KEY_TYPE KeyScanCode=0;
    
	KeyScanCode |= GPIO_IN(K_UP ) ? 0 : KEY_UP ;
	KeyScanCode |= GPIO_IN(K_DN ) ? 0 : KEY_DN ;
	KeyScanCode |= GPIO_IN(K_LT ) ? 0 : KEY_LT ;
	KeyScanCode |= GPIO_IN(K_RT ) ? 0 : KEY_RT ;
	KeyScanCode |= GPIO_IN(K_ENT) ? 0 : KEY_ENT;
	KeyScanCode |= GPIO_IN(K_ESC) ? 0 : KEY_ESC;
	KeyScanCode |= GPIO_IN(K_INC) ? 0 : KEY_INC;
	KeyScanCode |= GPIO_IN(K_DEC) ? 0 : KEY_DEC;
	KeyScanCode |= GPIO_IN(K_FUN) ? 0 : KEY_FUN;
	
  return KeyScanCode;
}

6. 使用说明

  • 按需求配置宏

    意义
    KEY_MAX_NUM 定义最大按键数量(1~64)
    KEY_BUF_SIZE 定义按键缓冲区大小(2,4,8,16,32,64,128,256)
    KEY_LONG_EN 定义是否支持长按键(1 or 0)
    KEY_SHORT_SHIFT 定义shift键,短按有效(0 or 按键键值码)
    KEY_PRESS_DLY 定义长按键延时n个扫描周期开始判定有效值(1~255)
    KEY_PRESS_TMR 定义长按键n个扫描周期为1次有效扫描值(1~255)
    KEY_LONG_SHIFT 长按键反码输出(仅一次),未定义的长按连续输出(0 or 按键键值码)
  • 每20ms~50ms调用KeyScan()扫描按键。

  • 调用KeyGetBufLen()判断是否有按键,调用KeyGet()获得按键值。

void KeyTest(void)
{
	while(1)
	{
		
		KeyScan();
		delay_ms(20);
		KeyScan();

			switch(KeyGet())
			{
				case  KEY_UP : printf("Key Read : UP \r\n");break;
				case  KEY_DN : printf("Key Read : DN \r\n");break;			
				case  KEY_LT : printf("Key Read : LT \r\n");break;	
				case  KEY_RT : printf("Key Read : RT \r\n");break;
				case  KEY_ENT: printf("Key Read : ENT\r\n");break;			
				case  KEY_ESC: printf("Key Read : ESC\r\n");break;	
				case  KEY_INC: printf("Key Read : INC\r\n");break;
				case  KEY_DEC: printf("Key Read : DEC\r\n");break;			
				case  KEY_FUN: printf("Key Read : FUN\r\n");break;
				case  KEY_UP_L : printf("Key Read : UP for long key \r\n");break;
				case  KEY_DN_L : printf("Key Read : DN for long key \r\n");break;	
				case  KEY_UP_SF : printf("Key Read : UP with shift key \r\n");break;
				case  KEY_DN_SF : printf("Key Read : DN with shift key \r\n");break;			
				case  KEY_LT_SF : printf("Key Read : LT with shift key \r\n");break;	
				case  KEY_RT_SF : printf("Key Read : RT with shift key \r\n");break;
				case  KEY_ENT_SF: printf("Key Read : ENT with shift key \r\n");break;			
				case  KEY_ESC_SF: printf("Key Read : ESC with shift key \r\n");break;	
				case  KEY_INC_SF: printf("Key Read : INC with shift key \r\n");break;
				case  KEY_DEC_SF: printf("Key Read : DEC with shift key \r\n");break;			
				default :	break;		
			}
	}	
	
}

8. 更新说明

  • V0.1 2011-3-2

    • 1.支持矩阵键盘和IO按键两种
    • 2.支持长按键和短按键两种触发方式。
  • V0.2 2011-3-5

    • 1.最大按键数量16个,可继续扩充至64个.
    • 2.支持长按键和短按键并行触发.
    • 3.增加短按键部分改为按键释放时返回.
  • V0.3 2013-11-4

    • 1.重写按键获取的逻辑,长按键算法不成熟,暂时去掉
    • 2.矩阵按键没用到,暂时去掉
    • 3.增加按键消抖算法
  • V0.4 2013-11-6

    • 1.增加环形buf
    • 2.重写接口函数,便于在OS环境中调用,当然裸奔也支持.
  • V0.5 2013-11-6

    • 1.增加长按键的支持
    • 2.增加shift键的支持
    • 3.增加按键数量的定义,定义后根据按键数量选择合适的数据类型,从而节省ram和rom
    • 4.处于兼容性的考虑,将最大按键支持数量由64个缩减至32个
  • V0.6 2013-11-24

    • 1.修正长按键输出后,还输出短按键的bug
    • 2.修改的KeyScan()的逻辑,将长按键细分为长按键连续输出和长按键反码输出(仅一次)两种方式
    • 3.shift键按下时也提供按键值输出,方便应用程序判断shift键的状态
    • 4.由于第3点的修改,短按键和shift键不在冲突,即长按键/短按键/shift键相互独立
    • 5.将无按键返回0xff,改成返回0
    • 6.增加一个KeyFlush()函数,用于清空buf
  • V0.7 2019-04-26

    • 1.参照liunx上kfifo的代码优化环形buf的算法.
    • 2.将KeyHit()函数重命名为KeyBufLen()函数,将返回有无按键改为返回按键缓冲数量.
    • 3.KEY_TYPE 改为使用stdint.h中的数据类型定义,并重新启用64个按键的支持.

About

基于位操作的按键驱动

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages