一、概述
1、矩阵键盘的作用
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态。
2、两种扫描
(1)数码管扫描(输出扫描)
原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果。
(2)矩阵键盘扫描(输入扫描)
原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果。
二、开发板上的矩阵按键模块
1、矩阵按键的组成
矩阵按键模块中有16个按键,它们按照4×4的方式排列,与它们相对接的是P1寄存器的8个位,其中0-3位对应矩阵按键模块的每一列,4-7位对应矩阵按键的每一行。
2、矩阵键盘的扫描方式
(1)按行扫描:为了找到被按下的按键,可以选择按行扫描的方式,首先将P1的4-7位轮流配置为低电平(其它三位置为高电平),如果从第一行开始扫描,那么就先将P17配置为低电平,P16、P15、P14配置为高电平,然后检测P1的0-3位,其中哪一位是低电平,那么该位对应列的第一行那个按键就是处于被按下的状态,以此类推。
(2)按列扫描:为了找到被按下的按键,可以选择按列扫描的方式,首先将P1的0-3位轮流配置为低电平(其它三位置为高电平),如果从第一列开始扫描,那么就先将P13配置为低电平,P12、P11、P10配置为高电平,然后检测P1的4-7位,其中哪一位是低电平,那么该位对应行的第一列那个按键就是处于被按下的状态,以此类推。(建议采用按列扫描,若使用按行扫描,P15的电平会忽高忽低,而P15可能还会影响蜂鸣器,从而造成异常现象,这个具体看开发板的原理图,有些板子已经将这个引脚冲突改善,不会有此异常现象)
三、矩阵键盘应用实验
1、在液晶屏上显示被按下的矩阵按键序号实验
(1)项目包含的文件:其中Delay.c、Delay.h、LCD1602.c及LCD1602.h全部沿用上一例的代码,这里不再给出,INTRINS.H及REGX52.H在系统include目录中,不需要自己编写。
(2)将源文件及头文件添加到项目中,然后进行编译。
①MatrixKey.c文件:
#include <REGX52.H>
#include "Delay.h"
/**
* @brief 矩阵键盘读取按键键码
* @param 无
* @retval KeyNumber 按下按键的键码值
如果按键按下不放,程序会停留在该函数中,松手后才会返回键码值
没有按键按下,函数返回0
*/
unsigned char MatrixKey()
{
unsigned char KeyNumber = 0; //用该变量记录被按下的按键
P1 = 0xFF; //按列扫描,首先扫描第一列
P1_3 = 0; //P1_3对应第一列,置为低电平,其它三位置为高电平
if(P1_7 == 0)
{
Delay(20); //按键消抖
while(P1_7 == 0);
Delay(20);
KeyNumber = 1; //第一列第一行
}
if(P1_6 == 0)
{
Delay(20); //按键消抖
while(P1_6 == 0);
Delay(20);
KeyNumber = 5; //第一列第二行
}
if(P1_5 == 0)
{
Delay(20); //按键消抖
while(P1_5 == 0);
Delay(20);
KeyNumber = 9; //第一列第三行
}
if(P1_4 == 0)
{
Delay(20); //按键消抖
while(P1_4 == 0);
Delay(20);
KeyNumber = 13; //第一列第四行
}
P1 = 0xFF; //接着扫描第二列
P1_2 = 0; //P1_2对应第二列,置为低电平,其它三位置为高电平
if(P1_7 == 0)
{
Delay(20); //按键消抖
while(P1_7 == 0);
Delay(20);
KeyNumber = 2; //第二列第一行
}
if(P1_6 == 0)
{
Delay(20); //按键消抖
while(P1_6 == 0);
Delay(20);
KeyNumber = 6; //第二列第二行
}
if(P1_5 == 0)
{
Delay(20); //按键消抖
while(P1_5 == 0);
Delay(20);
KeyNumber = 10; //第二列第三行
}
if(P1_4 == 0)
{
Delay(20); //按键消抖
while(P1_4 == 0);
Delay(20);
KeyNumber = 14; //第二列第四行
}
P1 = 0xFF; //接着扫描第三列
P1_1 = 0; //P1_1对应第三列,置为低电平,其它三位置为高电平
if(P1_7 == 0)
{
Delay(20); //按键消抖
while(P1_7 == 0);
Delay(20);
KeyNumber = 3; //第三列第一行
}
if(P1_6 == 0)
{
Delay(20); //按键消抖
while(P1_6 == 0);
Delay(20);
KeyNumber = 7; //第三列第二行
}
if(P1_5 == 0)
{
Delay(20); //按键消抖
while(P1_5 == 0);
Delay(20);
KeyNumber = 11; //第三列第三行
}
if(P1_4 == 0)
{
Delay(20); //按键消抖
while(P1_4 == 0);
Delay(20);
KeyNumber = 15; //第三列第四行
}
P1 = 0xFF; //接着扫描第四列
P1_0 = 0; //P1_0对应第四列,置为低电平,其它三位置为高电平
if(P1_7 == 0)
{
Delay(20); //按键消抖
while(P1_7 == 0);
Delay(20);
KeyNumber = 4; //第四列第一行
}
if(P1_6 == 0)
{
Delay(20); //按键消抖
while(P1_6 == 0);
Delay(20);
KeyNumber = 8; //第四列第二行
}
if(P1_5 == 0)
{
Delay(20); //按键消抖
while(P1_5 == 0);
Delay(20);
KeyNumber = 12; //第四列第三行
}
if(P1_4 == 0)
{
Delay(20); //按键消抖
while(P1_4 == 0);
Delay(20);
KeyNumber = 16; //第四列第四行
}
return KeyNumber;
}
②MatrixKey.h文件:
#ifndef __MatrixKey_H__
#define __MatrixKey_H__
unsigned char MatrixKey();
#endif
③main.c文件:
#include <REGX52.H>
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char KeyNum = 0;
void main()
{
LCD_Init(); //初始化
while(1)
{
KeyNum = MatrixKey();
if(KeyNum) //如果有按键按下
{
LCD_ShowNum(1,1,KeyNum,2); //屏幕显示按下的按键序号
}
}
}
(3)将生成的.hex文件下载到开发板中,按下矩阵按键,屏幕上会显示按键对应的键码值。
2、矩阵键盘密码锁实验
(1)项目包含的文件:其中MatrixKey.c、MatrixKey.h、Delay.c、Delay.h、LCD1602.c及LCD1602.h全部沿用上一例的代码,这里不再给出,INTRINS.H及REGX52.H在系统include目录中,不需要自己编写。
(2)将源文件及头文件添加到项目中,然后进行编译。
main.c文件:
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"
unsigned char KeyNum = 0;
unsigned int Password; //4位密码(32位,4个字节)
unsigned char Count = 0; //记录已输入密码位数
void main()
{
LCD_Init(); //初始化
LCD_ShowString(1,1,"Password:");
LCD_ShowNum(2,1,Password,4);
while(1)
{
KeyNum = MatrixKey();
if(KeyNum) //如果有按键按下
{
if(KeyNum <= 10) //如果s1-s10按键按下,输入密码
{
if(Count < 4)
{
Password *= 10; //把上一位密码左移(给下一位密码腾出位置)
Password += KeyNum % 10; //获取输入的1位密码
}
Count++;
}
if(KeyNum == 11) //s11作为确认键
{
if(Password == 2345)
{
LCD_ShowString(1,14,"OK"); //密码正确显示OK
Delay(5000); //停留5秒
Password = 0; //密码清零
Count = 0; //计数清零
LCD_ShowNum(2,1,Password,4); //更新显示
LCD_ShowString(1,14," ");
}
else
{
LCD_ShowString(1,14,"ERR"); //密码错误显示ERR
Delay(5000); //停留5秒
Password = 0; //密码清零
Count = 0; //计数清零
LCD_ShowNum(2,1,Password,4); //更新显示
LCD_ShowString(1,14," ");
}
}
if(KeyNum == 12) //s12作为手动清空输入键
{
Password = 0; //密码清零
Count = 0; //计数清零
LCD_ShowNum(2,1,Password,4); //更新显示
}
LCD_ShowNum(2,1,Password,4); //显示当前输入的密码
}
}
}
(3)将生成的.hex文件下载到开发板中进行测试。