(基于江协科技)51单片机入门:4.矩阵键盘

矩阵键盘

矩阵键盘的本质是利用行列的排序方式去节省银脚

和独立按键没有太大区别

矩阵键盘扫描

和四位一体数码管类似,数码管也是一个数字一个数字的亮灯

矩阵键盘对是否有按键按下的判断也是,一行一行 或 一列一列的进行判断

由于判断的速度过快,给人的感觉是按下就出现相应的效果

1.矩阵键盘联动LDC显示屏

不是矩阵键盘控制LDC显示是,矩阵键盘出现了什么状态导致了,单片机去控制LDC

类比:小明考试考差了,然后改了成绩。不是分数改了成绩,是小明改的成绩

直接对 P1 赋值 FF 各线路都是高电频

对某一列赋值为 0 然后判断每行,一旦发现有一行出现等于0的情况,就能根据行列找到是那个按键被按下

下方为分装出的函数:

cpp 复制代码
// 头文件
#ifndef __key_h_
#define __key_h_

unsigned char key();

#endif

// 源文件
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.H"

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

利用上方函数的返回值,去调用下方江协科技的打印函数就能实现矩阵键盘联动LCD屏的效果

下方为江协科技的LCD1602的源码:

cpp 复制代码
// 头文件
#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
cpp 复制代码
// 源文件
#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');
	}
}

2.矩阵键盘密码锁

利用上文的的矩阵键盘函数返回值进行判断

1:1~10为密码输入按键

2:11为判断判断按键

3:12为删除按键

主体的运行流程:

cpp 复制代码
#include <REGX52.H>
#include "LCD1602.H"
#include "key.h"
#include "Delay.h"

int main()
{
	unsigned char c = 0;			// 接收返回值,暂存返回值 	
	unsigned int a = 2345; 			// 真密码
	unsigned int password =0 ;	    // 密码判定变量
	LCD_Init();
	LCD_ShowString(1,1,"Holle World");
	while(1)
	{
		c = key();
		if(c>0&&c<=10&&password<1000)
		{
			password*=10;
			password+=c%10;
			LCD_ShowNum(2,1,password,4);
		}
		if(c==11)
		{
			if(password == a)
			{
				LCD_ShowString(1,1,"right       ");
				password = 0;
				LCD_ShowNum(2,1,password,4);
			}
			else
			{
				LCD_ShowString(1,1,"lose         ");
				password = 0;
				LCD_ShowNum(2,1,password,4);
			}
		}
		if(c==12)
		{
				password/=10;
				LCD_ShowNum(2,1,password,4);
		}
	}
	return 0;
}
相关推荐
数据超市4 小时前
快速CAD转到PPT的方法,带教程
大数据·python·科技·信息可视化·数据挖掘
TDengine (老段)4 小时前
从细胞工厂到智能制造:Extracellular 用 TDengine 打通数据生命线
java·大数据·数据库·科技·制造·时序数据库·tdengine
YeGop4 小时前
51单片机数码管显示函数分享(8051汇编)
汇编·嵌入式硬件·51单片机
geobuilding10 小时前
Geobuilding模型转换,深圳市科技风贴图建筑物3dtiles倾斜摄影数据
科技
九河云11 小时前
软件开发平台 DevCloud
运维·服务器·数据库·科技·华为云
ken223214 小时前
在被窝里使用笔记本电脑,容易损坏键盘?
计算机外设·电脑
某林21214 小时前
如何使用ROS 2与STM32进行串口通信,并实现通过键盘按键‘1’来控制LED灯开关
stm32·嵌入式硬件·计算机外设
寺中人14 小时前
最新科技早报
科技·早报
hazy1k14 小时前
51单片机基础-PWM、频率与占空比
stm32·单片机·嵌入式硬件·51单片机
程序猿追19 小时前
轻量级云原生体验:在OpenEuler 25.09上快速部署单节点K3s
人工智能·科技·机器学习·unity·游戏引擎