打印

通用完整状态,含去抖按键扫描程序

[复制链接]
5394|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
babyqym|  楼主 | 2012-9-19 15:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 babyqym 于 2012-9-19 15:18 编辑

//======================按键头文件================
//title key.h
#ifndef KEY_H
#define KEY_H
/********************************************************/
/* Include File                    */
/********************************************************/
//#include "ADC.h"
/********************************************************/
/* Macro Define                    */
/********************************************************/
//define key value
#define KEY_BLANK  0
#define KEY_1       1
#define KEY_2       2
#define KEY_3       3  

#define KEY_POWER     KEY_1
#define KEY_VOL_DOWN  KEY_2
#define KEY_VOL_UP    KEY_3
//define key state
#define KEY_RELEASE  0
#define KEY_FIRST_DOWN  1
#define KEY_DOWN        2
#define KEY_FIRST_RPT   3
#define KEY_PRT_DOWN    4
#define KEY_REPEAT      5
#define KEY_LONG_DOWN   6
#define KEY_SHORT_UP    7
#define KEY_LONG_UP     8
/********************************************************/
/* Extern reference variable         */
/********************************************************/

  extern unsigned char KeyAction;
  extern unsigned char KeyState;
  extern unsigned char KeyValue;

/********************************************************/
/* Extern reference Function Prototype      */
/********************************************************/
extern void InitinalKey(void);
extern void ScanKey(void);
#endif


//=========================按键程序文件==============

/********************************************************/
/* Include File                    */
/********************************************************/
#include "GPIO.h"  
#include "Key.h"  
#include "SM39R04G1.h"

/********************************************************/
/* Macro Define                    */
/********************************************************/
/*K1    K2    K3
  0     133     265
  66     199     331*/
#define Key1Limit 207
#define Key2Limit 522
#define Key3Limit 830
#define KeyGapCount 5  //155ms=5*31.03ms old 6
#define KeyRPTCount 10  //1000ms=32*32.266ms old 40
#define KeyLongTime 6  //1930ms=1000ms+6*155ms
/********************************************************/
/*     Prototype of static function           */
/********************************************************/
static unsigned char ReadKey(void);
/********************************************************/
/* RAM Define                    */
/********************************************************/
static unsigned char LastKey;
static unsigned char keyCount;
static unsigned char LongCount;

unsigned char KeyAction;
unsigned char KeyState;
unsigned char KeyValue;
/********************************************************/
/* Function Define                */
/********************************************************/

void InitinalKey(void)
{
SetPortProperty(PORT3,2,Q_BIDIRECT);
SetPortProperty(PORT3,3,Q_BIDIRECT);
P3_2=1;
P3_3=1;
KeyAction = 0;
KeyState = KEY_RELEASE;
KeyValue = KEY_BLANK;
}
/**************************************************************************
*                                                                        *
**************************************************************************/
static unsigned char ReadKey(void)
{
unsigned char keyID;
keyID=0;
if ((P3&0x08)==0x00)
{
  keyID=1;
}
else if((P3&0x04)==0x00)
{
   keyID=2;
}
return keyID;
}
/**************************************************************************/
/*                                                                        */
/**************************************************************************/
void ScanKey(void)
{
unsigned char CurrentKeyValue;

   KeyAction = 0;
CurrentKeyValue = ReadKey();

if (CurrentKeyValue != LastKey)
{
  LastKey = CurrentKeyValue;
}
else
{
  if (CurrentKeyValue != KEY_BLANK)
  {
   KeyValue = CurrentKeyValue;
   switch (KeyState)
   {
    case KEY_RELEASE:
     keyCount = 0;
     KeyAction = 1;
     KeyState = KEY_FIRST_DOWN;
     break;
    case KEY_FIRST_DOWN:
      KeyAction =0;
      KeyState =KEY_DOWN;
      keyCount = 1;
      break;
    case KEY_DOWN:
     if (keyCount > KeyRPTCount)
     {
      KeyAction = 1;
      KeyState = KEY_FIRST_RPT;
     }
     else
     {
      keyCount++;
     }
     break;
    case KEY_FIRST_RPT:
      KeyAction =0;
      KeyState =KEY_PRT_DOWN;
      keyCount = 0;
      LongCount = 1;
     break;
     case KEY_PRT_DOWN:
       if (keyCount > KeyGapCount)
     {
      KeyAction = 1;
      if(LongCount==KeyLongTime)
      {
        KeyState = KEY_LONG_DOWN;
        LongCount++;
      }
      else
      {
        KeyState = KEY_REPEAT;
        if(LongCount<KeyLongTime)
        {
           LongCount++;
        }
      }
     }
     else
     {
      keyCount++;
     }
     break;
   case KEY_REPEAT:
      KeyAction =0;
      KeyState =KEY_PRT_DOWN;
      keyCount = 1;
     break;
   case KEY_LONG_DOWN:
      KeyAction =0;
      KeyState =KEY_PRT_DOWN;
      keyCount = 0;
     break;   
   }
  }
  else
  {
   switch (KeyState)
   {
    case KEY_RELEASE:
       break;
     case KEY_FIRST_DOWN:
     case KEY_DOWN:
       KeyAction =1;
       KeyState =KEY_SHORT_UP;
     break;
    case KEY_FIRST_RPT:
     case KEY_PRT_DOWN:
     case KEY_REPEAT:
     case KEY_LONG_DOWN:
       KeyAction =1;
       KeyState =KEY_LONG_UP;
     break;
    case KEY_SHORT_UP:
    case KEY_LONG_UP:
      KeyAction =0;
      KeyState =KEY_RELEASE ;
      break;
   }
  }
}
}



