用状态机做独立按键检测
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
人机界面最重要的就是按键了,觉得按键做的最好的就是手机的按键了,有长按、敌探、连发等功能。还有组合等。一个好的按键程序用书本上学的按键检测方法已经不能适应工程的需要了,为此人们设计出一种状态机检测按键的方法。在一个系统中按键是随机的,因此系统软件对按键要一直循环查询,由于按键检测过程需要进行消抖处理,因此取状态机的时间序列为10ms,这样不仅可以跳过按键抖动的影响,同时也小于0.3-0.5秒的稳定闭合期,不会将按键的操作过程丢失。程序实现方法,用定时器定时10ms,每隔10ms检测一次按键,将一个按键的检测过程分为几个不同的状态,最简单的分为初使状态-按键闭合确认状态-按键释放状态,如果要求按键实现的功能越多,状态也就越多,比如还有常用的长按状态。以下是一个状态机按键程序,仅供参考。程序基于AVR 单片机, key.h文件的一部分
#define KEY0_PORT PORTD
#define KEY0_DDR DDRD
#define KEY0_PIN PIND
#define KEY0 PD0
#define KEY1_PORT PORTD
#define KEY1_DDR DDRD
#define KEY1_PIN PIND
#define KEY1 PD1
#define KEY2_PORT PORTD
#define KEY2_DDR DDRD
#define KEY2_PIN PIND
#define KEY2 PD2
#define KEY3_PORT PORTD
#define KEY3_DDR DDRD
#define KEY3_PIN PIND
#define KEY3 PD3
#define KEY0_STATUS (BIT_STATUS(KEY0_PIN,KEY0))
#define KEY1_STATUS (BIT_STATUS(KEY1_PIN,KEY1))
#define KEY2_STATUS (BIT_STATUS(KEY2_PIN,KEY2))
#define KEY3_STATUS (BIT_STATUS(KEY3_PIN,KEY3))
#define KEY_SERIES_FLAG 200 //按键连发开始所需时间长度
#define KEY_SERIES_DELAY 5 //按键连发的时间间隔长度
//按键属性
#define KEY_DOWN 0xA0
#define KEY_LONG 0xB0
#define KEY_LIAN 0xC0
#define KEY_UP 0xD0
#define KEY_LONG 0xB0
#define KEY_LIAN 0xC0
#define KEY_UP 0xD0
#define NO_KEY 0x00
#define KEY0_DOWN 0X01
#define KEY1_DOWN 0X02
#define KEY2_DOWN 0X03
#define KEY3_DOWN 0X04
#define KEY0_PRESS (KEY_DOWN|KEY0_DOWN)
#define KEY1_PRESS (KEY_DOWN|KEY1_DOWN)
#define KEY2_PRESS (KEY_DOWN|KEY2_DOWN)
#define KEY3_PRESS (KEY_DOWN|KEY3_DOWN)
key.c文件一部分
static uchar Get_Key(void)
{
if (KEY0_STATUS==0) return KEY0_DOWN;
if (KEY1_STATUS==0) return KEY1_DOWN;
if (KEY2_STATUS==0) return KEY2_DOWN;
if (KEY3_STATUS==0) return KEY3_DOWN;
return NO_KEY;
}
uchar Key_Scan(void)
{
static uchar Key_State = 0; //按键状态
static uchar Key_Prev = 0; //上一次按键 static uchar Key_Delay = 0; //按键连发时间 static uchar Key_Series = FALSE; //标志连发开始
uchar Key_Press = NO_KEY; //按键值
uchar Key_Return = NO_KEY; //按键返回值
Key_Press = Get_Key();
switch (Key_State)
{
case 0://按键初始态00
if (Key_Press !=NO_KEY)//有按键按下
{
Key_State = 1;//转到按键确认
Key_Prev = Key_Press;//保存按键状态
}
break;
case 1://按键确认态01
if ( Key_Press ==Key_Prev )//确认和上次按键相同
{
Key_State = 2;//判断按键长按
//返回按键按下键值,按键按下就响应,如果想弹起来再响应
//可以在弹起来后再返回按键值
Key_Return = KEY_DOWN | Key_Prev;
}
else//按键抬起,是抖动,不响应按键
{
Key_State = 0;
}
break;
case 2://按键释放态10
if (Key_Press == NO_KEY )//按键释放了
{
Key_State = 0;
Key_Delay = 0;
Key_Series = FALSE;
Key_Return = KEY_UP | Key_Prev; //返回按键抬起值 break;
}
if ( Key_Press ==Key_Prev )
{
Key_Delay++;
if ((Key_Series==TRUE) && (Key_Delay>KEY_SERIES_DELAY)) {
Key_Delay = 0;
Key_Return = KEY_LIAN | Key_Press; //返回连发的值 Key_Prev = Key_Press; //记住上次的按键.
break;
}
if (Key_Delay>KEY_SERIES_FLAG)
{