按键介绍:
按键是一种电子开关,使用时轻轻按开关按钮就可式开关接通,当松手时,开关断开。开发板上使用的按键及内部简易图如下图:
按键管脚两端距离长的表示默认是导通状态,距离短的默认是断开状态,如果按键按下,初始导通状态变为断开,初始断开状态变为导通。
通常的按键所用开关位机械弹性开关,当机械触点断开,闭合时,电压信号如下图所示:
由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开,因而在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间在长短由按键的机械特性决定,一般为5ms和10ms.按键稳定闭合时间的长短则由操作人员的按键动作决定的,一般为零点几秒至数秒。按键抖动会引起按键被误读多次。为了确保CPU对按键的一次闭合仅作为一次处理,必须进行消抖。
按键的消抖有两种方式,一种是硬件消抖,另一种是软件消抖。为了使电路更加简单,通常采用软件消抖。我们开发板也采用软件消抖,一般来说一个简单的按键消抖就是先读取按键的状态,在得到按键按下之后,延时10ms,再次读取按键的状态,如果按键还是按下状态,那么说明按键已经按下。其中延时10ms就是软件消抖处理,至于硬件消抖,大家可以百度了解下,网上都有非常 详细的介绍。
这里给大家列出单片机常用的软件去抖动方法:
- 先设置IO口为高电平(由于开发板IO都有上拉电阻,所以默认IO为高电平)。
- 读取IO口电平确认是否有按键按下。
- 如有IO电平为低电平后,延时几个毫秒。
- 在读取该IO电平,如果仍然为低电平,说明按键按下。
- 执行按键控制程序。
硬件设计 :
/********************************************************************
****************** 实验名称:独立按键实验
接线说明:
实验现象:下载程序后,按下“独立按键”模块中 K1 键,控制 D1 指示灯亮灭
注意事项:
*********************************************************************
******************/
#include "reg52.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
//定义独立按键控制脚
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
//定义 LED1 控制脚
sbit LED1=P2^0;
/*
使用宏定义独立按键按下返回的键值
为什么要定义这个宏呢?是为了方便与我们在程序当中直接使用这个返回值,这样
后期在调用这个函数扫描的时候,得到它的返回值可以直接用KEY1_PRESS来代表,而
不是直接用1 2 3 4来表示 。1 2 3 4在我们用户在看着这个程序的时候,不知道1代表什么
2代表什么,现在KEY1_PRESS 通过英文字母我们可以知道是K1按键按下
当然觉得能看懂,也可以不用宏定义,直接用1 2 3 4 0 来表示这几个
*/
#define KEY1_PRESS 1
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY_UNPRESS 0
/********************************************************************
***********
* 函 数 名 : delay_10us
* 函数功能 : 延时函数,ten_us=1 时,大约延时 10us
* 输 入 : ten_us
* 输 出 : 无
*********************************************************************
**********/
void delay_10us(u16 ten_us)
{
while(ten_us--);
}
/********************************************************************
***********
* 函 数 名 : key_scan
* 函数功能 : 检测独立按键是否按下,按下则返回对应键值
* 输 入 : mode=0:单次扫描按键
mode=1:连续扫描按键
* 输 出 : KEY1_PRESS:K1 按下
KEY2_PRESS:K2 按下
KEY3_PRESS:K3 按下
KEY4_PRESS:K4 按下
KEY_UNPRESS:未有按键按下
*********************************************************************
**********/
u8 key_scan(u8 mode)
{
static u8 key=1;//static 修饰符,key的值不会被改变,会保存上次的值
//if(mode)key=1;同if(mode==1)key=1,mode=1为真,就进入这个if,key=1,就是连续检测
//mode=1时候 mode==1不成立,为假,就不执行这个if语句,是单次检测
if(mode)key=1;
if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))//任意按键按下的时候为低电平
{
delay_10us(1000);//延时进行消抖处理
/*按键按下后key=0,不松开就不会在进入这个if,再次进行扫描按键,不会在返回这个简
return KEY1_PRESS......这几个键值了,如果没有这个key=0,不松开程序就不停的在进入
这个if在进行扫描
*/
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=0,如果没有这个key=1,下次按键按下的时候key=0就不满足if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))这个,不能进行扫描,不采集的,所以在按键松开后(就是没有按键按下的时候)会执行else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) 扫描后把赋值,更改为key=1退出程序,下次按键在按下的时候key=1,继续执行if里面的语句。
*/
key=1;
}
//如果按键按下,执行完return KEY1_PRESS 这条语句,返回的函数直接返回出去了,就直接
//退出这个函数了,自然后面的语句就不会在执行,如果没有按键按下,第二个if语句有而不会
//执行下去,直接就执行后面的语句,所以这条语句放在else if 的里面或者外面都可以
return KEY_UNPRESS;
}
/********************************************************************
***********
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*********************************************************************
**********/
void main()
{
//因为这个ey_scan(u8 mode)是有返回值的,所以要定义一个U8类型的值来保存这个返回的键值
u8 key=0;
while(1)
{
key=key_scan(0);//传入0的值是按键的单次检测,连续检测为0
if(key==KEY1_PRESS)//检测按键 K1 是否按下
LED1=!LED1;//按键按下的时候LED默认为高电平,所以!LED1为低电平,LED点亮,
//再次按键的时候LED1为低电平,!LED1为高电平,LED关闭
}
}