//===========================主程序中的调用=======
#include "SM39R04G1.h"
#include "GPIO.h"
#include "Time0.h"
#include "key.h"
#include "AS44CE373.h"
void main(void)
{
CKCON=0;//set 1T mode
EA=0;
SetPort(PORT3,PUSH_PULL);
P3_2=0;
InitinalT0();

InitinalKey();
AS44CE373Init();
EA=1;
for(;;)
{
  if(TFlag==1)
  {
   ScanKey();
   if(KeyAction)
   {
    switch(KeyState)
    {
     case KEY_FIRST_DOWN:
      if(KeyValue==1)
      {
       SetChannelDirect(1);
      }
      else if(KeyValue==2)
      {
       SetChannelDirect(2);
      }
      break;
     case KEY_FIRST_RPT:
      if(KeyValue==1)
      {
      
      }
      else if(KeyValue==2)
      {
      
      }
      break;
     case KEY_REPEAT:
      if(KeyValue==1)
      {
       SetChannelDirect(1);
      }
      else if(KeyValue==2)
      {
       SetChannelDirect(2);
      }
      break;
     case KEY_SHORT_UP:
      if(KeyValue==1)
      {
      
      }
      else if(KeyValue==2)
      {
      
      }
      break;
    }
   
    KeyAction=0;
   }

   P3_7=!P3_7;
   //P3_3=!P3_2;
  // P3_4=!P3_3;
  // P3_5=!P3_4;
   TFlag=0;
  }
  
}
}



//===========================设计思路=============

定时器T0每隔32ms中断一次,设置全局标志TFlag,主程序中,判断TFlag,如果为真则进入执行,执行完成后设置TFlag=0, 完成一次32ms周期执行过程,等待下一个32ms执行周期。
ScanKey();在32ms周期内执行一次,来看看这个函数:
首先设置KeyAction=0,设置按键为没有动作态,这个变量是全局的,在后面按键任务中用来判断按键是否有动作,说说按键动作,在这里按键有9种状态,头文件中有定义:
#define KEY_RELEASE  0 //按键处于释放的状态
#define KEY_FIRST_DOWN  1//按键第一次有效按下
#define KEY_DOWN        2// 按键在first down 和first rpt 之间的n次按下
#define KEY_FIRST_RPT   3//按键第一次长按下
#define KEY_PRT_DOWN    4
#define KEY_REPEAT      5//按键长按下后的重复
#define KEY_LONG_DOWN   6//超长按下态
#define KEY_SHORT_UP    7//第一次长按下前按键释放
#define KEY_LONG_UP     8//第一次长按下后的释放
这里做了个注视,希望可以看懂,
这些状态我们不一定全部用到,KEY_DOWN,KEY_PRT_DOWN只是过渡态。
KeyAction只在KEY_FIRST_DOWN,KEY_FIRST_RPT ,KEY_REPEAT,KEY_LONG_DOWN,KEY_SHORT_UP,KEY_LONG_UP的时候才被置位。

