基于VScode的ESP32开发学习(四):事件循环

本文档展示了如何在ESP32上使用事件循环(event loop)和定时器来处理不同事件。代码中创建了一个默认事件循环,并注册了多个定时器事件处理函数,包括定时器开始、到期和停止事件。同时,还创建了一个任务事件源,用于执行迭代事件。当定时器事件或任务迭代事件发生时,会触发相应的事件处理函数。定时器事件处理函数会记录定时器的执行次数,达到一定次数后停止定时器并发送停止事件。
摘要由CSDN通过智能技术生成

代码

#include "esp_log.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "event_source.h"

static const char* TAG = "default_event_loop";

static esp_event_handler_instance_t s_instance;         //用来标注事件处理函数的上下文标识

static int TIMER_START_HANDLER_0 = 0;                   //传入hanlder的参数
static int TIMER_START_HANDLER_1 = 1;

static char* get_id_string(esp_event_base_t base, int32_t id) {         //获取id将其含义转为字符串
    char* event = "";
    if (base == TIMER_EVENTS) {                         //如果事件类型为定时器
        switch(id) {
            case TIMER_EVENT_STARTED:
            event = "TIMER_EVENT_STARTED";
            break;
            case TIMER_EVENT_EXPIRY:
            event = "TIMER_EVENT_EXPIRY";
            break;
            case TIMER_EVENT_STOPPED:
            event = "TIMER_EVENT_STOPPED";
            break;
        }
    } else {
        event = "TASK_ITERATION_EVENT";
    }
    return event;
}

/* Event source periodic timer related definitions */
ESP_EVENT_DEFINE_BASE(TIMER_EVENTS);    //定义EVENT_BASE

esp_timer_handle_t TIMER;       //定义定时器

// Callback that will be executed when the timer period lapses. Posts the timer expiry event to the default event loop.
//定时器回调函数,会被周期执行,传递expiry event事件到默认的event循环里。
static void timer_callback(void* arg)
{
    ESP_LOGI(TAG, "%s:%s: posting to default loop", TIMER_EVENTS, get_id_string(TIMER_EVENTS, TIMER_EVENT_EXPIRY));
    ESP_ERROR_CHECK(esp_event_post(TIMER_EVENTS, TIMER_EVENT_EXPIRY, NULL, 0, portMAX_DELAY));
}

// Handler which executes when the timer started event gets executed by the loop.
//第一个用于处理timer started event事件的处理函数
static void timer_started_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
    int start_handler_num = *((int*) handler_args);
    ESP_LOGI(TAG, "%s:%s: timer_started_handler, instance %d", base, get_id_string(base, id), start_handler_num);
}

// Second handler which executes when the timer started event gets executed by the loop.
//第二个用于处理timer started event事件的处理函数
static void timer_started_handler_2(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
    ESP_LOGI(TAG, "%s:%s: timer_started_handler_2", base, get_id_string(base, id));
}

// Handler which executes when the timer expiry event gets executed by the loop. This handler keeps track of
// how many times the timer expired. When a set number of expiry is reached, the handler stops the timer
// and sends a timer stopped event.
//定时器循环事件handler,每次发送定时到达事件,同时此回调记录定时器执行次数,达到指定次数的时候会停止定时器并发送定时器停止事件。
static void timer_expiry_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
    static int count = 0;
    count++;

    if (count >= TIMER_EXPIRIES_COUNT) {
        // Stop the timer
        ESP_ERROR_CHECK(esp_timer_stop(TIMER));

        ESP_LOGI(TAG, "%s:%s: posting to default loop", base, get_id_string(base, TIMER_EVENT_STOPPED));

        // Post the event that the timer has been stopped
        ESP_ERROR_CHECK(esp_event_post(TIMER_EVENTS, TIMER_EVENT_STOPPED, NULL, 0, portMAX_DELAY));
    }

    ESP_LOGI(TAG, "%s:%s: timer_expiry_handler, executed %d out of %d times", base, get_id_string(base, id), count, TIMER_EXPIRIES_COUNT);
}

// Handler which executes when any timer event (started, expiry, stopped) get executed by the loop
static void timer_any_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
    ESP_LOGI(TAG, "%s:%s: timer_any_handler", base, get_id_string(base, id));
}

