BUTTON使用指南
BUTTON介绍
Button驱动包括两层:通用定时器(GPT)的硬件访问层(HAL)和RT-Thread的适配层。 按钮库使用引脚设备来检测各种按钮动作。 它使用一个计时器来处理去抖动,而另一个计时器来检测长按动作。
它支持以下操作
按下:按钮被按下
释放:按钮被释放
长按:按钮被按下并保持由 BUTTON_ADV_ACTION_CHECK_DELAY 指定的时间
点击:按钮被按下和释放,中间不会触发长按动作
BUTTON配置
PINMUX引脚配置
需要将相应的key引脚配置为IO模式。
HAL_PIN_Set(PAD_PA77, GPIO_A77, PIN_PULLUP, 1); //key3
HAL_PIN_Set(PAD_PA78, GPIO_A78, PIN_PULLUP, 1); //key4
HAL_PIN_Set(PAD_PA79, GPIO_A79, PIN_PULLUP, 1); //key5
HAL_PIN_Set(PAD_PA80, GPIO_A80, PIN_PULLUP, 1); //key6
BUTTON功能代码流程
相关文件如下: 1、button驱动文件 button_service.c 2、button动作执行文件 button_srv_custom.c 代码整体流程为: init_pin() --> button_service_callback() --> button_event_handler() --> button_keypad_cb() 接口实现如下:
int32_t button_keypad_cb(lv_key_t key, lv_indev_state_t event)
{
if ((LV_INDEV_STATE_PR == event) && (LV_KEY_HOME == key))
{
LOG_I("keypad pressed HOME");
#ifdef BSP_USING_PC_SIMULATOR
/* For simulator, don't call the wakeup procedure. Therefor, here, if aod running, wake up now. */
if (app_gui_aod_wakeup()) return 0;
#endif
/* if ota running, wake up now. */
if (app_ota_status_get()) return 0;
#ifdef POWER_ON_GUIDE
/* if power_on_guide is running, ignore it. */
if (power_on_guide_active()) return 0;
#endif
#ifdef APP_POPUP_USED
/* refer to apple's watch solution */
popup_destroy_all();
#endif
#ifdef GUI_APP_FRAMEWORK
/* switch applicaiton between Main and Clock. Customer will modify it according to requirement. */
if (gui_app_is_actived("Main"))
{
#if defined(HOME_DOUBLE_CLICK_FUNCTION)
mainmenu_db_func_entry();
#else
gui_app_run("Tileview");
#endif
}
else
{
gui_app_run("Main");
#if defined(GUI_APP_FRAMEWORK)&& !defined (APP_TRANS_ANIMATION_NONE)
lvsf_gesture_bars_realign();
#endif
}
#endif
}
else if ((LV_INDEV_STATE_PR == event) && (LV_KEY_ESC == key))
{
LOG_I("keypad pressed ESC");
#ifdef GUI_APP_FRAMEWORK
gui_app_goback();
#endif
}
else if ((LV_INDEV_STATE_PR == event) && (LV_KEY_UP == key))
{
LOG_I("keypad pressed UP");
}
else if ((LV_INDEV_STATE_PR == event) && (LV_KEY_DOWN == key))
{
LOG_I("keypad pressed DOWN");
}
return LV_BLOCK_EVENT;
}
BUTTON使用流程
button采用订阅sub pin_service服务方式,button_service_callback实施监听订阅的按键消息,读取订阅按键消息来执行相应的动作。 1、button初始化
static int init_pin(void)
{
button_active_state_t active_state;
//key1 配置
#if (SWITCH_ON_PIN < GPIO1_PIN_NUM)
/* SWITCH_ON PIN is by HPSYS side */
#if defined (BSP_KEY1_ACTIVE_HIGH) && (BSP_KEY1_ACTIVE_HIGH == 1)
active_state = BUTTON_ACTIVE_HIGH;
#else
active_state = BUTTON_ACTIVE_LOW;
#endif
button_config(SWITCH_ON_PIN, active_state, "btn0"); //初始化key1
#endif /* SWITCH_ON_PIN < GPIO1_PIN_NUM */
gui_ctx_init();
button_key1_handle = datac_open(); //获取订阅消息
RT_ASSERT(DATA_CLIENT_INVALID_HANDLE != button_key1_handle);
datac_subscribe(button_key1_handle, "btn0", button_service_callback, BSP_KEY1_PIN); //配置消息订阅的回调函数
button_keypad_map_set(BSP_KEY1_PIN, LV_KEY_HOME);//配置该按键的keypad功能,key1 -- HOME
#ifdef BSP_KEY2_PIN
#if defined (BSP_KEY2_ACTIVE_HIGH) && (BSP_KEY2_ACTIVE_HIGH == 1)
active_state = BUTTON_ACTIVE_HIGH;
#else
active_state = BUTTON_ACTIVE_LOW;
#endif
button_config(BSP_KEY2_PIN, active_state, "btn1");
button_key2_handle = datac_open();
RT_ASSERT(DATA_CLIENT_INVALID_HANDLE != button_key2_handle);
datac_subscribe(button_key2_handle, "btn1", button_service_callback, BSP_KEY2_PIN);
button_keypad_map_set(BSP_KEY2_PIN, LV_KEY_UP);
#endif
#ifdef BSP_KEY3_PIN
#if defined (BSP_KEY3_ACTIVE_HIGH) && (BSP_KEY3_ACTIVE_HIGH == 1)
active_state = BUTTON_ACTIVE_HIGH;
#else
active_state = BUTTON_ACTIVE_LOW;
#endif
button_config(BSP_KEY3_PIN, active_state, "btn2");
button_key3_handle = datac_open();
RT_ASSERT(DATA_CLIENT_INVALID_HANDLE != button_key3_handle);
datac_subscribe(button_key3_handle, "btn2", button_service_callback, BSP_KEY3_PIN);
button_keypad_map_set(BSP_KEY3_PIN, LV_KEY_DOWN);
#endif
rt_pm_request(PM_SLEEP_MODE_IDLE);
sys_poweron_mng_init();
rt_pm_release(PM_SLEEP_MODE_IDLE);
return 0;
}
BUTTON回调函数
**
* @brief Button service callback function of btn data service
* @param arg Data service callback argment
*/
static int button_service_callback(data_callback_arg_t *arg)
{
LOG_I("button_service_callback: msg_id 0x%x", arg->msg_id);
if (MSG_SERVICE_DATA_NTF_IND == arg->msg_id)//判断是否是NTF的消息ID
{
button_action_t action;
RT_ASSERT(arg->data_len == sizeof(action));
action = *(button_action_t *)arg->data;
if (PM_HIBERNATE_BOOT != SystemPowerOnModeGet())
button_long_press_decode(action);//长按按键定时器
#if defined (BF0_HCPU) && defined (USING_BUTTON_LIB) && !defined (BSP_USING_PC_SIMULATOR)
button_event_handler(action, arg->user_data);//按键服务函数
#endif
}
return 0;
}
按键服务函数如下
/**
* @brief bButton event handle function
* @param action Button action status
* @param key_pin pin of key.
*/
static void button_event_handler(button_action_t action, uint32_t key_pin)
{
LOG_I("button:%d, %d", gui_is_active(), action);
if (RT_ERROR == button_event_cb(action)) //defined in button_srv_custome.c. user can self_defined.
return;
#ifdef BSP_USING_PM
if (gui_is_invalid())
{
if (PM_HIBERNATE_BOOT == SystemPowerOnModeGet())
{
LOG_I("button_handler(invalid 1 ): action %d sys_get_is_power_on %d", action, sys_get_is_power_on());
sys_pwron_evt_t evt;
gui_pm_action_t pm_action;
if (!sys_get_is_power_on())
{
evt = SYS_PWRON_EVT_INVALID;
switch (action)
{
case BUTTON_RELEASED:
{
evt = SYS_PWRON_EVT_BUTTON_RELEASED;
break;
}
case BUTTON_LONG_PRESSED:
{
evt = SYS_PWRON_EVT_BUTTON_LONG_PRESSED;
break;
}
default:
{
pm_action = GUI_PM_ACTION_INVALID;
}
}
if (GUI_PM_ACTION_INVALID != evt)
{
sys_poweron_fsm(evt);
}
}
}
else
LOG_I("The GUI is not initialized, please try again later");
return;
}
if (!gui_is_active())
{
/* button event handler in UI active state */
gui_pm_action_t pm_action;
sys_pwron_evt_t evt;
LOG_I("button_handler(inactive 2 ): action %d sys_get_is_power_on %d", action, sys_get_is_power_on());
if (!sys_get_is_power_on())
{
evt = SYS_PWRON_EVT_INVALID;
switch (action)
{
case BUTTON_RELEASED:
{
evt = SYS_PWRON_EVT_BUTTON_RELEASED;
break;
}
case BUTTON_LONG_PRESSED:
{
evt = SYS_PWRON_EVT_BUTTON_LONG_PRESSED;
break;
}
default:
{
pm_action = GUI_PM_ACTION_INVALID;
}
}
if (GUI_PM_ACTION_INVALID != evt)
{
sys_poweron_fsm(evt);
}
}
else
{
pm_action = GUI_PM_ACTION_INVALID;
switch (action)
{
case BUTTON_PRESSED:
{
pm_action = GUI_PM_ACTION_BUTTON_PRESSED;
break;
}
case BUTTON_RELEASED:
{
pm_action = GUI_PM_ACTION_BUTTON_RELEASED;
break;
}
case BUTTON_CLICKED:
{
pm_action = GUI_PM_ACTION_BUTTON_CLICKED;
break;
}
case BUTTON_LONG_PRESSED:
{
pm_action = GUI_PM_ACTION_BUTTON_LONG_PRESSED;
break;
}
default:
{
pm_action = GUI_PM_ACTION_INVALID;
}
}
if (GUI_PM_ACTION_INVALID != pm_action)
{
app_gui_wakeup(pm_action);
}
}
}
else //gui_is_active()
#endif /* BSP_USING_PM */
{
/* button event handler in UI inactive state */
LOG_I("button_handler(active 3 ): action %d", action);
lv_disp_trig_activity(NULL);
switch (action)
{
case BUTTON_CLICKED:
{
button_keypad_status.last_key = button_keypad_to_ascii(key_pin);
button_keypad_status.last_key_state = KEYPAD_KEY_STATE_PRESSED;
break;
}
case BUTTON_LONG_PRESSED:
{
#ifdef BSP_USING_PM
gui_pm_fsm(GUI_PM_ACTION_BUTTON_LONG_PRESSED);
#endif
break;
}
default:
;
}
}
}
按键功能函数
int32_t button_keypad_cb(lv_key_t key, lv_indev_state_t event)
{
if ((LV_INDEV_STATE_PR == event) && (LV_KEY_HOME == key))//判断是否是 LV_KEY_HOME 按键按下
{
LOG_I("keypad pressed HOME");
#ifdef BSP_USING_PC_SIMULATOR
/* For simulator, don't call the wakeup procedure. Therefor, here, if aod running, wake up now. */
if (app_gui_aod_wakeup()) return 0;
#endif
/* if ota running, wake up now. */
if (app_ota_status_get()) return 0;
#ifdef POWER_ON_GUIDE
/* if power_on_guide is running, ignore it. */
if (power_on_guide_active()) return 0;
#endif
#ifdef APP_POPUP_USED
/* refer to apple's watch solution */
popup_destroy_all();
#endif
#ifdef GUI_APP_FRAMEWORK
/* switch applicaiton between Main and Clock. Customer will modify it according to requirement. */
if (gui_app_is_actived("Main"))
{
#if defined(HOME_DOUBLE_CLICK_FUNCTION)
mainmenu_db_func_entry();
#else
gui_app_run("Tileview");
#endif
}
else
{
gui_app_run("Main");
#if defined(GUI_APP_FRAMEWORK)&& !defined (APP_TRANS_ANIMATION_NONE)
lvsf_gesture_bars_realign();
#endif
}
#endif
}
else if ((LV_INDEV_STATE_PR == event) && (LV_KEY_ESC == key))
{
LOG_I("keypad pressed ESC");
#ifdef GUI_APP_FRAMEWORK
gui_app_goback();
#endif
}
#ifdef _MSC_VER
else if ((LV_INDEV_STATE_PR == event) && (LV_KEY_NEXT == key))
{
}
#endif
else if ((LV_INDEV_STATE_PR == event) && (LV_KEY_UP == key))//判断是否是 LV_KEY_UP 按键按下
{
LOG_I("keypad pressed UP");
}
else if ((LV_INDEV_STATE_PR == event) && (LV_KEY_DOWN == key))//判断是否是 LV_KEY_DOWN 按键按下
{
LOG_I("keypad pressed DOWN");
}
return LV_BLOCK_EVENT;
}
//打印log
常见报错
BUTTON 扩展
1、增加key 先在KConfig文件里面增加key4
menuconfig BSP_USING_KEY4
bool "Use key4"
default n
if BSP_USING_KEY4
config BSP_KEY4_PIN
int "KEY4 pin number"
default -1
config BSP_KEY4_ACTIVE_HIGH
bool "Level is high if key is pressed"
default n
endif
2、配置menuconfig;“max button number”

3、增加初始化代码
#ifdef BSP_KEY4_PIN
#if defined (BSP_KEY4_ACTIVE_HIGH) && (BSP_KEY4_ACTIVE_HIGH == 1)
active_state = BUTTON_ACTIVE_HIGH;
#else
active_state = BUTTON_ACTIVE_LOW;
#endif
button_config(BSP_KEY4_PIN, active_state, "btn3");
button_key4_handle = datac_open();
RT_ASSERT(DATA_CLIENT_INVALID_HANDLE != button_key4_handle);
datac_subscribe(button_key4_handle, "btn4", button_service_callback, BSP_KEY4_PIN);
button_keypad_map_set(BSP_KEY4_PIN, LV_KEY_DOWN);//配置该按键的功能
#endif
在button_keypad_cb()函数中增加功能按键,以供调用。
else if ((LV_INDEV_STATE_PR == event) && (LV_KEY_DOWN == key))
{
LOG_I("keypad pressed DOWN");
}
\sifli_solution\sdk\customer\peripherals\Kconfig