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
在HarmonyOS鸿蒙Next南向设备中,实现S1、S2、User三个物理按键的独立事件,可以通过以下步骤进行:
-
设备树配置:在设备树中定义S1、S2、User三个物理按键的GPIO引脚。确保每个按键对应的GPIO引脚在设备树中有明确的定义。
-
驱动层实现:在驱动层为每个按键注册中断处理函数。通过
gpio_request
和gpio_direction_input
函数配置GPIO引脚为输入模式,并使用request_irq
函数为每个按键注册中断处理函数。 -
中断处理:在中断处理函数中,根据按键的GPIO状态判断按键的按下和释放事件。可以使用
gpio_get_value
函数读取GPIO引脚的状态。 -
事件上报:在中断处理函数中,根据按键的状态变化,通过
input_report_key
函数上报按键事件。使用input_sync
函数同步事件。 -
用户空间处理:在用户空间,可以通过读取
/dev/input/eventX
设备文件来获取按键事件。使用struct input_event
结构体解析事件数据,并根据EV_KEY
事件类型和KEY_*
键值判断具体是哪个按键的事件。 -
应用层处理:在应用层,可以通过监听输入事件来处理按键事件。使用
InputManager
或KeyEvent
类来捕获和处理按键事件。
通过以上步骤,可以在HarmonyOS鸿蒙Next南向设备中实现S1、S2、User三个物理按键的独立事件处理。
更多关于HarmonyOS鸿蒙Next南向设备:实现S1,S2,User三个物理按键的独立事件的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html