矩阵按键的组合按键触发

/*在做产品时,硬件电路设计中,除了四路输入的要加上拉电阻,四路列输出也应该串入一个470欧左右的限流电阻,否则当同一行的两个按键按下时,很容易烧坏单片机的IO口*/

/***12个按键,每一个按键都会让蜂鸣器发出“嘀”的一声,同时按下S1和S12会点亮一个LED灯,同时按下S4和S9会熄灭LED灯***/
#include "REG52.H"
#define const_voice_short 40
#define const_key_time 12
#define const_key_time_comb 14 //组合按键去抖动延时时间
void initial_myself();
void initial_peripheral();
void delay_long(unsigned int uiDelaylong);
void T0_time();
void key_service();
void key_scan();
 
/*
 任意两个组合按键不能处于同一行,否则触发性能大打折扣。
 做产品的时候,在硬件电路设计中,除了四路行输入要加上拉电阻外,
 四路列输出也应该串入一个470欧左右的限流电阻,否则当一行的两个
 按键同时按下时,很容易烧坏单片机的IO口。
*/
sbit key_sr1=P0^1; //第一行输入
sbit key_sr2=P0^2; //第二行输入
sbit key_sr3=P0^3; //第三行输入
sbit key_dr1=P0^4; //第一列输出
sbit key_dr2=P0^5; //第二列输出
sbit key_dr3=P0^6; //第三列输出
sbit key_dr4=P0^7; //第四列输出
sbit led_dr=P3^5; //LED灯
sbit beep_dr=P1^5;
unsigned char ucKeyStep=1; //按键扫描步骤变量
unsigned char ucKeySec=0; //被触发的按键编号
unsigned int uiKeyTimeCnt[12]=0; //12个按键去抖动延时计数器
unsigned char ucKeyLock[12]=0; //12个按键触发后自锁的变量标志
unsigned int uiKeyTimeCnt_01_12=0; //S1和S12组合按键去抖动延时计数器
unsigned char ucKeyLock_01_12=0; //S1和S12组合按键触发后自锁的变量标志
unsigned int uiKeyTimeCnt_04_09=0; //S4和S9组合按键去抖动延时计数器
unsigned char ucKeyLock_04_09=0; //Ss和S9组合按键触发后自锁的变量标志
unsigned int uiListRecord=1; //记录当前扫描到了第几列
unsigned int uiVoiceCnt=0; //蜂鸣器鸣叫的时间计数器
unsigned int uiKeyStatus=0xfff; //此变量每一位代表一个按键的状态,共12个按键。1代表没有被按下,0代表被按下
void main()
{
 initial_myself();
 delay_long(100);
 initial_peripheral();
 while(1)
 {
  key_service();
 }
}
void key_scan()  //按键扫描函数,放到定时中断里
{
 /*
  第一步:先把16个按键翻译成独立按键。
  第二步:再按独立按键的去抖动方式进行按键识别
  第三步:参考独立按键的方式,来实现组合按键
 */
 switch(ucKeyStep)
 {
  case 1: //把12个按键的状态快速记录在uiKeyStatus变量的每一位中,相当于把矩阵键盘翻译成独立按键
   for(uiListRecord=1;uiListRecord<5;uiListRecord++)
   {
    if(uiListRecord==1) //第一列低电平
    {
  key_dr1=0;
  key_dr2=1;
  key_dr3=1;
  key_dr4=1;
   //如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态
   if(key_sr1==0)
    uiKeyStatus=uiKeyStatus&0xffe; //S1被按下
   
   if(key_sr2==0)
    uiKeyStatus=uiKeyStatus&0xfef; //S5被按下
   
   if(key_sr3==0)
    uiKeyStatus=uiKeyStatus&0xeff; //S9被按下  
    }
   
    else if(uiListRecord==2) //第二列低电平
    {
  key_dr1=1;
  key_dr2=0;
  key_dr3=1;
  key_dr4=1;
   //如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态
   if(key_sr1==0)
    uiKeyStatus=uiKeyStatus&0xffd; //S2被按下
   
   if(key_sr2==0)
    uiKeyStatus=uiKeyStatus&0xfdf; //S6被按下
   
   if(key_sr3==0)
    uiKeyStatus=uiKeyStatus&0xdff; //S10被按下  
    }
   
    else if(uiListRecord==3) //第三列低电平
    {
  key_dr1=1;
  key_dr2=1;
  key_dr3=0;
  key_dr4=1;
   //如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态
   if(key_sr1==0)
    uiKeyStatus=uiKeyStatus&0xffb; //S3被按下
   
   if(key_sr2==0)
    uiKeyStatus=uiKeyStatus&0xfbf; //S7被按下
   
   if(key_sr3==0)
    uiKeyStatus=uiKeyStatus&0xbff; //S11被按下  
    }
   
    else  //第四列低电平
    {
  key_dr1=1;
  key_dr2=1;
  key_dr3=1;
  key_dr4=0;
   //如果是薄膜按键或者走线比较长的按键,此处应该加几个空延时,等待列输出信号稳定再判断输入的状态
   if(key_sr1==0)
    uiKeyStatus=uiKeyStatus&0xff7; //S4被按下
   
   if(key_sr2==0)
    uiKeyStatus=uiKeyStatus&0xf7f; //S8被按下
   
   if(key_sr3==0)
    uiKeyStatus=uiKeyStatus&0x7ff; //S12被按下  
    }
   }
  ucKeyStep=2; //切换到下一运行步骤
  break;
  
 case 2:  //像独立按键一样进行去抖动和翻译。
  if((uiKeyStatus&0x001)==0x001) //说明1号按键没有被按下
  {
   uiKeyTimeCnt[0]=0;
   ucKeyLock[0]=0;
  }
  else if(ucKeyLock[0]==0)
  {
   uiKeyTimeCnt[0]++;
   if(uiKeyTimeCnt[0]>const_key_time)
   {
    uiKeyTimeCnt[0]=0;
    ucKeyLock[0]=1; //自锁按键,防止不断触发
    ucKeySec=1;  //触发号按键
   }
  }
  
  if((uiKeyStatus&0x002)==0x002) //说明2号按键没有被按下
  {
   uiKeyTimeCnt[1]=0;
   ucKeyLock[1]=0;
  }
  else if(ucKeyLock[1]==0)
  {
   uiKeyTimeCnt[1]++;
   if(uiKeyTimeCnt[1]>const_key_time)
   {
    uiKeyTimeCnt[1]=0;
    ucKeyLock[1]=1; //自锁按键,防止不断触发
    ucKeySec=2;  //触发2号按键
   }
  }
  
  if((uiKeyStatus&0x004)==0x004) //说明3号按键没有被按下
  {
   uiKeyTimeCnt[2]=0;
   ucKeyLock[2]=0;
  }
  else if(ucKeyLock[2]==0)
  {
   uiKeyTimeCnt[2]++;
   if(uiKeyTimeCnt[2]>const_key_time)
   {
    uiKeyTimeCnt[2]=0;
    ucKeyLock[2]=1; //自锁按键,防止不断触发
    ucKeySec=3;  //触发3号按键
   }
  }
  
  if((uiKeyStatus&0x008)==0x00) //说明4号按键没有被按下
  {
   uiKeyTimeCnt[3]=0;
   ucKeyLock[3]=0;
  }
  else if(ucKeyLock[3]==0)
  {
   uiKeyTimeCnt[3]++;
   if(uiKeyTimeCnt[3]>const_key_time)
   {
    uiKeyTimeCnt[3]=0;
    ucKeyLock[3]=1; //自锁按键,防止不断触发
    ucKeySec=4;  //触发4号按键
   }
  }
  
  if((uiKeyStatus&0x010)==0x010) //说明5号按键没有被按下
  {
   uiKeyTimeCnt[4]=0;
   ucKeyLock[4]=0;
  }
  else if(ucKeyLock[4]==0)
  {
   uiKeyTimeCnt[4]++;
   if(uiKeyTimeCnt[4]>const_key_time)
   {
    uiKeyTimeCnt[4]=0;
    ucKeyLock[4]=1; //自锁按键,防止不断触发
    ucKeySec=5;  //触发5号按键
   }
  }
  
  if((uiKeyStatus&0x020)==0x020) //说明6号按键没有被按下
  {
   uiKeyTimeCnt[5]=0;
   ucKeyLock[5]=0;
  }
  else if(ucKeyLock[5]==0)
  {
   uiKeyTimeCnt[5]++;
   if(uiKeyTimeCnt[5]>const_key_time)
   {
    uiKeyTimeCnt[5]=0;
    ucKeyLock[5]=1; //自锁按键,防止不断触发
    ucKeySec=6;  //触发6号按键
   }
  }
  
  if((uiKeyStatus&0x040)==0x040) //说明7号按键没有被按下
  {
   uiKeyTimeCnt[6]=0;
   ucKeyLock[6]=0;
  }
  else if(ucKeyLock[6]==0)
  {
   uiKeyTimeCnt[6]++;
   if(uiKeyTimeCnt[6]>const_key_time)
   {
    uiKeyTimeCnt[6]=0;
    ucKeyLock[6]=1; //自锁按键,防止不断触发
    ucKeySec=7;  //触发7号按键
   }
  }
  
  if((uiKeyStatus&0x080)==0x080) //说明8号按键没有被按下
  {
   uiKeyTimeCnt[7]=0;
   ucKeyLock[7]=0;
  }
  else if(ucKeyLock[7]==0)
  {
   uiKeyTimeCnt[7]++;
   if(uiKeyTimeCnt[7]>const_key_time)
   {
    uiKeyTimeCnt[7]=0;
    ucKeyLock[7]=1; //自锁按键,防止不断触发
    ucKeySec=8;  //触发8号按键
   }
  }
  
  if((uiKeyStatus&0x100)==0x100) //说明9号按键没有被按下
  {
   uiKeyTimeCnt[8]=0;
   ucKeyLock[8]=0;
  }
  else if(ucKeyLock[8]==0)
  {
   uiKeyTimeCnt[8]++;
   if(uiKeyTimeCnt[8]>const_key_time)
   {
    uiKeyTimeCnt[8]=0;
    ucKeyLock[8]=1; //自锁按键,防止不断触发
    ucKeySec=9;  //触发9号按键
   }
  }
  
  if((uiKeyStatus&0x200)==0x200) //说明10号按键没有被按下
  {
   uiKeyTimeCnt[9]=0;
   ucKeyLock[9]=0;
  }
  else if(ucKeyLock[9]==0)
  {
   uiKeyTimeCnt[9]++;
   if(uiKeyTimeCnt[9]>const_key_time)
   {
    uiKeyTimeCnt[9]=0;
    ucKeyLock[9]=1; //自锁按键,防止不断触发
    ucKeySec=10;  //触发10号按键
   }
  }
  
  if((uiKeyStatus&0x400)==0x400) //说明11号按键没有被按下
  {
   uiKeyTimeCnt[10]=0;
   ucKeyLock[10]=0;
  }
  else if(ucKeyLock[10]==0)
  {
   uiKeyTimeCnt[10]++;
   if(uiKeyTimeCnt[10]>const_key_time)
   {
    uiKeyTimeCnt[10]=0;
    ucKeyLock[10]=1; //自锁按键,防止不断触发
    ucKeySec=11;  //触发11号按键
   }
  }
  
  if((uiKeyStatus&0x800)==0x800) //说明12号按键没有被按下
  {
   uiKeyTimeCnt[11]=0;
   ucKeyLock[11]=0;
  }
  else if(ucKeyLock[11]==0)
  {
   uiKeyTimeCnt[11]++;
   if(uiKeyTimeCnt[11]>const_key_time)
   {
    uiKeyTimeCnt[11]=0;
    ucKeyLock[11]=1; //自锁按键,防止不断触发
    ucKeySec=12;  //触发12号按键
   }
  }
  
  
  if((uiKeyStatus&0x801)==0x000) //S1和S12的组合按键被按下
  {
   if(ucKeyLock_01_12==0)
   {
    uiKeyTimeCnt_01_12++;
    if(uiKeyTimeCnt_01_12>const_key_time_comb)
    {
     uiKeyTimeCnt_01_12=0;
     ucKeyLock_01_12=1;
     ucKeySec=13; //触发13号组合按键
    }
   }
  }
  
  else
  {
   uiKeyTimeCnt_01_12=0;
   ucKeyLock_01_12=0;
  }
  
  if((uiKeyStatus&0x108)==0x000) //S4和S9的组合按键被按下
  {
   if(ucKeyLock_04_09==0)
   {
    uiKeyTimeCnt_04_09++;
    if(uiKeyTimeCnt_04_09>const_key_time_comb)
    {
     uiKeyTimeCnt_04_09=0;
     ucKeyLock_04_09=1;
     ucKeySec=14; //触发14号组合按键
    }
   }
  }
  
  else
  {
   uiKeyTimeCnt_04_09=0;
   ucKeyLock_04_09=0;
  }
  
  
  uiKeyStatus=0xfff; //及时恢复状态,方便下一次扫描
  ucKeyStep=1; //返回第一步
  break;
 }
}

