ESP32 IDF开发 应用篇⑬ 连接Wifi回调函数esp_event_handler_register专题

ESP32 IDF开发 应用篇⑬ 连接Wifi回调函数esp_event_handler_register专题


别迷路-导航栏
快速导航找到你想要的(文章目录)

此篇文章如果对你有用,请点赞收藏,您的支持就是博主坚持的动力。

1、博主写这篇技术文章的目的:

(1)、灵活运用wifi联网的全过程;

2、 概述

在前面章节已经为大家介绍了ESP32 WIFI STA 及AP模式的基本应用,本章是基于上一个章节的详细解析篇
所以理论不多说,直接主题。

3、 esp_event_handler_register函数的详细介绍

函数的实现是在esp-idf\components\esp_event\default_event_loop.c文件中
函数的功能:将事件处理程序注册到系统事件循环,在这里也列数来几个参数的功能

/**
 * @brief 将事件处理程序注册到系统事件循环。
 *
 *此函数可用于注册以下任一处理程序:(1)特定事件,
 *(2)某个事件基础的所有事件,或(3)系统事件循环已知的所有事件。
 *
 *-特定事件:指定确切的event_base和event_id
 *-具有特定基准的所有事件:指定确切的event_base并将ESP_EVENT_ANY_ID用作event_id
 *-循环已知的所有事件:将ESP_EVENT_ANY_BASE用作event_base,将ESP_EVENT_ANY_ID用作event_id
 *
 *可以将多个处理程序注册到事件。将单个处理程序注册到多个事件是
 *也可以。但是,将同一处理程序多次注册到同一事件将导致
 *以前的注册将被覆盖。
 *
 * @param [in] event_base事件的基本ID,用于为其注册处理程序
 * @param [in] event_id要为其注册处理程序的事件的ID
 * @param [in] event_handler处理程序函数,在调度事件时将调用该函数
 * @param [in] event_handler_arg数据,除事件数据外,在调用时传递给处理程序
 *
 * @note 事件循环库不维护event_handler_arg的副本,因此用户应
 *确保在调用处理程序时event_handler_arg仍指向有效位置
 *
 * @返回
 *-ESP_OK:成功
 *-ESP_ERR_NO_MEM:无法为处理程序分配内存
 *-ESP_ERR_INVALID_ARG:事件库和事件ID的无效组合
 *-其他:失败
 */
esp_err_t esp_event_handler_register(esp_event_base_t event_base,
                                        int32_t event_id,
                                        esp_event_handler_t event_handler,
                                        void* event_handler_arg);

以上是官方对改函数的介绍,下面我们具体分析函数的每一个参数的意义,及回调函数是怎么被执行的。
带着一下几个问题来分析:
(1)、函数

esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID,&event_handler, NULL)

中的WIFI_EVENT参数的原型是什么,event_base还可以传递哪些参数?
(2)、event_id有哪些,在回调函数中执行顺序是怎么样的?
(3)、系统时如何执行回调函数的?

解答上上问题:
(1)、event_base的分析:
①、首先event_base的数据类型是:

typedef const char*  esp_event_base_t; /**< unique pointer to a subsystem that exposes events */

说明此传递的是一个字符串;
②、将传递的参数直接跳转到定义处发现有如下定义:

const char * WIFI_EVENT = "wifi_event";
const char * IP_EVENT = "ip_event";
const char * ETH_EVENT = "eth_event";
编写程序验证:在上一章的idf_wifi_sta.c文件中添加2条调试信息
//注册wifi 连接过程中回调函数
  ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
    ESP_LOGI(TAG, "WIFI_EVENT :%s",WIFI_EVENT);
    ESP_LOGI(TAG, "IP_EVENT :%s",IP_EVENT);
调试结果:

在这里插入图片描述
发现并不是上面的字符串。在使用Source Insight搜索WIFI_EVENT关键字时发现在esp-idf\components\esp_wifi\include\esp_wifi_types.h文件中有如下定义:

/** @brief WiFi event base declaration */
ESP_EVENT_DECLARE_BASE(WIFI_EVENT);

