51 矩阵按键
在开发板的右下区域,我们可以看见一个4x4规格的按键矩阵,这就是矩阵按键
通过扫描的方式,可以读出任意按键的状态,即在按键数量较多时,通过矩阵方式进行组合可以减少IO的占用
STC89C52RC开发板上的矩阵按键模块(图源:普中科技开发手册)
矩阵键盘的扫描
数码管扫描(输出扫描)
原理:按照一个顺序逐个显示数码管,然后循环这个过程,实现所有数码管同时显示的
有关数码管的扫描,详见51 20231117 数码管-CSDN博客
矩阵键盘扫描(输入扫描)
原理:类似于数码管扫描,分为按行扫描和按列扫描
矩阵键盘的判断就是不断扫描
按行扫描:给需要判断的行给0,其它给1,当按下某一列对应的按键时,对应那列变成0,以此来确定按下的是哪个按键
(由于开发板电路问题,STC89C52的P15口在逐行扫描会出问题(P15接到步进电机,步进电机接到BZ,即蜂鸣器,这个开发板采用的是一种无源蜂鸣器,接收到一定频率高低变化的电压会响)
(但是STC89C52RC好像不会有这个问题,因为它的步进电机接的是P25)
STC89C52RC开发板上的步进电机模块(图源:普中科技开发手册)
这里使用按列扫描:即给P10~P13电平,判断P14~P17
(单片机的端口默认是高电平,只有给低电平才能判断)
//矩阵按键模块(列扫描)
#include<STC89C5xRC.H>
#include"Delay.h"
unsigned char MatrixKey()
{
unsigned char KeyNumber = 0;
P1 = 0xff;
P13 = 0;
//除了P13以外全部置1
if(P17 == 0)
{
Delay(20);
while(P17 == 0);
KeyNumber = 1;
}
if(P16 == 0)
{
Delay(20);
while(P16 == 0);
KeyNumber = 5;
}
if(P15 == 0)
{
Delay(20);
while(P15 == 0);
KeyNumber = 9;
}
if(P14 == 0)
{
Delay(20);
while(P14 == 0);
KeyNumber = 13;
}
//扫描第一列
P1 = 0xff;
P12 = 0;
if(P17 == 0)
{
Delay(20);
while(P17 == 0);
KeyNumber = 2;
}
if(P16 == 0)
{
Delay(20);
while(P16 == 0);
KeyNumber = 6;
}
if(P15 == 0)
{
Delay(20);
while(P15 == 0);
KeyNumber = 10;
}
if(P14 == 0)
{
Delay(20);
while(P14 == 0);
KeyNumber = 14;
}
P1 = 0xff;
P11 = 0;
if(P17 == 0)
{
Delay(20);
while(P17 == 0);
KeyNumber = 3;
}
if(P16 == 0)
{
Delay(20);
while(P16 == 0);
KeyNumber = 7;
}
if(P15 == 0)
{
Delay(20);
while(P15 == 0);
KeyNumber = 11;
}
if(P14 == 0)
{
Delay(20);
while(P14 == 0);
KeyNumber = 15;
}
P1 = 0xff;
P10 = 0;
if(P17 == 0)
{
Delay(20);
while(P17 == 0);
KeyNumber = 4;
}
if(P16 == 0)
{
Delay(20);
while(P16 == 0);
KeyNumber = 8;
}
if(P15 == 0)
{
Delay(20);
while(P15 == 0);
KeyNumber = 12;
}
if(P14 == 0)
{
Delay(20);
while(P14 == 0);
KeyNumber = 16;
}
return KeyNumber;
}
配合LCD1602的显示函数,我们可以实现按下哪个按键就显示对应数字
#include <STC89C5xRC.H>
#include "Delay.h"
#include "LCD1602.h"
#include"MatrixKey.h"
unsigned char Keynum = 0;
void main()
{
LCD_Init();
LCD_ShowString(1, 1, "Hello");
while(1)
{
Keynum = MatrixKey();
if(Keynum)
{
LCD_ShowNum(2, 1, Keynum, 2);
}
}
}
---
对于STC89C52RC,是可以采用逐行扫描的方式进行扫描的
#include<STC89C5xRC.H>
#include"Delay.h"
/**
* @brief 矩阵键盘读取按键键码
* @param 无
* @retval KeyNumber 按下按键的键码值
* 如果按下按键不放,程序会停留在此函数,松手的一瞬间返回按键键码
* 没有按键时,返回0
**/
unsigned char MatrixKey()
{
unsigned char Keynumber = 0;
P1 = 0xff;
P17 = 0;
if(P13 == 0)
{
Keynumber = 1;
}
if(P12 == 0)
{
Keynumber = 2;
}
if(P11 == 0)
{
Keynumber = 3;
}
if(P10 == 0)
{
Keynumber = 4;
}
P1 = 0xff;
P16 = 0;
if(P13 == 0)
{
Keynumber = 5;
}
if(P12 == 0)
{
Keynumber = 6;
}
if(P11 == 0)
{
Keynumber = 7;
}
if(P10 == 0)
{
Keynumber = 8;
}
P1 = 0xff;
P15 = 0;
if(P13 == 0)
{
Keynumber = 9;
}
if(P12 == 0)
{
Keynumber = 10;
}
if(P11 == 0)
{
Keynumber = 11;
}
if(P10 == 0)
{
Keynumber = 12;
}
P1 = 0xff;
P14 = 0;
if(P13 == 0)
{
Keynumber = 13;
}
if(P12 == 0)
{
Keynumber = 14;
}
if(P11 == 0)
{
Keynumber = 15;
}
if(P10 == 0)
{
Keynumber = 16;
}
return Keynumber;
}
利用矩阵键盘实现密码锁
通过矩阵键盘的输入检测,我们可以实现一个包含密码判断、重复输入等功能的简易密码锁
不过这里有个缺陷,就是用于储存输入数据的类型是int,最多只能支持4位密码
#include <STC89C5xRC.H>
#include "Delay.h"
#include "LCD1602.h"
#include"MatrixKey.h"
unsigned char Keynum = 0;
unsigned int Password = 0;
//0~65535, 定义4位密码即可
unsigned char count = 0;
void main()
{
LCD_Init();
LCD_ShowString(1, 1, "Password:");
while(1)
{
Keynum = MatrixKey();
if(Keynum)
{
if(Keynum <= 10)
//如果按下的按键为S1~S10,输入密码
{
count++;
//计算输入次数
if(count <= 4)
{
Password *= 10;
//上一位密码左移
Password += Keynum % 10;
//1-9得到原来的数,10取0
//获取一位密码
}
}
if(Keynum == 11)
//S11被按下,表示确认
{
if(Password == 1234)
{
LCD_ShowString(1, 13, "OK ");
//密码正确
}
else
{
LCD_ShowString(1, 13, "err");
Password = 0;
//重置状态
count = 0;
}
}
if(Keynum == 12)
//S12按下,取消,即清空
{
Password = 0;
count = 0;
}
LCD_ShowNum(2, 1, Password, 4);
//更新显示
}
}
}
利用字符串实现长密码锁
我们可以通过字符串实现支持更长密码的密码锁,这里需要用到字符串处理的相关知识
#include <STC89C5xRC.H>
#include<string.h>
#include<stdio.h>
#include"Delay.h"
#include"MatrixKey.h"
#include"LCD1602.h"
char password[8] = {0};
//注意\n需要占一个位置
int count = 0;
int Keynum = 0;
void main()
{
LCD_Init();
LCD_ShowString(1, 1, "Password:");
while(1)
{
Keynum = MatrixKey();
if(Keynum)
{
if(Keynum <= 10)
//判断是否输入
{
count++;
if(count <= 7)
{
switch(Keynum)
//通过按键向字符串中加入对应数字
{
case 1:strcat(password, "1");break;
case 2:strcat(password, "2");break;
case 3:strcat(password, "3");break;
case 4:strcat(password, "4");break;
case 5:strcat(password, "5");break;
case 6:strcat(password, "6");break;
case 7:strcat(password, "7");break;
case 8:strcat(password, "8");break;
case 9:strcat(password, "8");break;
case 10:strcat(password, "0");break;
}
}
LCD_ShowString(2, 1, password);
}
if(Keynum == 11)
{
if(strcmp(password, "7355608") == 0)
//判断密码是否正确
//玩cs玩的
{
LCD_ShowString(1, 1, " ");
LCD_ShowString(2, 1, " ");
LCD_ShowString(1, 1, "Bomb has been");
LCD_ShowString(2, 1, "planted!");
}
else
{
count = 0;
strcpy(password, "");
//重置字符串
LCD_ShowString(1, 13, "ERR");
LCD_ShowString(2, 1, " ");
}
}
if(Keynum == 12)
{
strcpy(password, "");
LCD_ShowString(2, 1, " ");
count = 0;
}
}
//LCD_ShowString(2, 1, password);
//由于要显示文字,实时显示密码就不能放在这里了,否则在最后还是显示密码
}
}