单片机按键灵活应用---矩阵式按键以及防抖方案-----day7

单片机按键灵活应用—矩阵式按键-----day7

电路原理图如下所示:
在这里插入图片描述
在这里插入图片描述
程序设计:
1.矩阵按键如果单独选取一行效果等同于day6中的独立式按键。
使端口P2.4为低则代码如下:P2.0-P2.3为按键使能引脚。

void main()
{
	unsigned char keydata;
    P0=0xFF;                    //置P0口
    P1=0xFF;                    //置P1口  
    delay(10);                  //延时
	ConfigTimer0(1);
	EA = 1;
	P2_4 = 0;
    while(1)
    { 
	      if((P2&0X0f) == 0X0e)
		  {
		      Dis[0] = ucDataOneTab[1];//显示1
		  }   
		  else if((P2&0X0f) == 0X0d)  
		  {
		  	  Dis[0] = ucDataOneTab[2];
		  }  
		  else if((P2&0X0f) == 0X0b)  
		  {
		  	  Dis[0] = ucDataOneTab[3];
		  }    
		  else if((P2&0X0f) == 0X07)  
		  {
		  	  Dis[0] = ucDataOneTab[4];
		  }  
    }
}   

1.逐行扫描法

在这里插入图片描述
扫描步骤如下:
在这里插入图片描述
在这里插入图片描述
上图中说明第四行有按键按下,读取f的值即可。
看程序中的注释吧,写的很清晰了。嘎嘎。

void Delay( uint tt )
{
    while( tt-- );
}

void ConfigTimer0(unsigned int ms)
{
    unsigned long tmp;//临时变量
    
    tmp = 11059200 / 12;      //定时器计数频率
    tmp = (tmp * ms) / 1000;  //计算所需的计数值
    tmp = 65536 - tmp;        //计算定时器重载值
    tmp = tmp + 18;           //补偿中断响应延时造成的误差
    T0RH = (unsigned char)(tmp>>8);  //定时器重载值拆分为高低字节
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0;   //清零T0的控制位
    TMOD |= 0x01;   //配置T0为模式1
    TH0 = T0RH;     //加载T0重载值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
}
//逐行扫描法
unsigned char Key_Scan(void)
{
   uchar Key_Temp,Scan_Code,Temp_Code;
   P2 = 0XF0;
   Key_Temp = P2;		 //取回P2端口的值
   if((Key_Temp&0xf0)^0xf0)	    //0XE0 0b1110 0000 & 0b1111 0000  --0b1110 0000	^0b1111 0000= 0b0001 0000  判断高4位是否有按键按下
   {			//高4位不全是1则说明有按键按下
       Scan_Code = 0xfe;  //0B1111 1110  	  开启第一行扫描  按流程图来
	   while((Scan_Code&0x10) != 0x00) //0XFE = 0B1111 1110  0B1111 0111  //分行查询当前行是否有按键按下。循环判断四次
	   {
	        P2 = Scan_Code;
			if((P2&0XF0)^0XF0)	  //如果成立则说明有按键按下,高四位有0
			{
			     Temp_Code = (P2&0XF0)|0X0F;//1110 0111	&0x f0 = 0b1110 0000 |0x0f = 0b1110 1111 ~0b0001 0000  //取回P2口的值
				 return((~Temp_Code)+(~Scan_Code));	// 0b0001 0000+0000 0001  =0x11	// 取1列1行值
			}	
			else
			{
			    Scan_Code = (Scan_Code<<1)|0X01;// 0b1111 1110 <<1 = 1111 1100 | 0000 0001 = 1111 1101 	移动4次后退出循环
			}
			
		   	Delay(10);	
			  
	   }     
   }

   return(0);
}

//
void main()
{
	unsigned char keydata;
    P0=0xFF;                    //置P0口
    P1=0xFF;                    //置P1口  
    delay(10);                  //延时
	ConfigTimer0(1);
	EA = 1;

	P2_4 = 0;

    while(1)
    { 
	     keydata = Key_Scan(); 
		 if(keydata != 0)
		 {
		     switch(keydata)
			 {
			      case 0x11:keyvalue = 0;break; //第一行第一列
				  case 0x21:keyvalue = 1;break;//第一行第二列
				  case 0x41:keyvalue = 2;break;//第一行第三列
				  case 0x81:keyvalue = 3;break;//第一行第四列

				  case 0x12:keyvalue = 4;break;//第二行第一列
				  case 0x22:keyvalue = 5;break;//第二行第二列
				  case 0x42:keyvalue = 6;break;//第二行第三列
				  case 0x82:keyvalue = 7;break;//第二行第四列

				  case 0x14:keyvalue = 8;break;//第三行第一列
				  case 0x24:keyvalue = 9;break;//第三行第二列
				  case 0x44:keyvalue = 10;break;//第三行第三列
				  case 0x84:keyvalue = 11;break;//第三行第四列

				  case 0x18:keyvalue = 12;break;//第四行第一列
				  case 0x28:keyvalue = 13;break;//第四行第二列
				  case 0x48:keyvalue = 14;break;//第四行第三列
				  case 0x88:keyvalue = 15;break;//第四行第四列
			 }   
		 }	 
		 keydata = 0;
		 Dis[0] = ucDataOneTab[keyvalue%16]; 
    }
}   
void InterruptTimer0() interrupt 1
{
    static unsigned char i;  
     
    TH0 = T0RH;  //重新加载重载值
    TL0 = T0RL;
	
	SendData(Dis[i], ucDataTwoTab[i]);
	if(i<7)
	{
	   i++;
	}
	else 
	{
	   i = 0;
	}
}

