51单片机——矩阵键盘

文章目录

  • 一.矩阵键盘原理图
  • 二.矩阵键盘原理图解析
  • 三.矩阵键盘按下以后显示到LCD1602上的代码
  • 四.矩阵键盘密码锁代码

一.矩阵键盘原理图

51单片机——矩阵键盘_第1张图片
51单片机——矩阵键盘_第2张图片

二.矩阵键盘原理图解析

1.从矩阵键盘原理图可知,矩阵键盘流通方向是图二2.1和2.2的两幅图红线位置,然后总的就是图二的2.3的位置,也就是P17,P16,P15,P14口的经过的按键s1,s5,s9,s11对应的是P13位置,由于按键没有按下,则没有导通,也就是单片机的两个IO口连接,也就是图一,图一蓝色位置为开关,如果IO口里面是VCC的时候,就会跳到VCC的那里,如果是GND则跳到GND的位置,然后另一个IO口则连接起来。
2.单片机IO口默认高电平,所以我们给P17,P16,P15,P14口高电平,P13口低电平,如图三3.1,所以如果按下按键s1的话,就导通,之后会变成图三的3.2。

图一
51单片机——矩阵键盘_第3张图片
图二
2.1
51单片机——矩阵键盘_第4张图片
2.2
51单片机——矩阵键盘_第5张图片
2.3
51单片机——矩阵键盘_第6张图片

图三
3.1
51单片机——矩阵键盘_第7张图片
3.2
51单片机——矩阵键盘_第8张图片

三.矩阵键盘按下以后显示到LCD1602上的代码

Matrix.h

#ifndef __MATRIX_H__
#define __MATRIX_H__

unsigned char MatrixKey(void);

#endif

Matrix.c

#include 
#include "Delay.h"

unsigned char MatrixKey() //矩阵按键函数
{
	unsigned char keynumber=0;
	
	P1=0xFF;
	P1_3=0; //扫描第一列
	if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=1;}//按下松开后,keynumber=1,也就是按了k1
	if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=5;}
	if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=9;}
	if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=13;}
	
	P1=0xFF;
	P1_2=0; //扫描第二列
	if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=2;}
	if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=6;}
	if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=10;}
	if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=14;}
	
	P1=0xFF;
	P1_1=0; //扫描第三列
	if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=3;}
	if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=7;}
	if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=11;}
	if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=15;}
	
	P1=0xFF;
	P1_0=0; //扫描第四列
	if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=4;}
	if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=8;}
	if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=12;}
	if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=16;}
	
	return keynumber;
}

Delay.h

#ifndef __DALAY_H__
#define __DALAY_H__

void Delay1ms(void);
void Delay20ms(void);

#endif

Delay.c

#include 
#include 

void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

void Delay20ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 36;
	j = 217;
	do
	{
		while (--j);
	} while (--i);
}

LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

void LCD_Init(void);
void LCD_Showstring(unsigned char line,unsigned char column,unsigned char *string);
void LCD_Shownum(unsigned char line,unsigned char column,unsigned int number,unsigned char length);

#endif

LCD1602.c

#include 
#include "Delay.h"

#define LCE_Dataport P0

sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;




void LCD_WriteCommand(unsigned char Command)//写指令
{
	LCD_RS=0;
	LCD_RW=0;
	LCE_Dataport=Command;
	LCD_EN=1;
	Delay1ms();
	LCD_EN=0;
	Delay1ms();
}

void LCD_WriteData(unsigned char Data)//写数据
{
	LCD_RS=1;
	LCD_RW=0;
	LCE_Dataport=Data;
	LCD_EN=1;
	Delay1ms();
	LCD_EN=0;
	Delay1ms();
}

void LCD_Init(void)//初始化
{
	LCD_WriteCommand(0x38);
	LCD_WriteCommand(0x0C);
	LCD_WriteCommand(0x06);
	LCD_WriteCommand(0x01);
}

void LCD_Setcursor(unsigned char line,unsigned char column)
{
	if(line==1)//设置光标位置
	{
		//第一列是数字1,但是位置是0x00,要把数字1转换0x00,就把数字1-1就0,所以转十六进制就是0x00
		LCD_WriteCommand(0x80|(column-1));
	}
	else
	{
		//第二行的第一列是从0x40开始,第二列是0x41,相当于0x40+0x01,0x01就是与上面一致
		LCD_WriteCommand(0x80|(column-1)+0x40);
	}
}

