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

一、矩阵键盘的工作原理

(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);
			}
		}
}
		
相关推荐
yutian06062 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
不想当程序猿_5 小时前
【蓝桥杯每日一题】求和——前缀和
算法·前缀和·蓝桥杯
析木不会编程5 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉9 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名6779 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式大圣10 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室10 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费10 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_3975623112 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
艺术家天选12 小时前
STM32点亮LED灯
stm32·单片机·嵌入式硬件