51单片机-矩阵键盘

223 阅读4分钟

矩阵键盘的介绍

  • 在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式
  • 采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态

202204021326649.png

扫描的概念

  • 数码管扫描(输出扫描)

    原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果

  • 矩阵键盘扫描(输入扫描)

    原理1:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果(逐行(列)扫描)

    原理2:将所有行置高电平,所有列置低电平,查看高电平有无被拉低,若有说明这一行有按键被按下。再重复这一操作判断是哪一列被按下。(行列扫描)

  • 以上两种扫描方式的共性:节省I/O口

矩阵键盘逐行(列)扫描代码

#include <REGX52.H>
#include "Delay.h"/**
  * @brief  矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
            如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
  */
unsigned char MatrixKey()
{
    unsigned char KeyNumber=0;
    
    P1=0xFF;
    P1_3=0;
    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;
    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;
    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;
    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;
}
//当然也可以用
//if(P1_7==0){Delay(20);if(P1_7==0);KeyNumber=1;}但是这样就没有松手检测

矩阵键盘行列扫描代码

#include <REGX52.H>
#include "Delay.h"/**
  * @brief  矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
            如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
  */
unsigned char MatrixKey()
{
    unsigned char KeyNumber;
    P0=0x0f;
    if(P0!=0x0f)//读取按键是否按下
    {
	Delay(20);//延时20ms进行消抖
	if(P0!=0x0f)//再次检测键盘是否按下
	{	
     
	P0=0x0f;
	switch(P0)
	{
		case(0X07):	KeyNumber=4;break;
		case(0X0b):	KeyNumber=3;break;
		case(0X0d):     KeyNumber=2;break;
		case(0X0e):	KeyNumber=1;break;
	}
	
	P0=0XF0;
	switch(GPIO_KEY)
	{
		case(0X70):	KeyNumber=KeyNumber+12;break;
		case(0Xb0):	KeyNumber=KeyNumber+8;break;
                case(0Xd0):     KeyNumber=KeyNumber+4;break;
		case(0Xe0):	KeyNumber=KeyNumber;break;
	}
			

}

练习可以写一下

1.矩阵键盘控制一位数码管静态现实键值

2.利用定时器扫描矩阵键盘,实现动态现实数码管两位键值

矩阵键盘密码锁代码

#include <REGX52.H>
#include "LCD1602.h"
#include "MatrixKey.h"
#include <stdio.h>
#include <string.h>
#define LEN 7   //LEN 为密码位数加一unsigned char pass[LEN]="123ABC"; //预设密码
unsigned char KeyNum;
unsigned char key[LEN]="      ";
unsigned int  a=0;
unsigned int  i=0;  //i记录输入次数
void main(){
    LCD_Init();
    LCD_ShowString(1,1,"PassWord:");
    while(1)
    {
        KeyNum=MatrixKey();
        if(KeyNum!=0&&KeyNum!='*'&&KeyNum!='#'&&a<6&&i<6)
        {
            {key[a]=KeyNum;
            LCD_ShowString(2,1,key);
            
            }a+=1;
        }
        
        if(KeyNum=='#'&&i<6)
        {
            if(strcmp(pass,key)==0)
                {LCD_ShowString(1,12,"OK");for(a=0;a<6;a++)key[a]='                          ';LCD_ShowString(2,1,key);a=0;LCD_ShowString(2,1,"Welcome!");i=7;}
            else
                {LCD_ShowString(1,12,"ERR");i+=1;for(a=0;a<6;a++)key[a]=' ';LCD_ShowString(2,1,key);a=0;}
                        
        }
        if(KeyNum=='*'&&i<6)
        {
            a-=1;
            key[a]=' ';
            LCD_ShowString(2,1,key);
        }
        if(i==6)
            LCD_ShowString(2,1,"LOCK  ");
            
    }
    
}