介绍
扫描的概念
数码管扫描(输出扫描)
原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果
矩阵键盘扫描(输入扫描)
原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果
以上两种扫描方式的共性:节省I/O口
单片机中的按键扫描
如图,当我们只看第一行矩阵按键时,将P17接地,忽略P16,P15,P14,我们会发现,矩阵按键和独立按键是一样的。
仅对第一行进行研究,此时如果P13=0,则证明S1按下了;P12=0,则证明S2按下了;以此类推。这样就可以判断出一行中哪个按键按下了。
要选中哪一行进行扫描,即对P17,P16,P15,P14输入的数据做出修改即可,要扫描哪一行就输入0,反之则输入1,在同一时间,只能一行给0,不能同时给出多个0。
但是由于引脚冲突问题,在扫描时会导致蜂鸣器也发出声音,因此我们不采用逐行扫描,改用逐列扫描。
逐列扫描原理和逐行扫描相同,只不过在选择扫描的列时,给P13-P10输入高低电平,再通过检测P17-P14来判断一列中哪一个按键按下。
知识点——弱上拉模式
详情看手册
实现判断按键坐标
要使用到LCD1602,则需要复制相关头文件和函数文件以及Delay文件。
小技巧:自定义模板:
右键进入编辑页面,竖杠(|)代表嵌入模板后光标所停位置
先建立好MatrixKey的.c和.h文件
.h文件的编写
#ifndef ___MATRIXKEY_H__
#define __MATRIXKEY_H__
unsigned char MatrixKey();
#endif
.c文件的编写
对应的代码有对应的解释
#include <REGX52.H>
#include "Delay.h"
unsigned char MatrixKey()//不需要输入值,但是有返回值
{
unsigned char KeyNum = 0;
P1 = 0xFF;//将P10-P17全部输入高电平
P1_3 = 0;//选中第一列
if(P1_7==0)
{
Delay(20);//消抖
while (P1_7==0)//检测松手——若没松手,则执行空循环,不执行下一步,若松手才执行下一步
Delay(20);
KeyNum = 1;//P1_7对应第一个按键,则给KeyNum赋予1
//之所以不直接在函数中实现LCD显示,是因为防止耦合性较高,降低操作与按键扫描的紧密性
}
else if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNum=5;}
else if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNum=9;}
else if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNum=13;}
P1 = 0xFF;
P1_2 = 0;//line 2
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNum=2;}
else if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNum=6;}
else if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNum=10;}
else if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNum=14;}
P1 = 0xFF;
P1_1 = 0;//line 3
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNum=3;}
else if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNum=7;}
else if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNum=11;}
else if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNum=15;}
P1 = 0xFF;
P1_0 = 0;//line 4
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNum=4;}
else if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNum=8;}
else if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNum=12;}
else if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNum=16;}
return KeyNum;
}
main.c
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"
unsigned char KeyNum;
void main(void)
{
LCD_Init();
LCD_ShowString(1,1,"The Key Number:");
while (1)
{
KeyNum = MatrixKey();
if (KeyNum)//一定要添加判断KeyNum是否等于0,否则将会出现按下按键只会出现一瞬的对应数字
{ //这是因为单片机刷新很快,按键的数字只会出现在一瞬间,然后很快被常态的00取代
//所以直接把00状态删除就不会出现BUG
LCD_ShowNum(2,1,KeyNum,2);
}
}
}
本次编译还使用到了Delay.c,Delay.h,LCD1602.c,LCD1602.h等文件,必须在有这些文件的情况下才能编译。
实现矩阵键盘密码锁
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"
unsigned char KeyNum;//0~255
unsigned int InputWord = 0;
unsigned int PassWord = 1231;//unsigned int能储存更多位密码:0~65535
int count = 0;
void main(void)
{
LCD_Init();
LCD_ShowString(1,1,"Pass Word:");
while (1)
{
KeyNum = MatrixKey();
if (KeyNum)//保持KeyNum非零
{
if(KeyNum <= 10)//输入1—10时为密码区
{
if(count < 4)//至多输入四位数的密码
{
InputWord *= 10;//密码左移,即实现从左到右输入密码
//实现输入10变0
//方法一
//if(KeyNum == 10){InputWord = 0};
//方法二
InputWord += KeyNum % 10;
}
count++;//每输入一位数字加一,使输入次数减一
}
if(KeyNum == 11)//确认键
{
//判断正误
if(InputWord == PassWord){LCD_ShowString(1,15,"OK");}
else{LCD_ShowString(1,15,"NO");}
InputWord=0;
count=0;//密码和输入次数置零
}
if(KeyNum == 12)//清空键
{
InputWord = 0;
count = 0;//密码和输入次数置零
LCD_ShowString(1,15," ");//ok和no置零
}
if(KeyNum == 13)//删除键
{
InputWord /= 10;//密码右移
count--;//输入次数加一
}
/*if(KeyNum = 14)//设置密码
{
LCD_ShowString(1,1,"New Pass Word:");
}*/
LCD_ShowNum(2,1,InputWord,4);//将此步骤移到最后,就不用没操作一次就需要更新一次
//但是和设置密码的代码相矛盾
}
}
}