写在前面:
本节的主要内容是同矩阵键盘与LCD1602液晶屏联系,实现按键的数值显示,以及按键电子锁小项目。需要源码直接转至:三、代码分享;
目录
一、硬件部分
1.1矩阵按键
1.2LCD1602液晶显示屏幕
二、原理图
2.1矩阵按键模块
2.2单片机核心模块
三、 代码分享
3.1矩阵按键的数值显示
3.2矩阵按键实现电子锁项目;
总结
实验介绍:利用51单片机的矩阵按键模块以及LCD1602液晶屏幕显示模块,实现矩阵键盘的控制显示等;包括:电路分析、源码分享以及电子锁项目的讲解;通过此节学习熟悉51单片机的相关模块理解,加深对电路分析,扫描概念的理解,相关C语言程序的理解与学习;
实验设备:普中51-实验开发板
实验目录:
1、矩阵按键的数值显示;
2、矩阵按键实现电子锁项目;
矩阵按键是单片机外部设备中所使用的排布类似于矩阵的键盘组。在前面我们讲解过普通的独立按键模块;矩阵键盘可以看作是独立按键的一种升级,因为独立按键中一个按键需要一个I/O进行输入输出,当按键的数量增多时,I/O的数量也随之需要增多;矩阵键盘通过将多数按键进行矩阵排列,从而实现利用较少的IO口控制较多的按键;
矩阵键盘的组成结构:为了减少I/O口的占用,通常将按键排成矩阵形式;在矩阵键盘中,每一条水平线与垂直线在交叉处通过一个按键进行连接,这样(4×4=16)的矩阵键盘只需要通过8个接口就可以实现控制;下图为矩阵键盘的实物图;
LCD1602液晶显示屏幕主要用于矩阵键盘的测试;矩阵键盘的输出显示将在LCD1602上面进行显示;对于LCD1602液晶显示模块感兴趣的朋友可参考我前面对1602的博客;
51单片机--LCD1602显示自定义字符、HD44780驱动(含源码、含驱动程序、含指令集讲解)!!!好文推荐!-CSDN博客
矩阵按键与LCD1602液晶显示屏幕在开发板上的位置如下图所示:
下图为普中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,进行第四列扫描;
下图为单片机的核心模块电路图,用到的引脚是红色框选的部分,与矩阵按键模块相连;
项目说明:按下一个按键后,在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
//引脚配置:
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;
}
实验现象:
按键显示数据
项目说明:初设一个四位数字的密码,进行矩阵键盘按键输入,按键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
//引脚配置:
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屏幕相结合,进行串联。大家在看完博客后,一定要动手自己进行联系!!!
创作不易,还请大家多多点赞,收藏支持~!!!