【普中51单片机教程 - 4】:独立按键 & 矩阵按键

独立按键

机械按键的介绍

如下图所示,图中为独立按键,距离长的引脚为1、3脚和2、4脚,距离短的为1、2脚和3、4脚。

当按键未按下时,1、3和2、4脚为导通状态,1、2和3、4脚为断开状态,当按键按下时1、2和3、4脚才导通。
在这里插入图片描述

因为使用的按键开关属于机械的弹性开关,假设以下按键开关的连接方式如下图所示:2脚接到单片机管脚,1脚接到GND,当按键按下时,1、2脚接通,为低电平,当按键释放时,1、2脚断开,由上拉电阻将电压拉高,为高电平。

在这里插入图片描述
在这里插入图片描述

由上图我们可看到按键在按下、释放时的理想波形,但是在实际的机械按键会出现抖动的情况,也就会可能出现按下按键多次执行该按键的功能。

在这里插入图片描述

消抖的方法

  • 软件消抖:可在按键按下时增加一个延迟,再对按键进行扫描判断(根据实际经验,抖动通常在5~10ms的一个范围)
  • 硬件消抖:可在电路中增加RC振荡电路等(RC振荡电路会有一个充放电的过程,就像相当于延迟)

硬件设计

下图为独立按键模块中的硬件设计部分,其P32、P33又是外部中断的管脚
在这里插入图片描述

软件设计

案例:通过开发板上的独立按键K1、K2、K3、K4来控制D1指示灯的亮灭。

#include <reg51.h>

typedef unsigned char u8;
typedef unsigned int u16;

sbit KEY1 = P3^1;
sbit KEY2 = P3^0;
sbit KEY3 = P3^2;
sbit KEY4 = P3^3;

sbit LED1 = P2^0;

//定义返回的键值
#define KEY1_PRESS 1
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY_UNPRESS 0

void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 108;
	j = 145;
	do
	{
		while (--j);
	} while (--i);
}

//按键扫描
u8 Key_scan(u8 mode) //参数model控制扫描方式:单次扫描、连续扫描
{
	static u8 key = 1;
	if (mode) key = 1; //当mode为真时,为连续扫描
	if (key==1 & (KEY1==0||KEY2==0||KEY3==0||KEY4==0)) //有按键按下时
	{
		Delay10ms(); //消抖处理
		key = 0;
		if(KEY1 == 0)
			return KEY1_PRESS;
		else if(KEY2 == 0)
			return KEY2_PRESS;
		else if(KEY3 == 0)
			return KEY3_PRESS;
		else if(KEY4 == 0)
			return KEY4_PRESS;
	}
	else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) //没有按键按下时
		key = 1;
	return KEY_UNPRESS;
}
void main()
{
	u8 key = 0;
	while(1)
	{
		key = Key_scan(0);
		if(key == KEY1_PRESS)
			LED1 = !LED1;
	}
}

矩阵按键

如果单片机需要更多的按键,若还是采用独立按键的接法,就会占用IO资源,而单片机系统的IO资源往往比较宝贵,当用到多个按键的时候,为了较少IO用到的引脚,引入了矩阵按键

矩阵按键的介绍

以4x4的矩阵键盘为例,识别按键通常有行列扫描、线反转法等,下面只针对行列扫描的方法进行讲解。

行列扫描时,通常将某一列的IO口输出为低电平,然后判断哪一行为低电平,若有某一行为低电平即可知道是哪个按键按下。

在以下的案例中,令P13输出为低电平,即P1口为11110111=0xf7,通过判断P17、16、15、14这四行哪一行为低电平,即可判断哪个按键按下。

在这里插入图片描述

软件设计

案例:通过数码管显示矩阵按键S1-S16按下后键值0-F

#include <reg51.h>

typedef unsigned char u8;
typedef unsigned int u16;

#define KEY_MATRIX_PORT		P1

#define SMG_A_DP_PORT		P0

u8 gsmg_code[17] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 
					0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};

void Delay10ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 108;
	j = 145;
	do
	{
		while (--j);
	} while (--i);
}

u8 key_matrix_ranks_scan(void)
{
	u8 key_value = 0;
	
	KEY_MATRIX_PORT = 0xf7; //第一列为低电平
	if (KEY_MATRIX_PORT != 0xf7) //有按键按下
	{
		Delay10ms();
		switch(KEY_MATRIX_PORT)
		{
			case 0x77: key_value=1; break; //S1按下时
			case 0xb7: key_value=5; break;
			case 0xd7: key_value=9; break;
			case 0xe7: key_value=13; break;
		}	
	}
	while(KEY_MATRIX_PORT!=0xf7); //等待释放,当按键按下时KEY值不等于0xf7,一直循环,当按键释放时,KEY等于0xf7,跳出循环
	
	KEY_MATRIX_PORT = 0xfb; //第二列为低电平
	if (KEY_MATRIX_PORT != 0xfb) //有按键按下
	{
		Delay10ms();
		switch(KEY_MATRIX_PORT)
		{
			case 0x7b: key_value=2; break; 
			case 0xbb: key_value=6; break;
			case 0xdb: key_value=10; break;
			case 0xeb: key_value=14; break;
		}	
	}
	while(KEY_MATRIX_PORT!=0xfb);
	
	KEY_MATRIX_PORT = 0xfd; //第三列为低电平
	if (KEY_MATRIX_PORT != 0xfd) //有按键按下
	{
		Delay10ms();
		switch(KEY_MATRIX_PORT)
		{
			case 0x7d: key_value=3; break; 
			case 0xbd: key_value=7; break;
			case 0xdd: key_value=11; break;
			case 0xed: key_value=15; break;
		}	
	}
	while(KEY_MATRIX_PORT!=0xfd);
	
	KEY_MATRIX_PORT = 0xfe; //第四列为低电平
	if (KEY_MATRIX_PORT != 0xfe) 
	{
		Delay10ms();
		switch(KEY_MATRIX_PORT)
		{
			case 0x7e: key_value=4; break; //S1按键按下时
			case 0xbe: key_value=8; break;
			case 0xde: key_value=12; break;
			case 0xee: key_value=16; break;
		}	
	}
	while(KEY_MATRIX_PORT!=0xfe);	
	
	return key_value;
}

void main()
{
	u8 key = 0;
	while(1)
	{
		key = key_matrix_ranks_scan();
		if(key!=0)
		{
			SMG_A_DP_PORT = gsmg_code[key-1];
		}
			
	}
}

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

街 三 仔

你的鼓励是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值