打印

一个C语言写的键盘扫描小程序

[复制链接]
楼主: xiangrui21
手机看帖
扫描二维码
随时随地手机跟帖
21
itelectron| | 2010-1-7 22:10 | 只看该作者 回帖奖励 |倒序浏览
偶也 贴一个  

#define  TK                                8                        //主程序执行时间8ms  //8
#define  timer20ms          (30/TK)                //延时时间20ms       //(30/TK)
#define  timer3S                  (800/TK)        //延时时间3S         //(1200/TK)
#define  timer100ms          (500/TK)        //延时时间100ms      //(1000/TK)
KEY                KeyDat;                   //定义数据结构


/***************************
【函数】:HC166_read(void)
【功能】:HC166驱动与硬件相关
【参数】:无
***************************/
unsigned char HC166_read(void)//HC166_read
{
  unsigned char i,set,k;
  
  Bits1_PutBit(2, FALSE);//L cp底电平
  Bits1_PutBit(1, FALSE);//L PCLK时钟低电平
  Bits1_PutBit(1, TRUE); //H PCLK//时钟高电平,上升沿有效
  Bits1_PutBit(2, TRUE); //H cp高电平

  for(i = 0, set = 0; i < 8;i ++)//依次读取锁存的8位数据
  {
    set <<= 1;
          if (!Bit1_GetVal())set ++;
    Bits1_PutBit(1, FALSE);//L PCLK时钟低电平
    Bits1_PutBit(1, TRUE);//H PCLK//时钟高电平,上升沿有效
  }
    switch(set) //读取扫描值
  {
    case 0x00:      k=0x00;  break; //
    case K_Run:     k=0x01;  break; //GetRun
    case K_Stop:    k=0x02;  break; //GetStop
    case K_Down:    k=0x03;  break; //GetDown
    case K_Jog:     k=0x04;  break; //GetJog
    case K_Shif:    k=0x05;  break; //GetShif
    case K_Up:      k=0x06;  break; //GetUp
    case K_Enter:   k=0x07;  break; //GetEnter
    case K_Mode:    k=0x08;  break; //GetMode
    case K_Enter+K_Up:      k=0x09;  break; //组合键K_Enter+K_Up
    case K_Enter+K_Down:    k=0x10;  break; //组合键K_Enter+K_Down
    default:        k=0x00;  break; //点亮LED2
  }
  return k;
}


/***************************
【函数】:GetKey(void)
【功能】:判断是否有按键
【参数】:无
***************************/
void GetKey(void)
{

  KeyDat.KeyTemp=HC166_read();
  if(KeyDat.KeyTemp!=0)       //有按键
  {
    KeyDat.KeyDog=timer20ms;
    KeyDat.KeyPower++;       
  }
}

/***************************
【函数】:KeyDog(void)
【功能】:按键延时
【参数】:无
***************************/
void Key_Dog(void)
{
  if(0==--KeyDat.KeyDog)        //按键松开
  {
    KeyDat.KeyData=HC166_read();//读键盘
    if(KeyDat.KeyData!=0)
    {
      KeyDat.KeyPower++;       //进入KeyOffShort(void)
      KeyDat.KeyDog=timer3S;   //计数器装载3S
    }
    else
    {
      KeyDat.KeyPower=0;
      KeyDat.KeyData=0;         //返回
    }       
  }
}

/***************************
【函数】:KeyOffShort(void)
【功能】:判断按键是否松开
【参数】:无
***************************/
void KeyOffShort(void)
{
  if(HC166_read()==0)       //判断按键松开
  {
    KeyDat.KeyPower=0;
    KeyDat.KeyData|=HaveKey;//定义短击标记
  }
  else
  {
          if(0==--KeyDat.KeyDog)  //3秒延时到否
          {
      KeyDat.KeyDog=timer100ms;//计数器装载100ms
      KeyDat.KeyPower++;       //进入KeyOffLong(void)
          }
  }
}


