ESP-IDF ESP32按键检测(单击、长按、连击)

头文件,bsp_key.h

#define KEY_NUM     2    //按键数量

typedef enum{
    KEY1_RELEASE = 0x00,
    KEY1_LONGCLICKED,
    KEY1_LONGLONG,      
    KEY1_MULTICLICKED_1,
    KEY1_MULTICLICKED_2,
    KEY1_MULTICLICKED_3,
    KEY1_MULTICLICKED_4,
    KEY1_MULTICLICKED_5,
    KEY2_RELEASE,
    KEY2_LONGCLICKED,   
    KEY2_LONGLONG,    
    KEY2_MULTICLICKED_1,
    KEY2_MULTICLICKED_2,
    KEY2_MULTICLICKED_3,
    KEY2_MULTICLICKED_4,
    KEY2_MULTICLICKED_5,
};

#define LONG_PRESS_THRESHOLD 1000   //长长按时间
#define IDLE_COUNT_THRESHOLD 200    //空闲时间
#define CLICK_LONG_THRESHOLD 500    //长按时间
#define CLICK_COUNT_MAX 1500        
#define CONFIRM_COUNT 25            //消抖时间

typedef struct{
    int (*Scan)(void);
    void (*Init)(void);
    uint16_t KeyCnt;
    uint8_t IdleCnt;
    uint8_t ClickCnt;
    uint8_t LongPressed;
    uint8_t State;
}Key_t;

通过修改头文件中的宏定义可以修改按键检测的参数。

源文件,bsp_key.c

定义按键对象

Key_t g_Key_List[KEY_NUM];

初始化代码

/*************************************  USER CODE  *************************************/

/*
*********************************************************************************************************
*	函 数 名: Key1_Scan
*	功能说明: 扫描按键1的状态
*	形    参: 无
*	返 回 值: 按键1的状态
*********************************************************************************************************
*/
static int Key1_Scan(void)
{
    return gpio_get_level(9);
}

/*
*********************************************************************************************************
*	函 数 名: Key2_Scan
*	功能说明: 扫描按键2的状态
*	形    参: 无
*	返 回 值: 按键2的状态
*********************************************************************************************************
*/
static int Key2_Scan(void)
{
    return gpio_get_level(2);
}

/*
*********************************************************************************************************
*	函 数 名: Key1_Init
*	功能说明: 初始化按键1的配置
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static void Key1_Init(void)
{
    gpio_config_t io_conf = {
        .intr_type = GPIO_INTR_DISABLE, //falling edge interrupt
        .mode = GPIO_MODE_INPUT, //set as input mode
        .pin_bit_mask = 1<<GPIO_NUM_9, //bit mask of the pins GPIO9
        .pull_down_en = 0, //disable pull-down mode
        .pull_up_en = 1 //enable pull-up mode
    };
    //configure GPIO with the given settings
    gpio_config(&io_conf);
}

/*
*********************************************************************************************************
*	函 数 名: Key2_Init
*	功能说明: 初始化按键2的配置
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static void Key2_Init(void)
{
    gpio_config_t io_conf2 = {
        .intr_type = GPIO_INTR_DISABLE, //falling edge interrupt
        .mode = GPIO_MODE_INPUT, //set as input mode
        .pin_bit_mask = 1<<GPIO_NUM_2, //bit mask of the pins GPIO9
        .pull_down_en = 0, //disable pull-down mode
        .pull_up_en = 1 //enable pull-up mode
    };
    //configure GPIO with the given settings
    gpio_config(&io_conf2);
}
/*************************************  END  *************************************/

