esp-idf 之事件循环(Event Loop)例程详解

本文是将Default Event Loop:esp-idf/examples/system/esp_event/default_event_loop at release/v3.3 · espressif/esp-idf 例程内的README和代码注释翻译一下,便于各位看官理解并理顺思路。

README

事件循环库Event Loop Library (‘esp_event’) 默认事件循环例程Default Event Loop Example

本例程是事件循环库的一个示例。为了保持简单,示例仅限于使用默认事件循环。
默认事件循环是系统自带的事件循环,在一般情况下已经够用。
如果需要,用户也可以参考 user_event_loops 例程创建用户自定义的事件循环。

例程的内容如下:

事件的声明与定义 (Declaring and Defining Events)

本例程展示了如何在头文件中声明event base和event ID,并在源文件中进行定义。
在头文件中使用了 ESP_EVENT_DECLARE_BASE这个宏来声明 event base, 而event IDs 在一个枚举enum中进行声明(参考esp-idf/event_source.h at release/v3.3 · espressif/esp-idf)。
。在源文件 main.c 中使用了 ESP_EVENT_DEFINE_BASE这个宏来定义event base.

创建默认事件循环 (Creating the Default Event Loop)

本例程中使用了esp_event_loop_create_default这个API来创建默认事件循环。

向默认事件循环发送事件 (Posting Events to the Default Event Loop)

简单说,就是向默认事件循环发送事件相当于事件的handler依次执行队列中的命令。 使用API esp_event_post来向默认事件循环发送事件。例程中也展示了如何同时传递事件数据。

Handler的注册与注销 (Handler Registration/Unregistration)

本例程使用 esp_event_handler_register注册了三个handler:
(1) 特定事件
(2) 特定event base的任意事件
(3) 任意事件
使用 esp_event_handler_unregister来注销handler。注销handler之后,即便事件此前已注册的事件再次被发送时,也不会再执行了。

例程解析 (Example Flow Explained)

以例程的LOG输出来解释:

