一、认识矩阵键盘
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式
采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态
扫描的概念
数码管扫描(输出扫描)
原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果
矩阵键盘扫描(输入扫描)
原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果
以上两种扫描方式的共性:节省I/O口
单片机的I/O口是弱上拉、强下拉的
当引脚输出为1时,驱动能力很弱,允许外部装置将其拉低。当引脚输出为低时,它的驱动能力很强,可吸收相当大的电流
二、简单的矩阵键盘实现
目标 :按下按键后,LCD屏显示键码。
把上节的Delay.c、Delay.h和LCD1602.c、LCD1602.h复制到项目中。
新建一个MatrixKey.c文件和MatrixKey.h
- 点击templates,在空白处右键,点击configure templates
- 点击新建图标,输入#ifndef,在Text中输入模板内容,点击OK
注意,要在下划线中间打一个竖杠,这样在点击模板后,光标会出现在该位置。
- 在MatrixKey.h文件中编辑,双击#ifndef,可以看到
在光标处输入MATRIXKEY
完整的MatrixKey.h文件内容为:
#ifndef __MATRIXKEY__H__
#define __MATRIXKEY__H__unsigned char MatrixKey();#endif
- 矩阵键盘的输入扫描要先确定列,再确定行。完整的MatrixKey.c文件为:
#include <REGX52.H>
#include "Delay.h"
/*** @brief 矩阵键盘读取按键键码* @param 无* @retval KeyNumber 按下按键的键码值如果按下按键不松手,程序会停留在此函数,松手的一瞬间,返回按键键码;没有按键按下时,返回0*/
unsigned char MatrixKey()
{unsigned char KeyNumber=0;P1=0xFF;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_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_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_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文件:
#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);}}
}
三、矩阵键盘密码锁
目标:S1 ~ S9为数字1 ~ 9,S10为0,S11为确认,S12为取消。
把刚刚的简单项目复制一份,在旧项目的基础上进行过更改。
- 先实现一位数字输出。main.c文件如下:
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10) //是否按下S1~S10{Passward = KeyNum%10; //获取一位密码}LCD_ShowNum(2, 1, Passward, 2);}}
}
按下S1,LCD显示01,按下S2,LCD显示02……按下S10,LCD显示00.
- 实现输入一串数字
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10) //是否按下S1~S10{Passward *= 10; //密码左移一位Passward += KeyNum%10; //获取一位密码}LCD_ShowNum(2, 1, Passward, 4);}}
}
这个程序好像可以实现密码输入。按下S1,显示0001,按下S3,显示0013。但是当数字很大超出数据范围时,密码就出现错误了,显示的数字就不按按下的按键显示了。
所以就需要计次。定义一个变量Count
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward, Count;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10) //是否按下S1~S10{if(Count<4){Passward *= 10; //密码左移一位Passward += KeyNum%10; //获取一位密码}Count++;}LCD_ShowNum(2, 1, Passward, 4);}}
}
- 验证密码,若正确则OK,否则ERR
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward, Count;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10) //是否按下S1~S10{if(Count<4) //次数判断{Passward *= 10; //密码左移一位Passward += KeyNum%10; //获取一位密码Count++; //计次加一}LCD_ShowNum(2, 1, Passward, 4);}if(KeyNum == 11) //是否按下S11确认{if(Passward == 4399){LCD_ShowString(1, 14, "OK");}else{LCD_ShowString(1, 14, "ERR");}}}}
}
再加上清零和更新显示
if(KeyNum == 11) //是否按下S11确认{if(Passward == 4399){LCD_ShowString(1, 14, "OK ");Passward = 0; //密码清零Count = 0; //计次清零LCD_ShowNum(2, 1, Passward, 4); //更新显示}else{LCD_ShowString(1, 14, "ERR");Passward = 0; //密码清零Count = 0; //计次清零LCD_ShowNum(2, 1, Passward, 4); //更新显示}}
- 按下取消,清零
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward, Count;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10) //是否按下S1~S10{if(Count<4) //次数判断{Passward *= 10; //密码左移一位Passward += KeyNum%10; //获取一位密码Count++; //计次加一}LCD_ShowNum(2, 1, Passward, 4);}if(KeyNum == 11) //是否按下S11确认{if(Passward == 4399){LCD_ShowString(1, 14, "OK ");Passward = 0; //密码清零Count = 0; //计次清零LCD_ShowNum(2, 1, Passward, 4); //更新显示}else{LCD_ShowString(1, 14, "ERR");Passward = 0; //密码清零Count = 0; //计次清零LCD_ShowNum(2, 1, Passward, 4); //更新显示}}if(KeyNum == 12) //是否按下S12取消{Passward = 0; //密码清零Count = 0; //计次清零LCD_ShowNum(2, 1, Passward, 4); //更新显示}}}
}