|
 (原文件名:无标题.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;     
}
=====================================================================
在此基础上做修改,可以非常容易的把“连_发”功能加上,不管是单键,还是多键,都能“连_发”。这个还是留给各位去实现吧。
剑法如何,欢迎各位后生评判。
本贴被 machao 编辑过,最后修改时间:2008-10-09,20:31:09. |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|