文章目录
- 一、ESP32
- 二、实现
- 1.源文件
- 2.头文件
- 三、调用
- 总结
一、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_11typedef 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, //5KEY2_CLICK, //6KEY2_CLICK_RELEASE,KEY2_LONG_PRESS,KEY2_LONG_PRESS_CONTINUOUS,KEY2_LONG_PRESS_RELEASE,KEY3_CLICK, //11KEY3_CLICK_RELEASE,KEY3_LONG_PRESS,KEY3_LONG_PRESS_CONTINUOUS,KEY3_LONG_PRESS_RELEASE,KEY4_CLICK, //16KEY4_CLICK_RELEASE,KEY4_LONG_PRESS,KEY4_LONG_PRESS_CONTINUOUS,KEY4_LONG_PRESS_RELEASE,KEY5_CLICK, //21KEY5_CLICK_RELEASE,KEY5_LONG_PRESS,KEY5_LONG_PRESS_CONTINUOUS,KEY5_LONG_PRESS_RELEASE,KEY6_CLICK, //26KEY6_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中也提供了相应的例程,相对更加完善