/*
*********************************************************************************************************
*	函 数 名: bsp_Key_Init
*	功能说明: 初始化按键列表,设置扫描和初始化函数指针,初始化按键状态和计数器
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_Key_Init(void)
{
    g_Key_List[0].Scan = Key1_Scan;
    g_Key_List[0].Init = Key1_Init;
    g_Key_List[1].Scan = Key2_Scan;
    g_Key_List[1].Init = Key2_Init;

    for (uint8_t i = 0; i < KEY_NUM; i++)
    {
        g_Key_List[i].KeyCnt = 0;
        g_Key_List[i].IdleCnt = 0;
        g_Key_List[i].ClickCnt = 0;
        g_Key_List[i].LongPressed = 0;
        g_Key_List[i].State = 0;
    }

    g_Key_List[0].Init();
    g_Key_List[1].Init();
}

按键扫描代码:

/*
*********************************************************************************************************
*	函 数 名: bsp_key_scan
*	功能说明: 扫描按键状态,处理长按、短按和松手事件
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static void bsp_key_scan(void)
{
    uint8_t KeyVal = 0x00;

    for(uint8_t i = 0; i < KEY_NUM; i++)
    {
        if (g_Key_List[i].Scan() == 0)
        {
            if (g_Key_List[i].KeyCnt < CLICK_COUNT_MAX)
                g_Key_List[i].KeyCnt++;
            
            /* 长长按 */
            if (g_Key_List[i].KeyCnt > LONG_PRESS_THRESHOLD && !g_Key_List[i].LongPressed)
            {
                KeyVal = i * 8 + KEY1_LONGLONG;
                g_Key_List[i].State = KeyVal;
                // printf("长长按, KeyVal = 0x%x\r\n", KeyVal);
                xQueueSend(gpio_evt_queue, &KeyVal, NULL);
                g_Key_List[i].LongPressed = 1;
                g_Key_List[i].KeyCnt = 0;
            }
            g_Key_List[i].IdleCnt = 0;
        }
        else
        {
            /* Release */
            if (g_Key_List[i].State != i*8)
            {
                if (g_Key_List[i].KeyCnt == 0)
                {
                    KeyVal = i * 8;
                    g_Key_List[i].State = i*8;
                    xQueueSend(gpio_evt_queue, &KeyVal, NULL);
                    // printf("Release\r\n");
                }
                else
                    g_Key_List[i].KeyCnt--;
            }

            if (g_Key_List[i].LongPressed)
            {
                g_Key_List[i].KeyCnt = 0;
                g_Key_List[i].LongPressed = 0;
                g_Key_List[i].ClickCnt = 0;
            }

            /* 单击、多击松手 */
            if (g_Key_List[i].IdleCnt++ >= IDLE_COUNT_THRESHOLD)
            {
                g_Key_List[i].KeyCnt = 0;

                if (g_Key_List[i].ClickCnt)
                {
                    KeyVal = i * 8 + KEY1_MULTICLICKED_1 - 1 + g_Key_List[i].ClickCnt;
                    g_Key_List[i].State = KeyVal;
                    xQueueSend(gpio_evt_queue, &KeyVal, NULL);
                    // printf("按键%d击, KeyVal = 0x%x\r\n",g_Key_List[i].ClickCnt,KeyVal);
                }
                g_Key_List[i].ClickCnt = 0;
                g_Key_List[i].IdleCnt = 0;
            }
            /* long Press */
            if (g_Key_List[i].KeyCnt > CLICK_LONG_THRESHOLD)
            {
                KeyVal = i * 8 + KEY1_LONGCLICKED;
                g_Key_List[i].State = KeyVal;
                xQueueSend(gpio_evt_queue, &KeyVal, NULL);
                g_Key_List[i].KeyCnt = 0;
                // printf("按键长按, KeyVal = 0x%x\r\n", KeyVal);
                g_Key_List[i].ClickCnt = 0;
            }
            /* 单击、多击 */
            else if (g_Key_List[i].KeyCnt <= CLICK_LONG_THRESHOLD && g_Key_List[i].KeyCnt >= CONFIRM_COUNT)
            {
                g_Key_List[i].ClickCnt++;
                g_Key_List[i].KeyCnt = 0;
            }
        }
    }
}

代码中使用 xQueueSend(gpio_evt_queue, &KeyVal, NULL) 发送键值至其他线程,在裸机中使用可以替换为向自己的队列FIFO写键值。

示例:

扫描线程,周期2ms,在裸机环境中可使用systick定时器,在systick中断中调用bsp_key_scan函数。

void key_task_example(void* arg)
{
    for(;;)
    {
        bsp_key_scan();
        vTaskDelay(2);
    }
}
static void gpio_task_example(void* arg)
{
    uint32_t KeyVal;

    for(;;) {
        if(xQueueReceive(gpio_evt_queue, &KeyVal, portMAX_DELAY)) 
        {
            switch (KeyVal)
            {
                case KEY1_RELEASE :
                    printf("Release\r\n");
                break;

                case KEY1_LONGCLICKED :
                    printf("KEY1_LONGCLICKED\r\n");
                break;

                case KEY1_LONGLONG :
                    printf("KEY1_LONGLONGCLICKED\r\n");
                break;

                case KEY1_MULTICLICKED_1 :
                    printf("KEY1_MULTICLICKED_1\r\n");
                break;

                case KEY1_MULTICLICKED_2 :
                    printf("KEY1_MULTICLICKED_2\r\n");
                break;

                case KEY1_MULTICLICKED_3 :
                    printf("KEY1_MULTICLICKED_3\r\n");
                break;                     
                
                case KEY1_MULTICLICKED_4 :
                    printf("KEY1_MULTICLICKED_4\r\n");
                break;                     
                
                case KEY1_MULTICLICKED_5 :
                    printf("KEY1_MULTICLICKED_5\r\n");
                break;                

                default: break;
            }
        }
    }
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值