HarmonyOS鸿蒙Next南向设备:实现S1,S2,User三个物理按键的独立事件

HarmonyOS鸿蒙Next南向设备:实现S1,S2,User三个物理按键的独立事件 实现 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 -> %d\n", sender, event);
}

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

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

    ret += DTButton_Init();
    
    // 设置 GPIO_8 按键的回调函数,同时需要响应按下,释放以及长按三个事件
    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[i] && name)
    {
        if (strcmp(gBtnName[i], 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 volatile hi_u64 sHisTick = 0;
    static int sPreKey = SSU_None;

    int curKey = GetSSU();

    if ((sPreKey == SSU_None) && (curKey != SSU_None))
    {
        static 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[i].name;

        if (gBtnClicked[i].pressClicked)
        {
            if (gBtnInfo[i].event & Pressed)
                gBtnInfo[i].callback(name, Pressed);
            gBtnClicked[i].pressClicked = 0;
            gBtnClicked[i].longPressInterval = 0;
        }

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

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

        if (gBtnClicked[i].longPressClicked)
        {
            if (gBtnInfo[i].event & LongPressed)
                gBtnInfo[i].callback(name, LongPressed);
            gBtnClicked[i].longPressClicked = 0;
            gBtnClicked[i].longPressInterval = LONG_PRESS_END;
        }

        if (gBtnClicked[i].releaseClicked)
        {
            if (gBtnInfo[i].event & Released)
                gBtnInfo[i].callback(name, Released);
            gBtnClicked[i].releaseClicked = 0;
            gBtnClicked[i].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 == 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[i].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);

            if (ret == 0)
            {
                gBtnInfo[index].name = name;
                gBtnInfo[index].index = index;
                gBtnInfo[index].event = event;
                gBtnInfo[index].callback = callback;
            }
        }
        else if ((SSU_USR <= index) && (index < MAX_KEY_NUM))
        {
            ret = 0;
        }
    }

    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 physical 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 physical button
 *
 * Return Value:
 *     None
 */
void DTButton_Disable(const char* name);

#endif
2 回复

在HarmonyOS鸿蒙Next南向设备中,实现S1、S2、User三个物理按键的独立事件,可以通过以下步骤进行:

  1. 设备树配置:在设备树中定义S1、S2、User三个物理按键的GPIO引脚。确保每个按键对应的GPIO引脚在设备树中有明确的定义。

  2. 驱动层实现:在驱动层为每个按键注册中断处理函数。通过gpio_requestgpio_direction_input函数配置GPIO引脚为输入模式,并使用request_irq函数为每个按键注册中断处理函数。

  3. 中断处理:在中断处理函数中,根据按键的GPIO状态判断按键的按下和释放事件。可以使用gpio_get_value函数读取GPIO引脚的状态。

  4. 事件上报:在中断处理函数中,根据按键的状态变化,通过input_report_key函数上报按键事件。使用input_sync函数同步事件。

  5. 用户空间处理:在用户空间,可以通过读取/dev/input/eventX设备文件来获取按键事件。使用struct input_event结构体解析事件数据,并根据EV_KEY事件类型和KEY_*键值判断具体是哪个按键的事件。

  6. 应用层处理:在应用层,可以通过监听输入事件来处理按键事件。使用InputManagerKeyEvent类来捕获和处理按键事件。

通过以上步骤,可以在HarmonyOS鸿蒙Next南向设备中实现S1、S2、User三个物理按键的独立事件处理。

更多关于HarmonyOS鸿蒙Next南向设备:实现S1,S2,User三个物理按键的独立事件的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next南向设备中,实现S1、S2、User三个物理按键的独立事件,可以通过以下步骤进行:

  1. 按键驱动配置:在设备树中为S1、S2、User按键配置GPIO引脚,并设置相应的中断触发方式(如上升沿、下降沿)。

  2. 事件处理函数:在驱动层为每个按键注册中断处理函数,当按键按下或释放时,触发相应的事件。

  3. 事件上报:在中断处理函数中,通过input_report_key函数上报按键事件,区分不同的按键值(如KEY_S1、KEY_S2、KEY_USER)。

  4. 应用层监听:在应用层通过InputManager监听按键事件,根据不同的按键值执行相应的逻辑。

  5. 调试与验证:通过日志或调试工具验证按键事件的独立性和准确性,确保每个按键的事件都能被正确识别和处理。

通过这些步骤,可以实现S1、S2、User三个物理按键的独立事件处理。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!