作用:按键检测、示例在10ms任务中通过读取引脚电平进行单击、双击、长按检测。
Key.c
#include "key.h"
/* 10ms task */
T_KEY_STATE KEY_state;
void Key_Scan()
{
//按下
if(GPIO_Input_Pin_Data_Get(KEY_PORT,KEY_PIN) == RESET && KEY_state.isRelease != PRESS)
//if(GPIO_ReadInputDataBit(GPIOB,GPIO_PIN_1) == RESET)
{
KEY_state.relieving_shaking++; //消抖
if(KEY_state.relieving_shaking >= RELIEVE_COUNT && GPIO_Input_Pin_Data_Get(KEY_PORT,KEY_PIN) == RESET) //30ms
{
KEY_state.relieving_shaking = 0;
KEY_state.idle_gap = 0;
KEY_state.isRelease = PRESS;
}
}
//释放
else if(GPIO_Input_Pin_Data_Get(KEY_PORT,KEY_PIN) == SET && KEY_state.isRelease != RELEASE)
//else if(GPIO_ReadInputDataBit(GPIOB,GPIO_PIN_1) == SET)
{
KEY_state.relieving_shaking++; //消抖
if(KEY_state.relieving_shaking >= RELIEVE_COUNT && GPIO_Input_Pin_Data_Get(KEY_PORT,KEY_PIN) == SET) //30ms
{
KEY_state.relieving_shaking = 0;
KEY_state.isRelease = RELEASE;
}
}
switch(KEY_state.isRelease)
{
case PRESS:
KEY_state.click_count++;
if(KEY_state.click_count >= SINGLE_DOUBLE_INTERVAL)
{
//KEY_state.lock = UNLOCK; //长按功能与长按不释放功能应该互斥
KEY_state.key_action = KEY_LONG_PRESS_NO_RELEASE;
}
break;
case RELEASE:
if(KEY_state.click_count == 0)
{
KEY_state.idle_gap++;
if(KEY_state.idle_gap >= IDLE_COUNT) //200ms
{
KEY_state.idle_gap = 0;
KEY_state.key_action = KEY_IDLE;
}
}
if(KEY_state.single_double_flag == 1)
{
KEY_state.single_double_interval++;
if(KEY_state.single_double_interval >= DOUBLT_INTERVAL) //500ms
{
KEY_state.single_double_interval = 0;
KEY_state.single_double_flag = 0;
KEY_state.key_action = KEY_SHORT_PRESS;
KEY_state.lock = UNLOCK;
}
}
if(KEY_state.click_count > 0 && KEY_state.click_count < SINGLE_DOUBLE_INTERVAL) //1s
{
KEY_state.click_count = 0;
if(!KEY_state.single_double_flag)
{
KEY_state.single_double_flag = 1; //记录
}
else
{
KEY_state.single_double_flag = 0;
KEY_state.single_double_interval = 0;
KEY_state.key_action = KEY_DOUBLE_CLICK;
KEY_state.lock = UNLOCK;
}
}
if(KEY_state.click_count >= SINGLE_DOUBLE_INTERVAL)
{
KEY_state.click_count = 0;
KEY_state.lock = UNLOCK;
KEY_state.key_action = KEY_LONG_PRESS; //长按
}
break;
default:break;
}
}
Key.h
#ifndef __KEY_H__
#define __KEY_H__
#include "main.h"
#define KEY_PORT GPIOA
#define KEY_PIN GPIO_PIN_4
#define RELIEVE_COUNT 3 //消抖计数30ms
#define IDLE_COUNT 20 //空闲计数200ms
#define DOUBLT_INTERVAL 50 //双击间隔500ms
#define KEY_LOCK_INTERVAL 50 //按键锁定间隔500ms
#define SINGLE_DOUBLE_INTERVAL 100 //长按和短按的时间1s
enum E_KEY_action{
KEY_IDLE = 0, //空闲
KEY_SHORT_PRESS, //短按
KEY_LONG_PRESS, //长按
KEY_DOUBLE_CLICK, //双击
KEY_LONG_PRESS_NO_RELEASE, //长按未抬起
};
enum E_PRESS{
RELEASE = 0,
PRESS,
};
enum E_LOCK{
UNLOCK = 0,
LOCK,
};
typedef struct{
uint8_t click_count;
uint8_t relieving_shaking;
uint8_t single_double_interval;
uint8_t single_double_flag;
uint8_t isRelease;
uint8_t idle_gap;
uint8_t key_action;
uint8_t lock;
uint8_t key_lock;
uint8_t key_lock_count;
}T_KEY_STATE;
extern T_KEY_STATE KEY_state;
void Key_Scan(void);
#endif
Task:
void task()
{
//按键每次触发间隔500ms
if(!KEY_state.key_lock)
{
Key_Scan();
}
else
{
KEY_state.key_lock_count++;
if(KEY_state.key_lock_count > KEY_LOCK_INTERVAL) //按键响应后,指定时间内不再响应
{
KEY_state.key_lock_count = 0;
KEY_state.key_lock = UNLOCK; //解锁按键
}
}
if(!KEY_state.lock)
{
switch(KEY_state.key_action)
{
case KEY_IDLE:
break;
case KEY_SHORT_PRESS:
KEY_state.lock = LOCK;
KEY_state.key_lock = LOCK; //触发按键上锁
LOG("KEY_SHORT_PRESS\n");
break;
case KEY_LONG_PRESS:
KEY_state.lock = LOCK;
KEY_state.key_lock = LOCK; //触发按键上锁
LOG("KEY_LONG_PRESS\n");
break;
case KEY_DOUBLE_CLICK:
KEY_state.lock = LOCK;
KEY_state.key_lock = LOCK; //触发按键上锁
LOG("KEY_DOUBLE_CLICK\n");
break;
case KEY_LONG_PRESS_NO_RELEASE:
KEY_state.lock = LOCK;
KEY_state.key_lock = LOCK; //触发按键上锁
LOG("KEY_LONG_PRESS_NO_RELEASE\n");
break;
default:break;
}
}
}