单片机 矩阵式按键

单片机  矩阵式按键

一、简述

        在单片机应用系统中,通过按键实现数据输入及功能控制是非常普遍的,通常在所需按键数量不多时,系统常采用独立式按键。需要按键数量比较多,为了减少I/O口的占用,通常将按键排列成矩阵。

工程文件等:链接: https://pan.baidu.com/s/1kCf8jGU26GR_Nv1P7xxngQ 密码: 8ax7

二、效果


三、工程结构

1、Keil工程


2、仿真电路


三、编程思路

    

    没有按键按下时,X0~X3是低电平,Y0~Y3是高电平。

    某一个按键按下,其所在的行是高电平,列是低电平。

1、判断有无键被按下

    方法是:将全部行线X0~X3置低电平,然后检测列线的状态。只要有一列的电平为低,则表示键盘中有键被按下,而且闭合的键位于低电平线与4根行线相交叉的4个按键之中。若所有列线均为高电平,则键盘中无键按下。

2、确定哪个键按下

    方法是:在确认有键按下后,依次将行线置为低电平,即在置某根行线为低电平时,其他线为高电平(其实就是屏蔽其他行的按键状态,只有当前检测行的按键状态有效);在确定某根行线位置为低电平后,再逐行检测各列线的电平状态,若某列为低(说明当前检测行有按键按下),则该列线与置为低电平的行线交叉处的按钮就是闭合的按键。

四、代码

key.c文件

#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
	uint key,key_num;//键盘扫描值,键盘键值
/********************************************************************/
//函数名:delay_1ms(uint x)
//功能:利用定时器0精确定时1ms; 自加 time_t的值为后面时间调整函数服务
//调用函数:
//输入参数:x,1ms计数
//输出参数:
//说明:延时的时间为1ms乘以x
/********************************************************************/
void delay_1ms(uint x)
{
	TMOD=0X01;//开定时器0,工作方式为1
	TR0=1;//启动定时器0;
	while(x--)
	{
		TH0=0Xfc;//定时1ms初值的高8位装入TH0
		TL0=0X18;//定时1ms初值的低8位装入TL0
		while(!TF0);//等待,直到TF0为1
		TF0=0;
	}		
	TR0=0;//停止定时器0;
}

/**********************************************************/
//函数名:keyscan()
//功能:得出4x4键盘的行列扫描值
//调用函数:delay_1ms(uint x)
//输入参数:
//输出参数:
//说明:通过P1口的扫描得出扫描值key,无键按下key为16
/**********************************************************/
uchar keyscan()
{
 	uchar code_h;		//行扫描值
	uchar code_l;		//列扫描值
	P1=0XF0;			 //P1.0-P1.3全为0,(行状态全为低电平)
	if((P1&0xF0)!=0XF0)	//如果P1.4-P1.7不全为1,可能有键按下(为准确识别按键动作)
	{
	    delay_1ms(5);	//廷时去抖动,为准确识别按键动作
	    if((P1&0xF0)!=0XF0)//重读高4位(列状态),若还是不全为1,定有键按下
            {			
	        code_h=0xfe;  //开始行扫描 (0xfe:11111110)
	        while((code_h&0x10)!=0x00)//判断是否扫描四行(X0~X3)完毕,若不是,继续扫描(0x10:00010000)	 
               {
	           P1=code_h;	//P1.0置为0,其余高电平	
	           if((P1&0xF0)!=0XF0) //如果P1.4-P1.7不全为1,该行有键按下(0xF0:11110000)
                   {
		       		code_l=(P1&0xF0|0x0F);//保留P1口高4位,低4位变为1,作为列值
		       		return((~code_h)+(~code_l));//键盘编码=行扫描值+列扫描值 (取反后用)				 
	           }
	           else                           //左移后补0,但是我们需要将其他位置1,所以+1
		       		code_h=(code_h<<1)|0x01;  //若该行无键按下,行扫描值左移+1,扫描下一行 
	         }
	     }
	 }
	return(16);	 //无键按下,返回0 
 }

