51单片机学习记录——矩阵按键的使用

本文介绍了使用LCD1402液晶显示屏和矩阵按键的编程实践,包括模块化编程的应用、LCD1402的基本操作函数和矩阵按键的扫描原理。作者还分享了在VSCode中配置Keil5环境的过程,并实现了一个简单的矩阵按键密码锁示例。
摘要由CSDN通过智能技术生成

前言

LCD1402的使用

矩阵按键

矩阵按键的介绍       

矩阵按键的使用

 矩阵按键测试

 矩阵按键密码小样例

今日所遇问题

 总结


前言

        今天将之前所写的延时函数以及进行了模块化编程处理,使得在以后需要再次使用的时候只需要复制代码后加上一个头文件直接使用即可,并且了解了部分LCD1402的使用方法,目前不去深究其原理,只需要了解如何在LCD上面显示最终可以用来调试自己的代码方便得多,其次,我在vscode上面部署了keil5的环境配置,vscode上面写代码会方便很多,下面附上大佬的vscode部署keil5的教程:

VS Code编写Keil uVison 5工程_vs keil-CSDN博客文章浏览阅读1.1w次,点赞39次,收藏92次。VS Code编写Keil uVison 5工程写在前面实现的功能和暂时不能做的工作准备工作KeilVS Code下载过程VS Code插件的安装Keil Assistant的使用如何添加Keil工程功能展示写在前面我可能写的比较多,但只是为了更加清楚,整个过程真的非常简单由于不喜欢的Keil的编程界面和颜色(自己搭的不满意),很喜欢VS Code的编程界面和语法高亮等功能,所以想用VS Code编辑Keil工程文件,搭建环境这些又比较复杂,所以找到一个偷懒的方式,那就是使用大神开发的VS Code的_vs keilhttps://blog.csdn.net/weixin_43576926/article/details/107736692?ops_request_misc=&request_id=&biz_id=102&utm_term=vscode%20keilv5&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-2-107736692.142%5Ev99%5Epc_search_result_base9&spm=1018.2226.3001.4187然后对矩阵键盘进行了学习,完成了一个密码锁的小功能,那我们开始今天的记录吧。

LCD1402的使用

        学过c语言的同学都知道模块化编程所带来的便利性,所以我直接提供LCD1402的头文件以及使用源码,大家可以复制直接使用,main函数是测试代码,大家也可以跟着试一下,.c文中的注释有其各个函数的使用方法,实在不懂可以去翻看江科大的教学视频。

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
void main()
{
	LCD_Init();
	LCD_ShowChar(1,1,'A');
	LCD_ShowString(1,3,"Hello");
	LCD_ShowNum(1,9,123,3);
	LCD_ShowSignedNum(1,13,-66,2);
	LCD_ShowHexNum(2,1,0xAB,2);
	LCD_ShowBinNum(2,3,0xAA,8);
	while(1)
	{
	
	}
}

