STM32 简易按键KEY处理

一般的按键功能都需要做防抖处理,中间就涉及到了阻塞延迟,但是在实际项目开发中应当尽量避免不必的阻塞。可以使用计时功能去处理按键防抖,在系统滴答时钟中断中实现按键功能检测,按键功能处理是在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;
			}
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章