写在前面:

        本节的主要内容是同矩阵键盘与LCD1602液晶屏联系,实现按键的数值显示,以及按键电子锁小项目。需要源码直接转至:三、代码分享

目录

一、硬件部分

1.1矩阵按键        

1.2LCD1602液晶显示屏幕         

二、原理图

2.1矩阵按键模块

2.2单片机核心模块

三、 代码分享

  3.1矩阵按键的数值显示   

 3.2矩阵按键实现电子锁项目;

        总结

实验介绍:利用51单片机的矩阵按键模块以及LCD1602液晶屏幕显示模块,实现矩阵键盘的控制显示等;包括:电路分析、源码分享以及电子锁项目的讲解;通过此节学习熟悉51单片机的相关模块理解,加深对电路分析,扫描概念的理解,相关C语言程序的理解与学习;

实验设备:普中51-实验开发板

实验目录

1、矩阵按键的数值显示;

2、矩阵按键实现电子锁项目;

一、硬件部分

1.1矩阵按键        

       矩阵按键是单片机外部设备中所使用的排布类似于矩阵的键盘组。在前面我们讲解过普通的独立按键模块;矩阵键盘可以看作是独立按键的一种升级,因为独立按键中一个按键需要一个I/O进行输入输出,当按键的数量增多时,I/O的数量也随之需要增多;矩阵键盘通过将多数按键进行矩阵排列,从而实现利用较少的IO口控制较多的按键

        矩阵键盘的组成结构:为了减少I/O口的占用,通常将按键排成矩阵形式;在矩阵键盘中,每一条水平线与垂直线在交叉处通过一个按键进行连接,这样(4×4=16)的矩阵键盘只需要通过8个接口就可以实现控制;下图为矩阵键盘的实物图;

1.2LCD1602液晶显示屏幕         

        LCD1602液晶显示屏幕主要用于矩阵键盘的测试;矩阵键盘的输出显示将在LCD1602上面进行显示;对于LCD1602液晶显示模块感兴趣的朋友可参考我前面对1602的博客;

51单片机--LCD1602显示自定义字符、HD44780驱动(含源码、含驱动程序、含指令集讲解)!!!好文推荐!-CSDN博客

        矩阵按键与LCD1602液晶显示屏幕在开发板上的位置如下图所示:

二、原理图

2.1矩阵按键模块

        下图为普中51实验板的矩阵按键模块的电路图,图中共有16个(4行、4列)的按键;通过8个(P10-P17)端口进行控制;例如:当S1按键按下时;P17与P13端口处于短路状态;基于矩阵按键模块自身特有的特点,我们引入扫描的概念;

扫描:

1、数码管的显示:在数码管的动态显示部分,我们讲述同时显示两位以及以上的数码管时,采用的方式是:显示第一位--->显示第二位--->显示第三位.....然后快速进行循环;达到肉眼无法分辨的速度,即可实现同时显示;

2、矩阵按键模块:读取第一行(列)--->读取第二行(列)--->读取第三行(列)......然后快速进行循环;矩阵按键的扫描一共有两种扫描方式,分别是行扫描以及列扫描;

        可能上述对于矩阵键盘的扫描还解释的不够清楚;下面我将通过举例进一步说明: 

采用逐行扫描先令P17、P16、P15、P14引脚为0111,进行第一行(S1、S2、S3、S4)的扫描,对P13、P12、P11、P10引脚进行检测;若其中有0或低电平,则说明对应的按键按下;(如:检测到P13为低电平,则说明S1按键被按下);

再令P17、P16、P15、P14引脚为1011,进行第二行(S4、S5、S6、S7)的扫描,对P13、P12、P11、P10引脚进行检测;若其中有0或低电平,则说明对应的按键按下;

再令P17、P16、P15、P14引脚为1101,进行第三行扫描;

再令P17、P16、P15、P14引脚为1110,进行第四行扫描;

 采用逐列扫描:先令P13、P12、P11、P10引脚为0111,进行第一列(S1、S5、S9、S13)的扫描,对P17、P16、P15、P14引脚进行检测;若其中有0或低电平,则说明对应的按键按下;(如:检测到P14为低电平,则说明S13按键被按下);

先令P13、P12、P11、P10引脚为1011,进行第二列(S2、S6、S10、S14)的扫描,对P17、P16、P15、P14引脚进行检测;若其中有0或低电平,则说明对应的按键按下;

再令P13、P12、P11、P10引脚为1101,进行第三列扫描;

再令P13、P12、P11、P10引脚为1110,进行第四列扫描;

2.2单片机核心模块

下图为单片机的核心模块电路图,用到的引脚是红色框选的部分,与矩阵按键模块相连;

三、 代码分享

  3.1矩阵按键的数值显示   

