一个按键程序的思考

来源:互联网 发布:ipad淘宝购物车打不开 编辑:程序博客网 时间:2024/06/05 22:53

2017.07.26 程序笔记

今天思考一个关于按键的程序:结构体如下

if(PC_Get_Key(&key)==TURE){     if(key==0x1B)     {          PC_DOSReturen();      }}
思考了一下,这个可以作为电堆按键检测的一个大体的框架,结合基本的按键处理程序,就可以实现功能
If(0 == io_KeyEnter)     //如果有键按下了 {     Delayms(20) ;     //先延时20ms避开抖动时期     If(0 == io_KeyEnter)     //然后再检测,如果还是检测到有键按下     {         return KeyValue ;   //是真的按下了,返回键值     }     else     {         return KEY_NULL     //是抖动,返回空的键值     }     while(0 == io_KeyEnter) ; //等待按键释放 } 
下面是基本的C51处理按键的一部分
因为51单片机I/O口内部结构的限制,在读取外部引脚状态的时候,需要向端口写1,在51单片机复位后,不需要进行此操作也可以进行读取外部引脚的操作。因此,在按键的端口没有复用的情况下,可以省略此步骤。而对于其它一些真正双向I/O口的单片机来说,将引脚设置成输入状态,是必不可少的一个步骤。
//初始化引脚为输入 void KeyInit(void) {     io_key_1 = 1;     io_key_2 = 1;     io_key_3 = 1;     io_key_4 = 1; } //根据按键硬件连接定义按键键值 #define KEY_VALUE_1   0x0e #define KEY_VALUE_2   0x0d #define KEY_VALUE_3   0x0b #define KEY_VALUE_4   0x07 #define KEY_NULL      0x0f 
下面我们来编写按键的硬件驱动程序。根据第一章所描述的按键检测原理,我们可以很容易的得出如下的代码:
static uint8 KeyScan(void) {     if(io_key_1 == 0)return KEY_VALUE_1 ;     if(io_key_2 == 0)return KEY_VALUE_2 ;     if(io_key_3 == 0)return KEY_VALUE_3 ;     if(io_key_4 == 0)return KEY_VALUE_4 ; 
 return KEY_NULL ; } 
其中io_key_1等是我们按键端口的定义,如下所示:
sbit io_key_1 = P3 ^ 0 ; sbit io_key_2 = P3 ^ 1 ; sbit io_key_3 = P3 ^ 2 ; sbit io_key_4 = P3 ^ 3 ; 
KeyScan()作为底层按键的驱动程序,为上层按键扫描提供一个接口,这样我们编写的上层按键扫描函数可以几乎不用修改就可以拿到我们的其它程序中去使用,使得程序复用性大大提高。同时,通过有意识
的将与底层硬件连接紧密的程序和与硬件无关的代码分开写,使得程序结构层次清晰,可移植性也更好。对于单片机类的程序而言,能够做到函数级别的代码重用已经足够了。在编写我们的上层按键扫描函数之前,需要先完成一些宏定义。
//定义长按键的TICK数,以及连发间隔的TICK数 #define KEY_LONG_PERIOD     100 #define KEY_CONTINUE_PERIOD 25 //定义按键返回值状态(按下,长按,连发,释放) #define KEY_DOWN        0x80 #define KEY_LONG        0x40 #define KEY_CONTINUE    0x20 #define KEY_UP          0x10 //定义按键状态 #define KEY_STATE_INIT          0 #define KEY_STATE_WOBBLE        1 #define KEY_STATE_PRESS         2 #define KEY_STATE_LONG          3 #define KEY_STATE_CONTINUE      4 #define KEY_STATE_RELEASE       5 接着我们开始编写完整的上层按键扫描函数,按键的短按,长按,连按,释放等等状态的判断均是在此函数中完成。对照状态流程转移图,然后再看下面的函数代码,可以更容易的去理解函数的执行流程。完整的函数代码如下: void GetKey(uint8 *pKeyValue) {     static uint8 s_u8KeyState = KEY_STATE_INIT;     static uint8 s_u8KeyTimeCount = 0;     static uint8 s_u8LastKey = KEY_NULL;   //保存按键释放时候的键值     uint8 KeyTemp = KEY_NULL;     KeyTemp = KeyScan();     //获取键值     switch(s_u8KeyState)     {     case KEY_STATE_INIT:     { 
 if(KEY_NULL != (KeyTemp))         {             s_u8KeyState = KEY_STATE_WOBBLE;         }     }     break;     case KEY_STATE_WOBBLE:   //消抖     {         s_u8KeyState = KEY_STATE_PRESS;     }     break;     case KEY_STATE_PRESS:     {         if(KEY_NULL != (KeyTemp))         {             s_u8LastKey = KeyTemp; //保存键值,以便在释放按键状态返回键值             KeyTemp |= KEY_DOWN;   //按键按下             s_u8KeyState = KEY_STATE_LONG;         }         else         {             s_u8KeyState = KEY_STATE_INIT;         }     }     break;     case KEY_STATE_LONG:     {         if(KEY_NULL != (KeyTemp))         {             if(++s_u8KeyTimeCount > KEY_LONG_PERIOD)             {                 s_u8KeyTimeCount = 0;                 KeyTemp |= KEY_LONG;   //长按键事件发生                 s_u8KeyState = KEY_STATE_CONTINUE;             }         }         else         {             s_u8KeyState = KEY_STATE_RELEASE;         }     }     break;     case KEY_STATE_CONTINUE: 
{         if(KEY_NULL != (KeyTemp))         {             if(++s_u8KeyTimeCount > KEY_CONTINUE_PERIOD)             {                 s_u8KeyTimeCount = 0;                 KeyTemp |= KEY_CONTINUE;             }         }         else         {             s_u8KeyState = KEY_STATE_RELEASE;         }     }     break;     case KEY_STATE_RELEASE:     {         s_u8LastKey |= KEY_UP;         KeyTemp = s_u8LastKey;         s_u8KeyState = KEY_STATE_INIT;     }     break;     default:         break;     }     *pKeyValue = KeyTemp; //返回键值 } 关于这个函数内部的细节我并不打算花过多笔墨去讲解。对照着按键状态流程转移图,然后去看程序代码,你会发现其实思路非常清晰。最能让人理解透彻的,莫非就是将整个程序自己看懂,然后想象为什么这个地方要这样写,抱着思考的态度去阅读程序,你会发现自己的程序水平会慢慢的提高。所以我更希望的是你能够认认真真的看完,然后思考。也许你会收获更多。不管怎么样,这样的一个程序已经完成了本章开始时候要求的功能:按下,长按,连按,释放。事实上,如果掌握了这种基于状态转移的思想,你会发现要求实现其它按键功能,譬如,多键按下,功能键等等,亦相当简单,在下一章,我们就去实现它。