独立按键
机械按键的介绍
如下图所示,图中为独立按键,距离长的引脚为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];
}
}
}