原创 4*4键盘扫描

2007-12-9 19:18 5707 11 16 分类: 汽车电子

                      4*4键盘扫描文档<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


  今天把4*4键盘的程序从单片机上移植到了NIOS上。


   4*4键盘扫描电路


<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" /> 8b79f1aa-3049-41bf-abba-5ef7c90eed93.GIF



 


程序采用间隔时间进行扫描法,由于键盘的抖动时间为10ms-20ms之间,所以在定时器中加入一个标志位,当定时10ms后,就进入判断,采用类似FPGA的状态机法,进行扫描。有效的避开了抖动。


状态一,判断是否有键按下,有键按下,则转到状态二。


状态二:再进行判断有没键按下,有按下,则进行扫描,进入状态三。没有,则返回状态一。


   状态三: 根据行码,和列码进行判断键值,根据相应的键值执行相应的程序。进入状态四


   状态四: 判断键是否释放,松开,则返回状态一,没有,则在状态四。


首先分为行信号(key4—key7),作为输入端口,用于读取IO口上的电平值,初始时写0


列信号(key0---key3),作为输出端口,为送入扫描信号。


在初始时,将所有的列信号(输出口)(key3—key3)置为低电平,在没有任何键按下时,读取(输入口)key4—key7上的电平值将为1,当任何一个按键按下时,则key4-key7中将会有一行被拉低,则表示有键按下。


这时就开始从key0-key3送入扫描字,进行扫描。扫描字为0111,101111011110


如果在它的输入端口发现一个0值,则就知道了在哪一列上有键按下。没有的话,则扫描字左移,继续扫描。根据行值,列值,来读出键值。


 


根据上面的接口电路。Key7—key0对应着键盘的接口高位到低位。


假如:开始key7-key4作为输入口,由于上拉电阻,则读出的数据为1key0-key3作为输出口,写低电平。当键S4按下时,则Key4电平被拉低,判断出在第一行上有键按下。这时,进行扫描。在key0-key3送入扫描字1110,读取key4-key7口上电平,发现key4上的电平为0,则判断出第四列有键按下。则得出s4键按下。键值为key7:key0=1110 (行码)&1110(列扫描字)==1110 1110以此累推。


 


总结:经过移植几种程比较,这种效率最高。而且占用的时间比较少。不过在NIOS上移植,可以结合FPGA,直接做个4*4键盘扫描控制器,当有键按下时,可以进入中断。这样的话,节省了CPU的时间。当有键按下时,送出键按下标志位。进入中断。读取键值,执行键盘程序。可见NIOS的强大功能,和可配置性,还有很多东西待去学习。


/**********************************************************


*功能: 键盘扫描函数


*说明:


*********************************************************/


unsigned char read_key(void)


{


   unsigned char i;


   unsigned char key_return = 0;


  


   IOWR_ALTERA_AVALON_PIO_DIRECTION(KEY_PIO_BASE,0X<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />0f);


   //高四位作为输入,读取数据,低四位为输出


   Key_data=0x00;//低四位输出口写0


    switch (key_state)


  {


      case 0:


           // 读按键高四位I/O电平,当有键按下时为0,没按下时为1 


    if((IORD_ALTERA_AVALON_PIO_DATA(KEY_PIO_BASE)&0xf0)==0xf0)


      {


              break;//无键按下返回


      }


     else


      {


             key_state=1; //有键按下      


      }break;


     


      case 1://进行扫描键值


             {


       if((IORD_ALTERA_AVALON_PIO_DATA(KEY_PIO_BASE)&0xf0)==0xf0)


                                                      //读取高四位电平


         {


              break;//无键按下返回,是误动作


         }


      else


        { //有键按下去抖


                    key_line=0x08;


                    for(i=1;i<=4;i++)


                    {


                           Key_data=~key_line;//1111 0111


                           key_value=0xf0&IORD_ALTERA_AVALON_PIO_DATA(KEY_PIO_BASE);


                           if (key_value == 0xf0)


        {


          key_line >>= 1;       // 没有按键,继续扫描


        }


        else


        {


          key_state=2;          // 有按键,停止扫描,转入下一个状态


         }


                    }


              }


             }


            


             case 2:


       {


            switch (key_line|key_value) //0000 1000


             {


                 case 0x78:


              key_return=1;break;


           case 0x74:


              key_return=2;break;


           case 0x72:


              key_return=3;break;


           case 0x71:


              key_return=4;break;


           case 0xb8:


              key_return=5;    break;


           case 0xb4:


              key_return=6;break;


           case 0xb2:


              key_return=7;break;


           case 0xb1:


              key_return=8;break;


            case 0xd8:


              key_return=9;break;


           case 0xd4:


              key_return=10;break;


           case 0xd2:


              key_return=11;break;


           case 0xd1:


              key_return=12;break;


            case 0xe8:


              key_return=13;    break;


           case 0xe4:


              key_return=14;break;


           case 0xe2:


              key_return=15;break;


           case 0xe1:


              key_return=16;break;  


            }  


        key_state = 3;  // 状态转换到键释放态


        


        } break;


       


       case 3:       //键已经释放,确认了有键按下


       


        {


        Key_data=0xf0;//低四位写0,高四位作为输入口,不受影响


       if((0xf0&IORD_ALTERA_AVALON_PIO_DATA(KEY_PIO_BASE))==0xf0)


        key_state = 0;


        }


         break; //按键已释放,转换到按键初始态


       


      


      }


      return key_return;         //当返回为0时,表示没有键按下,


  }        


 
