1

我正在熟悉使用 ESP-IDF 框架在 ESP32 上进行开发,这也是我第一次在 freeRTOS 上进行开发。

我的简单探索性应用程序将涉及响应来自两个不同来源的输入:与我的开发计算机的串行连接,以及与 MQTT 客户端的连接(例如)。

阅读关于 freeRTOS 的介绍性材料似乎建议我应该创建单独的任务来监视和处理每个输入源。

但是,ESP-IDF 中的项目示例(构建在 freeRTOS 之上)不包含对xTaskCreateor的调用vTaskStartScheduler()。相反,我看到在事件循环中注册了事件句柄和回调:

static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
{
    esp_mqtt_client_handle_t client = event->client;
    int msg_id;
    static int cnt = 0;
    // your_context_t *context = event->context;
    switch (event->event_id) {
        case MQTT_EVENT_CONNECTED:
            ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
            //... Some other actions ...
            break;
        case MQTT_EVENT_DISCONNECTED:
            ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
            break;
        case MQTT_EVENT_SUBSCRIBED:
            ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
            //... Some other actions ...
            break;
        default:
            ESP_LOGI(TAG, "Other event id:%d", event->event_id);
            break;
    }
    return ESP_OK;
}

static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
    ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
    mqtt_event_handler_cb(event_data);
}

static void mqtt_app_start(void)
{
    const esp_mqtt_client_config_t mqtt_cfg = {
        .uri = CONFIG_BROKER_URI,
        .cert_pem = (const char *)mqtt_eclipse_org_pem_start,
    };

    esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
    esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
    esp_mqtt_client_start(client);
}
void app_main(void)
{
    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
     * Read "Establishing Wi-Fi or Ethernet Connection" section in
     * examples/protocols/README.md for more information about this function.
     */
    ESP_ERROR_CHECK(example_connect());
    mqtt_app_start();
}

我不明白为什么 ESP-IDF 会在看起来像是一种相当专用的方法之上强加一个事件循环结构来管理代码块之间共享处理器时间以响应外部事件。我怀疑我错过了一个关键的理解,它清楚地说明了每个工具(事件循环和任务管理器)适用于什么范围/上下文。

最终,我的下一步将是创建自己的任务或创建自己的事件来处理来自我的开发机器的串行输入。哪一个?

4

1 回答 1

3

请记住,ESP IDF 示例的目的是以最简单的方式演示特定子系统 API 的使用。为此,他们忽略了不必要的细节,这些细节在构建真正的软件架构时可能变得很重要:)

在这种情况下,MQTT 库使用Event Loop Library (ELL),这是 Espressif 提供的抽象事件处理程序服务,以简化您的生活。它在一个专门的任务中执行。ELL 发出的任何事件回调都在此专用任务中运行,由接收来自 ELL 的回调的所有模块共享。

这是一种妥协。如果您有许多不是实时关键的轻量级(即不阻止它们运行的​​任务)事件处理程序,那么在单个任务中执行它们是节省资源的好方法。它还允许一个相当简单的架构。

如果您需要做任何“繁重的”(即阻止任务)作为对事件的响应,那么您不应该在 ELL 任务中执行此操作。创建您自己的处理线程并让 ELL 事件处理程序简单地在那里发布一条消息以开始处理。

这与 UART 基本相同 - 乐鑫的驱动程序创建一个任务,并在那里执行“数据接收”处理程序。因此,您的问题的答案是:如果您需要阻止任务,请为此目的创建自己的任务并将处理从事件处理程序推迟到那里。如果没有,请随意搭载 UART 或 ELL 任务的事件处理程序。

于 2021-01-31T21:07:01.907 回答