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”

../_images/button_4.png

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