矩阵键盘电路
首先看看矩阵键盘的电路连接:

如果每个按键都要单独进行检查,那么就需要16个接口,但为了节省接口矩阵键盘是采用逐行或者逐列进行扫描,选中一行或者选中一列,然后判断该行(列)中具体哪个按键被按下然后就可以捕捉了,然后通过循环快速扫描四行(列),从而实现对所有按键进行扫描。
独立按键的准双向口
在51单片机中,I/O的工作模式是准双向口。可以双向输入给I/O
当接口输出1时,内部此时是弱上拉电阻(待会会说到)。
当接口输入0时,内部此时是接地状态。
只有接口输出为1时,才能读取状态变化。
弱上拉电阻
弱上拉电阻,通俗易懂的就是,当接口同时输入1和0时,此时接口会选择输出0,若接口输出为0时,需要很大的电流才能使接口输出1
所以为什么在单片机的矩阵键盘中,一般接口处于输出1的状态,这样一旦捕捉到0的变化,就会立刻输出0。
LED显示矩阵键盘按下的数字
这里将复用之前的原代码,即Delay,LCD1602等函数,请自行查看之前的内容。
才之前的基础上,新增matrixKey的头文件与C文件:
matrixKey.h
cpp
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__
unsigned char MatrixKey();
#endif
matrixKey.c
这里是实现读取键盘的实现:
根据前面所说的,我们需要将P1全部接口置1,此时全部不工作
扫描第一列,将P1_3置0,此时第一列工作
然后开始检测第一列的四个按钮(前后需要delay来消抖)
一旦检测到就将记录下该按钮代表的数字,然后return返回。
就这样依次检测1,2,3,4列。
cpp
#include <REGX52.H>
#include "Delay.h"
unsigned char MatrixKey()
{
unsigned char KeyNumber = 0;
P1 = 0xFF;//P1全部置高电平
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全部置高电平
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全部置高电平
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全部置高电平
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;
}
main.c
现在来到主函数:
首先将LCD初始化,第一列显示如下代码的字符串。
然后开始循环接收MatrixKey函数所返回的字符。
由于返回的字符初始值为0,所以我们可以直接利用该字符进行判断条件。
所以一旦接收到字符,此时就调用LCDshow函数显示该字符即可。
cs
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "matrixKey.h"
unsigned char KeyNum;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"MatrixKey");
while(1)
{
KeyNum = MatrixKey();
if(KeyNum)
{
LCD_ShowNum(2,1,KeyNum,2);
}
}
}
矩阵键盘密码锁
在刚刚的基础上进行操作,制作一个四位密码的锁
处理按下的数字转化成密码
当按下之后,我们需要对该数字进行处理:
我们输入的数字必须是0-9,但是键盘并没有0这个按键
所以我们将按键10当成0
每按下一个按键,都让Password自身乘10再加上按下的字数,这样就完成一次密码输入。
由于是四位密码,我们需要一个计数变量,密码小于4时则可以进行密码输入。
每输入一次那么就刷新显示一次。
cpp
if(KeyNum <= 10)
{
if(count < 4)
{
Password *= 10;
Password += KeyNum%10;
count++;
}
LCD_ShowNum(2,1,Password,4);
}
确认密码
我们将按键11设为确认键。
一旦按下按键11,则开始进行判断
如果输入密码为指定密码。则在第一行最右边显示OK,否则显示ERR,此时刷新密码和计数,并刷新显示。
如果输入密码不正确,那么显示ERR,同样刷新密码和计数,以及刷新显示。
cpp
if(KeyNum == 11)
{
if(Password == 2345)
{
LCD_ShowString(1,14,"OK ");
Password = 0;
count = 0;
LCD_ShowNum(2,1,Password,4);
}
else
{
LCD_ShowString(1,14,"ERR");
Password = 0;
count = 0;
LCD_ShowNum(2,1,Password,4);
}
}
取消输入
我们将按键12设为取消输入。
一旦按下按键12,此时清空计数与密码,并刷新显示。
cpp
if(KeyNum == 12)
{
count = 0;
Password = 0;
LCD_ShowNum(2,1,Password,4);
}
密码锁的完整代码
cpp
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "matrixKey.h"
unsigned char KeyNum;
unsigned int Password, count;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Password!");
while(1)
{
KeyNum = MatrixKey();
if(KeyNum)
{
if(KeyNum <= 10)
{
if(count < 4)
{
Password *= 10;
Password += KeyNum%10;
count++;
}
LCD_ShowNum(2,1,Password,4);
}
if(KeyNum == 11)
{
if(Password == 2345)
{
LCD_ShowString(1,14,"OK ");
Password = 0;
count = 0;
LCD_ShowNum(2,1,Password,4);
}
else
{
LCD_ShowString(1,14,"ERR");
Password = 0;
count = 0;
LCD_ShowNum(2,1,Password,4);
}
}
if(KeyNum == 12)
{
count = 0;
Password = 0;
LCD_ShowNum(2,1,Password,4);
}
}
}
}