Skip to content

调度程序用于将执行从中断处理程序模式转移到线程&主模式。这确保了所有中断处理程序都很短,并且所有中断都被尽快处理。这对于某些应用程序非常有益。 从概念上讲,调度程序通过使用事件队列来工作。通过使用 app_sched_event_put()将事件放入队列中来安排事件。这通常是通过在中断处理程序模式下运行的事件处理程序来完成的。通过调用app_sched_execute()事件将会被执行并一一从队列中弹出,直到队列为空。这通常在主循环中完成。没有优先级的概念,因此事件总是按照它们放入队列的顺序执行。

包含

c
#include "app_timer.h"
#include "nrf_drv_clock.h"
#include "app_scheduler.h"

// makefile
$(SDK_ROOT)/components/libraries/scheduler/app_scheduler.c \
$(SDK_ROOT)/components/libraries/timer/app_timer.c \
$(SDK_ROOT)/components/libraries/util/app_util_platform.c \
$(SDK_ROOT)/integration/nrfx/legacy/nrf_drv_clock.c \
$(SDK_ROOT)/components/drivers_nrf/nrf_soc_nosd/nrf_nvic.c \
$(SDK_ROOT)/modules/nrfx/drivers/src/nrfx_clock.c \
$(SDK_ROOT)/modules/nrfx/drivers/src/nrfx_power.c \

include path

c
$(SDK_ROOT)/components/libraries/scheduler \

sdk.config.c

c
//==========================================================
// <e> APP_SCHEDULER_ENABLED - app_scheduler - Events scheduler
//==========================================================
#ifndef APP_SCHEDULER_ENABLED
#define APP_SCHEDULER_ENABLED 1
#endif
// <q> APP_SCHEDULER_WITH_PAUSE  - Enabling pause feature
 

#ifndef APP_SCHEDULER_WITH_PAUSE
#define APP_SCHEDULER_WITH_PAUSE 0
#endif

// <q> APP_SCHEDULER_WITH_PROFILER  - Enabling scheduler profiling
 

#ifndef APP_SCHEDULER_WITH_PROFILER
#define APP_SCHEDULER_WITH_PROFILER 0
#endif

// </e>

Initialization

The scheduler is initialized using the APP_SCHED_INIT() macro, which takes two parameters:

  • EVENT_SIZE: the maximum size of events to be passed through the scheduler.
  • QUEUE_SIZE: the maximum number of entries in the scheduler queue.
c
// Scheduler settings
#define SCHED_MAX_EVENT_DATA_SIZE   sizeof(nrf_drv_gpiote_pin_t)
#define SCHED_QUEUE_SIZE            10

Then write the following line above your main loop in order to initialize the Scheduler using the above parameters:

c
APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);

add a call to app_sched_execute() in your main loop. The app_sched_execute() function will pull events and call its handler in thread mode. It will execute all events scheduled since the last time it was called.

c
app_sched_execute();

调度中断或事件

调度的回调事件

c
void button_scheduler_event_handler(void *p_event_data, uint16_t event_size) {
	button_handler(*((nrfx_gpiote_pin_t*)p_event_data));
}

通过按键中断时间来添加调度事件

c
static void gpiote_event_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
    // 将中断处理的事件添加调度,更改 button_handler(pin);
    app_sched_event_put(&pin, sizeof(pin), button_scheduler_event_handler);
}```
按键处理函数
```c
static void button_handler(nrf_drv_gpiote_pin_t pin) {
    uint32_t err_code;
    // Handle button press.
    switch (pin) {
	    case BUTTON_1:
	        NRF_LOG_INFO("Start toggling LED 1.");
	        // 开始定时器
	        err_code = app_timer_start(m_led_a_timer_id, APP_TIMER_TICKS(500), NULL);
	        APP_ERROR_CHECK(err_code);
	        break;
	    case BUTTON_2:
	        NRF_LOG_INFO("Stop toggling LED 1.");
	        err_code = app_timer_stop(m_led_a_timer_id);
	        APP_ERROR_CHECK(err_code);
	        break;
	    default:
	        break;
    }
    // 判断在主线程还是中断处理中执行
    if (current_int_priority_get() == APP_IRQ_PRIORITY_THREAD) {
        NRF_LOG_INFO("Button handler is executing in thread/main mode.");
    } else {
        NRF_LOG_INFO("Button handler is executing in interrupt handler mode.");
    }
}

LED 与按键中断配置 gpio_init()... 参考 GPIO

main 函数

c
int main(void) {
    lfclk_request();
    log_init();
    gpio_init();
    timer_init();
    APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
    NRF_LOG_INFO("Scheduler tutorial example started.");
    while (true) {
        app_sched_execute();
    }
}

调度 Timmer

更改调度事件大小

c
// 更改最大的传递的事件大小
#define SCHED_MAX_EVENT_DATA_SIZE   sizeof(nrf_drv_gpiote_pin_t)
// 为
#define SCHED_MAX_EVENT_DATA_SIZE   MAX(sizeof(nrf_drv_gpiote_pin_t), APP_TIMER_SCHED_EVENT_DATA_SIZE)

修改 sdk.config.c

#define APP_TIMER_CONFIG_USE_SCHEDULER 1

现在定时器的运行在线程模式中

Released under the GPL License.