[文章]南向设备:实现S1,S2,User三个物理按键的独立事件

阅读量0
0
3
实现S1,S2,User三个物理按键的独立事件,咱们在按下S1按钮后会在串口窗口上打印S1 -> 4,说明了S1按钮被按下,S2按钮就是,按下去的那一刻会打印S2 -> 1,松开后会打印S2 -> 4,还有就是长按user按钮会打印一个USR -> 2,这些按钮都是可以自定义设置的,俄罗斯方块就是典型例子,可以通过按键控制方块的位置,控制方块的方向等操作。

代码如下:
dt_btn_demo.c
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "dt_btn_util.h"

static void Button_jltf_Callback(const char* sender, BtnEvent event)
{
    printf("[dt4sw] Button_jltf_Callback() : %s -> %dn", sender, event);

    if( event == Pressed )     { /* Pressed == 1     按下事件处理代码 */ }
    if( event == LongPressed ) { /* LongPressed == 2 长按事件处理代码 */ }
    if( event == Released )    { /* Released == 4    释放事件处理代码 */ }
}

static void* DTBtnDemo_jltf_Task(const char* arg)
{
    int ret = 0;

    printf("[dt4sw] DTBtnDemo_jltf_Task()n");

    ret += DTButton_Init(); // 初始化按键事件处理上下文

    /* 设置GPIO_8按键的回调函数,同时需要响应按下,释放以及长按三个事件 */
    /* 按键触发顺序: Pressed -> LongPressed(optional) -> Released */
    ret += DTButton_Enable("GPIO_8", Button_jltf_Callback, Pressed | LongPressed | Released);

    /* 分别设置S1, S2, USER按键的回调函数 */
    ret += DTButton_Enable("S1", Button_jltf_Callback, Released);
    ret += DTButton_Enable("S2", Button_jltf_Callback, Pressed | LongPressed | Released);
    ret += DTButton_Enable("USR", Button_jltf_Callback, LongPressed);

    if( ret == 0 )
    {
        while(1)
        {
            usleep(100000);
        }

        DTButton_Disable("GPIO_8");  // 取消 GPIO_8 按键的所有按键事件
        DTButton_Disable("S1");      // 取消 S1 按键的所有按键事件
        DTButton_Disable("S2");      // 取消 S2 按键的所有按键事件
        DTButton_Disable("USR");     // 取消 USER 按键的所有按键事件

        DTButton_Deinit(); // 关闭按钮事件处理上下文
    }
    else
    {
        printf("[dt4sw] Falied to enable button!n");
    }

    return (void*)arg;
}

static void DTBtnDemo_Entry(void)
{
    osThreadAttr_t attr = {0};

    printf("[dt4sw] DTBtnDemo_Entry()n");

    attr.name = "DTBtnDemo_jltf_Task";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024;
    attr.priority = osPriorityNormal;

    if (osThreadNew((osThreadFunc_t)DTBtnDemo_jltf_Task, NULL, &attr) == NULL)
    {
        printf("[dt4sw] Falied to create DTBtnDemo Task!n");
    }
}

SYS_RUN(DTBtnDemo_Entry);



dt_btn_util.c

#include <unistd.h>
#include <string.h>
#include "cmsis_os2.h"
#include "hi_systick.h"
#include "hi_adc.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "dt_btn_util.h"

#define BUTTON_STACK_SIZE   2048
#define PRESS_INTERVAL      20000
#define LOOP_INTERVAL       40000
#define LONG_PRESS_INTERVAL 64
#define LONG_PRESS_END      0xFFFF
#define INDEX_ERR           -1
#define MAX_KEY_NUM         SSU_None

enum
{
    ADC_USR_MIN = 5,
    ADC_USR_MAX = 228,
    ADC_S1_MIN,
    ADC_S1_MAX  = 512,
    ADC_S2_MIN,
    ADC_S2_MAX  = 854
};

enum
{
    SSU_USR = 15,
    SSU_S1,
    SSU_S2,
    SSU_None
};

typedef struct
{
    const char* name;
    unsigned int index;
    unsigned int event;
    PBtnCallback callback;
} ButtonInfo;

typedef struct
{
    int pressClicked;
    int longPressClicked;
    int longPressInterval;
    int releaseClicked;
} ButtonClicked;