// Handler which executes when the timer stopped event gets executed by the loop. Since the timer has been
// stopped, it is safe to delete it.
static void timer_stopped_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
    ESP_LOGI(TAG, "%s:%s: timer_stopped_handler", base, get_id_string(base, id));

    // Delete the timer
    esp_timer_delete(TIMER);

    ESP_LOGI(TAG, "%s:%s: deleted timer event source", base, get_id_string(base, id));
}

/* Event source task related definitions */
ESP_EVENT_DEFINE_BASE(TASK_EVENTS);

static void task_iteration_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
    int iteration = *((int*) event_data);
    ESP_LOGI(TAG, "%s:%s: task_iteration_handler, executed %d times", base, get_id_string(base, id), iteration);
}

static void task_event_source(void* args)
{
    for(int iteration = 1; iteration <= TASK_ITERATIONS_COUNT; iteration++) {

        ESP_LOGI(TAG, "%s:%s: posting to default loop, %d out of %d", TASK_EVENTS,
                get_id_string(TASK_EVENTS, TASK_ITERATION_EVENT), iteration, TASK_ITERATIONS_COUNT);

        // Post that the loop has iterated. Notice that the iteration count is passed to the handler. Take note
        // that data passed during event posting is a deep copy of the original data.
        ESP_ERROR_CHECK(esp_event_post(TASK_EVENTS, TASK_ITERATION_EVENT, &iteration, sizeof(iteration), portMAX_DELAY));

        if (iteration == TASK_ITERATIONS_UNREGISTER) {
            ESP_LOGI(TAG, "%s:%s: unregistering task_iteration_handler", TASK_EVENTS, get_id_string(TASK_EVENTS, TASK_ITERATION_EVENT));
            ESP_ERROR_CHECK(esp_event_handler_instance_unregister(TASK_EVENTS, TASK_ITERATION_EVENT, s_instance));
        }

        vTaskDelay(pdMS_TO_TICKS(TASK_PERIOD));
    }

    vTaskDelay(pdMS_TO_TICKS(TASK_PERIOD));

    ESP_LOGI(TAG, "%s:%s: deleting task event source", TASK_EVENTS, get_id_string(TASK_EVENTS, TASK_ITERATION_EVENT));

    vTaskDelete(NULL);
}

/* Handler for all events */
static void all_event_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
    ESP_LOGI(TAG, "%s:%s: all_event_handler", base, get_id_string(base, id));
}

/* Example main */
void app_main(void)
{
    ESP_LOGI(TAG, "setting up");

    // Create the default event loop
    //创建默认事件循环
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    // Register the specific timer event handlers. Timer start handler is registered twice.
    //注册特定的定时器事件处理函数,定时器开始事件处理函数被注册了两次
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler, &TIMER_START_HANDLER_0, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler, &TIMER_START_HANDLER_1, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler_2, NULL, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_EXPIRY, timer_expiry_handler, NULL, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STOPPED, timer_stopped_handler, NULL, NULL));

    // Register the handler for all timer family events. This will execute if the timer is started, expired or is stopped.
    //注册一个总处理函数,当事件id是started, expired,stopped三者之一时,它都会被执行
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, ESP_EVENT_ANY_ID, timer_any_handler, NULL, NULL));

    // Register the handler for task iteration event; need to pass instance handle for later unregistration.
    //注册一个处理函数用于任务迭代事件(?翻译存疑),需要传递一个instance参数用于之后的注销
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler, NULL, &s_instance));

    // Register the handler for all event. This will execute if either the timer events or the task iteration event
    // is posted to the default loop.
    //注册一个用于所有事件的handler,定时器事件和任务迭代事件也会触发执行
    ESP_ERROR_CHECK(esp_event_handler_instance_register(ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, all_event_handler, NULL, NULL));

    // Create and start the event sources
    //创建并启动事件源
    esp_timer_create_args_t timer_args = {
        .callback = &timer_callback,            //设置当定时器终止时,要调用的回调函数
    };

    ESP_ERROR_CHECK(esp_timer_create(&timer_args, &TIMER));         //创建定时器

    ESP_LOGI(TAG, "starting event sources");

     // Create the event source task with the same priority as the current task
     //创建与当前任务具有相同优先级的事件源任务
    xTaskCreate(task_event_source, "task_event_source", 2048, NULL, uxTaskPriorityGet(NULL), NULL);

    ESP_ERROR_CHECK(esp_timer_start_periodic(TIMER, TIMER_PERIOD));

    // Post the timer started event
    //给定时器传递启动事件信号
    ESP_LOGI(TAG, "%s:%s: posting to default loop", TIMER_EVENTS, get_id_string(TIMER_EVENTS, TIMER_EVENT_STARTED));
    ESP_ERROR_CHECK(esp_event_post(TIMER_EVENTS, TIMER_EVENT_STARTED, NULL, 0, portMAX_DELAY));
}

