您的位置:首页 > 其它

【按键】[独立按键] - 1: 单击,双击,三击以及N击

2016-03-23 18:03 288 查看
此按键程序的实现的功能是单个独立按键的[单击],[长按],[双击],[三击]以及[多击]。本文分为三个部分,

第一个部分是说[单击],[长按]的程序;

第二部分是讲[双击]

第三部分是讲[三击],[N击]

一、 [单击]、[长按]程序

1. 简单介绍本按键程序的单击和长按

首先说一下单击,长按的响应情况,就是按多久算单击或者长按,按下按键马上返回有效键值,还是释放之后返回有效键值等等,下面说下它在什么情况下返回有效的【单击】和【长按】。

首先看一张时序图:



注:

T1:是单击的按键消抖时长,这里预设的是30ms,也可以根据需求自行定义;

T2:是单击时,按键释放的有效时间段,提前或者超过这个时间段释放的按键都再是单击了。提前释放则是无效键值,超过后释放则是长按。

T3:是长按时长,按键超过此时长,则为长按。这里的预设值是3s,同样可根据需求自行更改。

【单击】:按键按下超过消抖时长T1(30ms),并且在T2时间段内释放按键,按键一释放,马上返回有效按键值—【单击】。

注意:单击是释放后,才返回有效按键值,不释放时,是无效按键值。

【长按】:按键按下的时间超过预设的长按时长T3(3s) ,马上返回有效按键值—【长按】;

注意:长按是只要按下的时间超过预设的长按时长,马上返回有效键值。但是,如果按键一直按着不释放,则只返回一次有效按键值,不重复返回,直到释放之后,才开始重新读取键值。

2. 按键程序的架构

按键程序可以分为四个部分,

第一部分:判断有无按键按下

第二部分:按键是否有效(按键消抖)

第三部分:确定有效按键的种类(单击还是长按)

第四部分:等待按键释放

3. 按键程序的源代码以及注释

程序的注释写的很详细,应该是可以读懂的,如果有疑问可以留言讨论。

以下是key.c 的源代码:

//============================ key.c ===================

#define KEY_INPUT           P1.0    // 按键IO

#define KEY_STATE_0         0       // 按键状态
#define KEY_STATE_1         1
#define KEY_STATE_2         2
#define KEY_STATE_3         3

#define LONG_KEY_TIME       300     // LONG_KEY_TIME*10MS = 3S
#define SINGLE_KEY_TIME     3       // SINGLE_KEY_TIME*10MS = 30MS

#define N_KEY    0                  // no click
#define S_KEY    1                  // single click
#define L_KEY    10                 // long press

unsigned char key_driver(void)
{
static unsigned char key_state = 0;         // 按键状态变量
static unsigned int key_time = 0;           // 按键计时变量
unsigned char key_press, key_return;

key_return = N_KEY;                         // 清除 返回按键值

key_press = KEY_INPUT;                      // 读取当前键值

switch (key_state)
{
case KEY_STATE_0:                       // 按键状态0:判断有无按键按下
if (!key_press)                     // 有按键按下
{
key_time = 0;                   // 清零时间间隔计数
key_state = KEY_STATE_1;        // 然后进入 按键状态1
}
break;

case KEY_STATE_1:                       // 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
if (!key_press)
{
key_time++;                     // 一次10ms
if(key_time>=SINGLE_KEY_TIME)   // 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;
{
key_state = KEY_STATE_2;    // 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
}
}
else key_state = KEY_STATE_0;       // 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
break;

case KEY_STATE_2:                       // 按键状态2:判定按键有效的种类:是单击,还是长按
if(key_press)                       // 如果按键在 设定的长按时间 内释放,则判定为单击
{
key_return = S_KEY;            // 返回 有效按键值:单击
key_state = KEY_STATE_0;       // 返回 按键状态0,继续等待按键
}
else
{
key_time++;

if(key_time >= LONG_KEY_TIME)   // 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=200*10ms=2000ms), 则判定为 长按
{
key_return = L_KEY;         // 返回 有效键值值:长按
key_state = KEY_STATE_3;    // 去状态3,等待按键释放
}
}
break;

case KEY_STATE_3:                         // 等待按键释放
if (key_press)
{
key_state = KEY_STATE_0;          // 按键释放后,进入 按键状态0 ,进行下一次按键的判定
}
break;

default:                                // 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
key_state = KEY_STATE_0;
break;
}

return key_return;                          // 返回 按键值
}


使用注意:

1)硬件:按键的一端接地(GND),另一端接IO口。IO为输入,一定要有上拉电阻。

2)定时器:这里为了精确的定时,所以使用了定时器,定时器的时间是10ms。

3)扫描周期:调用此函数时,一定确保”扫描周期“要小于10ms。不然按键内所涉及的时间就会不准,会偏大。所涉及的时间包括消抖时长按键长按时长等。

扫描周期定义:从 第一次进入按键扫描程序 开始,到第二次进入按键扫描程序时 结束,之间所用的时间。

测量扫描周期的方法:可以在按键扫描程序的第一句,添加IO口取反函数,然后用示波器查看改IO口,其IO口周期的一般就是扫描周期了。

4. 按键程序的使用实例

这里以C51位硬件平台进行实例讲解

1)实例程序的功能:

单击:点亮LED1

长按:熄灭LED1

2)硬件:

按键IO:P1.0

LED1 :P2.0

以下是 main.c 源代码:

//============================ main.c ===================

#include "reg51.h"
#include "key.c"

sbit LED1 = P2.0;                             // 定义LEDIO口

unsigned char g_u8_KeyValue;                  // 按键值
unsigned char g_flag_10ms_key;                // 10ms 计时标志

//timer0,初始化函数 ,定时时间为 10ms
void T0_Init_10ms(void)
{
TMOD |= 0x01;
TH0 = (65535 - 10000)/256;
TL0 = (65535 - 10000)%256;

ET0 = 1;
TR0 = 1;
EA = 1;
}

//主函数
void main(void)
{
P1.0 = 1;                                  // P1.0 拉高
T0_Init_10ms();                            // 定时器0,初始化,定时10ms

while(1)
{
if(g_flag_10ms_key)                     // 等待10ms,定时完成
{
g_flag_10ms_key = 0;                // 清零10ms定时标志

g_u8_KeyValue = key_driver();       // 读取按键值

switch(g_u8_KeyValue)
{
case S_KEY: LED1 = 1; break;    // 单击 点亮LED1
case L_KEY: LED1 = 0; break;    // 长按 熄灭LED1
}
}
}
}

//timer0 中断服务程序
void IRQ_T0(void) interrupt 1
{
g_flag_10ms_key = 1;                        // 置位 10ms 定时标志
}


Pillar Peng

2016.3.23 18:00

其余分享链接:

第二部分:【按键】[独立按键] - 2: 双击

第三部分:【按键】[独立按键] - 3: 三击以及N击
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息