项目说明:按下一个按键后,在LCD1602上显示按键的数字;

代码分享:

main.c文件

 #include "LCD1602.h"//包含驱动程序头文件
 unsigned keyword;//定义变量
	void main()//定义主函数
	{
		LCD_Init();//LCD1602进行初始化
	while(1)//程序循环
	    {
		keyword=MatriKey();//调用判断按键是否按下的函数,返回值为按键数
	   	if(keyword)//判断是否有按键按下
	    LCD_ShowNumber(1,1,keyword,2);//如果有按键按下,在屏幕上显示按下的按键
	    }
	}

LCD1602.h文件

 #include "LCD1602.c"//包含驱动程序
void LCD_Init();//LCD1602初始化声明
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);//LCD1602显示字符串函数声明;
void unsigned char MatriKey();//LCD1602显示自定义字符函数声明;
void LCD_ShowNumber(unsigned char Line,unsigned char Column,unsigned int  number,unsigned char length);//LCD1602显示十进制数字函数声明

LCD1602.c文件(驱动程序)

 #include <REGX52.H>	
	
  //引脚配置:
sbit LCD_RS=P2^6;	//   RS引脚为数据/指令选择   1为数据,0为指令
sbit LCD_RW=P2^5;	//   RW引脚为读/写选择       1为读,0为写
sbit LCD_EN=P2^7;	//   EN引脚为使能            1为数据有效,下降沿执行命令
#define LCD_DataPort P0	 //定义P0引脚为数据端口



 //延迟函数的定义;LCD1602延时函数,12MHz调用可延时xms;
void LCD_Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;

   while(xms--)
   {
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
}


//写指令函数定义:  LCD1602写指令函数
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;//选择为指令,1为数据,0为指令
	LCD_RW=0;//选择为写, 1为读,0为写
	LCD_DataPort=Command;//写入指令的内容
	LCD_EN=1;	  //使能脚E先上升沿写入
	LCD_Delay(1);
	LCD_EN=0;	 //使能脚E后负跳变完成写入
	LCD_Delay(1);
}



// 写数据函数定义:  LCD1602写数据函数
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1; //选择为数据,1为数据,0为指令
	LCD_RW=0; //选择为写, 1为读,0为写
	LCD_DataPort=Data;//写入指数据的内容
	LCD_EN=1;	 //使能脚E先上升沿写入
	LCD_Delay(1);
	LCD_EN=0;  	 //使能脚E后负跳变完成写入
	LCD_Delay(1);
}


 //初始化函数定义:	LCD1602屏幕初始化
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}


 //LCD1602 进行清屏
 void LCD_clear()
 {
 		LCD_WriteCommand(0x01);
 }
 
//设置光标位置
void LCD_SetCursor(unsigned char Line,unsigned char Column)//(行数1-2,列数1-16)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}



 //  字符串函数定义:   LCD1602显示字符串
  void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);

	}
}



//  字符数字函数定义:   LCD1602显示十进制数字

int Pow(int x,int y)
{
	unsigned char i;
	int result = 1;
	for(i = 0; i < y; i++)
	{
		result *= x;
	}
	return result;
}

void LCD_ShowNumber(unsigned char Line,unsigned char Column,unsigned int  number,unsigned char length)
{
	unsigned char i;
	unsigned char temp;
	LCD_SetCursor(Line,Column);
	for(i =length ; i > 0 ; i--)
	{
		temp = number/Pow(10,i-1)%10 + '0';	//循环将每一位都提取出来并转换为字符
		LCD_WriteData(temp);
	}
}





