【ESP32】按键驱动,长按、短按,可设置多个按键


一、ESP32

之后的项目要用到ESP32,对按键驱动进行移植

二、实现

1.源文件

支持短按、长按和多个按键。
我在这里设置了五个按键,如果还有需要可以继续添加,在头文件这里进行修改。

#include "user_key.h"
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"






KeyEvent_CallBack_t KeyScanCBS;
 

static void hal_keyConfig(void);

static unsigned char hal_getKey1Sta(void);
static unsigned char hal_getKey2Sta(void);
static unsigned char hal_getKey3Sta(void);
static unsigned char hal_getKey4Sta(void);
static unsigned char hal_getKey5Sta(void);
static unsigned char hal_getKey6Sta(void);
	
unsigned char (*getKeysState[KEYNUM])() = {  hal_getKey1Sta,hal_getKey2Sta,hal_getKey3Sta,hal_getKey4Sta,hal_getKey5Sta,hal_getKey6Sta
								};
								
 

unsigned char KeyStep[KEYNUM];								//按键检测流程
unsigned short KeyScanTime[KEYNUM];							//去抖延时
unsigned short KeyPressLongTimer[KEYNUM];						//长按延时
unsigned short KeyContPressTimer[KEYNUM];						//连续长按延时	

void hal_KeyInit(void)
{
	unsigned char i;
	KeyScanCBS = 0;
	hal_keyConfig();
 
	for(i=0; i<KEYNUM; i++)
	{
		KeyStep[i] = KEY_STEP_WAIT;
		KeyScanTime[i] = KEY_SCANTIME;
		KeyPressLongTimer[i] = KEY_PRESS_LONG_TIME;
		KeyContPressTimer[i] = KEY_PRESS_CONTINUE_TIME;
	}
 
}
 
void hal_KeyScanCBSRegister(KeyEvent_CallBack_t pCBS)
{
	if(KeyScanCBS == 0)
	{
			KeyScanCBS = pCBS;
	}
}	

void hal_KeyProc(void)
{
	unsigned char i,KeyState[KEYNUM];
	unsigned char  keys;

	for(i=0; i<KEYNUM; i++)
	{	
		keys = 0; 
 
		KeyState[i] = getKeysState[i]();
		switch(KeyStep[i])
		{
			case KEY_STEP_WAIT:		//等待按键
				if(KeyState[i])
				{
					KeyStep[i] = KEY_STEP_CLICK;	
				}
			break;
			case KEY_STEP_CLICK:				//按键单击按下
				if(KeyState[i])
				{
					if(!(--KeyScanTime[i]))
					{
						KeyScanTime[i] = KEY_SCANTIME;
						KeyStep[i] = KEY_STEP_LONG_PRESS;
						//keys = i+1;										//记录按键ID号
						//state = KEY_CLICK;								//按键单击按下
						keys = (i*5)+1;					
						 
					}
				}else
				{
					KeyScanTime[i] = KEY_SCANTIME;
					KeyStep[i] = KEY_STEP_WAIT;
				}
			break;
			case KEY_STEP_LONG_PRESS:			//按键长按
				if(KeyState[i])
				{	
					if(!(--KeyPressLongTimer[i]))
					{
						KeyPressLongTimer[i] = KEY_PRESS_LONG_TIME;
						KeyStep[i] = KEY_STEP_CONTINUOUS_PRESS;
						
						//keys = i+1;										//记录按键ID号
						//state = KEY_LONG_PRESS;							
						keys = (i*5)+3;								//长按确认
					}
				}else
				{
					KeyPressLongTimer[i] = KEY_PRESS_LONG_TIME;
					KeyStep[i] = KEY_STEP_WAIT;
					//keys = i+1;										//记录按键ID号
					//state = KEY_CLICK_RELEASE;						//单击释放
					keys = (i*5)+2;										//单击释放
				}
			break;
			case KEY_STEP_CONTINUOUS_PRESS:
				if(KeyState[i])
				{
					if(!(--KeyContPressTimer[i]))
					{
						KeyContPressTimer[i] = KEY_PRESS_CONTINUE_TIME;
						//keys = i+1;							//持续长按
						//state = KEY_LONG_PRESS_CONTINUOUS;
						keys = (i*5)+4;					//持续长按
					}
				}else
				{
					KeyStep[i] = KEY_STEP_WAIT;
					KeyContPressTimer[i] = KEY_PRESS_CONTINUE_TIME;
					keys = i+1;								//记录按键ID号
					 	
					keys = (i*5)+5;								//长按释放
				}
				 
			break;
			 		
		}
		if(keys)
		{
			if(KeyScanCBS)
			{
				KeyScanCBS((KEY_VALUE_TYPEDEF)keys);
			}
		}
	 
	}
	

}


