计算机三级嵌入式系统考试之矩阵键盘

今天开始刷题的时候,发现总是出现这个矩阵键盘的问题,然后我也没有耐下心来仔细看,随便抄了答案,但是总感觉不爽,不说把它搞得多透彻吧,但是最起码要知道咋算,于是在网上查找了相关资料,稍微理解了一点,所以我在这把我理解的稍微总结一下,可能里面会有理解有误的地方,欢迎各位大佬指出来
参考网址:
https://wenku.baidu.com/view/3f517aa6561252d381eb6e80.html

先贴上按键原理图
这里写图片描述

然后再把题库中的源代码贴出来,里面的空我都已经填上去了,我们主要是看一下整个代码的大概意思以及相关计算

//KEYOUTPUT是键盘扫描时的输出地址,KEYINPUT是键盘读入时的地址
#define KEYOUTPUT(*(volatile INT8U *)0x56000044)
#define KEYINPUT(*(volatile INT8U *)0x56000044)
INT16U ScanKey()
{
  INT16U key=0xFFFF;
  INT16U i;
  INT8U temp=0xFF,output;
  //rGPECON是端口E的控制寄存器
  rGPECON=((rGPECON & 0xFFFFFF00) | 0x00000055);//初始化GPE0~GPE3为输出
  rGPECON=rGPECON & 0xFFFF00FF;//初始化GPE4~GPE7为输入
  //下面判断键盘中是否有键按下
  for(i=1;((i<=8)&&(i>0));i<<=1)
  {
    output|=0xFF;
    output&=(~i);
    KEYOUTPUT=output;
    temp=KEYINPUT;
    if((temp&=0xF0)!=0xF0)//判断列信号是否全为1
    {
      key=(~i);
      key<<=8;
      key|=((temp&0xF0)|0x0F);//求得按键的返回值
      return (key);
    }
  }
  return 0xFFFF;
}

然后我们一点一点的来看整个代码

//KEYOUTPUT是键盘扫描时的输出地址,KEYINPUT是键盘读入时的地址
#define KEYOUTPUT(*(volatile INT8U *)0x56000044)
#define KEYINPUT(*(volatile INT8U *)0x56000044)

开头这两句就是定义了两个宏定义,用KEYOUTPUT代替了行扫描输出信号的相关IO口,用KEYINPUT来代替了列扫描的读入信号的相关IO口,就相当于我们用LED0来代替一个IO口时一样的,所以这里不做过多说明

INT16U key=0xFFFF;
INT16U i;
INT8U temp=0xFF,output;

这三句话就是定义了一些相关的变量以及给部分变量赋予了初值,我们需要注意的就是各个变量是8位的还是16位的,其中key和i是16位的,而temp和output是8位的

 //rGPECON是端口E的控制寄存器
  rGPECON=((rGPECON & 0xFFFFFF00) | 0x00000055);//初始化GPE0~GPE3为输出
  rGPECON=rGPECON & 0xFFFF00FF;//初始化GPE4~GPE7为输入

这两行代码就是配置与按键相关的IO口,其中GPE0~GPE3是作为行扫描信号的,我们需要让这四个IO口循环的输出低电平,所以我们要把GPE0~GPE3初始化为输出模式,而GPE4~GPE7是作为列扫描的读入信号,如果有按键按下,相对应列所对应的IO口就会被输入低电平(对照着上面那个原理图来说,假如现在按下了确认键,那么GPE7这个IO口就会被输入低电平),我们需要不断地循环读取GPE4~GPE7这四个IO口的电平状态,从而判断是哪一列有按键按下,然后后面再得到当检测到有按键按下那一时刻的 i 的值,就可以知道是哪一行的按键按下了,从而我们就知道具体是哪一行哪一列的按键被按下了

for(i=1;((i<=8)&&(i>0));i<<=1)

这是一个for循环,首先我们注意下for循环的循环条件,它让i从1开始循环,然后一直循环到i=8,关键的问题就是在于i的自增条件,它不是我们常用的i++或者i–,它是i<<=1,也就是说,每循环一次,i 就要左移一次,它的变化过程就是0001、0010、0100、1000,当 i 变化到1000的时候,它已经变成8了,此时这个for循环循环了4次,再往后面我们就会发现,其实这个循环4次就是让GPE0~GPE3这四个IO口循环输出低电平

output|=0xFF;
output&=(~i);
KEYOUTPUT=output;