运行结果

在这里插入图片描述

解析

我们从主函数开始开启,按执行顺序分析,这样方便理解

/* Example main */
void app_main(void)
{
    ESP_LOGI(TAG, "setting up");

    // Create the default event loop
    //创建默认事件循环
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    // Register the specific timer event handlers. Timer start handler is registered twice.
    //注册特定的定时器事件处理函数,定时器开始事件处理函数被注册了两次
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler, &TIMER_START_HANDLER_0, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler, &TIMER_START_HANDLER_1, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler_2, NULL, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_EXPIRY, timer_expiry_handler, NULL, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STOPPED, timer_stopped_handler, NULL, NULL));

    // Register the handler for all timer family events. This will execute if the timer is started, expired or is stopped.
    //注册一个总处理函数,当事件id是started, expired,stopped三者之一时,它都会被执行
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, ESP_EVENT_ANY_ID, timer_any_handler, NULL, NULL));

    // Register the handler for task iteration event; need to pass instance handle for later unregistration.
    //注册一个处理函数用于任务迭代事件(?翻译存疑),需要传递一个instance参数用于之后的注销
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler, NULL, &s_instance));

    // Register the handler for all event. This will execute if either the timer events or the task iteration event
    // is posted to the default loop.
    //注册一个用于所有事件的handler,定时器事件和任务迭代事件也会触发执行
    ESP_ERROR_CHECK(esp_event_handler_instance_register(ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, all_event_handler, NULL, NULL));

    // Create and start the event sources
    //创建并启动事件源
    esp_timer_create_args_t timer_args = {
        .callback = &timer_callback,            //设置当定时器终止时,要调用的回调函数
    };

    ESP_ERROR_CHECK(esp_timer_create(&timer_args, &TIMER));         //创建定时器

    ESP_LOGI(TAG, "starting event sources");

     // Create the event source task with the same priority as the current task
     //创建与当前任务具有相同优先级的事件源任务
    xTaskCreate(task_event_source, "task_event_source", 2048, NULL, uxTaskPriorityGet(NULL), NULL);

    ESP_ERROR_CHECK(esp_timer_start_periodic(TIMER, TIMER_PERIOD));

    // Post the timer started event
    //给定时器传递启动事件信号
    ESP_LOGI(TAG, "%s:%s: posting to default loop", TIMER_EVENTS, get_id_string(TIMER_EVENTS, TIMER_EVENT_STARTED));
    ESP_ERROR_CHECK(esp_event_post(TIMER_EVENTS, TIMER_EVENT_STARTED, NULL, 0, portMAX_DELAY));
}

第一步:创建默认事件循环ESP_ERROR_CHECK(esp_event_loop_create_default());

在这里插入图片描述
创建了个事件循环

第二步:注册事件

    //注册特定的定时器事件处理函数,定时器开始事件处理函数被注册了两次
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler, &TIMER_START_HANDLER_0, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler, &TIMER_START_HANDLER_1, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler_2, NULL, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_EXPIRY, timer_expiry_handler, NULL, NULL));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, TIMER_EVENT_STOPPED, timer_stopped_handler, NULL, NULL));

其中esp_event_handler_instance_register函数定义
在这里插入图片描述
参数说明
在这里插入图片描述

  • @param[in] event_base :事件类型id //这个翻译我觉得贴切点
  • @param[in] event_id the :事件id
  • @param[in] event_handler :处理函数入口
  • @param[in] event_handler_arg: 处理函数参数
  • @param[out] instance:一个与处理函数、数据相关连的 事件处理函数对象,可以为NULL。如果在删除整个event循环之前要注销特定回调实例,则需要保留此选项。我们允许多次注册同一个事件处理函数,但会产生不同的实例对象。如果循环中途不需要注销某特定处理函数实例,且处理函数也会随事件循环一同结束,则该参数可以为NULL。
    在这里插入图片描述
    便于理解参数 instance,扒了下定义,这下明白了,这是一个用于区分实例的上下文标识