/**********************************************************/
//函数名:keynum()
//功能:得出4x4按键的键值
//调用函数:keyscan()
//输入参数:
//输出参数:
//说明:通过key的值确定按键键值
/**********************************************************/
void keynum()
{
    uchar i,j;
    uchar code tab[4][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}}; 
    //4x4键盘各键值标注
    key=16;
    key = keyscan();//引入key值
    if((key&0x01)!=0) i=0;	//判断出按下按键的行列号 (即找出低电平的行、列)
    if((key&0x02)!=0) i=1;
    if((key&0x04)!=0) i=2;
    if((key&0x08)!=0) i=3;
    if((key&0x10)!=0) j=0;
    if((key&0x20)!=0) j=1;
    if((key&0x40)!=0) j=2;
    if((key&0x80)!=0) j=3;
    if(key!=16) 
    {
   		key_num = tab[i][j];//通过比较得出4x4键盘的键值
    }   
}

void main()
{
	uint shi,ge;
	shi = 0;
	ge = 0;
	P2 = 0x16;//初始值 为16
	while(1)
	{
		 keynum(); //获取到键值
		 if(key!=16)
		 {
		 	 shi = key_num/10;//获得十位	 
			 ge = key_num%10;//获得个位
			 if(shi)
			 {
			 	P2 = 0x10|ge;
			 }
			 else
			 {
			    P2 = ge;
			 }
		 }
		 delay_1ms(10);//延时
	}
}

五、总结

      方式二:无按键按下时,4行均为低电平,4列电平均为高电平;按键按下时,按键所在行为高电平,所在列为低电平。

    (此方式没有处理同时按下多个按键的问题)


key2.c文件

#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
	uint key,key_num;//键盘扫描值,键盘键值
/********************************************************************/
//函数名:delay_1ms(uint x)
//功能:利用定时器0精确定时1ms; 自加 time_t的值为后面时间调整函数服务
//调用函数:
//输入参数:x,1ms计数
//输出参数:
//说明:延时的时间为1ms乘以x
/********************************************************************/
void delay_1ms(uint x)
{
	TMOD=0X01;//开定时器0,工作方式为1
	TR0=1;//启动定时器0;
	while(x--)
	{
		TH0=0Xfc;//定时1ms初值的高8位装入TH0
		TL0=0X18;//定时1ms初值的低8位装入TL0
		while(!TF0);//等待,直到TF0为1
		TF0=0;
	}		
	TR0=0;//停止定时器0;
}

/**********************************************************/
//函数名:keyscan()
//功能:得出4x4键盘的行列扫描值
//调用函数:delay_1ms(uint x)
//输入参数:
//输出参数:
//说明:通过P1口的扫描得出扫描值key,无键按下key为16
/**********************************************************/
uchar keyscan()
{
	P1=0XF0;			 //P1.0-P1.3全为0,(行状态全为低电平)
	if((P1&0xF0)!=0XF0)	//如果P1.4-P1.7不全为1,可能有键按下(为准确识别按键动作)
	{
	    delay_1ms(5);	//廷时去抖动,为准确识别按键动作
	    if((P1&0xF0)!=0XF0)//重读高4位(列状态),若还是不全为1,定有键按下
        {	
       		return(~P1);//键盘编码 (取反后用)
	    }
	}
	return(16);	 //无键按下,返回0 
 }

/**********************************************************/
//函数名:keynum()
//功能:得出4x4按键的键值
//调用函数:keyscan()
//输入参数:
//输出参数:
//说明:通过key的值确定按键键值
/**********************************************************/
void keynum()
{
    uchar i,j;
    uchar code tab[4][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11},{12,13,14,15}}; 
    //4x4键盘各键值标注
    key=16;
    key = keyscan();//引入key值
    if((key&0x01)!=0) i=0;	//判断出按下按键的行列号 (即找出低电平的行、列)
    if((key&0x02)!=0) i=1;
    if((key&0x04)!=0) i=2;
    if((key&0x08)!=0) i=3;
    if((key&0x10)!=0) j=0;
    if((key&0x20)!=0) j=1;
    if((key&0x40)!=0) j=2;
    if((key&0x80)!=0) j=3;
    if(key!=16) 
    {
   		key_num = tab[i][j];//通过比较得出4x4键盘的键值
    }   
}

void main()
{
	uint shi,ge;
	shi = 0;
	ge = 0;
	P2 = 0x16;//初始值 为16
	while(1)
	{
		 keynum(); //获取到键值
		 if(key!=16)
		 {
		 	 shi = key_num/10;//获得十位	 
			 ge = key_num%10;//获得个位
			 if(shi)
			 {
			 	P2 = 0x10|ge;
			 }
			 else
			 {
			    P2 = ge;
			 }
		 }
		 delay_1ms(10);//延时
	}
}

猜你喜欢

转载自blog.csdn.net/nanfeibuyi/article/details/80469909