这是for循环里面的前3条语句,首先第一条output|=0xFF;,其实就是对output的初始化,然后第二条output&=(~i);,这条语句的意思就是先让 i 取反,然后再让output与取反后的 i 进行相与,相与的结果再赋给output,然后第三条KEYOUTPUT=output;,这条语句的意思就是把output的值给KEYOUTPUT,也就是把output的值给了行扫描信号对应的IO口了。如果这三条语句是第一次循环,那么这三条语句执行完之后,i=0x0001,output的值就是0xFE(注意,i 是16位数据,而output是8位数据,当8位数据与16位数据相与时,结果只能保留8位数据),把output的值化成二进制表示就是1111 1110,其实这个output就对应着上面那个原理图中的GPE7~GPE0,(我们只需要重点关注output的值就行,至于KEYOUTPUT的值,它只不过是就是把output给复制走了,output起到了中间桥梁的作用)即这个时候是就对应着是让GPE0为0,我们先不管后续的程序,假如现在进入到了第二次循环,那么对应的 i 就应该左移一位,即 i=0x0002,此时经过 output&=(~i);语句之后,output=0xFD,化为二进制表示就是1111 1101,即这个时候就对应着GPE1为0,继续往下循环下去,我们通过 i 的左移和相与的操作,就实现了矩阵按键的行扫描,即让四个行扫描信号循环的为低电平。
我们接着往下看源程序

temp=KEYINPUT;
if((temp&=0xF0)!=0xF0)//判断列信号是否全为1
 {
    key=(~i);
    key<<=8;
    key|=((temp&0xF0)|0x0F);//求得按键的返回值
    return (key);
 }

这段代码的作用就是判断有没有按键按下去,同时如果有按键按下去,则返回相应的码值
首先temp=KEYINPUT; ,就是把对应的IO口的值给读到变量temp上,以便用于后期的操作。

if(`(temp&=0xF0)!=0xF0`)//判断列信号是否全为1

这个if语句就是先让temp与上0xF0,即把temp的低四位给屏蔽掉,我们只关注高四位,因为高四位就分别对应着GPE7~GPE4。然后我们又有一个判断(temp&=0xF0)!=0xF0,这个就是用来判断temp的高四位是不是全部都为高电平,如果是,则代表着哪一列都没有按键按下去,如果temp的高四位有一个是低电平,那么就表示着低电平所对应的列有按键按下去,然后就进入到if语句里面进行处理。
首先就是key=(~i);,即把 i 取反,然后送给变量key,然后下一句key<<=8;,这条语句就是让key左移8位,假如key是0xFFFE,左移8位就相当于十六进制的左移2位,即左移8位后,key=0xFE00。然后下一句key|=((temp&0xF0)|0x0F);,这条语句的作用就是求得按键的返回值,假如现在temp=0x7*(此时我们先只看temp的高四位,低四位的值在这里意义不大,我用 * 号代替),然后temp与上0xF0后,temp=0x70,然后再和0x0F相或,结果是temp=0x7F,然后原来key的值再与此时的temp相或,相或的结果再赋给key,则计算完之后,key=0xFE7F,到这里,这个ScanKey()函数就说完了。(因为我们刚才假设的key=0xFFFE,temp=0x7*,也就是说这个时候是第一行、第四列的按键被按下,也就是我们上面原理图中的确认键被按下了,即如果我们得到这个ScanKey函数的返回值是0xFE7F的话,我们就可以知道,此时是确认键被按下了)
以上就是我们矩阵按键的工作原理,我说的也比较多,可能也比较乱,希望大家可以仔细地揣摩一下其中的原理,其实它也没那么复杂,只要一步步推导就可以了。其中关键点就是 i 的左移,它每左移一次,就代表着对应的行扫描信号就要是低电平,然后我们就去读取所有的列扫描信号,如果所有的列都是高电平,就代表着没有按键按下去,如果有一列是低电平,那么就是那一列有按键按下了。

矩阵按键扫描整体思路:
矩阵按键分为四行四列,起初初始化的时候所有的行和列所对应的引脚都是高电平,然后我们让那四行中的各行循环为低电平,假如说现在我们让第一行为低电平,其余三行还是高电平,然后我们就开始去读取那四列的信号状态,如果四列全为高电平,就代表没有按键按下,如果我们发现第2列对应的引脚是低电平的时候,那么就代表着第二列的四个按键中肯定有一个按键被按下,而我们现在是让第一行为低电平,那也就是说第一行、第二列的按键被按下了,然后我们再进行一些相关的数据运算,最终通过函数返回一个数值就完成了按键的扫描,每一个按键都对应着不一样的返回值,(如果没有按键按下,则返回值为0xFFFF)由此我们就可以通过返回值来判断是哪一个按键被按下了。

参考网址:
https://wenku.baidu.com/view/3f517aa6561252d381eb6e80.html

猜你喜欢

转载自blog.csdn.net/qq_36554582/article/details/81328093