一、矩阵键盘介绍
1、独立按键和矩阵键盘实物图及其原理图
可以看到矩阵键盘是4*4的一个结构,而独立按键是2*4的结构
从原理图可以看到,二者按键数量虽然不同,但I/O口数量均为8个,这也就是矩阵键盘的优势所在,大大减少了外设对I/O口的使用;
独立按键:4个按键为一小组,一端接GND(低电平),另外一端连接4个I/O口,也就是说,通过给予I/O口高低电平进行按键的扫描
矩阵键盘:低四位(接口1234)控制行,高四位(5678)控制列,也就是说整个按键就是一个坐标图,通过(行,列)/(列,行)坐标来进行扫描,从而判断哪个按键被按下。
2、两种扫描方式(逐行扫描、逐列扫描)
两组扫描方式其实原理都一样,区别就在于先扫描行还是先扫描列,如若先扫描行,那就是逐行扫描,反之则就是逐列扫描;
(1)逐行扫描
逐行扫描就是说先扫描第一行中的哪个按键按下了,如果没有再扫描第二行,看一下是不是第二行里的某个按键按下了,如果还没有找到按下的那个按键,那么就继续扫描第三行、第四行,知道找出哪个按键被按下了。
(2)逐列扫描
行列扫描就是说先扫描所有的行,确定是哪一行的按键被按下了,之后再扫描所有的列,找出哪一列有按键被按下了,这样只要扫描两次就可以确定出到底是哪个按键被按下了。
接下来科普一下:
二、传统51单片机I/O口的工作模式
描述:通过前面的输入输出的内容(LED控制与按键的使用),我们对控制I/O口有了一个基本的了解。如果需要输出高低电平,可以对该引脚进行写"1"或者"0";如果需要读取I/O的电平,直接判断该引脚是高电平或者低电平既可。
在程序上对P0 ~ P3的输入输出控制是一样的,但实际上它们内部结构是不一样的
1、开漏输出(双向I/O口)模式(P0)
输出:可以输出低电平,不能输出高电平(如果需要输出高电平,则引脚端需要在外部接上 拉电路,增强驱动能力)
输入:高低电平均可
2、弱上拉模式(准双向I/O口)模式(P1 P2 P3)
输出:高低电平均可(输出高电平时,驱动能力不强,也就是弱上拉,拉高电平的能力弱)
输入:高低电平均可
实际上所有的I/O都可以在引脚的外部接上拉电阻,增强I/O口的驱动能力,如下图所示为一个最小的单机最小系统原理图。
单片机内部上拉,则电流方向由单片机内部流向外部,称为拉电流;
单片机外部上拉,则电流方向由外部流向单片机内部,称为灌电流;
三、编程示例
1、LCD1602显示(实现按下哪个按键就显示相应的数字)
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char KeyNum;
void main()
{
LCD_Init(); //LCD初始化
LCD_ShowString(1,1,"MatrixKey"); //LCD显示字符串
while(1)
{
KeyNum = MatrixKey(); //获取矩阵键盘按键键码
if(KeyNum)
{
LCD_ShowNum(2,1,KeyNum,2); //输出显示键码
}
}
}
#include <REGX52.H>
#include "Delay.h"
unsigned char MatrixKey()
{
unsigned char KeyNumber=0;
P1 = 0xFF; //全部行和列都给高电平
P1_4 = 0; //只有第一列给予低电平(可以认为只有第一列才进行工作)
if(P1_0==0){Delay(10);while(P1_0==0);Delay(10);KeyNumber=1;} //如果第一行也给予0,那么
就是第一行第一列的那个按键工作,也就是第一个按键01工作,也就是通过这种十字交叉的形式来确定哪个按键进行工作
if(P1_1==0){Delay(10);while(P1_1==0);Delay(10);KeyNumber=5;}
if(P1_2==0){Delay(10);while(P1_2==0);Delay(10);KeyNumber=9;}
if(P1_3==0){Delay(10);while(P1_3==0);Delay(10);KeyNumber=13;}
P1 = 0xFF;
P1_5 = 0;
if(P1_0==0){Delay(10);while(P1_0==0);Delay(10);KeyNumber=2;}
if(P1_1==0){Delay(10);while(P1_1==0);Delay(10);KeyNumber=6;}
if(P1_2==0){Delay(10);while(P1_2==0);Delay(10);KeyNumber=10;}
if(P1_3==0){Delay(10);while(P1_3==0);Delay(10);KeyNumber=14;}
P1 = 0xFF;
P1_6 = 0;
if(P1_0==0){Delay(10);while(P1_0==0);Delay(10);KeyNumber=3;}
if(P1_1==0){Delay(10);while(P1_1==0);Delay(10);KeyNumber=7;}
if(P1_2==0){Delay(10);while(P1_2==0);Delay(10);KeyNumber=11;}
if(P1_3==0){Delay(10);while(P1_3==0);Delay(10);KeyNumber=15;}
P1 = 0xFF;
P1_7 = 0;
if(P1_0==0){Delay(10);while(P1_0==0);Delay(10);KeyNumber=4;}
if(P1_1==0){Delay(10);while(P1_1==0);Delay(10);KeyNumber=8;}
if(P1_2==0){Delay(10);while(P1_2==0);Delay(10);KeyNumber=12;}
if(P1_3==0){Delay(10);while(P1_3==0);Delay(10);KeyNumber=16;}
return KeyNumber;
2、矩阵键盘密码锁
我们要实现:按键1-10作为数字1-9和0,密码设为四位,通过输入密码判断所输入密码是否正确,给出判断,按键11作为“密码确认”的执行,按键12作为“取消输入”的执行,也就是实现一个普通电子锁的功能。
有了以上的基础之后,我们直接在原本代码基础上进行修改:
第一个难点:如何将按键10作为0的输出?-——通过对KeyNum取余,这样子输入1-9还是照常输出1-9,而按下按键10后,取余之后就会当作密码0进行使用,具体代码如下
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char KeyNum;
unsigned int Password; //重新定义一个名为password(密码)的变量
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Password"); //将显示屏上的第一行字符串改为Password
while(1)
{
KeyNum = MatrixKey();
if(KeyNum)
{
if(KeyNum <= 10) //如果按键按下且小于等于10
{
Password=KeyNum%10; //就让KeyNum对10取余,再赋值给Password,这样子就能
//实现按下按键10当作0来使用,避免按键密码缺0的情况
}
LCD_ShowNum(2,1,Password,2);
}
}
}
第二个难点:输入端我们已经解决,那么如何能够让LCD1602从左到右依次显示我们所输入的四位数字?
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char KeyNum;
unsigned int Password;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Password");
while(1)
{
KeyNum = MatrixKey();
if(KeyNum)
{
if(KeyNum <= 10)
{
Password*=10; //密码左移一位,此时Password默认0,假如按下1,执行接下来的操作,Password此时为1,如果再按下2,再进行一次循环,此时password为10,再执行第二条程序,password便从12,以此类推,这样子就能得到输入的四位密码
Password+=KeyNum%10;
}
LCD_ShowNum(2,1,Password,4); //将LCD显示数字改为4位,其默认为0000,如果输入1就输出0001
}
}
}
第三个难点:实现以上代码会发现,当我继续输入第五位数字时,第一位数字会被挤掉,怎么样控制输入密码者只能输入4位呢?————添加一个新的变量count再次进行判断,当它小于4时才能被录入
#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!=0)
{
if(KeyNum <= 10)
{
if(count < 4)
{
Password *= 10;
Password += KeyNum%10;
count ++; //只能输入4位数字,超过就不被录入
}
}
}
}
}
第四步:实现“确定密码'按键功能
#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!=0)
{
if(KeyNum <= 10)
{
if(count < 4)
{
Password *= 10;
Password += KeyNum%10;
count ++;
}
LCD_ShowNum(2,1,Password,4);
}
if(KeyNum == 11) //如果按下按键11,就确认密码,接下来进行密码验证
{
if(Password == 1125) //如果密码等于1125
{
LCD_ShowString(1,12,"ture"); //显示正确
Password = 0; //为了能再次输入密码让其为0
count = 0; //重新计数,再实行上面的操作
LCD_ShowNum(2,1,Password,4);
}else
{ LCD_ShowString(1,12,"Err"); //如不等于1125就显示错误
Password = 0;
count = 0;
LCD_ShowNum(2,1,Password,4);
}
}
最后一步:实现”取消“功能
以下就是完整代码:
#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!=0)
{
if(KeyNum <= 10)
{
if(count < 4)
{
Password *= 10;
Password += KeyNum%10;
count ++;
}
LCD_ShowNum(2,1,Password,4);
}
if(KeyNum == 11)
{
if(Password == 1125)
{
LCD_ShowString(1,12,"ture");
Password = 0;
count = 0;
LCD_ShowNum(2,1,Password,4);
}else
{ LCD_ShowString(1,12,"Err");
Password = 0;
count = 0;
LCD_ShowNum(2,1,Password,4);
}
}
} if(KeyNum == 12) //如果按下按键12
{
Password = 0; //密码归0,重新输入,实现“取消”功能
count = 0;
LCD_ShowNum(2,1,Password,4);
}
}
}