/***************************
【函数】:KeyOffLong(void)
【功能】:判断按键长击
【参数】:无
***************************/
void KeyOffLong(void)
{
  if(HC166_read()!=0)//判断长击按键弹起
  {
    if(0==--KeyDat.KeyDog)//3秒延时到
          {
            if(KeyDat.KeyTemp==HC166_read())//校验数据(判断组合键用)
            {
                    KeyDat.KeyData|=DubClick;//DubClick|HaveKey;//长击标记
              KeyDat.KeyDog=timer20ms;
            }
            else     
      {
        KeyDat.KeyData=0;  //数据归0
        KeyDat.KeyPower=0; //长击按键弹起后返回
      }
          }
  }
  else     //长击按键弹起
  {
    KeyDat.KeyData=0;  //数据归0
    KeyDat.KeyPower=0; //长按键弹起后返回
  }

}
/***************************
【函数】:void(*SubKey[])()
【功能】:函数指针定义
【参数】:无
***************************/
void(*SubKey[4])()=
{
  GetKey,Key_Dog,KeyOffShort,KeyOffLong       
};

/***************************
【函数】:void KeyBoard(void)
【功能】:主循环或者定时中断调用
【参数】:无
***************************/
void KeyBoard(void)//扫描键盘
{
  (*SubKey[KeyDat.KeyPower])();       
}

/***************************
【函数】:unsigned char JB_KeyData(void)()
【功能】:用户功能函数调用
【参数】:无
***************************/
unsigned char JB_KeyData(void)
{
  unsigned char i=0;
  if(KeyDat.KeyData>DubClick)//DubClick=0x40
  {
    i=KeyDat.KeyData;
    KeyDat.KeyData=0;       
  }
  return i;
}

使用特权

评论回复
评分
参与人数 1威望 +4 收起 理由
古道热肠 + 4
22
xuekui| | 2010-1-7 23:23 | 只看该作者
建议用硬件电路解决问题

使用特权

评论回复
23
xiangrui21|  楼主 | 2010-1-8 08:53 | 只看该作者
21楼也很强大,谢谢哈,我先都研究研究~!

再次感谢各位鼎力支持~!赞一个:victory:

使用特权

评论回复
24
leolle| | 2010-1-8 08:54 | 只看该作者
线反转更方便

使用特权

评论回复
25
elenment| | 2010-1-8 23:59 | 只看该作者
天哪  一个键盘扫描 就这么长的代码。。。
大家觉得 程序空间不要钱么??还是觉得处理器快的惊人??

使用特权

评论回复
26
maxking| | 2010-1-19 22:43 | 只看该作者
学习了.找不到"原野之狼"的旧帖,能否集中帖在这里?

使用特权

评论回复
27
冷漠| | 2010-1-20 13:49 | 只看该作者

谁能写到最简约?

本帖最后由 冷漠 于 2010-1-20 17:05 编辑

天哪  一个键盘扫描 就这么长的代码。。。
大家觉得 程序空间不要钱么??还是觉得处理器快的惊人??


敬佩25楼。比人简约一点点,就是创新。

唉!确实有不少人下功夫研究键盘扫描了,但是就是没国外教材上写的简约!怎么中国的教育方式真的有问题?

看完国外教材上写的键盘扫描程序,不仅是“拍案惊奇”的感觉,好像是令人窒息了。O(∩_∩)O,大有折剑不练的羞愧。

使用特权

评论回复
28
machunshui| | 2010-1-20 20:43 | 只看该作者
void ScanKey(void)
{       
        static ScanKeyStatge = 0;
       
        if(ScanKeyStatge == 0)
        {
                if(RB0 == 0 || RB1 == 0)
                {
                        ScanKeyStatge = 1;
                        SetSysTimer(0,15);//150ms延时
                }       
        }
        else if(ScanKeyStatge == 1)
        {
                if(GetSysTimer(0))
                {
                        GetKey();
                        ScanKeyStatge = 0;
                }       
        }               

}

使用特权

评论回复
29
红金龙吸味| | 2010-1-20 23:32 | 只看该作者
楼上思想不错,赞一个,本质都是释放
cpu。搬凳子过来听冷漠大侠讲课。

使用特权

评论回复
30
古道热肠| | 2010-1-21 00:14 | 只看该作者
呵呵,俺觉得老外的那本<<嵌入式系统构件>>的代码风格很值得学习.

使用特权