static volatile int gToClick = 0;
static volatile int gIsInit = 0;
static const char* gBtnName[] = {
    "GPIO_0",  "GPIO_1",  "GPIO_2",  "GPIO_3",  "GPIO_4",
    "GPIO_5",  "GPIO_6",  "GPIO_7",  "GPIO_8",  "GPIO_9",
    "GPIO_10", "GPIO_11", "GPIO_12", "GPIO_13", "GPIO_14",
    "USR",     "S1",      "S2",
    NULL
};

static volatile ButtonInfo gBtnInfo[MAX_KEY_NUM] = {0};
static volatile ButtonClicked gBtnClicked[MAX_KEY_NUM] = {0};

static void OnButtonPressed(char* arg);
static void OnButtonReleased(char* arg);

static int GetIndex(const char* name)
{
    int ret = INDEX_ERR;
    int i = 0;

    while( gBtnName && name )
    {
        if( strcmp(gBtnName, name) == 0 )
        {
            ret = i;
            break;
        }

        i++;
    }

    return ret;
}

static int GetSSU(void)
{
    unsigned short data = 0;
    int ret = SSU_None;

    if( hi_adc_read(HI_ADC_CHANNEL_2, &data, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0) == 0 )
    {
        if( (ADC_USR_MIN <= data) && (data <= ADC_USR_MAX) )  ret = SSU_USR;
        if( (ADC_S1_MIN  <= data) && (data <= ADC_S1_MAX ) )  ret = SSU_S1;
        if( (ADC_S2_MIN  <= data) && (data <= ADC_S2_MAX ) )  ret = SSU_S2;
    }

    return ret;
}

static void OnButtonPressed(char* arg)
{
    static volatile hi_u64 sHisTick = 0;
    WifiIotIoName gpio = (WifiIotIoName)arg;
    hi_u64 tick = hi_systick_get_cur_tick();

    gToClick = (tick - sHisTick) > PRESS_INTERVAL;

    if( gToClick )
    {
        sHisTick = tick;

        gBtnClicked[gpio].pressClicked = 1;

        GpioRegisterIsrFunc(gpio,
                            WIFI_IOT_INT_TYPE_EDGE,
                            WIFI_IOT_GPIO_EDGE_RISE_LEVEL_HIGH,
                            OnButtonReleased, arg);
    }         
}

static void OnButtonReleased(char* arg)
{
    WifiIotIoName gpio = (WifiIotIoName)arg;

    if( gToClick )
    {
        gBtnClicked[gpio].releaseClicked = 1;

        GpioRegisterIsrFunc(gpio,
                            WIFI_IOT_INT_TYPE_EDGE,
                            WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW,
                            OnButtonPressed, arg);
    }
}

static void SSUEventTrigger(void)
{
    static hi_u64 sHisTick = 0;
    static int sPreKey = SSU_None;

    int curKey = GetSSU();

    if( (sPreKey == SSU_None) && (curKey != SSU_None) )
    {
        hi_u64 tick = hi_systick_get_cur_tick();
        int toClick = (tick - sHisTick) > PRESS_INTERVAL;

        if( toClick )
        {
            gBtnClicked[curKey].pressClicked = 1;

            sPreKey = curKey;

            sHisTick = tick;
        }
    }
    else if( (sPreKey != SSU_None) && (curKey == SSU_None) )
    {
        gBtnClicked[sPreKey].releaseClicked = 1;

        sPreKey = curKey;
    }
}

static void EventHandler(void)
{
    int i = 0;

    for(i=0; i<MAX_KEY_NUM; i++)
    {
        const char* name = gBtnInfo.name;

        if( gBtnClicked.pressClicked )
        {
            if( gBtnInfo.event & Pressed )
                gBtnInfo.callback(name, Pressed);

            gBtnClicked.pressClicked = 0;
            gBtnClicked.longPressInterval = 0;
        }

        if( gBtnClicked.longPressInterval < LONG_PRESS_END )
        {
            gBtnClicked.longPressInterval++;
        }

        if( gBtnClicked.longPressInterval == LONG_PRESS_INTERVAL )
        {
            gBtnClicked.longPressClicked = 1;
        }

        if( gBtnClicked.longPressClicked )
        {
            if( gBtnInfo.event & LongPressed )
                gBtnInfo.callback(name, LongPressed);

            gBtnClicked.longPressClicked = 0;
            gBtnClicked.longPressInterval = LONG_PRESS_END;
        }

        if( gBtnClicked.releaseClicked )
        {
            if( gBtnInfo.event & Released )
                gBtnInfo.callback(name, Released);

            gBtnClicked.releaseClicked = 0;
            gBtnClicked.longPressInterval= LONG_PRESS_END;
        }
    }
}