接下来:

    // Register the handler for all timer family events. This will execute if the timer is started, expired or is stopped.
    //注册一个总处理函数,当事件id是started, expired,stopped三者之一时,它都会被执行
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TIMER_EVENTS, ESP_EVENT_ANY_ID, timer_any_handler, NULL, NULL));

    // Register the handler for task iteration event; need to pass instance handle for later unregistration.
    //注册一个处理函数用于任务迭代事件(?翻译存疑),需要传递一个instance参数用于之后的注销
    ESP_ERROR_CHECK(esp_event_handler_instance_register(TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler, NULL, &s_instance));

    // Register the handler for all event. This will execute if either the timer events or the task iteration event
    // is posted to the default loop.
    //注册一个用于所有事件的handler,定时器事件和任务迭代事件也会触发执行
    ESP_ERROR_CHECK(esp_event_handler_instance_register(ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, all_event_handler, NULL, NULL));

第三步:创建并启动事件源

    // Create and start the event sources
    //创建并启动事件源
    esp_timer_create_args_t timer_args = {
        .callback = &timer_callback,            //设置当定时器终止时,要调用的回调函数
    };

    ESP_ERROR_CHECK(esp_timer_create(&timer_args, &TIMER));         //创建定时器

    ESP_LOGI(TAG, "starting event sources");

esp_timer_create_args_t定义:
在这里插入图片描述
第四步:创建与当前任务具有相同优先级的事件源任务

     // Create the event source task with the same priority as the current task
     //创建与当前任务具有相同优先级的事件源任务
    xTaskCreate(task_event_source, "task_event_source", 2048, NULL, uxTaskPriorityGet(NULL), NULL);

    ESP_ERROR_CHECK(esp_timer_start_periodic(TIMER, TIMER_PERIOD));

定义xTaskCreate
用于创建任务
在这里插入图片描述
参数解释:
函数入口
进程名称
分配的栈大小
参数
优先级
句柄

定义esp_timer_start_periodic(TIMER, TIMER_PERIOD)
在这里插入图片描述
功能:启动一个定时器
参数:

  • @param timer:使用esp_timer_create定义的定时器句柄
  • @param period:设置定时器周期,单位ms

第五步:给定时器传递启动事件信号

    // Post the timer started event
    //给定时器传递启动事件信号
    ESP_LOGI(TAG, "%s:%s: posting to default loop", TIMER_EVENTS, get_id_string(TIMER_EVENTS, TIMER_EVENT_STARTED));
    ESP_ERROR_CHECK(esp_event_post(TIMER_EVENTS, TIMER_EVENT_STARTED, NULL, 0, portMAX_DELAY));

定义esp_event_post
在这里插入图片描述

  • @param[in] event_base:事件类型
  • @param[in] event_id :事件id
  • @param[in] event_data: 数据,传递给处理程序的特定于事件发生的数据
  • @param[in] event_data_size: 数据大小
  • @param[in] ticks_to_wait :最大排队等待时间

补充

1.static char* get_id_string(esp_event_base_t base, int32_t id)

static char* get_id_string(esp_event_base_t base, int32_t id) {         //获取id字符串
    char* event = "";
    if (base == TIMER_EVENTS) {                         //如果事件类型为定时器
        switch(id) {
            case TIMER_EVENT_STARTED:
            event = "TIMER_EVENT_STARTED";
            break;
            case TIMER_EVENT_EXPIRY:
            event = "TIMER_EVENT_EXPIRY";
            break;
            case TIMER_EVENT_STOPPED:
            event = "TIMER_EVENT_STOPPED";
            break;
        }
    } else {
        event = "TASK_ITERATION_EVENT";
    }
    return event;
}

从函数名字和功能我们大概能知道,该函数用于获取当前事件id的。
其中参数@esp_event_base_t定义如下
在这里插入图片描述
故我判断这里的变量base是一个字符串类型,通过判断base的内容,即可知道当前是什么状态。

3.ESP_EVENT_DEFINE_BASE(TIMER_EVENTS); //定义EVENT_BASE
查看定义
在这里插入图片描述
对于id=#id这个用法我不是很理解
只能猜测是创建了一个esp_event_base_t变量,名称叫做id,且其值为传入的字符串id的值

对于esp_event_base_t:
在这里插入图片描述
显而易见,一个字符串常量标识

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值