此处申明了WiFi event base declaration(wifi 事件的基本声明)

// Defines for declaring and defining event base
#define ESP_EVENT_DECLARE_BASE(id) extern esp_event_base_t id

搜索宏ESP_EVENT_DECLARE_BASE会发现系统中定义的回调事件还有:

•ETH_EVENT:以太网接口事件回调名称; •MESH_EVENT:wifi mesh事件回调名称;
•IP_EVENT:获得IP过程事件回调名称; •SC_EVENT:smartconfig过程事件回调名称;
•WEBSOCKET_EVENTS:websocket事件回调名称; •WIFI_EVENT:连接wifi事件回调名称;
•WIFI_PROV_EVENT:暂时不清楚;

在这里插入图片描述

(2)、event_id的解析
在每一个ESP_EVENT_DECLARE_BASE上面都有事件ID的枚举,以ESP_EVENT_DECLARE_BASE(WIFI_EVENT)为例:

/** WiFi event declarations */
typedef enum {
    WIFI_EVENT_WIFI_READY = 0,           /**< ESP32 WiFi ready */
    WIFI_EVENT_SCAN_DONE,                /**< ESP32 finish scanning AP */
    WIFI_EVENT_STA_START,                /**< ESP32 station start */
    WIFI_EVENT_STA_STOP,                 /**< ESP32 station stop */
    WIFI_EVENT_STA_CONNECTED,            /**< ESP32 station connected to AP */
    WIFI_EVENT_STA_DISCONNECTED,         /**< ESP32 station disconnected from AP */
    WIFI_EVENT_STA_AUTHMODE_CHANGE,      /**< the auth mode of AP connected by ESP32 station changed */

    WIFI_EVENT_STA_WPS_ER_SUCCESS,       /**< ESP32 station wps succeeds in enrollee mode */
    WIFI_EVENT_STA_WPS_ER_FAILED,        /**< ESP32 station wps fails in enrollee mode */
    WIFI_EVENT_STA_WPS_ER_TIMEOUT,       /**< ESP32 station wps timeout in enrollee mode */
    WIFI_EVENT_STA_WPS_ER_PIN,           /**< ESP32 station wps pin code in enrollee mode */
    WIFI_EVENT_STA_WPS_ER_PBC_OVERLAP,   /**< ESP32 station wps overlap in enrollee mode */

    WIFI_EVENT_AP_START,                 /**< ESP32 soft-AP start */
    WIFI_EVENT_AP_STOP,                  /**< ESP32 soft-AP stop */
    WIFI_EVENT_AP_STACONNECTED,          /**< a station connected to ESP32 soft-AP */
    WIFI_EVENT_AP_STADISCONNECTED,       /**< a station disconnected from ESP32 soft-AP */
    WIFI_EVENT_AP_PROBEREQRECVED,        /**< Receive probe request packet in soft-AP interface */

    WIFI_EVENT_MAX,                      /**< Invalid WiFi event ID */
} wifi_event_t;

以上就是WIFI_EVENT的所有ID。在实例中只用到:

    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) 
    {
    } 
	else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) //wifi断开时
	{
	}

(3)、回调函数esp_event_handler_t event_handler的执行:
在esp_event_loop_create_default函数中调用esp_event_loop_create,此函数中创建了回调函数的一些消息队列和信号量和创建任务:

esp_err_t esp_event_loop_create(const esp_event_loop_args_t* event_loop_args, esp_event_loop_handle_t* event_loop)
{
。。。
loop->queue = xQueueCreate(event_loop_args->queue_size , sizeof(esp_event_post_instance_t))
loop->mutex = xSemaphoreCreateRecursiveMutex();BaseType_t task_created = xTaskCreatePinnedToCore(esp_event_loop_run_task, event_loop_args->task_name,
                    event_loop_args->task_stack_size, (void*) loop,
                    event_loop_args->task_priority, &(loop->task), event_loop_args->task_core_id);
。。。。
}

在任务中等到消息队列和互斥信号量,接收到了就执行回调函数

