C51--06---矩阵键盘

一、矩阵键盘

1.定义:

4X4 16个按键组成,以矩阵的方式进行连接,叫做矩阵键盘;

2.优势

将按键排列成矩阵形式,两端都接在I/O口上,可以减少I/O口的占用;

注: 独立按键的模式,将一端集中接在GND上,另一端单独引出一个I/O口,这样当按键比较多时,就会占用很多I/O口;

3.读取方式

采用逐行、逐列的“扫描”,就可以读出任何位置按键的状态。

二、扫描的概念

1.数码管扫描(输出扫描)

  • 原理:
    显示 第一位--第二位--第三位--.... 快速循环此过程,
    由于MCU速度非常快 利用余晖和人眼视觉差 达到所有数码管同时显示的错觉。

    输出扫描:
     数码管:MCU I/O口 一直向数码管 输出数据  然后不断进行扫描 显示
    

2.矩阵按键扫描(输入扫描)

  • 原理:
    读取 第一行(列)--第二行(列)--第三行(列)--.... 快速循环此过程,
    由于MCU速度非常快 最终实现所有按键同时检测的效果。

    输入扫描:
     矩阵按键:按键值一直更新状态 向MCU输入数据 即MCU I/O口 不断读取矩阵按键的状态,MCU根据返回的数据 进行相应 的另外外设的操作。
    

3.扫描的目的:为了节省I/O口

  扫描很广泛的应用于 显示器 扫描,例如1920X1080  采用矩阵扫描的方式,只需要1920+1080个IO口即可 非常节省I/O口

三、单片机扫描矩阵键盘的两种方式

1.逐行扫描

逐行扫描示意图:

 ---P14-P17 扫描哪行 就赋值0 (P17-P14 逐行赋值0)
 ---然后顺序读取P10-P13的状态,0表示按下  1表示未按下 
 ---逐行循环前两个操作 完成逐行扫描

 注:一次只能扫描一行(列)不可同时赋值0

2.逐列扫描

逐列扫描示意图:

    ---P10-P13 轮流进行列扫描
    ---然后顺序读取P14-P17的状态,0表示按下  1表示未按下 
    ---逐行循环前两个操作 完成逐列扫描

    注:一次只能扫描一行(列)不可同时赋值0

```
 本开发板问题:P15口连接了蜂鸣器  在逐行扫描的过程中由于引脚冲突,蜂鸣器会一直响 而且关不掉,所以此次选择逐列扫描。
```

四、实例1:读取矩阵键盘的键码值

1、矩阵扫描函数

点击查看代码
#include <REGX52.H>
#include "Delay.h"

/**
  * @brief  读取 矩阵按键 键码值 (逐列扫描)
  * @param  无
  * @retval KeyNumber
  * 如果按下不放 就会一直在此函数循环  放开按键 会返回键码值 如果没有按下任何按键 则返回0;
  */
 unsigned int MatrixKey()
{
  unsigned int KeyNumber=0;
	
	P1=0xFF; //将P1 I/O 初始化  “1 无效 0有效”
	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 I/O 初始化  “1 无效 0有效”
	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 I/O 初始化  “1 无效 0有效”
	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 I/O 初始化  “1 无效 0有效”
	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;  //一定要将键码值返回

}

2、键码值读取显示函数

点击查看代码
#include <REGX52.H>
#include "MatrixKey.h"
#include "LCD1602.h"
unsigned int MatrixNum;
void main()
{
	
	LCD_Init();
	LCD_ShowString(1,1,"MatrixKey:");
	while(1)
	{
		MatrixNum=MatrixKey();
		if(MatrixNum){   //如果不对其进行判断,会一直扫描 这样00也会一直显示 由于扫描速度过快  就会看不到效果
		 LCD_ShowNum(2,1,MatrixNum,2);
		}
	}
}

五、实例2:矩阵键盘密码锁

main函数中:逻辑代码

点击查看代码
/*
  矩阵键盘密码锁 小项目实现
	使用驱动代码:
		1.LCD1602显示
		2.延迟函数
		3.矩阵键盘扫描驱动
*/

#include <REGX52.H>
#include "MatrixKey.h"
#include "LCD1602.h"
unsigned int MatrixNum;
unsigned int PassWord;
unsigned int PassWord_Right=1108;
unsigned char Count;
void main()
{
	
	LCD_Init();
	LCD_ShowString(1,1,"PassWord:");
	while(1)
	{
		MatrixNum=MatrixKey();
		if(MatrixNum){   //如果不对其进行判断,会一直扫描 这样00也会一直显示 由于扫描速度过快  就会看不到效果
			
         //密码区键值设置:实现密码输入
		   if(MatrixNum<=10){
			  if(Count<4){   //限制密码个数为4个
				PassWord=PassWord*10+ MatrixNum%10;  //显示4位密码
			    LCD_ShowNum(2,1,PassWord,4);
				Count++;
				}
		 }
		 
		 // OK键 功能实现:判断密码是否正确 并作出反应 
		 if(MatrixNum==11){
		    if(PassWord==PassWord_Right){
			  LCD_ShowString(1,14,"OK ");
			}else{
			  LCD_ShowString(1,14,"ERR");
			}
			 Count=0;
			 PassWord=0;
			 LCD_ShowNum(2,1,PassWord,4);
		 }
		 
		 // 取消键 实现数据清零
		 if(MatrixNum==12){
		    Count=0;
			PassWord=0;
			LCD_ShowNum(2,1,PassWord,4);
			LCD_ShowString(1,14,"   ");
		 }
		 
		}
	}
}

六、补充知识:单片机I/O口

1、单片机I/O口的工作模式:

(1) 准双向口/弱上拉

准双向口/弱上拉模式:
  
    不需要重新配置I/O口的输出状态,就可以控制输入输出状态的切换;
    因为0 低电平的驱动比较强   1 高电平的驱动能力比较弱,如果外部不干预,输出为1时,就是1所对应的状态(输出模式);
    但如果想改变为0对应的状态 此时我们并不需要重新更改I/O的值,而是直接使用外部装置 就可以将其拉低 变为0(此时相当于输入模式)。

注意:独立按键: 接到低电平上 检测0;而非接到高电平 检测1;原因就是:单片机是弱上拉模式

如下图:

内部接高电平  但当外部接地时,此时如果I/O口去进行读数据 那此时读取的是0 而非1 (内部高电平弱)

注:

    本开发板 P1/P2/P3 都是弱上拉的工作模式 P0接了一个电阻 也可以看做弱上拉模式;
    MCU I/O口: 双向口输出配置 ,同一个I/O 口既可以读出数据,也可以写入数据;

(2) 仅为输入(高阻)

(3) 开漏输出

七、配置固定模版代码

posted @ 2025-01-10 10:53  Mirco1218  阅读(500)  评论(0)    收藏  举报