矩阵键盘

矩阵键盘的扫描原理和protues仿真(附代码)

先附上protues仿真的原理图
矩阵键盘_第1张图片
首先要明白矩阵键盘的原理,由原理图可以看出矩阵键盘的值是要让端口赋值的,它不像独立键盘。独立键盘是有接地的。

那我们要怎么确认是哪一个按键按下呢?

很简单,只要确定按下的是哪一行哪一列就可以知道是哪个按键按下了,这个就是矩阵键盘最基本的原理。(形象一点的话可以画四条横线,然后在四条横线上画四条竖线,两线交叉的地方为一个点这样就是4×4十六个点)

我看的是郭天祥的书,在矩阵键盘这里,书上的方法很简单易懂,但是过于繁琐,我想把它简化一下。

首先要挖掘一下书上代码有哪些地方是有规律可以整合的,我发现主要的思路是这样的:
1.P3=0xfe(选中了第一行)
2.temp=P3&0xf0(temp取P3的列)
3.判断第一行是否有按键按下if(temp!=0xf0)(这里解释一下:因为第一行已经被选中置0了,只要我们按下第一行中的任一按键,4列就一定会有一行置0)
4.等待按键释放
5.P3=0xfd…重复上面的操作

总结一下:
定义一个行变量i,列变量j,一开始i=j=0,整体思路就是先选中第一行,判断第一行有没有按下的,有——直接送出4*i+j(此时i=0,是第一列j=0,第二列j=1,以此类推)选中是哪个数字;没有——i++,然后p3选中第二行判断第二行有没有按下,重复上面的操作。

举个栗子:

我按下了第三行第三列的按键。
首先选中第一行开始扫描,发现我的列没有变化,说明不在第一行,i++到第二行,选中第二行发现列还是没变化,说明不在第二行,i++到第三行,选中第三行判断列是否有变化,这次有变化了,因为我按的是第三行三列,当选中第三行的时候,第三行为0按下第三列按键,第三列也被置为0,检测出变化之后j锁定为2,此时4×2+2=10,选中数组表中第十个元素,输出到数码管中显示A(为什么是A呢因为我是按照最左上角的那个按键是0,往右是1、2…,所以地三行三列是10,也就是A)

下面贴上我的代码:

矩阵键盘代码:
/*****************************************
4.4
代码功能:
一个4×4的的矩阵式键盘,以P3.0~P3.3作
为行线,以P3.4~P3.7作为列线,在数码管上显示
每个按键相应的键值"0~F"

实体机接线:
P3端口(J29)接矩阵按键(JP3)
P0端口(J22)接单个数码管(J8)
********************************************/
#include 
#define uchar unsigned char
#define uint unsigned int
#include			//包含_crol_函数所在的头文件
uchar code table[]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 
                      0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};//0-F数字
void matrixkeyscan()
{
	uchar code table1[4][4] = {0xee, 0xde, 0xbe, 0x7e, 0xed, 0xdd, 0xbd, 0x7d,
          0xeb, 0xdb, 0xbb, 0x7b, 0xe7, 0xd7, 0xb7, 0x77};//用2维数组,表示位置
    uchar temp1=0xfe,temp2,i,j;
    for(i = 0; i < 4; i++) //扫描低四位,即扫描行
    {          
        P3=temp1;                     //输出一行0
        temp2=P3;                     //马上就读入按下的状态
        if((temp2 & 0xf0) != 0xf0)     //判断按键是否按下
        {
            for(j=0;j<4;j++)        //扫描高四位
                if(temp2==table1[i][j])    //查表,找到是哪个位置
				P0=table[(4*i+j)];        //查到了就返回按键的数值
        }
        else temp1 = _crol_(temp1, 1); //用循环左移来改变选中哪一行
    }     
}                        
void main()
{
	P0=0xff;  //数码管消影
	while(1)
	{
		matrixkeyscan();
	}	
}

还另外看到几种方法,分享学习一下

行反转法的基本概念是:
行列线的交叉位置布置按键。所有行和列加上拉电阻。
所有行作输出先送低电平,然后读入列值。 如果有任意键按下,那么一定对应列值有0出现,也就知道了按下的键所在列。
反过来驱动这一列为0,其他列为1。把行作输入。就可以判断按下的键所在行。

uchar keyscan()                    
{
    uchar i=0,j=0,key;
    P3=0xf0;               // 高位拉高,低位拉低
    if(((~P3)&0xf0)!=0)
    {
        delay(10);
        if(((~P3)&0xf0)!=0)
        {
            P3=0xfe;
            while(((~P3)&0x0f)!=0)        // 此语句保证只扫描四行
            {
                if(((~P3)&0xf0)!=0)
                {
                    switch((~P3)&0xf0)
                    {
                        case 0x10:
                            j=0;break;
                        case 0x20:
                            j=1;break;
                        case 0x40:
                            j=2;break;
                        case 0x80:
                            j=3;break;
                    }
                    return(4*i+j); 
                }
                else 
                {
                    P3=P3<<1;           //循环4次
                    i++;
                }
            }
        }
    }
    return (key) ;   
}  
/************************************************************** 
* 名称:KeyRvs() 
* 功能:P1外接4×4按键, 按照反转法读出键值
* 输出:按键值0~15/如无键按下, 返回16
*按键的键值分布图:
    0   1   2   3
    4   5   6   7   
    8   9   10  11
    12  13  14  15
***************************************************************/ 
uchar keyscan(void)    
{
    uchar temH, temL;
    uchar key_value;
    P3 = 0xf0;
    if(P3 != 0xf0)
    {
        delay(5);       //消抖
        if(P3 != 0xf0)  //的确是有按键被按下
        {
                P3 = 0xf0; temH = P3;   //低四位先输出0;读入,高四位含有按键信息
                P3 = 0x0f; temL = P3;   //然后反转输出0;读入,低四位含有按键信息
                switch(temH) {
                    case 0xe0: key_value = 0; break;
                    case 0xd0: key_value = 1; break;
                    case 0xb0: key_value = 2; break;
                    case 0x70: key_value = 3; break;
                    
                    default: return 16;//按下的不是上述按键,就当是没有按键
                }

                switch(temL) 
                {
                    case 0x0e: return key_value;
                    case 0x0d: return key_value + 4;
                    case 0x0b: return key_value + 8;
                    case 0x07: return key_value + 12;
                    
                    default: return 16;//按下的不是上述按键,就当是没有按键
                }
        }
    }
}//本程序虽然稍多几行,但是没有循环,还可以提前返回,所以执行的速度最快

你可能感兴趣的:(单片机)