一款轻量级支持短按、长按、双击等功能的按键例程

这个例程来源于杰理的SDK,只做了部分修改,方便移植到各个项目里面,具有短按、短按抬起、长按、长按抬起、连按、多击功能。

#ifndef _KEY_H
#define _KEY_H
#include "sys.h"

#define KEY0        HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_3)  //KEY0按键PH3
#define KEY1        HAL_GPIO_ReadPin(GPIOH,GPIO_PIN_2)  //KEY1按键PH2
#define KEY2        HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13) //KEY2按键PC13
#define WK_UP       HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)  //WKUP按键PA0

#define NO_KEY                  	0xff //无按键//

/*双击允许间隔时间*/
#define KEY_DOUBLE_CLICK_MAX_CNT    35  //25*10ms//
#define KEY_DOUBLE_CLICK_MIN_CNT    5   //5*10ms//


 /*按键门槛值*/
#define KEY_BASE_CNT            4   //消抖时间//
#define KEY_LONG_CNT        	50  //长按时间//
#define KEY_HOLD_CNT            50  //连按时间//
#define KEY_SHORT_CNT           7   //短按时间//

/*按键状态*/
#define KEY_SHORT_UP            0x1
#define KEY_LONG                0x2
#define KEY_HOLD                0x3
#define KEY_DOUBLE_CLICK        0x4
#define KEY_THREE_CLICK         0x5
#define	KEY_LONG_UP				0X6
#define	KEY_SHORT				0X7


extern volatile u8 g_cur_key_num;
extern volatile u8 g_cur_key_status;

void KEY_Init(void);//IO初始化
u8 Get_Key_Value(void);
void Key_Event_Handle(uint8_t key_status, uint8_t key_num);
void Key_Scan(void);
#endif

#include "key.h"

volatile u8 g_cur_key_num;
volatile u8 g_cur_key_status;

//按键初始化函数
void KEY_Init(void)
{
    GPIO_InitTypeDef GPIO_Initure;
    
    __HAL_RCC_GPIOA_CLK_ENABLE();           //开启GPIOA时钟
    __HAL_RCC_GPIOC_CLK_ENABLE();           //开启GPIOC时钟
    __HAL_RCC_GPIOH_CLK_ENABLE();           //开启GPIOH时钟
    
    GPIO_Initure.Pin=GPIO_PIN_0;            //PA0
    GPIO_Initure.Mode=GPIO_MODE_INPUT;      //输入
    GPIO_Initure.Pull=GPIO_PULLDOWN;        //下拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);
    
    GPIO_Initure.Pin=GPIO_PIN_13;           //PC13
    GPIO_Initure.Mode=GPIO_MODE_INPUT;      //输入
    GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
    GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOC,&GPIO_Initure);
    
    GPIO_Initure.Pin=GPIO_PIN_2|GPIO_PIN_3; //PH2,3
    HAL_GPIO_Init(GPIOH,&GPIO_Initure);
}

u8 Get_Key_Value(void)
{
	u8 key_num = NO_KEY;
	
	if (KEY0) {
		key_num = 1;
	}
	else if (KEY1)
	{
		key_num = 2;
	}
	else if (KEY2)
	{
		key_num = 3;
	}
	else if (WK_UP)
	{
		key_num = 4;
	}

	return key_num;
}


void Key_Event_Handle(uint8_t key_status, uint8_t key_num)
{
	g_cur_key_status = key_status;
	g_cur_key_num = key_num;
}

void Key_Scan(void)
{
	uint8_t key_status = 0, cur_key = NO_KEY, back_last_key = 0;
	static uint8_t s_filter_value = NO_KEY, s_filter_cnt = 0;
	static uint8_t s_last_key = NO_KEY, s_click_delay_cnt = 0, s_click_cnt = 0,s_notify_value = NO_KEY;
	static uint16_t s_press_cnt = 0;

	//清零按键值及其状态
	g_cur_key_status = 0;
	g_cur_key_num = NO_KEY;

	cur_key = Get_Key_Value(); //获取按键值//

    //消抖/
	if (cur_key != s_filter_value && s_filter_cnt) { //当前按键与上一次按键不同//
		s_filter_cnt = 0;
		s_filter_value = cur_key;
		return;
	}
	if (s_filter_cnt < KEY_BASE_CNT) {
		s_filter_cnt++;
		return;
	}

	if (cur_key != s_last_key) {
		if (cur_key == NO_KEY) { //按键被抬起  s_last_key != NO_KEY//

			if (s_press_cnt >= KEY_LONG_CNT) {
				key_status = KEY_LONG_UP;
				back_last_key = s_last_key;
				goto notify;
			}
			s_click_delay_cnt = 1; //按键等待下次连击开始//
		}
		else { //按键被按下 s_last_key = NO_KEY//
			s_press_cnt = 1;
			if (cur_key != s_notify_value) { //当前单击/连击与上次按键值不等//
				s_notify_value = cur_key;
				s_click_cnt = 1;
			}
			else {
				s_click_cnt++; //连击次数累加
			}
		}
		goto scan_end;
	}
	else {
		if (cur_key == NO_KEY) { //没有按键按下//
			if (s_click_cnt > 0) {

				if (s_click_delay_cnt >= KEY_DOUBLE_CLICK_MAX_CNT) { //按键抬起,判断单击/连击次数
					s_click_delay_cnt = 0;
					switch (s_click_cnt) {
						case 1: //单击//
							key_status = KEY_SHORT_UP;
							break;
						case 2: //双击//
							key_status = KEY_DOUBLE_CLICK;
							break;
						case 3: //三击//
							key_status = KEY_THREE_CLICK;
							break;
						default:
							break;
					}
					back_last_key = s_notify_value;
					goto notify;
				} else {
					s_click_delay_cnt++;
					goto scan_end;  //按键抬起延时时间未到,返回
				}
			} else {
				goto scan_end;  //没有按键需要处理
			}
		}
		else { //长按,连按//
			s_press_cnt++;

			if (s_press_cnt == KEY_LONG_CNT) { //长按//
				key_status = KEY_LONG;
			}
			else if (s_press_cnt == (KEY_LONG_CNT+KEY_HOLD_CNT)) {  //连按//
				key_status = KEY_HOLD;
				s_press_cnt = KEY_LONG_CNT;
			}
			else {
				goto scan_end;
			}
			back_last_key = cur_key;
			goto notify;
		}
	}

notify:

	s_notify_value = NO_KEY;
	s_click_cnt = 0;
	Key_Event_Handle(key_status, back_last_key);  //按键值及其状态转换
scan_end:

	s_last_key = cur_key;
}

这个例程不仅仅支持普通的IO按键,AD按键等其他类型的也都可以移植,只是获取按键值的函数不同罢了。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值