static void hal_keyConfig(void)
{
	gpio_pullup_en(K1_PIN);
    gpio_reset_pin(K1_PIN);
    gpio_set_direction(K1_PIN,GPIO_MODE_INPUT);

    // gpio_reset_pin(K2_PIN);
    // gpio_set_direction(K2_PIN,GPIO_MODE_OUTPUT);

    // gpio_reset_pin(K3_PIN);
    // gpio_set_direction(K3_PIN,GPIO_MODE_OUTPUT);

    // gpio_reset_pin(K4_PIN);
    // gpio_set_direction(K4_PIN,GPIO_MODE_OUTPUT);

    // gpio_reset_pin(K5_PIN);
    // gpio_set_direction(K5_PIN,GPIO_MODE_OUTPUT);


    // gpio_reset_pin(K6_PIN);
    // gpio_set_direction(K6_PIN,GPIO_MODE_OUTPUT);


}



static unsigned char hal_getKey1Sta(void)
{
	return (!gpio_get_level(K1_PIN));		
} 

static unsigned char hal_getKey2Sta(void)
{
	return (!gpio_get_level(K2_PIN));		
}

 
static unsigned char hal_getKey3Sta(void)
{
	return (!gpio_get_level(K3_PIN));		
}

static unsigned char hal_getKey4Sta(void)
{
	return (!gpio_get_level(K4_PIN));		
}

static unsigned char hal_getKey5Sta(void)
{
	return (!gpio_get_level(K5_PIN));		
}

static unsigned char hal_getKey6Sta(void)
{
	return (!gpio_get_level(K6_PIN));		
}

2.头文件

#ifndef _HAL_KEY_H
#define _HAL_KEY_H


//上键
// #define K1_PORT	GPIOB
// #define K1_PIN	GPIO_Pin_3
#define K1_PIN GPIO_NUM_2
#define K2_PIN 0
#define K3_PIN 0
#define K4_PIN 0
#define K5_PIN 0
#define K6_PIN 0

// //下键
// #define K2_PORT	GPIOB
// #define K2_PIN	GPIO_Pin_5

// //左键
// #define K3_PORT	GPIOB
// #define K3_PIN	GPIO_Pin_6

// //右键
// #define K4_PORT	GPIOB
// #define K4_PIN	GPIO_Pin_7
 

// //取消/返回
// #define K5_PORT GPIOB	
// #define K5_PIN	GPIO_Pin_10

//确定/设置
// #define K6_PORT GPIOB
// #define K6_PIN	GPIO_Pin_11

typedef enum
{
	KEY_S1,		//上键
	KEY_S2,		//下键
	KEY_S3,
	KEY_S4,
	KEY_S5,
	KEY_S6,
	KEYNUM
}KEY_TYPEDEF;			//按键定义

 

// 按键检测过程
typedef enum
{
	KEY_STEP_WAIT,			//等待按键
	KEY_STEP_CLICK,				//按键按下
	KEY_STEP_LONG_PRESS,				//长按
	KEY_STEP_CONTINUOUS_PRESS,  			//持续按下
}KEY_STEP_TYPEDEF;




typedef enum
{	
	KEY_IDLE,       	 		 							//按键空闲
	KEY_CLICK,          								//单击确认
	KEY_CLICK_RELEASE,            			//单击释放
	KEY_LONG_PRESS,			   						 	//长按确认
	KEY_LONG_PRESS_CONTINUOUS,							//长按持续
	KEY_LONG_PRESS_RELEASE								//长按释放
	 
}KEY_EVENT_TYPEDEF;