PARTNER CONTENT

文章评论5条评论)

登录后参与讨论

用户178123 2009-2-14 09:44

#include #define ulong unsigned long #define uint unsigned int #define uchar unsigned char extern void delay(unsigned int x); unsigned char Tab_key[]= //行列式键盘映射 {0x00, //无键按下 '7','8','9','/', '4','5','6','*', '1','2','3','-', 'C','0','=','+', //下面为按'C'同时再按的键: '7','8','9','/', '4','5','6','*', '1','2','3','-', '0','=','+',}; // P1口行列式键盘 // #define KEYPIN_L P1 // 定义键扫描列端口为 P1 低四位输入 // #define KEYPIN_H P1 // 定义键扫描行端口为 P1高 四位扫描输出 // // P1口行列式键盘 // //公用函数 unsigned char KeysCAN(void); // 键扫描函数 // //内部私有函数 unsigned char fnKeycode(unsigned char key); // 根据键盘 映射表输出顺序键值 // /* // P1口行列式键盘 // extern unsigned char KeysCAN(void); // 键扫描函数 // */ // P1口行列式键盘 // //--------------------------------------------------------- ------------------// unsigned char KeysCAN(void) // 键扫描 函数 // { unsigned char sccode,recode,keytemp = 0; KEYPIN_L = KEYPIN_L|0x0f; // P1低四位为列线输入 // KEYPIN_H = KEYPIN_H&0x0f; // P1高四位为行线发全零扫描码 // if ((KEYPIN_L&0x0f) != 0x0f) { delay(10); // 延时 10 MS 消抖 // if ((KEYPIN_L&0x0f) != 0x0f) { sccode = 0xef; // 逐行扫描码初值(1110 1111) // while(sccode != 0xff) //将扫描4次,keytemp为每次键值相 或的值 // { KEYPIN_H = sccode; // 输出行扫描码 // if ((KEYPIN_L&0x0f) != 0x0f) // 本行有键按下 // { recode = (KEYPIN_L&0x0f)|0xf0; // 只要低位,高位置1 // keytemp |= (~sccode)+(~recode); //特征码(高位为列P3,低位为行KEYPIN_H) // } sccode = (sccode << 1)|0x01; // 扫描码0向高位移动 // } } } KEYPIN_H = KEYPIN_H|0xf0; return(fnKeycode(keytemp)); } //--------------------------------------------------------- ------------------// unsigned char fnKeycode(unsigned char key) // 根据键盘映射表输出顺序键值 // { switch(key) { case 0x11: // 1 键 // key = 0x01; break; case 0x21: // 2 键 // key = 0x02; break; case 0x41: // 3 键 // key = 0x03; break; case 0x81: // 4 键 // key = 0x04; break; case 0x12: // 5 键 // key = 0x05; break; case 0x22: // 6 键 // key = 0x06; break; case 0x42: // 7 键 // key = 0x07; break; case 0x82: // 8 键 // key = 0x08; break; case 0x14: // 9 键 // key = 0x09; break; case 0x24: // 10 键 // key = 0x0A; break; case 0x44: // 11 键 // key = 0x0B; break; case 0x84: // 12 键 // key = 0x0C; break; case 0x18: // 13 键 // key = 0x0D; break; case 0x28: // 14 键 // key = 0x0E; break; case 0x48: // 15 键 // key = 0x0F; break; case 0x88: // 16 键 // key = 0x10; break; //以下为功能键// case 0x19: // 'C' +1 键 // key = 0x11; break; case 0x29: // 'C' +2 键 // key = 0x12; break; case 0x49: // 'C' +3 键 // key = 0x13; break; case 0x89: // 'C' +4 键 // key = 0x14; break; case 0x1A: // 'C' +5 键 // key = 0x15; break; case 0x2A: // 'C' +6 键 // key = 0x16; break; case 0x4A: // 'C' +7 键 // key = 0x17; break; case 0x8A: // 'C' +8 键 // key = 0x18; break; case 0x1C: // 'C' +9 键 // key = 0x19; break; case 0x2C: // 'C' +10 键 // key = 0x1A; break; case 0x4C: // 'C' +11 键 // key = 0x1B; break; case 0x8C: // 'C' +12 键 // key = 0x1C; break; // case 0x18: // 'C' +13 键 // // key = 0x1D; // break; case 0x38: // 'C' +14 键 // key = 0x1D; break; case 0x58: // 'C' +15 键 // key = 0x1E; break; case 0x98: // 'C' +16 键 // key = 0x1F; break; default : // 无键 // key = 0x00; break; } return(Tab_key[key]); }

