在本文中,我们通过样例来分析 ESP8266 连接 Wifi 的过程及需要用都的 API。
该程序在 SDK 中 examples/wifi/getting_started/station 目录中。项目包含一个 C 语言的源文件 - hello_world_main.c(位于 main 目录中), 其它的文件是 Make 构建系统需要的配置文件。
主程序解析 打开 station_example_main.c 文件,入口函数 app_main 位于文件末尾,代码如下:
1 2 3 4 5 6 7 void app_main () { ESP_ERROR_CHECK(nvs_flash_init()); ESP_LOGI(TAG, "ESP_WIFI_MODE_STA" ); wifi_init_sta(); }
首先,调用了系统 API: nvs_flash_init , 用来初始化默认的 “nvs” 分区。
然后就调用自定义的 wifi_init_sta 来启动 Wifi 连接。
启动 Wifi 首先看函数 wifi_init_sta 的实现代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 void wifi_init_sta (void ) { s_wifi_event_group = xEventGroupCreate(); tcpip_adapter_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 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 )); wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS }, }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); ESP_ERROR_CHECK(esp_wifi_start() ); ESP_LOGI(TAG, "wifi_init_sta finished." ); EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY); 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" ); } ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler)); ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler)); vEventGroupDelete(s_wifi_event_group); }
可以看到,程序首先通过 xEventGroupCreate 构建了一个事件组,该 API 是 RTOS 系统 API 的一个。
接下来,程序调用了 tcpip_adapter_init,构建 TCPIP 栈。
然后调用 esp_event_loop_create_default 构建默认的消息(事件)队列。
接着,初始化 Wifi 设备驱动,其实是为运行 Wifi 准备相关的数据结构,存储空间,该调用所涉及到的参数比较多,因此建议使用预定义的宏,代码:
1 2 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();ESP_ERROR_CHECK(esp_wifi_init(&cfg));
接下来的两行代码注册事件(消息)处理行数,
1 2 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 ));
这里我们注册了连个类型的事件: WIFI_EVENT - Wifi 相关事件 和 IP_EVENT - ip 相关事件,这两类事件又包含多个具体的事件,这就由第二个参数来标识: ESP_EVENT_ANY_ID - 表示接收类别下所有的事件,对于 WIFI_EVENT 来说就可以是: WIFI_EVENT_STA_START, WIFI_EVENT_STA_DISCONNECTED 等, IP_EVENT_STA_GOT_IP - 表示接收获得IP的事件。
再下面的代码是设定所要连接的AP的SSID和密码(该值可以通过 make menuconfig 进行设置),并设置 Wifi 工作模式,然后启动。
1 2 3 4 5 6 7 8 9 wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS }, }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); ESP_ERROR_CHECK(esp_wifi_start() );
ESP_ERROR_CHECK(esp_wifi_start() ); 这行代码启动 Wifi, 事件处理程序中的代码是异步执行的
因为这是一个演示程序,所以执行完成以后需要停止Wifi的连接,并打印是否连接上网络。
下面,执行一个租塞语句,要等待异步执行的事件处理结果,代码:
1 2 3 4 5 EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
该预计在 s_wifi_event_group 中等待 WIFI_CONNECTED_BIT 或 WIFI_FAIL_BIT 标致。
后续的代码就是打印联网结果及清理现场了。
事件处理 在函数 wifi_init_sta 中,注册了两个事件处理,都使用同样的事件处理函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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(); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { 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) { ip_event_got_ip_t * event = (ip_event_got_ip_t *) event_data; ESP_LOGI(TAG, "got ip:%s" , ip4addr_ntoa(&event->ip_info.ip)); s_retry_num = 0 ; xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } }
可以看到,当 WIFI_EVENT_STA_START 事件触发时,调用API: esp_wifi_connect 建立连接
当 WIFI_EVENT_STA_DISCONNECTED 事件触发时,如果重连次数小于设定的最多重连次数,则调用 esp_wifi_connect 重建连接,否则设置调用 xEventGroupSetBits,触发主线程中调用 xEventGroupWaitBits 的返回。
同样,如果发生 IP_EVENT_STA_GOT_IP 事件,则获取 IP 地址。