typedef enum
{
	KEY_IDLE_VAL,
	KEY1_CLICK,
	KEY1_CLICK_RELEASE,
	KEY1_LONG_PRESS,
	KEY1_LONG_PRESS_CONTINUOUS,
	KEY1_LONG_PRESS_RELEASE,		//5
	
	KEY2_CLICK,								//6
	KEY2_CLICK_RELEASE,
	KEY2_LONG_PRESS,
	KEY2_LONG_PRESS_CONTINUOUS,
	KEY2_LONG_PRESS_RELEASE,
	
	KEY3_CLICK,							//11
	KEY3_CLICK_RELEASE,
	KEY3_LONG_PRESS,
	KEY3_LONG_PRESS_CONTINUOUS,
	KEY3_LONG_PRESS_RELEASE,
	
	KEY4_CLICK,						//16
	KEY4_CLICK_RELEASE,
	KEY4_LONG_PRESS,
	KEY4_LONG_PRESS_CONTINUOUS,
	KEY4_LONG_PRESS_RELEASE,
	
	KEY5_CLICK,						//21
	KEY5_CLICK_RELEASE,
	KEY5_LONG_PRESS,
	KEY5_LONG_PRESS_CONTINUOUS,
	KEY5_LONG_PRESS_RELEASE,
	
	KEY6_CLICK,						//26
	KEY6_CLICK_RELEASE,
	KEY6_LONG_PRESS,
	KEY6_LONG_PRESS_CONTINUOUS,
	KEY6_LONG_PRESS_RELEASE,
	
	
}KEY_VALUE_TYPEDEF;


typedef void (*KeyEvent_CallBack_t)(KEY_VALUE_TYPEDEF keys);

//扫描按键的定时器Tick,以系统Tick(1ms)为单位,10=10ms
#define KEY_SCANT_TICK		10		//10ms

//按键消抖时间,以10ms为Tick,2=20ms
#define KEY_SCANTIME	2		//20ms

//连续长按时间
#define	KEY_PRESS_LONG_TIME	200	//2s

//持续长按间隔时间
#define KEY_PRESS_CONTINUE_TIME	15	//150ms 

void hal_KeyInit(void);
void hal_KeyProc(void);
void hal_KeyScanCBSRegister(KeyEvent_CallBack_t pCBS);





void user_key_task(void *pr);



#endif  

三、调用

首先,调用void hal_KeyInit(void)函数,然后需要在应用层实现按键的回调函数static void KeyEventHandle(KEY_VALUE_TYPEDEF keys),当按键被按下之后,将会调用该回调函数。一般可以把蜂鸣器响或者LED闪烁放在这里。

void hal_KeyProc(void)函数需要创建一个定时器放在其中进行执行,推荐使用ESP32的软件定时器。freertos的软件定时器,最小定时的时间要参考systick,只能到ms级别。而ESP32的软件定时器能道us级别。
当然,具体定时器的时间,要根据实际情况设置,如果是对按键反应时间要求比较高的场合,比如说秒表,计时器,要显示精准,那就可以将时间设置短一些。
如果对按键反应时间要求不高,就可以设置长一些,少消耗一些cpu资源。

//按键回调函数
static void KeyEventHandle(KEY_VALUE_TYPEDEF keys)
{
    if((keys==KEY1_CLICK)
	|| (keys==KEY2_CLICK)
	|| (keys==KEY3_CLICK)
	|| (keys==KEY4_CLICK)
	|| (keys==KEY5_CLICK)
	|| (keys==KEY6_CLICK))
	{
        printf("key1::key_CLICK%d",keys);
        //LedMsgInput(LED1,LED_LIGHT_100MS,1);
        printf("beep is sound\n");
        //hal_Oled_ClearArea(16,20,128,30);
        //OLED_ShowString(16,20,(uint8_t*)"key_CLICK",16,1);
        //OLED_Refresh();
		//LedMsgInput(LED1,LED_LIGHT,1);
	}else if((keys==KEY1_CLICK_RELEASE)
	|| (keys==KEY2_CLICK_RELEASE)
	|| (keys==KEY3_CLICK_RELEASE)
	|| (keys==KEY4_CLICK_RELEASE)
	|| (keys==KEY5_CLICK_RELEASE)
	|| (keys==KEY6_CLICK_RELEASE))
	{
        printf("key1::CLICK_RELEASE%d",keys);
		//LedMsgInput(LED1,LED_BLINK4,1);
	}else if((keys==KEY1_LONG_PRESS)
	|| (keys==KEY2_LONG_PRESS)
	|| (keys==KEY3_LONG_PRESS)
	|| (keys==KEY4_LONG_PRESS)
	|| (keys==KEY5_LONG_PRESS)
	|| (keys==KEY6_LONG_PRESS))
	{
        printf("key1::LONG_PRESS%d",keys);
		//LedMsgInput(LED1,LED_DARK,1);
	}
}

//软件定时器回调函数
static void periodic_timer_callback(void* arg)
{
    //int64_t time_since_boot = esp_timer_get_time();
    hal_KeyProc();
    //ESP_LOGI("example", "Periodic timer called, time since boot: %lld us", time_since_boot);
}

总结

ESP-IDF example中也提供了相应的例程,相对更加完善

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值