void LCD_Showstring(unsigned char line,unsigned char column,unsigned char *string)//line行,column列,string字符串
{//显示字符串,字符串直接等于指针,不用数组形式等于字符串,在等于指针形式,那传给指针的就是字符串的第一个字符的地址,然后string【i】一直往下就可以知道字符串,数组是连续的,如果baby的b在第一行第一列,那a就会在第一行,第二列。
	unsigned char i;
	LCD_Setcursor(line,column);		
	for(i=0;string[i]!='\0';i++)
	{
		LCD_WriteData(string[i]);//字符串本身就是地址,所以传进来的字符串用指针string来接
	}
}

int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

void LCD_Shownum(unsigned char line,unsigned char column,unsigned int number,unsigned char length)
{
	unsigned char i;
	LCD_Setcursor(line,column);	
	for(i=length;i>0;i--)
	{
		LCD_WriteData('0'+number/LCD_Pow(10,i-1) %10);
	}
}

main.c

#include 
#include "LCD1602.h"
#include "Matrix.h"

unsigned char keynum;

void main()
{
	LCD_Init();
	while(1)
	{
		keynum=MatrixKey();//定义变量keynum接收MatrixKey();的返回值
		LCD_Showstring(1,1,"hello");
	//这里必须加if语句,因为不加的话,假如按下按键1,while循环第一次循环,返回1,但是while执行的很快,
	//第二次在进入while的时候检测没有按下按键,由于设置keynumber=0,所以会返回0,然后就会显示0,无论怎么按,肉眼无法观察,
	//加了if以后,keynumber=0时,无法进入if语句,因为if要真的才能进去,非0即真,0假
		if(keynum)
		{
			LCD_Shownum(2,1,keynum,2);
		}
	}
}


四.矩阵键盘密码锁代码

Matrix.h

#ifndef __MATRIX_H__
#define __MATRIX_H__

unsigned char MatrixKey(void);

#endif

Matrix.c

#include 
#include "Delay.h"

unsigned char MatrixKey() //矩阵按键函数
{
	unsigned char keynumber=0;
	
	P1=0xFF;
	P1_3=0; //扫描第一列
	if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=1;}//按下松开后,keynumber=1,也就是按了k1
	if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=5;}
	if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=9;}
	if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=13;}
	
	P1=0xFF;
	P1_2=0; //扫描第二列
	if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=2;}
	if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=6;}
	if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=10;}
	if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=14;}
	
	P1=0xFF;
	P1_1=0; //扫描第三列
	if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=3;}
	if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=7;}
	if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=11;}
	if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=15;}
	
	P1=0xFF;
	P1_0=0; //扫描第四列
	if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=4;}
	if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=8;}
	if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=12;}
	if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=16;}
	
	return keynumber;
}

Delay.h

#ifndef __DALAY_H__
#define __DALAY_H__

void Delay1ms(void);
void Delay20ms(void);

#endif

Delay.c

#include 
#include 

void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

void Delay20ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 36;
	j = 217;
	do
	{
		while (--j);
	} while (--i);
}

LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__

void LCD_Init(void);
void LCD_Showstring(unsigned char line,unsigned char column,unsigned char *string);
void LCD_Shownum(unsigned char line,unsigned char column,unsigned int number,unsigned char length);

#endif

LCD1602.c

#include 
#include "Delay.h"

#define LCE_Dataport P0

sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;




void LCD_WriteCommand(unsigned char Command)//写指令
{
	LCD_RS=0;
	LCD_RW=0;
	LCE_Dataport=Command;
	LCD_EN=1;
	Delay1ms();
	LCD_EN=0;
	Delay1ms();
}

void LCD_WriteData(unsigned char Data)//写数据
{
	LCD_RS=1;
	LCD_RW=0;
	LCE_Dataport=Data;
	LCD_EN=1;
	Delay1ms();
	LCD_EN=0;
	Delay1ms();
}

