一、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连接方式一
更多推荐
【ESP32学习之路5——station模式下连接到WiFi热点】
发布评论