这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 关于按键处理(转贴)

共2条 1/1 1 跳转至

关于按键处理(转贴)

高工
2011-08-04 09:01:49     打赏
原贴:
http://www.ourdev.cn/bbs/bbs_content_all.jsp?bbs_sn=1567987




 (原文件名:无标题.jpg) 



马老师:

     在上图中,如果要检测按键的按下,如果要求在按键按下直至按键松开之后才定义一次按键完成,那么程序上如何检测P3。7的这种变化呢?(因P3。7这时的电平变化是一系列脉冲的)。请马老师指教,不胜感激。





=======================================================================================



首先谢谢捧场的朋友们。 



我把题目总结归纳,给出更具体的需求,便于大家出招打擂。 



1。原理图以楼主位的为基础,可以做稍微的改动,但要保持I/O复用的基本原则,也就是说,不能增加太多的I/O。最好还是原图的数目。 

2。要保证6个LED数码管显示正常,按键检测过程中不能出现闪烁、抖动、或破坏显示的现象 

3。系统需要使用组合键。即要能“同时”检测出多个键按下 

4。要考虑按键按下和释放过程中的消抖,消抖时间在10ms-20ms之间 

5。LZ位的要求是“在按键按下直至按键松开之后才定义一次按键完成”。这就是说不具备按键的“连_发”功能。我把要求改动为:按键不具备“连_ 发”功能。这样的话,按键稳定按下后就可以执行按键操作,但下一次按键的检测必需等待本次按键完全释放。这不违背LZ的“在按键按下直至按键松开之后才定 义一次按键完成”原则,但在实际操作中用户使用方便。否则用户按下键后,没有见到相应的反映,会一直按着不放,这样这个按键过程会“永远”完不成了。 

6。给出相应的C代码(主要是显示和读键部分,以及上层的调用关系等),和电路图(如果改动的话)。但显示扫描和消抖过程禁止使用软件延时,必须考虑使用定时器中断。 





擂主:本专栏斑竹





在71楼我已经出了试探招数,亮了点底牌,请后来者看过后斟酌仔细,然后再杀上前来也。



=====================================================================================

擂主本人在93楼使出了绝招,剑法如下:



 一、硬件原理图。就是LZ的图:



 (原LZ位图) 



只是里面有点BUG,不能多键按下,按50楼的图改动,增加5个二极管。



 (原50楼硬件修改图) 



至于改动原因,就不说了,前面已经有点评了。



另外,电路中的LS47可以省掉,直接用P1输出8位段码(89C2051的驱动能力10mA,点1个LED没问题),反正其它的口也没用吗。



二、具体功能,也是按LZ位制定的原则

1。要保证6个LED数码管显示正常,按键检测过程中不能出现闪烁、抖动、或破坏显示的现象  

2。系统需要使用组合键。即要能“同时”检测出多个键按下  

3。要考虑按键按下和释放过程中的消抖,消抖时间在10ms-20ms之间  

4。LZ位的要求是“在按键按下直至按键松开之后才定义一次按键完成”。这就是说不具备按键的“连_发”功能。我把要求改动为:按键不具备“连_ 发”功能。这样的话,按键稳定按下后就可以执行按键操作,但下一次按键的检测必需等待本次按键完全释放。这不违背LZ的“在按键按下直至按键松开之后才定 义一次按键完成”原则,但在实际操作中用户使用方便。否则用户按下键后,没有见到相应的反映,会一直按着不放,这样这个按键过程会“永远”完不成了。  

5。给出相应的C代码(主要是显示和读键部分,以及上层的调用关系等),和电路图(如果改动的话)。但显示扫描和消抖过程禁止使用软件延时,必须考虑使用定时器中断。



三、为了使学51的和AVR的都能使用,代码采用C编写。程序中采用P1、P3表示两个8位的I/O口,AVR可类似对应的使用 PORTA,PORTC。键输入为P3.7,对应AVR,可理解为PINC.7。系统6个LED数码管采用动态扫描显示,有5个按键,有一个位选是不复用 的。



