Bluetooth nrf 51822プログラムフレームワークの概要
20278 ワード
この文章はまずテンプレートを提供するフレームワークの部分プログラムを分析します.ここでは、テンプレートのコード(ランプとボタン)を例に挙げます.http://download.csdn.net/download/dfsae/99873181.主関数NRF 51822のフレームワークはイベント駆動フレームワークを採用している.まず主関数から分析する
メイン関数で初期化を行い、タイマーとブロードキャストを再起動し、メインサイクルでタスクスケジューリングと電源管理powerを実現します.manage();
1.1.タイマ
NRF 51822のタイマは、キューによって複数のタイマの管理が行われる.
1.1.1.データ構造
タイマーは主にtimer_に置かれますnode_t構造体構成配列で集中管理を行い、格納する方法はtimers_を参照Initの解析.timer_node_tの構成は以下の通りである.
app_timer.cでは、タイマキューに基づいた追加削除操作が提供される.
1.1.2.初期化関数
メイン関数でtimers_を呼び出すInit実現タイマの初期化
この初期化はapp_を呼び出したtimer.cのapp_timer_Init、同時にUSE_によるSCHEDULERコールバック関数app_を設定するtimer_evt_schedule.
app_timer_evt_scheduleでやった:1>.イベントを生成します.2>.イベントは、イベントスケジュールのAPI(app_sched_event_put)によって送信される.
タイマーの初期化は主に以下の通りである:1>.イベントコールバック関数(ある場合)を設定し、app_をバインドします.timer_evt_schedule関数.2>.割り当て転送数のタイマを初期化し、app_に対応する空間を割り当てるtimer.cでは、タイマシステム全体を管理するために内部変数を定義し、いくつかのパラメータを入力メモリに保存します.メモリの格納は、の最初のメモリに各タイマの割り当てステータス(state)と実行ステータス(is_running)が保存され、どちらもtimer_node_t構造体のパラメータ.中間保存timer_user_t構造体のデータの最後のブロックは対応するtimer_を格納するuser_op_t構造体データ.3>.オープン割込みの設定
1.1.2.タイマー関数の作成
最初にタイマの割り当てが完了すると、後続のタイマは使用前にユーザーによってカスタマイズされて割り当てることができます.割り当てはapp_を呼び出すだけですtimer_create関数でいいです.ユーザがこのタイマの動作モードとコールバック関数を入力すると、通常は空きタイマがp_に置かれていることがわかります.timer_idには、ユーザが現在割り当てられているタイマidを返す.プロセス中に対応IDのmp_しか修正されませんでしたnodesの値.たとえば、このインスタンスでbuttonを初期化すると、最後にタイマが割り当てられます.
1.1.3.タイマわりこみ
app_timer.cには、下位RTCを動作させる関数がいくつか用意されています.rtc 1_init-rtc 1_の初期化start-起動タイマrtc 1_stop-タイマーrtc 1_を終了counter_get-タイマのカウント値rtc 1_を取得compare0_set-ゼロオーバーコンパレータRTC 1_の設定IRQHandler-タイマ割り込み処理関数割り込み処理ここから始める.
timer_timeouts_check関数は,設定する対応するアプリケーションが時間のタイマに到達するか否かの検出を担当する.
ここのticks_Elapsedとticks_expired私も迂回されてめまいがします.でもこれを捨てて.この関数の本意は,タイムアウトしたタイマに対して,彼らが最初に設定したコールバック関数のコールバックを用いることである.以下のキーは参考になります.呼び出されたコールバック関数は2つのm_evt_schedule_funcとp_timer->p_timeout_handler.スケジューリングメカニズムがある場合は前者を呼び出し、スケジューリングカーネルに送信し、最後にメインサイクルでtimer_を行うcreate時にバインドされたコールバック関数スケジューリング.この例ではapp_がデフォルトで呼び出されます.timer_evt_schedule.スケジューリングメカニズムがない場合はtimer_を直接呼び出すcreate時にバインドされたコールバック関数.
もう1つのSWI 0割り込み、ソフトウェア割り込みがあります.SWI0_IRQHandler--SWI 0が中断し、プログラムの多くの場所でこの中断が置かれます.例えば前述のtimer_timeouts_check. SWI 0割り込み中にすべてのタイマ更新を実行
1.1.4.スタートタイマ
app_timer_start関数を使用してタイマを起動します.この関数にはtimerが呼び出されていますstart_op_schedule関数.ここで関数を割り当てるにはなぜmp_というパラメータがあるのかusers
1.2.キーを押す
キーを初期化し、buttons配列で使用するすべてのキーとその構成を定義します.具体的な意味はapp_button_cfg_t構造体.ここで変数を押します:m_detection_delay_timer_idタイマ.このタイマは遅延を計算するために使用され、初期化で作成され、後コールバックdetection_に時間を設定します.delay_timeout_handler関数.
同様に、初期化でイベントコールバック関数(ある場合)を設定し、app_をバインドします.button_evt_schedule関数.この関数の中の操作とタイマーの中の操作はあまり差がありません.
キー初期化では、主にキー部が管理する変数を初期化し、ハードウェアと割り込み部を構成し、割り込みコールバック関数gpiote_を設定します.event_handler、ピンレベル状態がマークされています.
キーが押されると、まずgpiote_がコールバックされます.event_handler関数.同時に対応する遅延パラメータを設定して起動するタイマタイミング.
検出遅延時間が達したらdetection_を呼び出すdelay_timeout_handlerコールバック関数、この関数でbuttonが呼び出されます.handler_executeキーで押した実行関数.この関数では、前のコールバック関数app_が呼び出されます.button_evt_scheduleはイベントをスケジューリングカーネルに送信します.次のカーネルがこのイベントをスケジューリングすると、キー応答イベントがスケジューリングされます.この例ではLEDBETTON_BUTTON_PIN_NO呼び出しを押すbutton_event_handler、これはサービスの特性を変更する値です.ここでは先に言いません.
理解できるのはグループを加えることができます:805601459(注釈CSDN)は交流を行います.本文は内部交流に限られ、商用は禁止されています!
int main(void)
{
// Initialize
leds_init(); //led ,
timers_init();
gpiote_init(); //
buttons_init();
ble_stack_init();
scheduler_init();
gap_params_init();
services_init();
advertising_init();
conn_params_init();
sec_params_init();
// Start execution
timers_start();
advertising_start();
// Enter main loop
for (;;)
{
app_sched_execute();
power_manage();
}
}
メイン関数で初期化を行い、タイマーとブロードキャストを再起動し、メインサイクルでタスクスケジューリングと電源管理powerを実現します.manage();
1.1.タイマ
NRF 51822のタイマは、キューによって複数のタイマの管理が行われる.
1.1.1.データ構造
タイマーは主にtimer_に置かれますnode_t構造体構成配列で集中管理を行い、格納する方法はtimers_を参照Initの解析.timer_node_tの構成は以下の通りである.
typedef struct
{
timer_alloc_state_t state; /**< */
app_timer_mode_t mode; /**< */
uint32_t ticks_to_expire; /**< ticks. */
uint32_t ticks_at_start; /**< RTC . */
uint32_t ticks_first_interval; /**< ticks */
uint32_t ticks_periodic_interval; /**< */
bool is_running; /**< True , False . */
app_timer_timeout_handler_t p_timeout_handler; /**< */
void * p_context; /**
app_timer.cでは、タイマキューに基づいた追加削除操作が提供される.
1.1.2.初期化関数
メイン関数でtimers_を呼び出すInit実現タイマの初期化
static void timers_init(void)
{
// Initialize timer module, making it use the scheduler
APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, true);
}
#define APP_TIMER_INIT(PRESCALER, MAX_TIMERS, OP_QUEUES_SIZE, USE_SCHEDULER) \
do \
{ \
static uint32_t APP_TIMER_BUF[CEIL_DIV(APP_TIMER_BUF_SIZE((MAX_TIMERS), \
(OP_QUEUES_SIZE) + 1), \
sizeof(uint32_t))]; \
uint32_t ERR_CODE = app_timer_init((PRESCALER), \
(MAX_TIMERS), \
(OP_QUEUES_SIZE) + 1, \
APP_TIMER_BUF, \
(USE_SCHEDULER) ? app_timer_evt_schedule : NULL); \
APP_ERROR_CHECK(ERR_CODE); \
} while (0)
この初期化はapp_を呼び出したtimer.cのapp_timer_Init、同時にUSE_によるSCHEDULERコールバック関数app_を設定するtimer_evt_schedule.
static __INLINE uint32_t app_timer_evt_schedule(app_timer_timeout_handler_t timeout_handler,
void * p_context)
{
app_timer_event_t timer_event;
timer_event.timeout_handler = timeout_handler;
timer_event.p_context = p_context;
return app_sched_event_put(&timer_event, sizeof(timer_event), app_timer_evt_get);
}
app_timer_evt_scheduleでやった:1>.イベントを生成します.2>.イベントは、イベントスケジュールのAPI(app_sched_event_put)によって送信される.
uint32_t app_timer_init(uint32_t prescaler,//
uint8_t max_timers,//
uint8_t op_queues_size,
void * p_buffer,
app_timer_evt_schedule_func_t evt_schedule_func)
{
int i;
//
if (!is_word_aligned(p_buffer))
{
return NRF_ERROR_INVALID_PARAM;
}
if (p_buffer == NULL)//
{
return NRF_ERROR_INVALID_PARAM;
}
rtc1_stop(); // RTC
m_evt_schedule_func = evt_schedule_func;// :app_timer_evt_schedule
// Initialize timer node array APP_TIMER_BUF
m_node_array_size = max_timers;
mp_nodes = p_buffer;
for (i = 0; i < max_timers; i++)
{
mp_nodes[i].state = STATE_FREE;
mp_nodes[i].is_running = false;
}
// Skip timer node array
p_buffer = &((uint8_t *)p_buffer)[max_timers * sizeof(timer_node_t)];
// Initialize users array
m_user_array_size = APP_TIMER_INT_LEVELS;
mp_users = p_buffer;
// Skip user array
p_buffer = &((uint8_t *)p_buffer)[APP_TIMER_INT_LEVELS * sizeof(timer_user_t)];
// operation
for (i = 0; i < APP_TIMER_INT_LEVELS; i++)
{
timer_user_t * p_user = &mp_users[i];
p_user->first = 0;
p_user->last = 0;
p_user->user_op_queue_size = op_queues_size;
p_user->p_user_op_queue = p_buffer;
// Skip operation queue
p_buffer = &((uint8_t *)p_buffer)[op_queues_size * sizeof(timer_user_op_t)];
}
m_timer_id_head = TIMER_NULL;
m_ticks_elapsed_q_read_ind = 0;
m_ticks_elapsed_q_write_ind = 0;
NVIC_ClearPendingIRQ(SWI0_IRQn);
NVIC_SetPriority(SWI0_IRQn, SWI0_IRQ_PRI);
NVIC_EnableIRQ(SWI0_IRQn);
rtc1_init(prescaler);
m_ticks_latest = rtc1_counter_get();
return NRF_SUCCESS;
}
タイマーの初期化は主に以下の通りである:1>.イベントコールバック関数(ある場合)を設定し、app_をバインドします.timer_evt_schedule関数.2>.割り当て転送数のタイマを初期化し、app_に対応する空間を割り当てるtimer.cでは、タイマシステム全体を管理するために内部変数を定義し、いくつかのパラメータを入力メモリに保存します.メモリの格納は、の最初のメモリに各タイマの割り当てステータス(state)と実行ステータス(is_running)が保存され、どちらもtimer_node_t構造体のパラメータ.中間保存timer_user_t構造体のデータの最後のブロックは対応するtimer_を格納するuser_op_t構造体データ.3>.オープン割込みの設定
1.1.2.タイマー関数の作成
最初にタイマの割り当てが完了すると、後続のタイマは使用前にユーザーによってカスタマイズされて割り当てることができます.割り当てはapp_を呼び出すだけですtimer_create関数でいいです.ユーザがこのタイマの動作モードとコールバック関数を入力すると、通常は空きタイマがp_に置かれていることがわかります.timer_idには、ユーザが現在割り当てられているタイマidを返す.プロセス中に対応IDのmp_しか修正されませんでしたnodesの値.たとえば、このインスタンスでbuttonを初期化すると、最後にタイマが割り当てられます.
uint32_t app_timer_create(app_timer_id_t * p_timer_id,
app_timer_mode_t mode,
app_timer_timeout_handler_t timeout_handler)
{
int i;
if (mp_nodes == NULL)
{
return NRF_ERROR_INVALID_STATE;
}
if (timeout_handler == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
if (p_timer_id == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
//
for (i = 0; i < m_node_array_size; i++)
{
if (mp_nodes[i].state == STATE_FREE)
{
mp_nodes[i].state = STATE_ALLOCATED;
mp_nodes[i].mode = mode;
mp_nodes[i].p_timeout_handler = timeout_handler;
*p_timer_id = i;
return NRF_SUCCESS;
}
}
return NRF_ERROR_NO_MEM;
}
1.1.3.タイマわりこみ
app_timer.cには、下位RTCを動作させる関数がいくつか用意されています.rtc 1_init-rtc 1_の初期化start-起動タイマrtc 1_stop-タイマーrtc 1_を終了counter_get-タイマのカウント値rtc 1_を取得compare0_set-ゼロオーバーコンパレータRTC 1_の設定IRQHandler-タイマ割り込み処理関数割り込み処理ここから始める.
void RTC1_IRQHandler(void)
{
//
NRF_RTC1->EVENTS_COMPARE[0] = 0;
NRF_RTC1->EVENTS_COMPARE[1] = 0;
NRF_RTC1->EVENTS_COMPARE[2] = 0;
NRF_RTC1->EVENTS_COMPARE[3] = 0;
NRF_RTC1->EVENTS_TICK = 0;
NRF_RTC1->EVENTS_OVRFLW = 0;
timer_timeouts_check();//
}
timer_timeouts_check関数は,設定する対応するアプリケーションが時間のタイマに到達するか否かの検出を担当する.
static void timer_timeouts_check(void)
{
if (m_timer_id_head != TIMER_NULL) //
{
app_timer_id_t timer_id;
uint32_t ticks_elapsed;
uint32_t ticks_expired;
// ticks 0
ticks_expired = 0;
// ticks_elapsed( ) ,
ticks_elapsed = ticks_diff_get(rtc1_counter_get(), m_ticks_latest);
// Auto variable containing the head of timers expiring
timer_id = m_timer_id_head;
// ticks_elapsed ticks_expired ( )
while (timer_id != TIMER_NULL)
{
timer_node_t * p_timer;
p_timer = &mp_nodes[timer_id]; //
//
if (ticks_elapsed < p_timer->ticks_to_expire)
{
break;
}
// ticks_elapsed( ) expired ticks ( )
ticks_elapsed -= p_timer->ticks_to_expire;
ticks_expired += p_timer->ticks_to_expire;
//
timer_id = p_timer->next;
//
timeout_handler_exec(p_timer);
}
// m_ticks_elapsed ticks
if (m_ticks_elapsed_q_read_ind == m_ticks_elapsed_q_write_ind)
{
// 。 ticks_expired
// m_ticks_elapsed ( 。)
//
if (++m_ticks_elapsed_q_write_ind == CONTEXT_QUEUE_SIZE_MAX)
{
// . ,
m_ticks_elapsed_q_write_ind = 0;
}
}
// ticks .
m_ticks_elapsed[m_ticks_elapsed_q_write_ind] = ticks_expired;
timer_list_handler_sched();
}
}
static void timeout_handler_exec(timer_node_t * p_timer)
{
if (m_evt_schedule_func != NULL)
{
uint32_t err_code = m_evt_schedule_func(p_timer->p_timeout_handler,
p_timer->p_context);
APP_ERROR_CHECK(err_code);
}
else
{
p_timer->p_timeout_handler(p_timer->p_context);
}
}
ここのticks_Elapsedとticks_expired私も迂回されてめまいがします.でもこれを捨てて.この関数の本意は,タイムアウトしたタイマに対して,彼らが最初に設定したコールバック関数のコールバックを用いることである.以下のキーは参考になります.呼び出されたコールバック関数は2つのm_evt_schedule_funcとp_timer->p_timeout_handler.スケジューリングメカニズムがある場合は前者を呼び出し、スケジューリングカーネルに送信し、最後にメインサイクルでtimer_を行うcreate時にバインドされたコールバック関数スケジューリング.この例ではapp_がデフォルトで呼び出されます.timer_evt_schedule.スケジューリングメカニズムがない場合はtimer_を直接呼び出すcreate時にバインドされたコールバック関数.
もう1つのSWI 0割り込み、ソフトウェア割り込みがあります.SWI0_IRQHandler--SWI 0が中断し、プログラムの多くの場所でこの中断が置かれます.例えば前述のtimer_timeouts_check. SWI 0割り込み中にすべてのタイマ更新を実行
void SWI0_IRQHandler(void)
{
timer_list_handler();
}
static void timer_list_handler(void)
{
app_timer_id_t restart_list_head = TIMER_NULL;
uint32_t ticks_elapsed;
uint32_t ticks_previous;
bool ticks_have_elapsed;
bool compare_update;
app_timer_id_t timer_id_head_old;
// tick List
ticks_previous = m_ticks_latest;
timer_id_head_old = m_timer_id_head;
// ticks
ticks_have_elapsed = elapsed_ticks_acquire(&ticks_elapsed);
//
compare_update = list_deletions_handler();
//
if (ticks_have_elapsed)
{
expired_timers_handler(ticks_elapsed, ticks_previous, &restart_list_head);
compare_update = true;
}
//
if (list_insertions_handler(restart_list_head))
{
compare_update = true;
}
//
if (compare_update)
{
compare_reg_update(timer_id_head_old);
}
}
1.1.4.スタートタイマ
app_timer_start関数を使用してタイマを起動します.この関数にはtimerが呼び出されていますstart_op_schedule関数.ここで関数を割り当てるにはなぜmp_というパラメータがあるのかusers
uint32_t app_timer_start(app_timer_id_t timer_id, uint32_t timeout_ticks, void * p_context)
{
uint32_t timeout_periodic;
// Schedule timer start operation
timeout_periodic = (mp_nodes[timer_id].mode == APP_TIMER_MODE_REPEATED) ? timeout_ticks : 0;
return timer_start_op_schedule(user_id_get(),
timer_id,
timeout_ticks,
timeout_periodic,
p_context);
}
static uint32_t timer_start_op_schedule(timer_user_id_t user_id,
app_timer_id_t timer_id,
uint32_t timeout_initial,
uint32_t timeout_periodic,
void * p_context)
{
app_timer_id_t last_index;
//
timer_user_op_t * p_user_op = user_op_alloc(&mp_users[user_id], &last_index);
if (p_user_op == NULL)
{
return NRF_ERROR_NO_MEM;
}
p_user_op->op_type = TIMER_USER_OP_TYPE_START;
p_user_op->timer_id = timer_id;
p_user_op->params.start.ticks_at_start = rtc1_counter_get();
p_user_op->params.start.ticks_first_interval = timeout_initial;
p_user_op->params.start.ticks_periodic_interval = timeout_periodic;
p_user_op->params.start.p_context = p_context;
user_op_enque(&mp_users[user_id], last_index);
timer_list_handler_sched();
return NRF_SUCCESS;
}
1.2.キーを押す
キーを初期化し、buttons配列で使用するすべてのキーとその構成を定義します.具体的な意味はapp_button_cfg_t構造体.ここで変数を押します:m_detection_delay_timer_idタイマ.このタイマは遅延を計算するために使用され、初期化で作成され、後コールバックdetection_に時間を設定します.delay_timeout_handler関数.
static void buttons_init(void)
{
// Note: Array must be static because a pointer to it will be saved in the Button handler
// module.
static app_button_cfg_t buttons[] =
{
{WAKEUP_BUTTON_PIN, false, BUTTON_PULL, NULL},
{LEDBUTTON_BUTTON_PIN_NO, false, BUTTON_PULL, button_event_handler}
};
APP_BUTTON_INIT(buttons, sizeof(buttons) / sizeof(buttons[0]), BUTTON_DETECTION_DELAY, true);
}
#define APP_BUTTON_INIT(BUTTONS, BUTTON_COUNT, DETECTION_DELAY, USE_SCHEDULER) \
do \
{ \
uint32_t ERR_CODE = app_button_init((BUTTONS), \
(BUTTON_COUNT), \
(DETECTION_DELAY), \
(USE_SCHEDULER) ? app_button_evt_schedule : NULL); \
APP_ERROR_CHECK(ERR_CODE); \
} while (0)
同様に、初期化でイベントコールバック関数(ある場合)を設定し、app_をバインドします.button_evt_schedule関数.この関数の中の操作とタイマーの中の操作はあまり差がありません.
uint32_t app_button_init(app_button_cfg_t * p_buttons,
uint8_t button_count,
uint32_t detection_delay,
app_button_evt_schedule_func_t evt_schedule_func)
{
uint32_t err_code;
if (detection_delay < APP_TIMER_MIN_TIMEOUT_TICKS)
{
return NRF_ERROR_INVALID_PARAM;
}
// .
mp_buttons = p_buttons;
m_button_count = button_count;
m_detection_delay = detection_delay;
m_evt_schedule_func = evt_schedule_func;
uint32_t pins_transition_mask = 0;
while (button_count--)
{
app_button_cfg_t * p_btn = &p_buttons[button_count];
nrf_gpio_cfg_input(p_btn->pin_no, p_btn->pull_cfg); //
pins_transition_mask |= (1 << p_btn->pin_no); //
}
// Register button module as a GPIOTE user.
err_code = app_gpiote_user_register(&m_gpiote_user_id,
pins_transition_mask,
pins_transition_mask,
gpiote_event_handler);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Create polling timer.
return app_timer_create(&m_detection_delay_timer_id,
APP_TIMER_MODE_SINGLE_SHOT,
detection_delay_timeout_handler);
}
キー初期化では、主にキー部が管理する変数を初期化し、ハードウェアと割り込み部を構成し、割り込みコールバック関数gpiote_を設定します.event_handler、ピンレベル状態がマークされています.
キーが押されると、まずgpiote_がコールバックされます.event_handler関数.同時に対応する遅延パラメータを設定して起動するタイマタイミング.
static void gpiote_event_handler(uint32_t event_pins_low_to_high, uint32_t event_pins_high_to_low)
{
uint32_t err_code;
// 。 ,
// : app_timer_start() p_context
STATIC_ASSERT(sizeof(void *) == sizeof(uint32_t));
err_code = app_timer_stop(m_detection_delay_timer_id); //
if (err_code != NRF_SUCCESS)
{
// The impact in app_button of the app_timer queue running full is losing a button press.
// The current implementation ensures that the system will continue working as normal.
return;
}
m_pin_transition.low_to_high = event_pins_low_to_high;
m_pin_transition.high_to_low = event_pins_high_to_low;
err_code = app_timer_start(m_detection_delay_timer_id,
m_detection_delay,
(void *)(event_pins_low_to_high | event_pins_high_to_low));
if (err_code != NRF_SUCCESS)
{
// The impact in app_button of the app_timer queue running full is losing a button press.
// The current implementation ensures that the system will continue working as normal.
}
}
検出遅延時間が達したらdetection_を呼び出すdelay_timeout_handlerコールバック関数、この関数でbuttonが呼び出されます.handler_executeキーで押した実行関数.この関数では、前のコールバック関数app_が呼び出されます.button_evt_scheduleはイベントをスケジューリングカーネルに送信します.次のカーネルがこのイベントをスケジューリングすると、キー応答イベントがスケジューリングされます.この例ではLEDBETTON_BUTTON_PIN_NO呼び出しを押すbutton_event_handler、これはサービスの特性を変更する値です.ここでは先に言いません.
static void detection_delay_timeout_handler(void * p_context)
{
uint32_t err_code;
uint32_t current_state_pins;
//
err_code = app_gpiote_pins_state_get(m_gpiote_user_id, ¤t_state_pins);
if (err_code != NRF_SUCCESS)
{
return;
}
uint8_t i;
// ,
for (i = 0; i < m_button_count; i++)
{
app_button_cfg_t * p_btn = &mp_buttons[i];
if (((m_pin_transition.high_to_low & (1 << p_btn->pin_no)) != 0)
&& (p_btn->button_handler != NULL))
{
// ,
if(p_btn->active_state == APP_BUTTON_ACTIVE_HIGH)
{
button_handler_execute(p_btn, APP_BUTTON_RELEASE);
}
// ,
else
{
button_handler_execute(p_btn, APP_BUTTON_PUSH);
}
}
else if (((m_pin_transition.low_to_high & (1 << p_btn->pin_no)) != 0)
&& (p_btn->button_handler != NULL))
{
// ,
if(p_btn->active_state == APP_BUTTON_ACTIVE_HIGH)
{
button_handler_execute(p_btn,APP_BUTTON_PUSH);
}
// ,
else
{
button_handler_execute(p_btn,APP_BUTTON_RELEASE);
}
}
}
}
static void button_handler_execute(app_button_cfg_t * p_btn, uint32_t transition)
{
if (m_evt_schedule_func != NULL)
{
uint32_t err_code = m_evt_schedule_func(p_btn->button_handler, p_btn->pin_no,transition);
APP_ERROR_CHECK(err_code);
}
else
{
if(transition == APP_BUTTON_PUSH)
{
p_btn->button_handler(p_btn->pin_no, APP_BUTTON_PUSH);
}
else if(transition == APP_BUTTON_RELEASE)
{
p_btn->button_handler(p_btn->pin_no, APP_BUTTON_RELEASE);
}
}
}
理解できるのはグループを加えることができます:805601459(注釈CSDN)は交流を行います.本文は内部交流に限られ、商用は禁止されています!