用户178123 2009-2-14 09:42

#include #define ulong unsigned long #define uint unsigned int #define uchar unsigned char extern void delay(unsigned int x); unsigned char Tab_key[]= //行列式键盘映射 {0x00, //无键按下 '7','8','9','/', '4','5','6','*', '1','2','3','-', 'C','0','=','+', //下面为按'C'同时再按的键: '7','8','9','/', '4','5','6','*', '1','2','3','-', '0','=','+',}; // P1口行列式键盘 // #define KEYPIN_L P1 // 定义键扫描列端口为 P1 低四位输入 // #define KEYPIN_H P1 // 定义键扫描行端口为 P1高 四位扫描输出 // // P1口行列式键盘 // //公用函数 unsigned char KeysCAN(void); // 键扫描函数 // //内部私有函数 unsigned char fnKeycode(unsigned char key); // 根据键盘 映射表输出顺序键值 // /* // P1口行列式键盘 // extern unsigned char KeysCAN(void); // 键扫描函数 // */ // P1口行列式键盘 // //--------------------------------------------------------- ------------------// unsigned char KeysCAN(void) // 键扫描 函数 // { unsigned char sccode,recode,keytemp = 0; KEYPIN_L = KEYPIN_L|0x0f; // P1低四位为列线输入 // KEYPIN_H = KEYPIN_H&0x0f; // P1高四位为行线发全零扫描码 // if ((KEYPIN_L&0x0f) != 0x0f) { delay(10); // 延时 10 MS 消抖 // if ((KEYPIN_L&0x0f) != 0x0f) { sccode = 0xef; // 逐行扫描码初值(1110 1111) // while(sccode != 0xff) //将扫描4次,keytemp为每次键值相 或的值 // { KEYPIN_H = sccode; // 输出行扫描码 // if ((KEYPIN_L&0x0f) != 0x0f) // 本行有键按下 // { recode = (KEYPIN_L&0x0f)|0xf0; // 只要低位,高位置1 // keytemp |= (~sccode)+(~recode); //特征码(高位为列P3,低位为行KEYPIN_H) // } sccode = (sccode << 1)|0x01; // 扫描码0向高位移动 // } } } KEYPIN_H = KEYPIN_H|0xf0; return(fnKeycode(keytemp)); } //--------------------------------------------------------- ------------------// unsigned char fnKeycode(unsigned char key) // 根据键盘映射表输出顺序键值 // { switch(key) { case 0x11: // 1 键 // key = 0x01; break; case 0x21: // 2 键 // key = 0x02; break; case 0x41: // 3 键 // key = 0x03; break; case 0x81: // 4 键 // key = 0x04; break; case 0x12: // 5 键 // key = 0x05; break; case 0x22: // 6 键 // key = 0x06; break; case 0x42: // 7 键 // key = 0x07; break; case 0x82: // 8 键 // key = 0x08; break; case 0x14: // 9 键 // key = 0x09; break; case 0x24: // 10 键 // key = 0x0A; break; case 0x44: // 11 键 // key = 0x0B; break; case 0x84: // 12 键 // key = 0x0C; break; case 0x18: // 13 键 // key = 0x0D; break; case 0x28: // 14 键 // key = 0x0E; break; case 0x48: // 15 键 // key = 0x0F; break; case 0x88: // 16 键 // key = 0x10; break; //以下为功能键// case 0x19: // 'C' +1 键 // key = 0x11; break; case 0x29: // 'C' +2 键 // key = 0x12; break; case 0x49: // 'C' +3 键 // key = 0x13; break; case 0x89: // 'C' +4 键 // key = 0x14; break; case 0x1A: // 'C' +5 键 // key = 0x15; break; case 0x2A: // 'C' +6 键 // key = 0x16; break; case 0x4A: // 'C' +7 键 // key = 0x17; break; case 0x8A: // 'C' +8 键 // key = 0x18; break; case 0x1C: // 'C' +9 键 // key = 0x19; break; case 0x2C: // 'C' +10 键 // key = 0x1A; break; case 0x4C: // 'C' +11 键 // key = 0x1B; break; case 0x8C: // 'C' +12 键 // key = 0x1C; break; // case 0x18: // 'C' +13 键 // // key = 0x1D; // break; case 0x38: // 'C' +14 键 // key = 0x1D; break; case 0x58: // 'C' +15 键 // key = 0x1E; break; case 0x98: // 'C' +16 键 // key = 0x1F; break; default : // 无键 // key = 0x00; break; } return(Tab_key[key]); } //有部分双键功能,自己看看吧