void key_service() //第三区,按键服务应用程序
{
 switch(ucKeySec)
 {
  case 1:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  
  case 2:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 3:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 4:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 5:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 6:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 7:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 8:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 9:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 10:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  
  case 11:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 12:
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 13:
   led_dr=0; //LED亮
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;
  case 14:
   led_dr=1; //LED灭
   uiVoiceCnt=const_voice_short;
   ucKeySec=0;
   break;   
  
 }
}
void T0_time() interrupt 1
{
 TF0=0;
 TR0=0;
 
 key_scan();
 
 if(uiVoiceCnt!=0)
 {
  uiVoiceCnt--;
  beep_dr=0;
 }
 else
 {
  ;
  beep_dr=1;
 }
 
 TH0=0xf8;
 TL0=0x2f;
 TR0=1;
}
void delay_long(unsigned int uiDelayLong)
{
 unsigned int i;
 unsigned int j;
 for(i=0;i<uiDelayLong;i++)
  for(j=0;j<500;j++)
   ;
}
void initial_myself()
{
 beep_dr=1;
 TMOD=0x01;
 TH0=0xf8;
 TL0=0x2f;
}
void initial_peripheral()
{
 EA=1;
 ET0=1;
 TR0=1;
}
posted @ 2019-12-07 22:40  烟火流沙  阅读(1073)  评论(0编辑  收藏  举报