void LCD_Init(void)//初始化
{
	LCD_WriteCommand(0x38);
	LCD_WriteCommand(0x0C);
	LCD_WriteCommand(0x06);
	LCD_WriteCommand(0x01);
}

void LCD_Setcursor(unsigned char line,unsigned char column)
{
	if(line==1)//设置光标位置
	{
		//第一列是数字1,但是位置是0x00,要把数字1转换0x00,就把数字1-1就0,所以转十六进制就是0x00
		LCD_WriteCommand(0x80|(column-1));
	}
	else
	{
		//第二行的第一列是从0x40开始,第二列是0x41,相当于0x40+0x01,0x01就是与上面一致
		LCD_WriteCommand(0x80|(column-1)+0x40);
	}
}

void LCD_Showstring(unsigned char line,unsigned char column,unsigned char *string)//line行,column列,string字符串
{//显示字符串,字符串直接等于指针,不用数组形式等于字符串,在等于指针形式,那传给指针的就是字符串的第一个字符的地址,然后string【i】一直往下就可以知道字符串,数组是连续的,如果baby的b在第一行第一列,那a就会在第一行,第二列。
	unsigned char i;
	LCD_Setcursor(line,column);		
	for(i=0;string[i]!='\0';i++)
	{
		LCD_WriteData(string[i]);//字符串本身就是地址,所以传进来的字符串用指针string来接
	}
}

int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

void LCD_Shownum(unsigned char line,unsigned char column,unsigned int number,unsigned char length)
{
	unsigned char i;
	LCD_Setcursor(line,column);	
	for(i=length;i>0;i--)
	{
		LCD_WriteData('0'+number/LCD_Pow(10,i-1) %10);
	}
}

main.c

#include 
#include "LCD1602.h"
#include "Matrix.h"

unsigned char keynum;
unsigned int password,count;

void main()
{
	LCD_Init();
	while(1)
	{
		keynum=MatrixKey();//定义变量keynum接收MatrixKey();的返回值
		LCD_Showstring(1,1,"password:");
	//这里必须加if语句,因为不加的话,假如按下按键1,while循环第一次循环,返回1,但是while执行的很快,
	//第二次在进入while的时候检测没有按下按键,由于设置keynumber=0,所以会返回0,然后就会显示0,无论怎么按,肉眼无法观察,
	//加了if以后,keynumber=0时,无法进入if语句,因为if要真的才能进去,非0即真,0假
		if(keynum)
		{
			if(keynum<=10) 							//如果s1-s10按键按下,代表输入密码
			{
				if(count<4)								//输入次数小于4
				{
					password*=10; 					//密码从右边开始输入完一位就向左移一位就会大10倍,所以这里是向左移一位
					password+=keynum%10;  	//s1-s9取余就是1—9,s10取余就是0,所以s1-s9对应数字9,s10对应0,
				}
				
				count++;									//记录按下按键次数
				LCD_Shownum(2,1,password,4);//显示密码四位
			}
			if(keynum==11)		//确认键
			{
				if(password==0x7B) //正确密码0123,0开头的密码会被表示成八进制,而不是十进制的0123,所以我们写密码,写十六进制就可以了
				{
					LCD_Showstring(1,14,"OK "); //输入成功,这里的ok后面需要加一个空格,因为输入错误以后的r会留下
					password=0;								//密码清0
					count=0;									//按键次数清0
					LCD_Shownum(2,1,password,4);//显示密码四位
				}
				else							//错误密码
				{
					LCD_Showstring(1,14,"ERR"); //输入失败
					password=0;								//密码清0
					count=0;									//按键次数清0
					LCD_Shownum(2,1,password,4);//显示密码四位
				}
			
			}
			if(keynum==12) 					//取消键
				{
					password=0;								//密码清0
					count=0;									//按键次数清0
					LCD_Shownum(2,1,password,4);//显示密码四位
					LCD_Showstring(1,14,"    ");//四个空格来取消掉之前写的err和ok
				}
			if(keynum==13)					//密码退位键
			{
				password/=10;
				count--;
				LCD_Shownum(2,1,password,4);//显示密码四位
			}
		}
	}
}



你可能感兴趣的:(51单片机,矩阵,计算机外设)