新闻  |   论坛  |   博客  |   在线研讨会
按键程序的总结
110xia | 2011-03-19 01:06:54    阅读:6250   发布文章

    关于按键程序偶总结出以下几个关键点:
    1. 按键数值的抓取
       第一,在这个过程中一定要有去抖动处理的,可以使用硬件去抖动,一般在按键输入口外加电容就可以了;也可以使用软件处理去抖动,程序中使用延时再判断的办法,一般延时10ms就可以了。
       第二,根据实际情况,设计多个按键同时按下,或某个(某些)按键先按下不松开,是否响应其他按键按下。
       第三,根据实际情况,设计某些按键是否有长按功能。
    2. 按键数值的处理
       在这个过程中,根据实际情况,有些是需要按键按下就动作,还有些是需要按键松开就动作,大多数情况是要求按键按下就动作的。
       例一,定时扫描按键,按键松开动作 软件处理抖动 4*4的键盘程序,定时10ms  调用 Matrix_Key_Detect() 这个函数,这是个普通的处理方法,在实际应用中,建议把它优化后在使用
// 矩阵键盘通用程序(引脚输入输出方向不切换)
//KEY_PINS 低4位为ROW(监听) 高4位为COL(输出,低电平)
// 7 6 5 4 3 2 1 0   
// Co4 Co3 Co2 Co1 Ro4 Ro3 Ro2 Ro1
 /* COL 4 3 2 1
 ROW 4
  3
  2
  1
*/
 
//Matrix_Key (row 行 col 列 从1开始计数)
#define KEY_PINS P0
sbit ROW1 = P0^0;
sbit ROW2 = P0^1;
sbit ROW3 = P0^2;
sbit ROW4 = P0^3;
sbit COL1 = P0^4;
sbit COL2 = P0^5;
sbit COL3 = P0^6;
sbit COL4 = P0^7;
 
unsigned char row=0,col=0;

//<返回其列号(col) 需要事先准备其行号掩码>
static unsigned char Matrix_Key_Scan_Col(const unsigned char rowbitmask)
{
 unsigned char i=0;
 unsigned char colmask;
 KEY_PINS = 0x0f;
 colmask=0x0f;
 while ( (KEY_PINS & rowbitmask)==0)
 {
  colmask = colmask<<1;
  KEY_PINS = colmask | 0x0f;
  i++;
 }
 return i;
}

//<检测是否有按键按下,并返回其行号(row)>
static unsigned char Matrix_Key_Scan_Row()
{
 KEY_PINS = 0x0f;
 
 if (ROW1 == 0)
 {
  return 1;
 }
 else if (ROW2 == 0)
 {
  return 2;
 }
 else if (ROW3 == 0)
 {
  return 3;
 }
 else if (ROW4 == 0)
 {
  return 4;
 }
 return 0;
}
unsigned char Matrix_Key_Detect() //行/列
{
 static unsigned char keep_time;
 static unsigned char keep_row;
 static unsigned char keep_col;
 static unsigned char state  = 0;
 unsigned char uScanReturn;
 switch (state)
 {
  case 0: //检测是否有按钮按下
   if (Matrix_Key_Scan_Row() != 0 )
   { //<初始化>
    keep_time = 0;
    keep_row = 0;
    keep_col = 0;
    state++;
   }
   break;
  case 1:
   uScanReturn = Matrix_Key_Scan_Row();
   if (uScanReturn != 0 ) //按键按下姿态
   {
    if (keep_time<250) keep_time++;
    if (keep_row == 0)
    {
     keep_row = uScanReturn;
    }
    if (keep_row != 0 && keep_col == 0)
    {
     keep_col = Matrix_Key_Scan_Col( 0x01<<(keep_row-1) );
    }
   }
   else     //按键松起姿态
   {
    if (keep_time>5) //检测到有效按键
    {
     keep_time = 0;
     state++;
    }
    else    //按键无效
    {
     state = 0;
    }
   }
   break;
  case 2:
   if (Matrix_Key_Scan_Row() == 0 )  //按键松起姿态(保持)
   {
    if (keep_time<250) keep_time++;
    if (keep_time>5) //检测到有效松起
    {
     /* 返回信息:检测到有效按键,并可以执行对应操作 */
     state = 0;
     row = keep_row;
     col = keep_col;
     return 1;
    }
   }
   else //按键被重新按下
   {
     keep_time=0; //重新计时
   }
   break;
 }
 return 0;
}

