×
单片机 > 单片机程序设计 > 详情

STM32 简易按键KEY处理

发布时间:2020-06-03 发布时间:
|

一般的按键功能都需要做防抖处理,中间就涉及到了阻塞延迟,但是在实际项目开发中应当尽量避免不必的阻塞。可以使用计时功能去处理按键防抖,在系统滴答时钟中断中实现按键功能检测,按键功能处理是在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;

}

}

}

}


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机CO2检测显示程序解析