单片机之矩阵键盘

介绍

在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式
采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态

 

 扫描的概念

数码管扫描(输出扫描)

原理:显示第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);//将此步骤移到最后,就不用没操作一次就需要更新一次
                                         //但是和设置密码的代码相矛盾
		}
	}
}

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值