其中LCD1402.c的头文件的代码如下所示:

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

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

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

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

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
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]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
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(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(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(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

其中LCD1402.c的头文件的代码如下所示:

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

矩阵按键

矩阵按键的介绍       

        在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,其采用了逐行和逐列的“扫描”来判断矩阵按键是否被按下,相比独立按键来说,节省的I/O口真的很多,假如有100个按键,使用独立按键的话需要100个I/O口,而采用矩阵键盘的方式的话只需要10+10=20个,所以矩阵键盘带来的优势还是很明显的,其设计图如下所示:

矩阵按键的使用

        由设计图可知,当P1_7和P1_3同时为0的时候,才能够判断S1被按下,其余16个按键的判断是否被按下的方式都时差不多的,因为学习了模块化编程,所以将按键的使用包装起来,其头文件和源码如下所示:

#ifndef __MATRIKEY_H__
#define __MATRIKEY_H__


#endif
#include <REGX52.H>
#include "Delay.h"

/*
    矩阵按键读取按键建码
    如果按键按下不放,程序会停留在此函数,松手一瞬间,返回按键按码,没用按键按下时返回0
*/
unsigned char MatrixKey()
{
    unsigned char KeyNumber = 0;
    P1 = 0xFF;
    P1_3 = 0;
    if (P1_7 == 0){Delay(20);while(P1_7 == 0);Delay(20);KeyNumber = 1;}
    if (P1_6 == 0){Delay(20);while(P1_6 == 0);Delay(20);KeyNumber = 5;}
    if (P1_5 == 0){Delay(20);while(P1_5 == 0);Delay(20);KeyNumber = 9;}
    if (P1_4 == 0){Delay(20);while(P1_4 == 0);Delay(20);KeyNumber = 13;}
  
    P1 = 0xFF;
    P1_2 = 0;
    if (P1_7 == 0){Delay(20);while(P1_7 == 0);Delay(20);KeyNumber = 2;}
    if (P1_6 == 0){Delay(20);while(P1_6 == 0);Delay(20);KeyNumber = 6;}
    if (P1_5 == 0){Delay(20);while(P1_5 == 0);Delay(20);KeyNumber = 10;}
    if (P1_4 == 0){Delay(20);while(P1_4 == 0);Delay(20);KeyNumber = 14;}

    P1 = 0xFF;
    P1_1 = 0;
    if (P1_7 == 0){Delay(20);while(P1_7 == 0);Delay(20);KeyNumber = 3;}
    if (P1_6 == 0){Delay(20);while(P1_6 == 0);Delay(20);KeyNumber = 7;}
    if (P1_5 == 0){Delay(20);while(P1_5 == 0);Delay(20);KeyNumber = 11;}
    if (P1_4 == 0){Delay(20);while(P1_4 == 0);Delay(20);KeyNumber = 15;}

    P1 = 0xFF;
    P1_0 = 0;
    if (P1_7 == 0){Delay(20);while(P1_7 == 0);Delay(20);KeyNumber = 4;}
    if (P1_6 == 0){Delay(20);while(P1_6 == 0);Delay(20);KeyNumber = 8;}
    if (P1_5 == 0){Delay(20);while(P1_5 == 0);Delay(20);KeyNumber = 12;}
    if (P1_4 == 0){Delay(20);while(P1_4 == 0);Delay(20);KeyNumber = 16;}    
    


    return KeyNumber;
}

其功能是按下第几个键就返回哪个值,以后在main函数中设置一个变量来接收返回值并判断值是几就可以判断按下的是什么键,基本知识大概就是这样。

 矩阵按键测试

        在了解完矩阵按键的使用,我们就可以在main函数中测试我们所写的函数了,其功能是安县哪个键就在LCD1402上面显示,将代码下载到板子上面发现,功能一切正常,其代码如下所示:

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatriKey.h"

unsigned char KeyNum;
int main()
{
		LCD_Init();
		LCD_ShowString(1,1,"MatriKey");
		while(1)
		{
			KeyNum=MatrixKey();
			if(KeyNum)
			{
				LCD_ShowNum(2,1,KeyNum,2);
			}	
		}
}

演示视频如下:

矩阵按键测试

 矩阵按键密码小样例

        现在进行对上述学习的东西进行一个混合练习,在main函数中设置好代码,如果如果输入的密码错误,就在LCD1402上面显示ERR,正确就显示OK,S1-S9分别表示1-9,S10控制的是0,S11和S12分别控制确定和取消,演示视频如下:

矩阵按键密码锁

代码如下:

        

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatriKey.h"

unsigned char KeyNum;
unsigned int Password,count;
int main()
{
		LCD_Init();
		LCD_ShowString(1,1,"Password:");
		while(1)
		{
			KeyNum=MatrixKey();
			if(KeyNum)
			{
				if(KeyNum<=10)//如果按下的键为1-10才显示
				{
					if(count<4)//如果输入次数小于4才加入密码
					{
						Password*=10;
						Password+=KeyNum%10;
						count++;
					}
				}
				LCD_ShowNum(2,1,Password,4);//更新显示
			}
			if(KeyNum==11)//如果按下s11按键表示确认密码
			{
				if(Password==2345){//如果密码等于2345 显示ok
					LCD_ShowString(1,14,"OK ");
					Password=0;
					count=0;
					LCD_ShowNum(2,1,Password,4);//更新显示

				}
				else//如果密码不等于2345 显示error
				{
					LCD_ShowString(1,14,"ERR");
					Password=0;
					count=0;
					LCD_ShowNum(2,1,Password,4);//更新显示
				}
			}
			if (KeyNum==12)//如果s12按下,直接取消
			{
				Password=0;
				count=0;
				LCD_ShowNum(2,1,Password,4);//更新显示
			}
				
		}
}

今日所遇问题

        1.在使用vscode编写代码后,确实方便了不少,但是在编写了代码之后得点击rebuild才能够下载到板子上面,不然电脑会一直搜索目标板,导致下载不成功;

        2.显示OK后代码,之前的ERR的最后一个R依然会显现,最终在OK后面加上一个空格去取代就可以;

   3.有些错误实在复制代码之后忘记改参数而引起的,比如在判断按键扫描的时候,忘记将P_3改为P_2,导致第二排按键失效,所以以后得好好注意这个问题。

 总结

        今天学习了LCD1402的使用,但是还没有学习到其原理等,后续还得好好学,其实用性还蛮不错的,通过对其的显示也创造出了一些有趣的东西,矩阵按键基于其巧妙的设计肯定是以后会经常用的,而且我觉得这个密码小项目还有值得优化修改的部分,以后肯定会慢慢优化,添加一些功能,就当对矩阵按键的练习了。

  • 25
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值