2.线翻转法
必须要有上拉电阻:

硬件原理如下:
在这里插入图片描述
通过程序将低4位送0高四位送1 1111 0000 ---->1101 0000
记录第一次为低电平的行位置,然后通过程序将低四位送高电平,高四位送低电平
0000 1111 ------> 0000 0111
设计思路如下:
通过行与列定位当期按键的键值:
第一行
key-1 (列值-1) 1-1=0 2-1=1 3-1 =2 4-1 =3
第二行(列值+3)
key+3 1+3 =4 2+3 =5 3+3 =6 4+3=7
第三行(列值+7)
key+7 1+7=8 2+7=9 3+7=10 4+7 =11
第四行(列值+11)
key+11 1+11=12 2+11=13 3+11=14 4+11=15

代码如下:

void  delay(uchar x)
{
    uchar j;
    while((x--)!=0)          //CPU执行x*12次
    { 
	   for(j=0;j<125;j++)
       {
		 ;
	   }
    }
}
void ConfigTimer0(unsigned int ms)
{
    unsigned long tmp;             //临时变量
    
    tmp = 11059200 / 12;           //定时器计数频率
    tmp = (tmp * ms) / 1000;       //计算所需的计数值
    tmp = 65536 - tmp;             //计算定时器重载值
    tmp = tmp + 18;                //补偿中断响应延时造成的误差
    T0RH = (unsigned char)(tmp>>8);//定时器重载值拆分为高低字节
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0;                  //清零T0的控制位
    TMOD |= 0x01;                  //配置T0为模式1
    TH0 = T0RH;     //加载T0重载值
    TL0 = T0RL;
    ET0 = 1;        //使能T0中断
    TR0 = 1;        //启动T0
}
void InterruptTimer0() interrupt 1
{
     
    TH0 = T0RH;    //重新加载重载值
    TL0 = T0RL;
	
	SendData(Dis[i], ucDataTwoTab[i]);
	if(i<7)
	{
	   i++;
	}
	else 
	{
	   i = 0;
	}
}

void Key_Scan()
{
   	temp = 0;
    P2=0xF0;                 
	temp=P2;                 
    temp=temp;	         
    temp = ~((temp>>4)|0xF0);	  
    if(temp==1)	
	{            
       key=1;
	}                
    else if(temp==2)   
	{      
       key=2;
	}	             
    else if(temp==4)  
	{       
       key=3;
	}	             
    else if(temp==8)  
	{      
       key=4;
	}	             
	else
	{
	   key = 16;
	}
        
    P2=0x0F;                 
	temp=P2;                    
    temp=temp&0x0F;
    temp=~(temp|0xF0);

	if(temp == 1)	        
	{
        key = key - 1;
	}
    else if(temp == 2)	     
	{
        key = key + 3; 
 	}
    else if(temp == 4)       
	{
        key = key + 7;
	}
    else if(temp == 8)       
	{
        key = key + 11;
	}
	else
	{
	  key = 16;
	}
    	
    dis_buf = key;	         //键值入显示缓存
    dis_buf = dis_buf&0x0f;
}


void Key_Down()
{
   P2 = 0XF0;
   if(P2 != 0xf0)
   {
          delay(50);		//消抖  50ms是比较稳定的
		  if(P2 != 0xf0)	//防止出现键值不稳定的现象。
		  {
//		      if(dis_buf < 10)
//			  {
//			     dis_buf++;
//			  } 
//			  else
//			  {
//			     dis_buf = 0;
//			  }
		    
		        Key_Scan();      
		  }   
   }
}
void main()
{
    P0=0xFF;                    //置P0口
    P1=0xFF;                    //置P1口  
    delay(10);                  //延时
	ConfigTimer0(1);
	EA = 1;
    
    while(1)
    { 		  
	 	   Key_Down();
		   Dis[0] = ucDataOneTab[dis_buf%16];
    }
}   

按键去抖:
硬件去抖:

软件去抖:
检测出键闭合后执行一个延时程序, 产生5ms~10ms的延时, 让前沿抖动消失后再一次检测键的状态, 如果仍保持闭合状态电平, 则确认为真正有键按下。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从小白到大师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值