一、认识矩阵键盘
在键盘中按键数量较多时,为了减少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
#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
#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
#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
#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
#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
#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
#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); //更新显示
}
}
}
}