【蓝桥杯单片机入门记录】矩阵键盘

一、矩阵键盘的工作原理

(1)矩阵键盘概述

  • 矩阵键盘是单片机外部设备中所使用的排布类似于矩阵的键盘组。(内部实际走线为矩阵,外形一般表现为矩阵)

(2)组成结构

  • 在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。
  • 这样,一个端口(如P1口)就可以构成4*4=16个按键,比直接将端口线用于键盘多出了一杯,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的
  • 内部实际走线为矩阵,外形一般表现为矩阵

(3)识别方法

  • 当按键没有按下时,所有的输入端都是高电平,代表无按键按下。行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了;
"行扫描法"
  • 又成逐行(列)扫描查询法,是一种最常用的按键识别方法:依次将行线置为低电平。在确定某根线位置为低电平后,再逐行检测各列线的电平状态。若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
"高低电平翻转法"
  • 首先让P口高四位为1,低四位为0,若有按键按下,则高思维中会有一个1翻转为0,低四位不会变,此时即可确定备案下的键的行的位置。然后让P口高四位为0,低四位为1,若有按键按下,则低四位中会有一个1翻转为01,高四位不会变,此时即可确定被按下的键的列位置。最后将上述两者进行或运算即可确定被按下的键的位置。

二、矩阵键盘电路原理图

  • 示例:假设只想编写一列,可以将P44输出为0(低电平)

三、单片机I/O口快速输入/输出

(1)例程1:以独立键盘程序为基础将]5跳线帽切换为矩阵键盘模式后先写出其中一列矩阵按键的程序。以S7、S6、S5、S4为例。

  • 只在原来的KeyScan函数的第一行加上P44 = 0;即可实现在矩阵键盘中使用一列键盘;
cs 复制代码
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>

//变量声明区域

unsigned char S7_Flag = 0,S6_Flag = 0,S5_Flag = 0,S4_Flag = 0;

//函数声明区域

//毫秒级延时函数
void Delay(unsigned int ms);


//按键扫描函数
void KeyScan(void);

//程序主体
void main()
{
	P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
while(1)
{
	KeyScan();
	
	if(S7_Flag == 1) {S7_Flag = 0; P00 = 0;}
	if(S6_Flag == 1) {S6_Flag = 0; P00 = 1;}
	if(S5_Flag == 1) {S5_Flag = 0; P06 = 0;}
	if(S4_Flag == 1) {S4_Flag = 0; P06 = 1;}
}	
	
	
}
//毫秒级延时函数
void Delay(unsigned int ms)		//@11.0592MHz
{
	unsigned char i, j;
	while(ms--)
	{
	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
	}
	
}
//按键扫描函数
void KeyScan(void)
{
	P44 = 0;
	if(P30 == 0)
	{
		Delay(10);
		if(P30 == 0)
		{
			S7_Flag = 1;
			while(!P30);
		}
	}
		if(P31 == 0)
		{
			Delay(10);
			if(P31 == 0)
			{
				S6_Flag = 1;
				while(!P31);
			}
		}
		
		if(P32 == 0)
		{
			Delay(10);
			if(P32 == 0)
			{
				S5_Flag =1;
				while(!P32);
			}
		}
		
		if(P33 == 0)
		{
			Delay(10);
			if(P33 == 0)
			{
				S4_Flag = 1;
				while(!P33);
			}
		}
}

(2)例程2:根据例程1可以编写多列矩阵键盘程序。本例以写出第一列、第二列矩阵键盘程序按下S7、56、S5、S4、S11、510、59、S8按键,依次用第一位数码管依次显示1、2、3、4、5、6、7、8数值。

  • 假设只写出第一列,将P44置为0时候,按下按键后,只要判断P30 P31 P32 P33谁为0即可;只写第二列,将P42置为0,仍是只要判断P30 P31 P32 P33谁为即可;
  • 但是如果现在要同时写两列,应该如何写,思路:因为单片机程序执行的非常快,所以可以先讲P44置为0,然后对第一列进行扫描,如果有按键被按下,即可知道哪个按键被按下;如果没有按键被按下,那么将接下来P44置为1,将P42置为0,再对第二列进行扫描,不停地进行扫描,循环进行,即可知道哪个按键被按下。
