【ESP32学习之路5——station模式下连接到WiFi热点】

一、Wi-Fi station 一般情况

WiFi station的工作流程参考ESP-IDF编程指南中的API指南的WiFi模块ESP32 WiFi station一般情况在不同阶段都有具体的描述。

二、WiFi station工作流程

在ESP-IDF下copy出/home/andy/esp/esp-idf/examples/wifi/getting_started/station,此demo连接到路由器。整个demo都是在调用ESP-IDF提供的接口,整个过程如下:

1、主程序

void app_main(void)
{
    //Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA!!!!");
    wifi_init_sta();
}

在main函数中对nvs进行初始化用于保存路由器信息,然后进入wifi_init_sta();函数连接到路由器

2、WiFi连接函数

WiFi连接函数大致分为三个阶段:1. Wi-Fi/LwIP 初始化阶段;2. Wi-Fi 配置阶段;3. Wi-Fi 启动阶段
具体过程在相关函数后注释了一些,细节还是看看乐鑫文档

void wifi_init_sta(void)
{
    s_wifi_event_group = xEventGroupCreate();
    //1. Wi-Fi/LwIP 初始化阶段
    ESP_ERROR_CHECK(esp_netif_init());//初始化LwIP,创建LwIP核心任务并初始化与LwIP相关的工作。
    printf("sequence1.\n");
    ESP_ERROR_CHECK(esp_event_loop_create_default());//创建一个系统事件任务,并初始化应用程序事件的回调函数
    esp_netif_create_default_wifi_sta();//创建有 TCP/IP 堆栈的默认网络接口实例绑定 station
    printf("sequence2.\n");
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));//创建 Wi-Fi 驱动程序任务,并初始化 Wi-Fi 驱动程序
    printf("sequence3.\n");
    //创建应用程序任务,应用程序可以在使用进行注册的回调中处理这些事件esp_event_handler_register()
    esp_event_handler_instance_t instance_any_id;
    esp_event_handler_instance_t instance_got_ip;
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                                                        ESP_EVENT_ANY_ID,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_any_id));
    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
                                                        IP_EVENT_STA_GOT_IP,
                                                        &event_handler,
                                                        NULL,
                                                        &instance_got_ip));
    printf("sequence4.\n");
    //2. Wi-Fi 配置阶段
    wifi_config_t wifi_config = {
        .sta = {
            .ssid = EXAMPLE_ESP_WIFI_SSID,
            .password = EXAMPLE_ESP_WIFI_PASS,
            /* Setting a password implies station will connect to all security modes including WEP/WPA.
             * However these modes are deprecated and not advisable to be used. Incase your Access point
             * doesn't support WPA2, these mode can be enabled by commenting below line */
	     .threshold.authmode = WIFI_AUTH_WPA2_PSK,

            .pmf_cfg = {
                .capable = true,
                .required = false
            },
        },
    };
    printf("sequence5.\n");
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );//设置wifi模式
    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );//配置wifi接口的参数
    ESP_ERROR_CHECK(esp_wifi_start() );//3. Wi-Fi 启动阶段
    //Wi-Fi 驱动程序将事件 WIFI_EVENT_STA_START 发布到事件任务中,然后,事件任务将执行一些正常操作并调用应用程序的事件回调函数
    ESP_LOGI(TAG, "wifi_init_sta finished.");

    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
            pdFALSE,
            pdFALSE,
            portMAX_DELAY);

    /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
     * happened. */
    if (bits & WIFI_CONNECTED_BIT) {
        ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else if (bits & WIFI_FAIL_BIT) {
        ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
                 EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
    } else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
    }
    printf("sequence7.\n");
    /* The event will not be processed after unregister */
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
    ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
    vEventGroupDelete(s_wifi_event_group);
    printf("sequence8.\n");
}

3、回调函数

在esp_wifi_start()即WiFi启动后调用esp_event_handler_instance_register()向WiFi组件注册事件通知,调用回调函数event_handler(),WiFi驱动程序将WIFI_EVENT_STA_START发布到事件任务;然后,事件任务将执行一些常规操作,并将调用应用程序事件回调函数。应用程序事件回调函数将WIFI_EVENT_STA_START中继到应用程序任务。
在idf中,整个WiFi协议栈是一个状态机,在每个时刻都有一个状态,当WiFi状态机的状态变化时就会调用event_handler()并给它传递适当的参数。

static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();//4. Wi-Fi 连接阶段
        printf("wifi event start.\n");
    } 
    else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {//6. Wi-Fi 断开阶段
        if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
            esp_wifi_connect();
            s_retry_num++;
            ESP_LOGI(TAG, "retry to connect to the AP");
        } else {
            xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
        }
        ESP_LOGI(TAG,"connect to the AP fail");
    } 
    else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {//5. Wi-Fi 获取 IP 阶段
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        s_retry_num = 0;
        xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
    }
    else
    {
        printf("sequence6.\n");
    }
}

可以看出回调函数有三个阶段:WiFi连接阶段;断开阶段;获取IP阶段

三、终端查看连接过程状态

将WiFi demo烧录进esp32开发板,通过log可以看到在启动WiFi后即esp_wifi_start()后进入回调函数WIFI_EVENT_STA_START中connect配置中的WiFi
当连接失败再次进入回调WIFI_EVENT_STA_DISCONNECTED中重连5次
然后 WIFI_CONNECTED_BIT 或 WIFI_FAIL_BIT 被置位后,打印出信息并删除一些变量,打印出ssid与password
最后注销事件通知
在这里插入图片描述
在log中看到ssid与password,进入sdkconfig文件夹中看到默认的SSID与PASSWORD,以及重连的次数为5次
在这里插入图片描述
现在在idf.py menuconfig中更改下ssid与password以连接到路由器。在example configuration中修改可以连接上的路由器名称与密码
在这里插入图片描述
修改完WiFi信息后再编译烧录进开发板看到输出信息如下,重连两次get IP成功连上路由器,连接成功后我关闭了路由器也就是断网在打开路由器并没有重连WiFi,这是因为在sta函数最后将该事件注销掉了也就不会处理该事件
在这里插入图片描述
将注销事件这三行程序注释掉再尝试断网,打开网络之后能重连上,注意在此demo中只会重连5次,5次之后便连接不上了。
在这里插入图片描述
在实际项目中应该断连之后应该一直尝试连接。可注释掉这几行当掉线时一直去连接
在这里插入图片描述
可以看出在掉线后在一直连接
在这里插入图片描述

参考

深入分析 ESP32 的 WiFi 状态机
ESP32之WIFI连接方式一

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值