crazy_embeddedsystem_775092187 2007-12-12 12:47

多个按键同时按下了怎么处理??

用户1316816 2007-12-11 13:31

这里是只有当键释放了,才能往下执行的..要想达到你的要求,要在程序里面再处理一下,应该是可以达到的. 这个要看程序具体要怎么写的.

用户65681 2007-12-11 09:44

有个问题?就是如果我HOLD着一个键不放,再按别的键的话那别的键就没有功能出了是吧?能否做到在这样的情况下也别的按键也有功能呢?
相关推荐阅读
用户1316816 2008-10-19 23:58
写下心情,一段平凡的日子
      2008,不平常的一年,这一年我毕业了,从自己的梦想走入了社会,也许刚入社会,总要有一段适应的过程,从实习到工作,离开学校也快半年了,时间总是过得这么快,有时又觉得又是那么的慢.曾经的梦想...
用户1316816 2008-08-28 20:27
我的毕业设计--存储示波器
<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />整个系统采用FPGA Cyclone 2C5芯片,在内嵌...
用户1316816 2008-03-15 12:12
基于FPGA的密码锁
采用4X4键盘电路,和一个四位动显示电路.来完成基本的控制功能 .1.4X4 键盘扫描电路的设计电路中分为键盘去抖电路和键盘译码电路。弹跳消除电路所使用的频率必须比其它电路的工作频率高,扫描电路的工作...
用户1316816 2008-03-13 18:43
简易电压源
/*****************************************************This program was produced by theCodeWizardAVR ...
用户1316816 2008-03-13 18:41
基于1302的万年历
这个是1302程序,液晶用12864来显示...
用户1316816 2008-03-13 18:38
模拟SPI接口程序
//***********************************************************//功能      : 由AVR作为主机,向FPGA发送数据,采用模拟SPI接...
EE直播间
更多
我要评论
5
11
关闭 站长推荐上一条 /3 下一条