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

一、矩阵键盘的工作原理

(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);
			}
		}
}
		
相关推荐
猫猫的小茶馆1 小时前
【STM32】FreeRTOS 任务的删除(三)
java·linux·stm32·单片机·嵌入式硬件·mcu·51单片机
学不动CV了1 小时前
单片机ADC采集机理层面详细分析(二)
c语言·arm开发·stm32·单片机·嵌入式硬件·开源·51单片机
学不动CV了1 小时前
51核和ARM核单片机OTA实战解析(二)
c语言·arm开发·stm32·单片机·嵌入式硬件·51单片机
Yuroo zhou2 小时前
IMU的精度对无人机姿态控制意味着什么?
单片机·嵌入式硬件·算法·无人机·嵌入式实时数据库
jackzhuoa3 小时前
java小白闯关记第一天(两个数相加)
java·算法·蓝桥杯·期末
嵌入式小白牙4 小时前
ARM-I2C硬实现
arm开发·单片机·嵌入式硬件
knight_20246 小时前
嵌入式学习日志————对射式红外传感器计次
stm32·单片机·嵌入式硬件·学习
深圳安凯星单片机开发方案公司7 小时前
用单片机怎么控制转速
单片机·51单片机
Ronin-Lotus7 小时前
嵌入式硬件篇---驱动板
单片机·嵌入式硬件·esp32·驱动板
##echo7 小时前
嵌入式Linux裸机开发笔记9(IMX6ULL)GPIO 中断实验(1)
linux·c语言·笔记·单片机·嵌入式硬件