南向设备:实现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);
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
本文内容参考了唐佐林老师的部分公开代码。