static void esp_event_loop_run_task(void* args)
{
    while(1) {
        err = esp_event_loop_run(event_loop, portMAX_DELAY);
}
esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t ticks_to_run)
{
while(xQueueReceive(loop->queue, &post, ticks_to_run) == pdTRUE) {//等待有消息来
xSemaphoreTakeRecursive(loop->mutex, portMAX_DELAY);//等待接收信号
。。。
handler_execute(loop, handler, post);//执行回调函数
}
}

而函数esp_event_handler_register的主要功能就是把回调函数event_handler赋值给结构体

esp_event_handler_instance_t

一路跟踪代码最后在

static esp_err_t handler_instances_add(esp_event_handler_instances_t* handlers, esp_event_handler_t handler, void* handler_arg)
{
    esp_event_handler_instance_t* handler_instance = calloc(1, sizeof(*handler_instance));
    handler_instance->handler = handler;
handler_instance->arg = handler_arg;
}

最后在handler_execute函数中执行结构体esp_event_handler_instance_t

static void handler_execute(esp_event_loop_instance_t* loop, esp_event_handler_instance_t *handler, esp_event_post_instance_t post)
{
(*(handler->handler))(handler->arg, post.base, post.id, post.data);
}

然而我找了半天也没有发现发送信号和消息的函数,只能猜测应该是在esp_wifi_start()函数发送,此函数被封装看不到代码。

4、 总结

经过上面的分析我们大概可以分为总结一下:
(1)。系统在初始化wifi的时候创建了一个wifi任务,通过消息和互斥信号的方式来控制任务的执行。
(2)、在启动wifi之后在连接AP或连接sta时会发送不同消息来触发不同事件ID这样,在回调函数中根据事件和id就知道wifi连接的全过程。
在函数:

static void event_handler(void* arg, esp_event_base_t event_base,int32_t event_id, void* event_data)
{
ESP_LOGI(TAG, "event_base: %s  ; event_id : %d",event_base,event_id);
}

打印所有的连接调试消息。

所有文章源代码:https://download.csdn.net/download/lu330274924/88518092

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
`esp_event_handler_instance_register`函数的第一个参数是一个`esp_event_base_t`类型的事件基础结构体,用于标识事件的类型。`esp_event_base_t`结构体包含两个成员变量:`char* event_base`和`int32_t event_id_start`。 在使用`esp_event_handler_instance_register`函数时,可以使用以下两种方式填写第一个参数: 1. 使用已定义的事件基础结构体 如果已经在代码中定义了事件基础结构体,则可以直接使用该结构体作为第一个参数。例如: ``` static const char *TAG = "example"; static const int EXAMPLE_EVENT_BASE = ESP_EVENT_BASE_ID_USER; ESP_EVENT_DEFINE_BASE(EXAMPLE_EVENT_BASE, TAG); ... ESP_ERROR_CHECK(esp_event_handler_instance_register(EXAMPLE_EVENT_BASE, ESP_EVENT_ANY_ID, &example_handler, NULL, &example_handler_instance)); ``` 在这个例子中,我们定义了一个名为`EXAMPLE_EVENT_BASE`的事件基础结构体,它的事件类型为用户自定义事件。然后,我们使用该事件基础结构体作为第一个参数调用`esp_event_handler_instance_register`函数。 2. 使用动态创建的事件基础结构体 如果没有已定义的事件基础结构体,可以使用`ESP_EVENT_DECLARE_BASE`宏动态创建事件基础结构体。例如: ``` ESP_EVENT_DECLARE_BASE(EXAMPLE_EVENT_BASE, "example"); ... ESP_ERROR_CHECK(esp_event_handler_instance_register(EXAMPLE_EVENT_BASE, ESP_EVENT_ANY_ID, &example_handler, NULL, &example_handler_instance)); ``` 在这个例子中,我们使用`ESP_EVENT_DECLARE_BASE`宏动态创建了一个名为`EXAMPLE_EVENT_BASE`的事件基础结构体,它的事件类型为`"example"`。然后,我们使用该事件基础结构体作为第一个参数调用`esp_event_handler_instance_register`函数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物联网程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值