四、显示扫描时间的计算与确定。每个LED点亮时间为2ms,6个LED循环扫描一遍为12ms。1秒内共循环1000/12=83次,超过25次,保证显示不出现闪烁、抖动等情况。按键读取插在LED的扫描过程中,不另外使用单独的时间。





五、代码框架



//=============定义全局变量

char dis_buff[6];                 // 这里存放每个LED显示段码值(BCD格式的)

char key_tmp,key_value = 0x00;    // 键值,8位,每位对应一个键,为0表示该位按键,为1表示无。高3位永远为0,

                                  // 因此。0b00011111表示无键按下;0b00011110表示0号键按下,0b00011100则表示0、1号键同时按下的组合键。



//==============主程序

main()

{

   while(1)

   {

     key_tmp = key_value;                // 读键值,放在key_tmp中,因key_value会在中断中变化的

     if (key_tmp < 128)                  // 有一次按键过程 

     {

        key_value = 128;                 // 防止多2次处理

        switch(key_tmp)                  //按键处理过程

        {

          case 0b00011110:

               // 0号键处理.......

               break;

        

          case 0b00011101:

               // 1号键处理..............

               break;

               ............



          case 0b00011100:

              // 2键组合键处理(0、1号键按下)..................... 

              break;

             ............

          case 0b00011000 

             // 3键组合处理(0、1、2号键按下)..................... 

             break;

        }

     ............. 

    }  

}

//--------------------------------------------

主程序就写这么多了,当然初始化部分都剩掉了,其它的系统功能我也不知道,这里重要的是键处理(千万不要在主程序的大循环中使用大量的软件延时, 影响switch的执行,这样键的响应就会受到影响了)。另外重要的是我的代码中需要一个2ms的定时中断,不要忘记初始化一个定时器。这个不用写了。 

//================================================================







//===================2ms定时中断服务(完成LED扫描显示和读键,消抖,确认的功能)=======

//====注意,此服务2ms执行一次,但执行时间很短======================

//=====此外,为了容易理解,下面是以138的ABC接2051的p3.0/p3.1/p3.2处理,那个JP1的作用就不考虑了,我也不知道他准备做什么===



timer_2ms_int()

{

      static char posit = 0;

      static char read_key,pre_key,delay_time;

      static char key_state = 0;



      P3 = 0x87;                          //关显示,消影(138的ABC = 7,y7输出0,其它为1)

      P1 = dis_buff[posit];               //送出BCD格式的段码值   

      P3 = 0x80 | posit;                  //开相应posit位的LED显示。 

      

      if (posit < 5)

      {

          read_key &= ~(1<<posit); 

          if (P3.7) read_key |= (1<<posir));     // 5次中断,读到5个键值

      }

      elas

      {                                                                 //这段12ms执行一次,消抖,判断都有了

          switch(key_state)

          {

                case 0:

                      if (pre_key == read_key)                          // 不管是单键还是多键,必须稳定的按下60ms后才算正式确认一次按键。

                      {   if (++delay_time>= 5) key_state = 1;}        // 调节delay_time的比较值,可以改变稳定确认的时间,如果实际按键

                      else                                              // 过程中感到120ms比较好,那么(++delay_time>= 10)。

                      {   delay_time = 0; }                             // 这里实际已经包含了按键按下和释放的消抖处理。

                      break;

                case 1:

                      key_value = pre_key;                              // 判断出一次有效的按键,注意:pre_key的高3位总是“0”

                      key_state = 2;

                      break;

                case 2:

                      if (read_key == 0b00011111)                       // 必须5个键全部释放才能进入下次按键操作

                      {                                                 // 只要开始发现释放了,就转到状态0,释放消抖在状态0中处理了。

                           delay_time = 0;

                           key_state = 0;

                      }

                      break;  

          }

          pre_key = read_key;      

      } 

      

      if ( ++posit> 5 ) posit = 0;     

}



=====================================================================

在此基础上做修改,可以非常容易的把“连_发”功能加上,不管是单键,还是多键,都能“连_发”。这个还是留给各位去实现吧。



关键词: 关于     按键     处理     转贴     按下     一次     显示     使用         

助工
2011-08-23 12:03:38     打赏
2楼
厉害了......

共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]