//判断按键按下的键数
unsigned char MatriKey()
{
unsigned char KeyNumber=0;//定义变量,利用此变量存放按键按下的键数
//进行行扫描	
    P1=0XFF;
	P1_7=0;//进行第一行判断
	if(P1_3==0)  {LCD_Delay(20);while(P1_3==0);LCD_Delay(20);KeyNumber=1;}
	if(P1_2==0)  {LCD_Delay(20);while(P1_2==0);LCD_Delay(20);KeyNumber=2;}
	if(P1_1==0)  {LCD_Delay(20);while(P1_1==0);LCD_Delay(20);KeyNumber=3;}
	if(P1_0==0)  {LCD_Delay(20);while(P1_0==0);LCD_Delay(20);KeyNumber=4;}
	P1=0XFF;
    P1_6=0;//进行第一行判断
	if(P1_3==0)  {LCD_Delay(20);while(P1_3==0);LCD_Delay(20);KeyNumber=5;}
	if(P1_2==0)  {LCD_Delay(20);while(P1_2==0);LCD_Delay(20);KeyNumber=6;}
	if(P1_1==0)  {LCD_Delay(20);while(P1_1==0);LCD_Delay(20);KeyNumber=7;}
	if(P1_0==0)  {LCD_Delay(20);while(P1_0==0);LCD_Delay(20);KeyNumber=8;}
	P1=0XFF;
	P1_5=0;//进行第二行判断
	if(P1_3==0)  {LCD_Delay(20);while(P1_3==0);LCD_Delay(20);KeyNumber=9;}
	if(P1_2==0)  {LCD_Delay(20);while(P1_2==0);LCD_Delay(20);KeyNumber=10;}
	if(P1_1==0)  {LCD_Delay(20);while(P1_1==0);LCD_Delay(20);KeyNumber=11;}
	if(P1_0==0)  {LCD_Delay(20);while(P1_0==0);LCD_Delay(20);KeyNumber=12;}
	P1=0XFF;
	P1_4=0;//进行第三行判断
	if(P1_3==0)  {LCD_Delay(20);while(P1_3==0);LCD_Delay(20);KeyNumber=13;}
	if(P1_2==0)  {LCD_Delay(20);while(P1_2==0);LCD_Delay(20);KeyNumber=14;}
	if(P1_1==0)  {LCD_Delay(20);while(P1_1==0);LCD_Delay(20);KeyNumber=15;}
	if(P1_0==0)  {LCD_Delay(20);while(P1_0==0);LCD_Delay(20);KeyNumber=16;}
	return KeyNumber;//返回被按下的按键数,如没有被按下,则返回值为0;
}
	






实验现象: 

按键显示数据

 3.2矩阵按键实现电子锁项目;

项目说明:初设一个四位数字的密码,进行矩阵键盘按键输入,按键S1-S9分别表示数字(1-9),S10表示数字0,S11表示确认键,按下后进行与设定密码对比;S12表示清零,重新输入;S13表示,清除一位,重新输入;

代码分享:

main.c文件

 #include "LCD1602.h"//包含驱动函数头文件
 unsigned  char keyword,count;定义变量,变量1:按键返回值,变量2:按键按下次数
 unsigned  int  password;//定义变量,用于设定初始密码;

	void main()//定义主函数
	{
		LCD_Init();//LCD1206屏幕初始化;
	    LCD_ShowString(1,1,"mima");//屏幕第一行显示字符串“mima”
		LCD_ShowNumber(2,1,0,4);//屏幕第二行初始化,初始显示0000
		
    	while(1)程序循环
	    {
	    	 keyword=MatriKey();变量2进行复制,按下按键赋按键值,未按下按键赋0
		      if(keyword)//判断是否按下按键
		        {
						if(keyword<=10)判断按键的数值是否在1-9
						{
						    if(count<4)//判断按键次数,是否超过4位密码
					    	{
                                //未超过4位数
						    	password*=10。。//进行左移
					    		password+= keyword%10;//取余后补充到最后一位
					    		count++;//次数加1
					      	}
					     }	
				LCD_ShowNumber(2,1,password,4);//更新后显示
			

				    	if(keyword==11)//按下key11,进行判断,与初始密码做判断
					     {
					       if(password==1022)
						    {	
                                //判断正确
                                LCD_ShowString(1,1,"Ture ");//显示字符“ture”
								LCD_ShowNumber(2,1,password,4);//显示正确密码1022
                            }
				            else
					            //判断错误
                             {
						         LCD_ShowString(1,1,"Error");//显示字符“Error”
							     password=0;
							     count=0;
						         LCD_ShowNumber(2,1,password,4);
							  }
				            }
					
	
                        	if(keyword==12)//按下按键12进行全部输入清零
	                    	{
			                	password=0;
						        count=0;
				                LCD_ShowNumber(2,1,password,4);
		                    }
		
		
		                	if(keyword==13)//按下按键13进行清除1位(即右移一位)
		                      {
				                if(count>0)
				    		    {
						        	password/=10;
						        	count--;
					           	}
								LCD_ShowNumber(2,1,password,4);
			                  }	
	              }		
		}
				
	}

	

LCD1602.h文件(与3.1节相同)

 #include "LCD1602.c"
void LCD_Init();	
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void unsigned char MatriKey();
void LCD_ShowNumber(unsigned char Line,unsigned char Column,unsigned int  number,unsigned char length);

LCD1602.c文件(与3.1节相同)

 #include <REGX52.H>	
	
		  //引脚配置:
sbit LCD_RS=P2^6;	//   RS引脚为数据/指令选择   1为数据,0为指令
sbit LCD_RW=P2^5;	//   RW引脚为读/写选择       1为读,0为写
sbit LCD_EN=P2^7;	//   EN引脚为使能            1为数据有效,下降沿执行命令
#define LCD_DataPort P0	 //定义P0引脚为数据端口



 //延迟函数的定义;LCD1602延时函数,12MHz调用可延时xms;
