一、矩阵键盘
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函数中:逻辑代码
点击查看代码
#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) 开漏输出
七、配置固定模版代码
标签:P1,06,C51,--,扫描,Delay,while,KeyNumber,20 From: https://www.cnblogs.com/xff1218/p/18660139