评论回复
31
古道热肠| | 2010-1-21 00:16 | 只看该作者
俺那MP3用的是状态机+定时器管理键盘.可以实现短接和长按执行不同的功能.推荐大家多用状态机.

使用特权

评论回复
32
古道热肠| | 2010-1-21 00:17 | 只看该作者
相关代码已在本版发表,楼主可搜一下参考.

使用特权

评论回复
33
sunkuan2007| | 2010-1-21 01:05 | 只看该作者
学习到了~~~~~~~~~~~~

使用特权

评论回复
34
冷漠| | 2010-1-21 09:36 | 只看该作者
论坛上早就讨论过了,但是我们没参加过讨论的人还是不能脱离俗套。

基本概念:实时系统要求对输入信号(开关、键盘)尽可能快的响应(假定不用外部过滤器件)。那么当一个按键/开关/机械触点闭合时,你的程序需要20~100ms 以后才响应?——智能玩具还可以,要是化工厂或者核反应堆控制装置,(假定要求你实现类似控制装置),我们怎么办?

俗套1、  如果一段对输入信号的响应程序,其执行时间开销大于输入信号的抖动时间,那么消抖是不是多此一举?
俗套2、  消抖的作用:几乎所有人都是一个答案:“为了抗干扰。”有一位说得更直接:“键盘输入管脚经常会有假信号输入。”O(∩_∩)O ???
      证实这一点(误导)很好办,用一个不带消抖的程序监控记录键盘的输入管脚,结果,在强干扰环境下,程序运行8小时,一个干扰也没记录到。

所以,只听到过一个人振聋发聩的声音“消抖是为了防止一次按键多次响应。”——中国教授从不这样讲课。
     也就是说:如果你能做到防止输入抖动时间 20~100ms 之内“一次按键多次响应”,或者说,你的程序能够保证一个消抖时间单位内“一次按键,一次响应”,你就可以在所有人正在处理消抖时,比他们快一步,(他们还在消抖,你已经响应执行完毕了。)你做的系统实时响应性能就是一流。

使用特权

评论回复
评分
参与人数 3威望 +3 收起 理由
kodec2104 + 1
xwl2512999 + 1
红金龙吸味 + 1
35
john_light| | 2010-1-21 09:39 | 只看该作者
“冷漠”网友的提法不落俗套,说的不错!

使用特权

评论回复
36
冷漠| | 2010-1-21 09:55 | 只看该作者
本帖最后由 冷漠 于 2010-1-21 10:03 编辑

“消抖是为了防止一次按键多次响应。”

也就是说,当你的键盘输入响应程序执行时间小于抖动时间时,可能响应程序执行完毕,键盘抖动还未结束,这时检测键盘输入程序就会认为是键盘按键的第二次输入,并触发响应程序的再次运行。——很多人都经历过这种情况,我们都是“先消抖,后响应。”但是没有人想过怎样“先响应,后处理抖动。”

        我们担心,检测键盘输入的第一次结果会是“假冒”的。那么2次,3次会不会消除疑虑?怎样实现1ms内3次确定输入值?

使用特权

评论回复
37
红金龙吸味| | 2010-1-21 11:11 | 只看该作者
也就是说:如果你能做到防止输入抖动时间 20~100ms 之内“一次按键多次响应”,或者说,你的程序能够保证一个消抖时间单位内“一次按键,一次响应”,你就可以在所有人正在处理消抖时,比他们快一步,(他们还在消抖,你已经响应执行完毕了。)你做的系统实时响应性能就是一流。精彩!
我们担心,检测键盘输入的第一次结果会是“假冒”的。那么2次,3次会不会消除疑虑?怎样实现1ms内3次确定输入值?
同样疑问,继续听课。

使用特权

评论回复
38
liudan0311| | 2010-2-5 11:41 | 只看该作者
多多向各位大神学习哈

使用特权

评论回复
39
jesseaz| | 2010-2-5 17:05 | 只看该作者
12楼用的中断扫描键盘么?我是菜鸟。

使用特权

评论回复
40
xwl2512999| | 2010-2-5 19:40 | 只看该作者
高手真多啊

使用特权

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

本版积分规则