独立按键实验
通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,电压信号
如下图所示:
由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时 也不会一下子断开,因而在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间 的长短由按键的机械特性决定的,一般为 5ms 到 10ms。按键稳定闭合时间的长 短则由操作人员的按键动作决定的,一般为零点几秒至数秒。按键抖动会引起按 键被误读多次。为了确保 CPU 对按键的一次闭合仅作一次处理,必须进行消抖。
按键消抖有两种方式,一种是硬件消抖,另一种是软件消抖。为了使电路更 加简单,通常采用软件消抖。我们开发板也是采用软件消抖,一般来说一个简单 的按键消抖就是先读取按键的状态,如果得到按键按下之后,延时 10ms,再次 读取按键的状态,如果按键还是按下状态,那么说明按键已经按下。其中延时 10ms 就是软件消抖处理,至于硬件消抖,大家可以百度了解下,网上都有非常 详细的介绍。
这里给大家列出单片机常用的软件去抖动方法:
-
先设置 IO 口为高电平(由于开发板 IO 都有上拉电阻,所以默认 IO 为高 电平)。
-
读取 IO 口电平确认是否有按键按下。
-
如有 IO 电平为低电平后,延时几个毫秒。
-
再读取该 IO 电平,如果仍然为低电平,说明按键按下。
-
执行按键控制程序。
独立按键电路构成是由各个按键的一个管脚连接在一起接地,按键其他引脚 分别接到单片机 IO 口。
我们知道单片机的 IO 口既可作为输出也可作为输入使用,当检测按键时用 的是它的输入功能,独立按键的一端接地, 另一端与单片机的 I/O 口相连,开 始时先给该 IO 口赋一高电平,然后让单片机不断地检测该 I/O 口是否变为低 电平,当按键闭合时,即相当于该 I/O 口通过按键与地相连,变成低电平,程 序一旦检测到 I/O 口变为低电平则说明按键被按下,然后执行相应的指令。
原理图如下:
/*
*独立按键实验
*效果:通过按键1控制LED1,进行暗亮操作
*/
#include "reg52.h"
typedef unsigned int u16;//对系统的默认数据类型重新命名
typedef unsigned char u8;
//对独立按键管脚进行定义
sbit KEY_PRESS1 = P3^1;
sbit KEY_PRESS2 = P3^0;
sbit KEY_PRESS3 = P3^2;
sbit KEY_PRESS4 = P3^3;
//对LED1进行定义
sbit LED1 = P2^0;
//使用宏定义独立按键按下的键值
#define KEY_PRESS1_value 1
#define KEY_PRESS2_value 2
#define KEY_PRESS3_value 3
#define KEY_PRESS4_value 4
#define UN_PRESS_value 0
/*
*延时函数:当ten_us=1时延时10us
*作用:进行消抖
*/
void delay_10us(u16 ten_us){
while(ten_us--);
}
/*
*键位检查函数: model = 0 时单次扫描 model= 1时连续扫描
*
*作用:检查键位是否已经按下
*/
u8 Key_Scan(u8 model){
static u8 key = 1;
if(model){
//连续扫描模式
key = 1;
}
if (key==1&&(KEY_PRESS1==0||KEY_PRESS2==0||KEY_PRESS3==0||KEY_PRESS4==0)){
delay_10us(1000);//消抖操作,防止误读
key = 0;
if(KEY_PRESS1 == 0){
//按键1 按下
return KEY_PRESS1_value;
}else if (KEY_PRESS2 == 0){
//按键2 按下
return KEY_PRESS2_value;
}else if (KEY_PRESS3 == 0){
//按键3 按下
return KEY_PRESS3_value;
}else if (KEY_PRESS4 == 0){
//按键4 按下
return KEY_PRESS4_value;
}
}else if(KEY_PRESS1==1&&KEY_PRESS2==1&&KEY_PRESS3==1&&KEY_PRESS4==1){
key = 1;
}
return UN_PRESS_value;
}
/*
*主函数
*/
void main(){
u8 key = 0;
while(1){
key = Key_Scan(0);//调用键位检查函数,单次扫描
if(key == KEY_PRESS1_value){//判断按键是否为按键1
LED1 = !LED1;//led灯状态翻转
}
}
}
key_scan 函数带一个形参 mode,该参数用来设定是否连续扫描按键,如果 mode 为 0,只能操作一次按键,只有当按键松开后才能触发下次的扫描,这样 做的好处是可以防止按下一次出现多次触发的情况。如果 mode 为 1,函数是支 持连续扫描的,即使按键未松开,在函数内部有 if(mode==1)这条判断语句,因 此 key 始终是等于 1 的,所以可以连续扫描按键,当按下某个按键,会一直返 回这 个按键的键值,这样做的好处是可以很方便实现连按操作。函数内的 delay_10us(1000)即为软件消抖处理,通常延时 10ms 即可。
key_scan 函数还带有一个返回值,如果未有按键按下,返回值即为 KEY_UNPRESS,否则返回值即为对应按键的键值,如 KEY1_PRESS、KEY2_PRESS、 KEY3_PRESS、 KEY4_PRESS,这都是程序开头定义好的宏,方便大家理解和使用。 函数内定义了一个 static 变量 key,相当于全局变量,所以该函数不是一个可 重入函数。还有一点要注意的就是该函数按键的扫描是有优先级的,因为函数内 用了 if…else if…else 格式,所以最先扫描处理的按键是 KEY1,其次是 KEY2,然后是 KEY3,最后是 KEY4。如果需要将其优先级设置一样,那么可以全 部用 if 语句。
main 函数中主要就是调用 key_scan 函数用于检测按键,此时传入的 mode 值为 0,表示单次扫描按键,然后将扫描按键的值保存在变量 key 中,最后通过if 判断语句控制 LED1 状态
结束!!!