static void* DTButton_Task(const char* arg)
{
    while( gIsInit )
    {
        SSUEventTrigger();
        EventHandler();
        usleep(LOOP_INTERVAL);
    }

    return (void*)arg;
}

int DTButton_Init(void)
{
    int ret = (int)GpioInit();

    if( ret == (int)HI_ERR_GPIO_REPEAT_INIT )
    {
        ret = 0;
    }

    if( !ret && !gIsInit )
    {
        int i = 0;
        osThreadAttr_t attr = {0};

        for(i=0; i<MAX_KEY_NUM; i++)
        {
            gBtnClicked.longPressInterval = LONG_PRESS_END;
        }

        attr.name = "DTButton_Task";
        attr.attr_bits = 0U;
        attr.cb_mem = NULL;
        attr.cb_size = 0U;
        attr.stack_mem = NULL;
        attr.stack_size = BUTTON_STACK_SIZE;
        attr.priority = osPriorityNormal;

        ret += (osThreadNew((osThreadFunc_t)DTButton_Task, NULL, &attr) == NULL);

        gIsInit = (ret == 0);
    }

    return ret;
}

void DTButton_Deinit(void)
{
    gIsInit = 0;
}

int DTButton_Enable(const char* name, PBtnCallback callback, unsigned int event)
{
    int ret = -1;

    if( callback )
    {
        int index = name ? GetIndex(name) : INDEX_ERR;

        if( (WIFI_IOT_IO_NAME_GPIO_0 <= index) && (index < WIFI_IOT_IO_NAME_MAX) )
        {   
            ret  = IoSetFunc((WifiIotIoName)index, 0);
            ret += GpioSetDir((WifiIotIoName)index, WIFI_IOT_GPIO_DIR_IN);
            ret += IoSetPull((WifiIotIoName)index, WIFI_IOT_IO_PULL_UP);
            ret += GpioRegisterIsrFunc((WifiIotIoName)index,
                                WIFI_IOT_INT_TYPE_EDGE,
                                WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW,
                                OnButtonPressed, (char*)index);                  
        }
        else if( (SSU_USR <= index) && (index < MAX_KEY_NUM) )
        {
            ret = 0;
        }

        if( ret == 0 )
        {
            gBtnInfo[index].name = name;
            gBtnInfo[index].index = index;
            gBtnInfo[index].event = event;
            gBtnInfo[index].callback = callback;
        }
    }

    return ret;
}

void DTButton_Disable(const char* name)
{
    int gpio = name ? GetIndex(name) : INDEX_ERR;

    if( gpio != INDEX_ERR )
    {
        gBtnInfo[gpio].name = 0;
        gBtnInfo[gpio].index = 0;
        gBtnInfo[gpio].event = 0;
        gBtnInfo[gpio].callback = 0;
    }
}


dt_btn_util.h


#ifndef DT_BTNUTIL_H
#define DT_BTNUTIL_H

/*
  Description:
      Button event ID.
*/
typedef enum
{
    None = 0,
    Pressed = 1,
    LongPressed = 2,
    Released = 4
} BtnEvent;

/*
  Description:
      Button event callback function pointer type.

  Parameter:
      sender -- string name for the GPIO button
      event  -- event ID which trigger the function call

  Return Value:
      0     -- Success
      other -- Failure
*/
typedef void (*PBtnCallback)(const char* sender, BtnEvent event);

/*
  Description:
      To initialize button event process context.

  Parameter:
      None

  Return Value:
      0     -- Success
      other -- Failure
*/
int DTButton_Init(void);

/*
  Description:
      To close button event process context.

  Parameter:
      None

  Return Value:
      None
*/
void DTButton_Deinit(void);

/*
  Description:
      To register callback functions for a GPIO button.

  Parameter:
      name     -- target GPIO port name for a phisical button
      callback -- callback function for button event
      event    -- the target button event to trigger callback

  Return Value:
      0     -- Success
      other -- Failure
*/
int DTButton_Enable(const char* name, PBtnCallback callback, unsigned int event);

/*
  Description:
      To unregister callback functions for a GPIO button.

  Parameter:
      name -- target GPIO port name for a phisical button

  Return Value:
      None
*/
void DTButton_Disable(const char* name);

#endif

本文内容参考了唐佐林老师的部分公开代码。


回帖

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