I (276) default_event_loop: setting up
I (276) default_event_loop: starting event sources
I (276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: posting to default loop
I (276) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 1 out of 5
I (296) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler
I (306) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_any_handler
I (316) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: all_event_handler
I (326) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: task_iteration_handler, executed 1 times
I (336) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (806) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 2 out of 5
I (806) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: task_iteration_handler, executed 2 times
I (806) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (1276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: posting to default loop
I (1276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_expiry_handler, executed 1 out of 3 times
I (1286) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_any_handler
I (1296) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: all_event_handler
I (1306) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 3 out of 5
I (1316) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: unregistering task_iteration_handler
I (1316) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: task_iteration_handler, executed 3 times
I (1336) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (1846) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 4 out of 5
I (1846) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (2276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: posting to default loop
I (2276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_expiry_handler, executed 2 out of 3 times
I (2286) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_any_handler
I (2296) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: all_event_handler
I (2346) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 5 out of 5
I (2346) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler
I (3276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: posting to default loop
I (3276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: posting to default loop
I (3286) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_expiry_handler, executed 3 out of 3 times
I (3296) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_any_handler
I (3306) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: all_event_handler
I (3316) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: timer_stopped_handler
I (3326) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: deleted timer event source
I (3326) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: timer_any_handler
I (3336) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: all_event_handler
I (3346) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: deleting task event source

设置 (Setting)

本例程使用了两个事件源:一个循环定时器和一个包含循环的任务。定时器在如下情况会产生事件:

  1. 定时器启动
  2. 定时器间隔时间到
  3. 定时器停止
    当任务每次循环时,也会产生事件。

除了如上事件对应的handler之外,还有一个handler,在任意事件发生的时候都会执行。
例程设定了定时器的重复执行次数和任务迭代次数。当定时器循环指定次数的时候,定时器会被停止。当任务迭代达到指定次数时,任务会被删除。对于任务循环来说,还有另外一个设定:即当迭代达到某个次数的时候,对应的handler被注销。

分步解析 (Step-by-Step Explanation)

如下输出内容即为关键点:
a.

I (297)  default_event_loop: setting up

此时默认事件循环已经被创建,同时各个事件handler已经被注册。

b.

I (276) default_event_loop: starting event sources
I (276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: posting to default loop
I (276) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 1 out of 5

两个事件源已经启动,并向默认事件循环发送事件。

c.

I (296) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_started_handler
I (306) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: timer_any_handler
I (316) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STARTED: all_event_handler
I (326) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: task_iteration_handler, executed 1 times
I (336) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler

(b) 中发送的事件对应handler已被执行,另外
timer_started_handlertask_iteration_handler, timer_any_handlerall_event_handler 都被执行。

任意定时器事件均会触发timer_any_handler的执行。可以看到定时器间隔时间到和定时器停止的时候也执行了timer_any_handler

任意事件均会触发all_event_handler的执行。所以在 TIMER_EVENTS:TIMER_EVENT_STARTEDTASK_EVENTS:TASK_ITERATION_EVENT 两个事件发生的时候可以看到它在执行。

对于定时器和任务事件,esp_event确保了他们是按照handler注册的顺序执行的。
如下输出也是如此,事件的发送和handler的执行都完全依照上述注册的顺序。

d.

...
I (1316) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: unregistering task_iteration_handler

此时 task_iteration_handler 已注销, 因此当 TASK_EVENTS:TASK_ITERATION_EVENT发送时已不再执行。

I (1867) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 4 out of 5
I (1867) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handler

...

I (1846) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: posting to default loop, 4 out of 5
I (1846) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: all_event_handle

任务迭代事件继续发送,但是只有 all_event_handler 被执行。

e.

...
I (3276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: posting to default loop
I (3276) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: posting to default loop
I (3286) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_expiry_handler, executed 3 out of 3 times
I (3296) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: timer_any_handler
I (3306) default_event_loop: TIMER_EVENTS:TIMER_EVENT_EXPIRY: all_event_handler
I (3316) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: timer_stopped_handler
I (3326) default_event_loop: TIMER_EVENTS:TIMER_EVENT_STOPPED: deleted timer event source

When the periodic timer expiry limit is reached, the event TIMER_EVENTS:TIMER_EVENT_STOPPED is posted to the loop. The periodic timer is consequently deleted in the handler timer_stopped_handler.
当定时器循环达到指定次数的时候,TIMER_EVENTS:TIMER_EVENT_STOPPED被发送到事件循环,然后在timer_stopped_handler中定时器被删除。

...
I (3346) default_event_loop: TASK_EVENTS:TASK_ITERATION_EVENT: deleting task event source
...

此时发送迭代事件的任务也被删除。例程执行结束。

代码:

/* esp_event (event loop library) basic example
   This example code is in the Public Domain (or CC0 licensed, at your option.)
   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include "esp_log.h"

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

#include "event_source.h"

static const char* TAG = "default_event_loop";

static char* get_id_string(esp_event_base_t base, int32_t 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 base定义 */
ESP_EVENT_DEFINE_BASE(TIMER_EVENTS);

esp_timer_handle_t TIMER;


//定时器回调,回调中向默认事件循环发送事件
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 
static void timer_started_handler(void* handler_args, esp_event_base_t base, int32_t id, void* event_data)
{
    ESP_LOGI(TAG, "%s:%s: timer_started_handler", base, get_id_string(base, id));
}


//定时器循环事件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) {
        // 停止定时器
        ESP_ERROR_CHECK(esp_timer_stop(TIMER));

        ESP_LOGI(TAG, "%s:%s: posting to default loop", base, get_id_string(base, TIMER_EVENT_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,在定时器开启、时间到、停止时均会执行
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。定时器停止之后即可安全删除定时器。
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));

    // 删除定时器
    esp_timer_delete(TIMER);

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

/* 任务相关的event base定义 */
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);


     //发送任务迭代事件,迭代次数同时被传递给handler。请注意传递的数据是原数据的深拷贝。
        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_unregister(TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler));
        }

        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*/
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());

    // 注册特定定时器事件handler
    ESP_ERROR_CHECK(esp_event_handler_register(TIMER_EVENTS, TIMER_EVENT_STARTED, timer_started_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(TIMER_EVENTS, TIMER_EVENT_EXPIRY, timer_expiry_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(TIMER_EVENTS, TIMER_EVENT_STOPPED, timer_stopped_handler, NULL));

    //注册所有定时器事件的handler,包括定时器开启、时间到和停止事件
    ESP_ERROR_CHECK(esp_event_handler_register(TIMER_EVENTS, ESP_EVENT_ANY_ID, timer_any_handler, NULL));

    // 注册迭代任务handler
    ESP_ERROR_CHECK(esp_event_handler_register(TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler, NULL));

    
//注册所有事件的handler,定时器事件和任务迭代事件都会触发它的执行
ESP_ERROR_CHECK(esp_event_handler_register(ESP_EVENT_ANY_BASE, ESP_EVENT_ANY_ID, all_event_handler, NULL));

    // 创建并启动定时器事件源
    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");

     // 创建任务事件源
    xTaskCreate(task_event_source, "task_event_source", 2048, NULL, uxTaskPriorityGet(NULL), NULL);

    ESP_ERROR_CHECK(esp_timer_start_periodic(TIMER, TIMER_PERIOD));

    // 发送定时器启动事件
    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-IDF框架的ESP32 SPI3通信的示例代码: ```c #include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/spi_master.h" #define PIN_CLK 18 #define PIN_MISO 19 #define PIN_MOSI 23 #define PIN_CS 5 void spi_task(void *pvParameters) { spi_device_handle_t spi; spi_bus_config_t bus_config = { .mosi_io_num = PIN_MOSI, .miso_io_num = PIN_MISO, .sclk_io_num = PIN_CLK, .quadwp_io_num = -1, .quadhd_io_num = -1, .max_transfer_sz = 0, }; spi_device_interface_config_t dev_config = { .command_bits = 0, .address_bits = 0, .dummy_bits = 0, .mode = 0, .duty_cycle_pos = 0, .cs_ena_pretrans = 0, .cs_ena_posttrans = 0, .clock_speed_hz = 1000000, // 设置时钟频率为1MHz .input_delay_ns = 0, .spics_io_num = PIN_CS, .flags = 0, .queue_size = 1, .pre_cb = NULL, .post_cb = NULL, }; spi_device_handle_t spi_handle; spi_bus_initialize(VSPI_HOST, &bus_config, 1); spi_bus_add_device(VSPI_HOST, &dev_config, &spi_handle); while (1) { uint8_t send_data = 0x55; uint8_t recv_data; spi_transaction_t trans_desc = { .flags = 0, .cmd = 0, .addr = 0, .length = 8, // 数据位宽为8位 .rxlength = 8, .tx_buffer = &send_data, .rx_buffer = &recv_data, }; spi_device_polling_transmit(spi_handle, &trans_desc); printf("Received data: 0x%02x\n", recv_data); vTaskDelay(1000 / portTICK_PERIOD_MS); } } void app_main() { xTaskCreate(spi_task, "spi_task", 2048, NULL, 10, NULL); } ``` 在这个示例中,我们使用了ESP32的VSPI总线,并且将引脚18、19和23分别连接到SPI3的CLK、MISO和MOSI信号。引脚5用作CS(片选)信号。 我们首先定义了SPI总线和设备的配置参数。然后,通过调用spi_bus_initialize()函数初始化SPI总线,并通过spi_bus_add_device()函数将SPI设备添加到总线上。 在任务函数spi_task()中,我们创建了一个spi_transaction_t结构体来描述传输的参数。然后,我们使用spi_device_polling_transmit()函数来发送和接收数据。 最后,我们在app_main()函数中创建了一个任务来执行SPI通信操作。 请根据你的具体需求进行适当的修改和配置。希望这个例程能帮助你使用ESP-IDF框架进行ESP32 SPI3通信!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值