1.首先需要启动低速时钟
NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
NRF_CLOCK->TASKS_LFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0)
{
// Do nothing.
}
2.初时化函数bsp_init中
m_registered_callback = callback; 这行是注册回调函数,通过参数传入
err_code = bsp_event_to_button_action_assign(num, BSP_BUTTON_ACTION_PUSH, BSP_EVENT_DEFAULT); 这行是分
配默认的事件
err_code = app_button_init((app_button_cfg_t *)app_buttons, //事件数组
BUTTONS_NUMBER, //按键个数
APP_TIMER_TICKS(50)); //50ms的TICK时间数
事件数组定义
static const app_button_cfg_t app_buttons[BUTTONS_NUMBER] =
{
#ifdef BSP_BUTTON_0
{BSP_BUTTON_0, false, BUTTON_PULL, bsp_button_event_handler},
#endif // BUTTON_0
#ifdef BSP_BUTTON_1
{BSP_BUTTON_1, false, BUTTON_PULL, bsp_button_event_handler},
#endif // BUTTON_1
#ifdef BSP_BUTTON_2
{BSP_BUTTON_2, false, BUTTON_PULL, bsp_button_event_handler},
#endif // BUTTON_2
#ifdef BSP_BUTTON_3
{BSP_BUTTON_3, false, BUTTON_PULL, bsp_button_event_handler},
#endif // BUTTON_3
#ifdef BSP_BUTTON_4
{BSP_BUTTON_4, false, BUTTON_PULL, bsp_button_event_handler},
#endif // BUTTON_4
#ifdef BSP_BUTTON_5
{BSP_BUTTON_5, false, BUTTON_PULL, bsp_button_event_handler},
#endif // BUTTON_5
#ifdef BSP_BUTTON_6
{BSP_BUTTON_6, false, BUTTON_PULL, bsp_button_event_handler},
#endif // BUTTON_6
#ifdef BSP_BUTTON_7
{BSP_BUTTON_7, false, BUTTON_PULL, bsp_button_event_handler},
#endif // BUTTON_7
};
使能APP Button
err_code = app_button_enable();
创建定APP定时器
err_code = app_timer_create(&m_bsp_button_tmr,
APP_TIMER_MODE_SINGLE_SHOT,
button_timer_handler);
3.指定按键与事件关联起来
uint32_t bsp_event_to_button_action_assign(uint32_t button, bsp_button_action_t action, bsp_event_t event)
{
uint32_t err_code = NRF_SUCCESS;
#if BUTTONS_NUMBER > 0
if (button < BUTTONS_NUMBER)
{
if (event == BSP_EVENT_DEFAULT)
{
// Setting default action: BSP_EVENT_KEY_x for PUSH actions, BSP_EVENT_NOTHING for RELEASE and LONG_PUSH actions.
event = (action == BSP_BUTTON_ACTION_PUSH) ? (bsp_event_t)(BSP_EVENT_KEY_0 + button) : BSP_EVENT_NOTHING;
}
switch (action)
{
case BSP_BUTTON_ACTION_PUSH: //按键压下事件指定
m_events_list[button].push_event = event;
break;
case BSP_BUTTON_ACTION_LONG_PUSH: //按键长按事件指定
m_events_list[button].long_push_event = event;
break;
case BSP_BUTTON_ACTION_RELEASE: ////按键释放事件指定
m_events_list[button].release_event = event;
break;
default:
err_code = NRF_ERROR_INVALID_PARAM;
break;
}
}
else
{
err_code = NRF_ERROR_INVALID_PARAM;
}
#else
err_code = NRF_ERROR_INVALID_PARAM;
#endif // BUTTONS_NUMBER > 0
return err_code;
}
4.app_button_init函数
err_code = nrf_drv_gpiote_init(); //初时化GPIOTE
err_code = nrf_drv_gpiote_in_init(p_btn->pin_no, &config, gpiote_event_handler); //GPIOTE IN事件设置
app_timer_create(&m_detection_delay_timer_id,
APP_TIMER_MODE_SINGLE_SHOT,
detection_delay_timeout_handler); //创建按键检测定时器
5.static void gpiote_event_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)由GPIOTE事件回调,回调中会启动
定时器一次err_code = app_timer_start(m_detection_delay_timer_id, m_detection_delay, NULL);
6.定时时间到会回调static void detection_delay_timeout_handler(void * p_context)函数一次,回调中由以下发出通知,即调用到
app_buttons数组中定义的函数bsp_button_event_handler
p_btn->button_handler(p_btn->pin_no, transition);
7.static void bsp_button_event_handler(uint8_t pin_no, uint8_t button_action)回调函数
static void bsp_button_event_handler(uint8_t pin_no, uint8_t button_action)
{
bsp_event_t event = BSP_EVENT_NOTHING;
uint32_t button = 0;
uint32_t err_code;
static uint8_t current_long_push_pin_no; /**< Pin number of a currently pushed button, that could become a long push if held long enough. */
static bsp_event_t release_event_at_push[BUTTONS_NUMBER]; /**< Array of what the release event of each button was last time it was pushed, so that no release event is sent if the event was bound after the push of the button. */
button = bsp_board_pin_to_button_idx(pin_no); //得到按键在数组中的序号
if (button < BUTTONS_NUMBER)
{
switch (button_action)
{
case APP_BUTTON_PUSH: //按键按下事件
event = m_events_list[button].push_event;
if (m_events_list[button].long_push_event != BSP_EVENT_NOTHING) //如果定义了长按键
{
err_code = app_timer_start(m_bsp_button_tmr, APP_TIMER_TICKS(BSP_LONG_PUSH_TIMEOUT_MS), (void*)¤t_long_push_pin_no); //启动长按键定时器
if (err_code == NRF_SUCCESS)
{
current_long_push_pin_no = pin_no;
}
}
release_event_at_push[button] = m_events_list[button].release_event;
break;
case APP_BUTTON_RELEASE: //按键释放
(void)app_timer_stop(m_bsp_button_tmr);
if (release_event_at_push[button] == m_events_list[button].release_event)
{
event = m_events_list[button].release_event;
}
break;
case BSP_BUTTON_ACTION_LONG_PUSH: //长按键事件,由长按键定时器调用进入
event = m_events_list[button].long_push_event;
}
}
if ((event != BSP_EVENT_NOTHING) && (m_registered_callback != NULL))
{
m_registered_callback(event); //回调到注册的按键事件函数
}
}
8.长按定时器回调函数,此函数在bsp_init中设置过
static void button_timer_handler(void * p_context)
{
bsp_button_event_handler(*(uint8_t *)p_context, BSP_BUTTON_ACTION_LONG_PUSH); //调用按键事件函数
}
9.回调到使用者注册的按键事件函数,注册由bsp_init实现
m_registered_callback(event);
10. 使用者自定义bsp_evt_handler按键事件注册
err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_evt_handler);
11.void bsp_evt_handler(bsp_event_t evt)函数
void bsp_evt_handler(bsp_event_t evt)
{
uint32_t err_code;
switch (evt)
{
case BSP_EVENT_KEY_0: //此事件值可由bsp_event_to_button_action_assign函数指定
break;
case BSP_EVENT_KEY_1: //此事件值可由bsp_event_to_button_action_assign函数指定
break;
default:
return; // no implementation needed
}
}
总结按键事件传递流程:
按键产生GPIOTE事件->回调gpiote_event_handler函数,启动一次性定时器(50ms,可设置)->定时器事件回调函数,调用
p_btn->button_handler(p_btn->pin_no, transition)去通知数组中定义的回调函数->bsp_button_event_handler处理按键按下,释放等事件,由m_registered_callback(event)调用将事件回调->最终调用到bsp_evt_handler函数
长按事件先由按键按下事件,启动一个长按键定时器(约1秒,可设置)->定时器时间到,回调button_timer_handler函数,此函数再直接调用bsp_button_event_handler函数->长按事件由m_registered_callback(event)调用将事件回调->最终调用到bsp_evt_handler函数