void LCD_Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;

   while(xms--)
   {
	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
}


//写指令函数定义:  LCD1602写指令函数
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;//选择为指令,1为数据,0为指令
	LCD_RW=0;//选择为写, 1为读,0为写
	LCD_DataPort=Command;//写入指令的内容
	LCD_EN=1;	  //使能脚E先上升沿写入
	LCD_Delay(1);
	LCD_EN=0;	 //使能脚E后负跳变完成写入
	LCD_Delay(1);
}



// 写数据函数定义:  LCD1602写数据函数
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1; //选择为数据,1为数据,0为指令
	LCD_RW=0; //选择为写, 1为读,0为写
	LCD_DataPort=Data;//写入指数据的内容
	LCD_EN=1;	 //使能脚E先上升沿写入
	LCD_Delay(1);
	LCD_EN=0;  	 //使能脚E后负跳变完成写入
	LCD_Delay(1);
}


 //初始化函数定义:	LCD1602屏幕初始化
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}


 //LCD1602 进行清屏
 void LCD_clear()
 {
 		LCD_WriteCommand(0x01);
 }
 
//设置光标位置
void LCD_SetCursor(unsigned char Line,unsigned char Column)//(行数1-2,列数1-16)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}



 //  字符串函数定义:   LCD1602显示字符串
  void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);

	}
}



//  字符数字函数定义:   LCD1602显示数字


int Pow(int x,int y)
{
	unsigned char i;
	int result = 1;
	for(i = 0; i < y; i++)
	{
		result *= x;
	}
	return result;
}

  void LCD_ShowNumber(unsigned char Line,unsigned char Column,unsigned int  number,unsigned char length)
{
	unsigned char i;
	unsigned char temp;
	LCD_SetCursor(Line,Column);
	for(i =length ; i > 0 ; i--)
	{
		temp = number/Pow(10,i-1)%10 + '0';	//循环将每一位都提取出来并转换为字符
		LCD_WriteData(temp);
	}
}






unsigned char MatriKey()
{
unsigned char KeyNumber=0;
	P1=0XFF;
	P1_7=0;
	if(P1_3==0)  {LCD_Delay(20);while(P1_3==0);LCD_Delay(20);KeyNumber=1;}
	if(P1_2==0)  {LCD_Delay(20);while(P1_2==0);LCD_Delay(20);KeyNumber=2;}
	if(P1_1==0)  {LCD_Delay(20);while(P1_1==0);LCD_Delay(20);KeyNumber=3;}
	if(P1_0==0)  {LCD_Delay(20);while(P1_0==0);LCD_Delay(20);KeyNumber=4;}
		P1=0XFF;
	P1_6=0;
	if(P1_3==0)  {LCD_Delay(20);while(P1_3==0);LCD_Delay(20);KeyNumber=5;}
	if(P1_2==0)  {LCD_Delay(20);while(P1_2==0);LCD_Delay(20);KeyNumber=6;}
	if(P1_1==0)  {LCD_Delay(20);while(P1_1==0);LCD_Delay(20);KeyNumber=7;}
	if(P1_0==0)  {LCD_Delay(20);while(P1_0==0);LCD_Delay(20);KeyNumber=8;}
		P1=0XFF;
	P1_5=0;
	if(P1_3==0)  {LCD_Delay(20);while(P1_3==0);LCD_Delay(20);KeyNumber=9;}
	if(P1_2==0)  {LCD_Delay(20);while(P1_2==0);LCD_Delay(20);KeyNumber=10;}
	if(P1_1==0)  {LCD_Delay(20);while(P1_1==0);LCD_Delay(20);KeyNumber=11;}
	if(P1_0==0)  {LCD_Delay(20);while(P1_0==0);LCD_Delay(20);KeyNumber=12;}
		P1=0XFF;
	P1_4=0;
	if(P1_3==0)  {LCD_Delay(20);while(P1_3==0);LCD_Delay(20);KeyNumber=13;}
	if(P1_2==0)  {LCD_Delay(20);while(P1_2==0);LCD_Delay(20);KeyNumber=14;}
	if(P1_1==0)  {LCD_Delay(20);while(P1_1==0);LCD_Delay(20);KeyNumber=15;}
	if(P1_0==0)  {LCD_Delay(20);while(P1_0==0);LCD_Delay(20);KeyNumber=16;}
	return KeyNumber;
}

实验现象:

矩阵键盘密码锁

 四、总结:

        本节的内容主要是学习的是51单片机开发板的矩阵键盘的内容,主要的难点在于同LCD1602屏幕相结合,进行串联。大家在看完博客后,一定要动手自己进行联系!!!

        创作不易,还请大家多多点赞,收藏支持~!!!

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