一般的按键功能都需要做防抖处理,中间就涉及到了阻塞延迟,但是在实际项目开发中应当尽量避免不必的阻塞。可以使用计时功能去处理按键防抖,在系统滴答时钟中断中实现按键功能检测,按键功能处理是在main里实现。
#define KEY_NR 2
/* 短按 */
#define KV_KEY1 0x01
#define KV_KEY2 0x02
/* 长按 */
#define LKV_KEY1 0x10
#define LKV_KEY2 0x20
#define KV_NULLKEY 0x00
#define KEY_PRESS 0x01
#define KEY_NO_PRESS 0x00
#define KEYBUF_MAX 32 /* 记录按键状态最大值 */
static unsigned char g_key_buf[KEYBUF_MAX];
static unsigned char g_key_inidx, g_key_rdidx;
static unsigned char g_key_cnt[KEY_NR];
static unsigned char g_key_inv[KEY_NR]; /* 表示按键按下状态 */
static unsigned int g_key_count = 0;
static unsigned int g_lkey_count = 0; /* 长按计数 */
static unsigned char g_keylast_val = KV_NULLKEY;
#define KEY_CNT 3
#define KEYOUT_CNT 600
#define KEYLONG_CNT 300
typedef struct {
GPIO_TypeDef *port;
unsigned short pin;
unsigned char kv_index; /* 定义短按按键索引 */
unsigned char lkv_index; /* 定义长按按键索引 */
}key_def_t;
static const key_def_t key_tab[] = {
{KEY1_PORT, KEY1_PIN, KV_KEY1, LKV_KEY1},
{KEY2_PORT, KEY2_PIN, KV_KEY2, LKV_KEY2},
{NULL, KV_NULLKEY, KV_NULLKEY},
};
首先定义按键结构体便于处理,定义了短按( kv_index)与长按(lkv_index)两个元素,如果需要其他实现的功能可以另外定义。关于短按与长按的时间后面讲到具体实现方法时再说明。
int bsp_key_init(void)
{
int i;
const key_def_t *pkey = key_tab;
GPIO_InitTypeDef GPIO_InitStructure;
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_MEDIUM;
while(NULL != pkey->port) {
GPIO_InitStructure.Pin = pkey->pin;
HAL_GPIO_Init(pkey->port, &GPIO_InitStructure);
pkey++;
}
g_key_inidx = g_key_rdidx = 0;
for(i = 0; i < KEY_NR; i++)
g_key_cnt[i] = g_key_inv[i] = 0;
g_key_count = 0;
g_lkey_count = 0;
return 0;
}
void bsp_key_proc(void)
{
int i;
const key_def_t *pkey = key_tab;
g_key_count++;
if(g_key_count >= KEYOUT_CNT) {
g_key_count = 0;
if(KV_NULLKEY != g_keylast_val) {
g_keylast_val = KV_NULLKEY;
g_key_buf[g_key_inidx] = KV_NULLKEY;
g_key_inidx = (g_key_inidx + 1) % KEYBUF_MAX;
}
}
for(i = 0; i < KEY_NR; i++) {
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(pkey[i].port, pkey[i].pin)) {
if(g_lkey_count < KEYLONG_CNT) g_lkey_count++;
if(g_key_cnt[i] < KEY_CNT) g_key_cnt[i]++;
else g_key_inv[i] = 1;
} else { /* 起到防抖作用 */
if(g_key_cnt[i]) g_key_cnt[i]--;
}
if(g_key_inv[i] && (0 == g_key_cnt[i])) { /* 按键按下并松开 */
if(g_lkey_count >= KEYLONG_CNT) g_key_buf[g_key_inidx] = pkey[i].lkv_index;
else g_key_buf[g_key_inidx] = pkey[i].kv_index;
g_keylast_val = g_key_buf[g_key_inidx];
g_key_inidx = (g_key_inidx + 1) % KEYBUF_MAX;
g_key_inv[i] = 0;
g_lkey_count = 0;
g_key_count = 0;
}
}
return 0;
}
/* 获取按键功能 */
uint8_t bsp_key_readv(void)
{
unsigned char key = KV_NULLKEY;
if(g_key_rdidx != g_key_inidx) {
key = g_key_buf[g_key_rdidx];
g_key_rdidx = (g_key_rdidx + 1) % KEYBUF_MAX;
}
return key;
}
/* 检测按键是否按下 */
int bsp_key_status(void)
{
if(g_key_rdidx != g_key_inidx) return KEY_PRESS;
return KEY_NO_PRESS;
}
真正的核心是bsp_key_proc()函数,通过计数的方法去检测按键的状态,用户也可以自行定义多种不同的按键状态。可以在系统滴答中断里面调用该函数,这种按键处理无阻塞,方便添加按键功能,随便按键按下时间长短。系统滴答中断为1ms,间隔10ms检测按键状态。
__weak void systick_handler_callback(void)
{
static int cnt = 0;
cnt++;
if (cnt >= 10) {
cnt = 0;
bsp_key_proc();
}
}
void SysTick_Handler(void)
{
HAL_IncTick();
systick_handler_callback();
}
int main(void)
{
unsigned char key;
bsp_key_init();
while (1)
{
if (bsp_key_status() != KV_NULLKEY) {
key = bsp_key_readv();
switch (key) {
case KV_KEY1:
break;
case KV_KEY2:
break;
case LKV_KEY1:
break;
case LKV_KEY2:
break;
default:
break;
}
}
}
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』