Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

AltStyle によって変換されたページ (->オリジナル) /