一、简介
在蓝牙协议栈下,库函数文件提供了一个 BSP(板级支持包) 来支持硬件外设上的按键和 LED 灯的控制,该文件以 bsp.c 和 bsp.h 进行命名。这里所谓的 BSP(板级支持包) 主要是整合了按键模块的功能和一些“板级指令”以及与 BLE 事件的交互,和你使用的开发板硬件配置相关。其中按键控制以软件按键 app button 库为基础。软件按键 app button 和软件定时 app timer 类似,可以注册多个软件按键。通过 GPIOTE 来实现任务的触发。
二、API
2.1 bsp_init
函数 | uint32_t bsp_init(uint32_t type, bsp_event_callback_t callback) |
---|---|
功能 | 初始化板级设备BSP。该函数初始化板级支持包以允许状态指示灯和按钮的反应。默认回调事件被分配给按键处理。 |
注意 | 在调用此函数之前,您必须启动以下所需模块: * 用于支持LED的app_timer * 用于支持按钮的app_gpiote |
参数 | type:使用设备的类型(LED和按键) callback:当检测到按钮按下/事件时调用的函数 |
返回值 | NRF_SUCCESS:初始化成功 NRF_ERROR_INVALID_STATE:应用程序计时器模块尚未初始化 NRF_ERROR_NO_MEM:达到计时器的最大数量 NRF_ERROR_INVALID_PARAM:GPIOTE已经有太多用户 |
NRF_ERROR_INVALID_STATE:尚未初始化按钮或GPIOTE
2.2 bsp_btn_ble_init
函数 | uint32_t bsp_btn_ble_init(bsp_btn_ble_error_handler_t error_handler, bsp_event_t * p_startup_bsp_evt) |
---|---|
功能 | 用于初始化BLE按钮模块。在调用此函数之前,必须使用按钮初始化BSP模块。 |
参数 | error_handler:当BLE按钮发生内部错误时调用错误处理程序模块 p_startup_bsp_evt:如果不是空指针,该值由启动时按下的按钮派生的事件(或BSP_EVENT_NOTHING)填充。例如,如果按下bond delete wakeup按钮来唤醒设备,则p_startup_bsp_evt设置为@ref BSP_EVENT_CLEAR_BONDING_DATA。 |
返回值 | NRF_SUCCESS:如果初始化成功。否则,将返回错误码。 |
uint32_t bsp_btn_ble_init(bsp_btn_ble_error_handler_t error_handler, bsp_event_t * p_startup_bsp_evt)
{
uint32_t err_code = NRF_SUCCESS;
m_error_handler = error_handler;
if (p_startup_bsp_evt != NULL)
{
startup_event_extract(p_startup_bsp_evt);
}
// 如果设备连接数保持为0,也就是断开状态下,开启按键配置函数
if (m_num_connections == 0)
{
// 广播设备按钮配置函数
err_code = advertising_buttons_configure();
}
return err_code;
}
当设备连接数保持为0时,启动按键配置函数。按键配置函数主要的功能就是配置对应的物理按键,当按下或释放按键的时候,触发对应的按键回调事件。按键配置函数内部如下:
/**@brief Function for configuring the buttons for advertisement.
*
* @retval NRF_SUCCESS Configured successfully.
* @return A propagated error code.
*/
static uint32_t advertising_buttons_configure()
{
uint32_t err_code;
err_code = bsp_event_to_button_action_assign(BTN_ID_DISCONNECT,
BTN_ACTION_DISCONNECT,
BSP_EVENT_DEFAULT);
RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code);
err_code = bsp_event_to_button_action_assign(BTN_ID_WHITELIST_OFF,
BTN_ACTION_WHITELIST_OFF,
BSP_EVENT_WHITELIST_OFF);
RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code);
err_code = bsp_event_to_button_action_assign(BTN_ID_SLEEP,
BTN_ACTION_SLEEP,
BSP_EVENT_SLEEP);
RETURN_ON_ERROR_NOT_INVALID_PARAM(err_code);
return NRF_SUCCESS;
}
按键配置函数内部有一个关键函数,通过这个函数配置了多个按键任务;
bsp_event_to_button_action_assign
2.3 bsp_event_to_button_action_assign
函数 | uint32_t bsp_event_to_button_action_assign(uint32_t button, bsp_button_action_t action, bsp_event_t event) |
---|---|
功能 | 配置多个按键任务。 |
参数 | button:应用程序按键的虚拟ID。通常与板子硬件相关。比如官方的pca10040有四个按键,那么使用的ID依次分配0-3,也就是一个物理按键对应分配一个ID。 action:触发动作,比如按下按键动作为APP_BUTTON_PUSH,释放按键的动作为APP_BUTTON_RELEASE,长按按键按下为BSP_BUTTON_ACTION_LONG_PUSH。 event:触发条件被触发后会产生的BSP按键回调事件。BSP模块中实现的按键功能在注册的按键事件触发后,不管是哪个按键,执行的处理函数都是一样的,处理过程就是根据按键按下或释放将上面第2个参数按键事件event,也就是BSP按键事件,传递给最终的按键事件回调处理函数bsp_event_handler()中。 |
2.4 BSP事件
/**@brief BSP events.
*
* @note Events from BSP_EVENT_KEY_0 to BSP_EVENT_KEY_LAST are by default assigned to buttons.
*/
typedef enum
{
BSP_EVENT_NOTHING = 0, /**< Assign this event to an action to prevent the action from generating an event (disable the action). */
BSP_EVENT_DEFAULT, /**< Assign this event to an action to assign the default event to the action. */
BSP_EVENT_CLEAR_BONDING_DATA, /**< Persistent bonding data should be erased. */
BSP_EVENT_CLEAR_ALERT, /**< An alert should be cleared. */
BSP_EVENT_DISCONNECT, /**< A link should be disconnected. */
BSP_EVENT_ADVERTISING_START, /**< The device should start advertising. */
BSP_EVENT_ADVERTISING_STOP, /**< The device should stop advertising. */
BSP_EVENT_WHITELIST_OFF, /**< The device should remove its advertising whitelist. */
BSP_EVENT_BOND, /**< The device should bond to the currently connected peer. */
BSP_EVENT_RESET, /**< The device should reset. */
BSP_EVENT_SLEEP, /**< The device should enter sleep mode. */
BSP_EVENT_WAKEUP, /**< The device should wake up from sleep mode. */
BSP_EVENT_SYSOFF, /**< The device should enter system off mode (without wakeup). */
BSP_EVENT_DFU, /**< The device should enter DFU mode. */
BSP_EVENT_KEY_0, /**< Default event of the push action of BSP_BUTTON_0 (only if this button is present). */
BSP_EVENT_KEY_1, /**< Default event of the push action of BSP_BUTTON_1 (only if this button is present). */
BSP_EVENT_KEY_2, /**< Default event of the push action of BSP_BUTTON_2 (only if this button is present). */
BSP_EVENT_KEY_3, /**< Default event of the push action of BSP_BUTTON_3 (only if this button is present). */
BSP_EVENT_KEY_4, /**< Default event of the push action of BSP_BUTTON_4 (only if this button is present). */
BSP_EVENT_KEY_5, /**< Default event of the push action of BSP_BUTTON_5 (only if this button is present). */
BSP_EVENT_KEY_6, /**< Default event of the push action of BSP_BUTTON_6 (only if this button is present). */
BSP_EVENT_KEY_7, /**< Default event of the push action of BSP_BUTTON_7 (only if this button is present). */
BSP_EVENT_KEY_LAST = BSP_EVENT_KEY_7,
} bsp_event_t;
三、使用例子
首先编写按键事件回调处理函数bsp_event_handler()
void bsp_event_handler(bsp_event_t event)
{
switch(event)
{
case BSP_EVENT_KEY_0:
// 做相应处理
break;
case BSP_EVENT_KEY_1:
// 做相应处理
break;
default:
break;
}
}
然后在 main() 函数中初始化
int main(void)
{
···
bsp_event_t startup_event;
bsp_init(BSP_INIT_BUTTONS, bsp_event_handler);
bsp_btn_ble_init(NULL, &startup_event);
bsp_event_to_button_action_assign(0, BSP_BUTTON_ACTION_RELEASE, BSP_EVENT_KEY_0);
bsp_event_to_button_action_assign(0, BSP_BUTTON_ACTION_LONG_PUSH, BSP_EVENT_KEY_1);
···
}
0 是应用程序按钮ID BSP_BUTTON_0,在 pca10040.h 中定义,通过修改BUTTON_1对应引脚实现物理按键控制。
#define BUTTONS_NUMBER 4
#define BUTTON_START 13
#define BUTTON_1 13
#define BUTTON_2 14
#define BUTTON_3 15
#define BUTTON_4 16
#define BUTTON_STOP 16
#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
#define BUTTONS_ACTIVE_STATE 0
#define BUTTONS_LIST { BUTTON_1, BUTTON_2, BUTTON_3, BUTTON_4 }
#define BSP_BUTTON_0 BUTTON_1
#define BSP_BUTTON_1 BUTTON_2
#define BSP_BUTTON_2 BUTTON_3
#define BSP_BUTTON_3 BUTTON_4
四、长按与短按的分离
原代码可以实现短按(长按)按下
,短按释放
,长按到时
的功能。需要注意的是长按仅仅只是由计时器检测,因此长按功能会和按钮按下以及按钮释放事件同时触发,在很多功能中我们希望短按长按各自有不同的功能,长按也不会触发短按的功能。由于长按短按都会按下按钮,不论如何都无法分开。因此在实际使用时需要检测短按释放
和长按释放
,但此时虽然长按时返回了一个长按事件处理,如果不作任何处理则按钮释放的时候又会产生一次释放事件。因此在长按功能下添加一条:
在板级设备初始化函数 bsp_init() 中,最开始进行初始化的时候,会对最开始声明的所有按键进行一次按键分配。这次按键分配为按键按下 BSP_BUTTON_ACTION_PUSH,相当于所有按键都分配了一次短按,触发事件为默认事件,此时,如果我们把这段代码进行注释,就可以避免初始化的时候对需要分配为长按的按键进行短按的事件分配。
然后分配
短按释放
和长按到时
事件
bsp_event_to_button_action_assign(0, BSP_BUTTON_ACTION_RELEASE, BSP_EVENT_KEY_0);
bsp_event_to_button_action_assign(0, BSP_BUTTON_ACTION_LONG_PUSH, BSP_EVENT_KEY_1);
五、修改长按到时的时间
默认为1秒钟
#define BSP_LONG_PUSH_TIMEOUT_MS (1000) /**< The time to hold for a long push (in milliseconds). */
/**@brief Types of BSP initialization.
*/
• 由 Leung 写于 2020 年 9 月 18 日
• 参考:青风电子社区
NRF按键中断BSP长按功能实现
网友评论