cs 复制代码
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>

//变量声明区域

unsigned char S7_Flag = 0,S6_Flag = 0,S5_Flag = 0,S4_Flag = 0,S11_Flag = 0,S10_Flag = 0,S9_Flag = 0,S8_Flag = 0;
unsigned char code SEG[] = {0XF0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};

//函数声明区域

//毫秒级延时函数
void Delay(unsigned int ms);


//按键扫描函数
void KeyScan(void);

//程序主体
void main()
{
	P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
	P2 = 0XC0;P0 = 0X01;P2 = 0XFF;P0 = 0XFF;//打开第一个数码管程序
while(1)
{
	KeyScan();
	
	if(S7_Flag == 1)  {S7_Flag = 0;  P0 = SEG[1];}
	if(S6_Flag == 1)  {S6_Flag = 0;  P0 = SEG[2];}
	if(S5_Flag == 1)  {S5_Flag = 0;  P0 = SEG[3];}
	if(S4_Flag == 1)  {S4_Flag = 0;  P0 = SEG[4];}
	if(S11_Flag == 1) {S11_Flag = 0; P0 = SEG[5];}
	if(S10_Flag == 1) {S10_Flag = 0; P0 = SEG[6];}
	if(S9_Flag == 1)  {S9_Flag = 0;  P0 = SEG[7];}
	if(S8_Flag == 1)  {S8_Flag = 0;  P0 = SEG[8];}
}	
	
	
}
//毫秒级延时函数
void Delay(unsigned int ms)		//@11.0592MHz
{
	unsigned char i, j;
	while(ms--)
	{
	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
	}
	
}
//按键扫描函数
void KeyScan(void)
{
	P44 = 0;P42 = 1;
	if(P30 == 0)
	{
		Delay(10);
		if(P30 == 0)
		{
			S7_Flag = 1;
			while(!P30);
		}
	}
		if(P31 == 0)
		{
			Delay(10);
			if(P31 == 0)
			{
				S6_Flag = 1;
				while(!P31);
			}
		}
		
		if(P32 == 0)
		{
			Delay(10);
			if(P32 == 0)
			{
				S5_Flag =1;
				while(!P32);
			}
		}
		
		if(P33 == 0)
		{
			Delay(10);
			if(P33 == 0)
			{
				S4_Flag = 1;
				while(!P33);
			}
		}
		P44 = 1;P42 = 0;
	if(P30 == 0)
	{
		Delay(10);
		if(P30 == 0)
		{
			S11_Flag = 1;
			while(!P30);
		}
	}
		if(P31 == 0)
		{
			Delay(10);
			if(P31 == 0)
			{
				S10_Flag = 1;
				while(!P31);
			}
		}
		
		if(P32 == 0)
		{
			Delay(10);
			if(P32 == 0)
			{
				S9_Flag =1;
				while(!P32);
			}
		}
		
		if(P33 == 0)
		{
			Delay(10);
			if(P33 == 0)
			{
				S8_Flag = 1;
				while(!P33);
			}
		}
}
		

(3)例程3:根据例程1可以编写多列矩阵键盘程序。本例以写出第一列、第二列矩阵键盘程序按下57、56、S5、54、S11、S10、59、S8按键,依次用第一位数码管依次显示1、2、3、4、5、6、7、8数值。注:使用一个按键关键词来代替某一个按键被按下。

cs 复制代码
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>

//变量声明区域

unsigned char Key_Flag = 0;
unsigned char code SEG[] = {0XF0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};

//函数声明区域

//毫秒级延时函数
void Delay(unsigned int ms);


