05 ESP32 Event Loop

事件循环含义

  • 如果学习过QT信号与槽,或者其他消息机制,这一部分会很好上手.ESP_IDF中的事件循环机制,可以实现不同组件之间的事件传递,能够降低不同组件之间的耦合,自由组合资源.举个简单的例子理解:

    A,B,C 三个节点想实现相互之间的消息传递,一种简单的方法是,A,B,C 分别不停的去访问其他节点,询问是否有新事件发生.这样势必会增加整体计算的负担,另外也会涉及到很多问题,比如何时清除事件标志,保证既能够通知到所有关心该事件的节点又能防止重复的通知.

  • 如果这时候引入D去统一管理,会把问题极大的简化.A,B,C分别到D处登记自己关心的事件,登记完成后由D去进行问询和分发,A,B,C可以专心做自己的事情,当需要发信号时,直接发送到D,当D发现有事件发生后,会根据登记的内容和先后顺序,通知对应的节点去处理.

ESP_IDF事件循环使用过程

  1. 定义事件处理函数 esp_event_handler_t

  2. 创建一个事件循环esp_event_loop_create(),创建完成后会返回事件循环句柄(作用相当于D)

  3. 向事件循环注册事件esp_event_handler_register_with(),添加回调函数.(注册关注哪个事件,事件发生后执行哪个函数)

  4. 事件发生时,向事件循环发生通知esp_event_post_to().

// 1. Define the event handler
void run_on_event(void* handler_arg, esp_event_base_t base, int32_t id, void* event_data)
{
    // Event handler logic
}

void app_main()
{
    // 2. A configuration structure of type esp_event_loop_args_t is needed to specify the properties of the loop to be
    // created. A handle of type esp_event_loop_handle_t is obtained, which is needed by the other APIs to reference the loop
    // to perform their operations on.
    esp_event_loop_args_t loop_args = {
        .queue_size = ...,
        .task_name = ...
        .task_priority = ...,
        .task_stack_size = ...,
        .task_core_id = ...
    };

    esp_event_loop_handle_t loop_handle;

    esp_event_loop_create(&loop_args, &loop_handle)

    // 3. Register event handler defined in (1). MY_EVENT_BASE and MY_EVENT_ID specifies a hypothetical
    // event that handler run_on_event should execute on when it gets posted to the loop.
    esp_event_handler_register_with(loop_handle, MY_EVENT_BASE, MY_EVENT_ID, run_on_event, ...);

    ...

    // 4. Post events to the loop. This queues the event on the event loop. At some point in time
    // the event loop executes the event handler registered to the posted event, in this case run_on_event.
    // For simplicity sake this example calls esp_event_post_to from app_main, but posting can be done from
    // any other tasks (which is the more interesting use case).
    esp_event_post_to(loop_handle, MY_EVENT_BASE, MY_EVENT_ID, ...);

    ...

    // 5. Unregistering an unneeded handler
    esp_event_handler_unregister_with(loop_handle, MY_EVENT_BASE, MY_EVENT_ID, run_on_event);

    ...

    // 6. Deleting an unneeded event loop
    esp_event_loop_delete(loop_handle);
}

使用事件循环注意事项

  1. 以上方法是来自新的ESP_IDF功能设计,我们在网上例程中会经常见到

    esp_event_loop_init(system_event_cb_tcb, void *ctx)

    这是向上兼容的比较早期的事件循环的版本,这个事件循环用于接收系统事件(如WiFi链接,具体可看system_event_info_t),另外在初始化就限定了只能有一个回调函数,功能不如现在的庞大.可以在这里查阅详情esp_event_legacy

最后更新于