例二 是将例一该善后的程序, 一个2*4的键盘, 当一个按键按下,不在响应其他按键盘。
//key 扫描
 unsigned char data key_io;
 unsigned char data keyflag;
 unsigned char data keyedge_old;
 
uchar Key_Det_col(uchar keycol){
 uchar keyrow;
 P0=(~keycol);
 _nop_();
 _nop_();
 keyrow=(~P0);
 return(keyrow);
}
/*----------------------------- Subroutine -------------------------------------
        Name: Key_Detect
    Function:
       Entry: key_io
        Exit: keyflag,keyedge_old,keyedge
     Caution:
-------------------------------------------------------------------------------*/
void Key_Detect(void){
 static unsigned char state=2;
 unsigned char keybuf;
 
 state++;
 if(state>2)
  state=0x00;
 if(state<2)
  keybuf=Key_Det_col(state+1);
 switch (state){
  case 0:
   key_io&=0xf0; //first cow
   key_io|=(keybuf>>4);
  break;
 
  case 1:    //second cow
   key_io&=0x0f;
   keybuf&=0xf0;
   key_io|=keybuf;
  break;
 
  case 2:
   keybuf=keyflag&key_io;
   if(keybuf==0){
    keyflag=key_io;   
    keyedge_old=0x00;
   }
   else {
    keyedge|=(keybuf&(~keyedge_old));
    keyedge_old=keybuf;
   }
  break;
 }
}
 
例三 根据需要当一个按键按下时,还需要响应其他按键盘,可以把 例二 改善一下,只需要改 void Key_Detect(void); 这个函数里面的内容:
/*----------------------------- Subroutine -------------------------------------
        Name: Key_Detect
    Function:
       Entry: key_io
        Exit: keyflag,keyedge_old,keyedge
     Caution:
-------------------------------------------------------------------------------*/
void Key_Detect(void){
 static unsigned char state=2;
 unsigned char keybuf;
 
 state++;
 if(state>2)
  state=0x00;
 if(state<2)
  keybuf=Key_Det_col(state+1);
 switch (state){
  case 0:
   key_io&=0xf0; //first cow
   key_io|=(keybuf>>4);
  break;
 
  case 1:    //second cow
   key_io&=0x0f;
   keybuf&=0x70;
   key_io|=keybuf;
  break;
 
  case 2:
   keybuf=keyflag&key_io;
  
   keyflag=key_io;    
   keyedge|=(keybuf&(~keyedge_old));
   keyedge_old=keybuf;
 
  break;
 }
}


另一种,定时检测按键的基本模式(包含长按处理):
按键扫描
有KEY?-YES-与上次相同?-No-Keyold=0-返回。
| |
| YES-Keyold++;
| Keyold=?=首键KEY DELAY-No-返回。
| |
| YES-Keyok=1; //按下不放第一定时间,后面处理长按功能
| 保存键值Keydata
| ?KEYLOOP此可以增加长按工特别标志-返回。
|
No--Keyold==0?-YES-返回。
|
N0--Keyok=1; //不为0说明按了键再放开,有效KEY处理
保存键值到Keydata
Keyold=0-返回。
 

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
知其然,知其所以然, 常年潜水 QQ 156534403
最近文章
89s52&LCM1602通讯模块
2011-03-19 01:46:20
按键电路
2011-03-19 01:36:25
按键程序的总结
2011-03-19 01:06:54
推荐文章
最近访客