//按键扫描函数
void KeyScan(void);

//程序主体
void main()
{
	P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
	P2 = 0XC0;P0 = 0X01;P2 = 0XFF;P0 = 0XFF;//打开第一个数码管程序
while(1)
{
	KeyScan();
	
	switch(Key_Flag)
	{
		case 7:P0 = SEG[1];break;
		case 6:P0 = SEG[2];break;
		case 5:P0 = SEG[3];break;
		case 4:P0 = SEG[4];break;
		case 11:P0 = SEG[5];break;
		case 10:P0 = SEG[6];break;
		case 9:P0 = SEG[7];break;
		case 8:P0 = SEG[8];break;
		default:break;
	}
}	
	
	
}
//毫秒级延时函数
void Delay(unsigned int ms)		//@11.0592MHz
{
	unsigned char i, j;
	while(ms--)
	{
	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
	}
	
}
//按键扫描函数
void KeyScan(void)
{
	P44 = 0;P42 = 1;
	if(P30 == 0)
	{
		Delay(10);
		if(P30 == 0)
		{
			Key_Flag = 7;
			while(!P30);
		}
	}
		if(P31 == 0)
		{
			Delay(10);
			if(P31 == 0)
			{
				Key_Flag = 6;
				while(!P31);
			}
		}
		
		if(P32 == 0)
		{
			Delay(10);
			if(P32 == 0)
			{
				Key_Flag = 5;
				while(!P32);
			}
		}
		
		if(P33 == 0)
		{
			Delay(10);
			if(P33 == 0)
			{
				Key_Flag = 4 ;
				while(!P33);
			}
		}
		P44 = 1;P42 = 0;
	if(P30 == 0)
	{
		Delay(10);
		if(P30 == 0)
		{
			Key_Flag = 11;
			while(!P30);
		}
	}
		if(P31 == 0)
		{
			Delay(10);
			if(P31 == 0)
			{
				Key_Flag = 10;
				while(!P31);
			}
		}
		
		if(P32 == 0)
		{
			Delay(10);
			if(P32 == 0)
			{
				Key_Flag = 9;
				while(!P32);
			}
		}
		
		if(P33 == 0)
		{
			Delay(10);
			if(P33 == 0)
			{
				Key_Flag = 8;
				while(!P33);
			}
		}
}
		
相关推荐
IT B业生2 小时前
51单片机教程(六)- LED流水灯
单片机·嵌入式硬件·51单片机
一枝小雨2 小时前
51单片机学习心得2(基于STC89C52):串口通信(UART)
单片机·嵌入式硬件·51单片机
IT B业生3 小时前
51单片机教程(一)- 开发环境搭建
单片机·嵌入式硬件·51单片机
海绵波波1075 小时前
Webserver(4.8)UDP、广播、组播
单片机·网络协议·udp
好想有猫猫5 小时前
【51单片机】串口通信原理 + 使用
c语言·单片机·嵌入式硬件·51单片机·1024程序员节
stm 学习ing7 小时前
C语言 循环高级
c语言·开发语言·单片机·嵌入式硬件·算法·嵌入式实时数据库
w微信150135078127 小时前
小华一级 代理商 HC32F005C6PA-TSSOP20 HC32F005系列
c语言·arm开发·单片机·嵌入式硬件
北京迅为8 小时前
【北京迅为】《STM32MP157开发板嵌入式开发指南》-第七十八章 Qt控制硬件
linux·stm32·单片机·嵌入式硬件
田三番11 小时前
使用 vscode 简单配置 ESP32 连接 Wi-Fi 每日定时发送 HTTP 和 HTTPS 请求
单片机·物联网·http·https·嵌入式·esp32·sntp
lucy1530275107911 小时前
【青牛科技】GC2803:白色家电与安防领域中 ULN2803 的卓越替代者
科技·单片机·智能家居·能源·安防·开关电源·白色家电