废话有点多,看看下一行:
CurrentKeyValue = ReadKey();
这里只是读取按键的值,即使没有按键按下也要读取的,只不过这里读取到的是空值,
需要说明的ReadKey()只需要读取按键的键值就好了,其他的不要做,这里可以是读取
矩阵扫描的键值,也可以是AD键盘的键值,这里程序中简单的读取了两个段口的电平。
再看看下面的判断:这里是精华了。
判断CurrentKeyValue是否和上次的按键值LastKey相同,LastKey是全局变量,
如果按键处于释放状态,LastKey一定是空值,连续两次读取的值是相同的,则会进入到else后的程序,
如果不同,则说明有按键按下或是有抖动,这里主要是通过连续两次读取按键值来确定按键是否处于稳定状态(按下或松开,
而不是抖动态,由于前面的是32ms的周期,所以一次有效的按键至少要2个周期64ms,如果诸位嫌长可以修改前面的T0定时器)
下面看看else中的内容,这里有连个部分一个是键值不等于KEY_BLANK,一个是键值等于KEY_BLANK,先说不等于KEY_BLANK,
由于CurrentKeyValue是局部变量,我们得把键值保存到全局变量KeyValue中,后面按键任务中使用它,后面的Switch语句不祥说,
按键的各种状态在这里头转换和设置。键值等于KEY_BLANK得部分也是一样,这是按键松开的动作,直到释放。

按键执行的任务在主程序中ScanKey()之后
这部分可以写成函数,实际我没有这样写,由于程序简单,就直接写在主程序中了:
   if(KeyAction)
   {
    switch(KeyState)
    {
     case KEY_FIRST_DOWN:
      if(KeyValue==1)
      {
       SetChannelDirect(1);
      }
      else if(KeyValue==2)
      {
       SetChannelDirect(2);
      }
      break;
     case KEY_FIRST_RPT:
      if(KeyValue==1)
      {
      
      }
      else if(KeyValue==2)
      {
      
      }
      break;
     case KEY_REPEAT:
      if(KeyValue==1)
      {
       SetChannelDirect(1);
      }
      else if(KeyValue==2)
      {
       SetChannelDirect(2);
      }
      break;
     case KEY_SHORT_UP:
      if(KeyValue==1)
      {
      
      }
      else if(KeyValue==2)
      {
      
      }
      break;
    }
   
    KeyAction=0;
   }
这个就不需要详细说明了,判断是否有动作,有动作则对不同动作状态做不同处理,在不同的动作状态下对不同的按键调用不同的按键程序。
需要注意的是之后一定要把KeyAction置0。另外需要在程序初始化中调用InitinalKey()。
写的不尽如人意,望泼水。
附件中是AD按键的扫描。
Key.rar (1.14 KB)

相关帖子

沙发
babyqym|  楼主 | 2012-9-19 21:10 | 只看该作者
后面的更精彩

使用特权

评论回复
板凳
3htech| | 2012-9-20 11:27 | 只看该作者
LZ可否写个流程图呢?

使用特权

评论回复
地板
duhemayi| | 2012-9-20 14:01 | 只看该作者
我觉得也是!LZ写个流程图吧,这样看着更清晰

使用特权

评论回复
5
数码小叶| | 2013-8-9 14:55 | 只看该作者
不错,学习下

使用特权

评论回复
6
韦斯克拉| | 2013-8-9 16:57 | 只看该作者
不错,学习下

使用特权

评论回复
7
fdsfdsa| | 2013-9-16 09:39 | 只看该作者
学习。

使用特权

评论回复
8
烟花不堪剪| | 2013-9-17 11:31 | 只看该作者
AD做按键,玩玩可以,实际使用的话可靠性不行的。。。

使用特权

评论回复
9
kingxw| | 2013-9-17 11:58 | 只看该作者
学习下思路

使用特权

评论回复
10
汽车电子| | 2013-9-17 12:05 | 只看该作者
按键三属性是不变的
按下、按住、弹起
围绕这个写程序就可以了,中间不用延时,用轮巡

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qym

13

主题

56

帖子

1

粉丝