В данной статье мы научимся настраивать ESP32 в режиме станции (STA) с помощью ESP-IDF. Другими словами, мы увидим, как установить Wi-Fi-соединение и подключиться к точке доступа, используя драйверы Wi-Fi esp-idf. Это руководство включает в себя объяснения необходимых API для подключения к Wi-Fi, подробную информацию о драйвере Wi-Fi и пример скетча для ESP-IDF, демонстрирующий подключение платы ESP32 к беспроводной сети.
Также на нашем сайте вы можете прочитать статью про использование Wi-Fi в ESP32-S3 с помощью ESP-IDF — возможно, некоторые аспекты работы с Wi-FI в ней рассмотрены более понятным для вас языком.
Прежде чем продолжить, убедитесь, что у вас установлена последняя версия VS Code и настроено расширение ESP-IDF:
- Установка ESP32 ESP-IDF на Windows и его интеграция с Visual Studio Code
- Установка ESP32 ESP-IDF на Linux Ubuntu
Дополнительно на нашем сайте вы можете прочитать статью про начало работы с ESP32 с использованием ESP-IDF.
API Wi-Fi для ESP32 ESP-IDF
Давайте сначала обсудим некоторые важные функции, необходимые для подключения ESP32 к Wi-Fi. ESP-IDF предоставляет библиотеку esp_wifi.h , которая используется для настройки и мониторинга работы сети Wi-Fi на ESP32. Это включает в себя настройку режимов точки доступа и станции Wi-Fi ESP32 в различных режимах безопасности, например, WPA, WEP и т. д., мониторинг пакетов Wi-Fi и сканирование ближайших точек доступа.
В этом руководстве мы сосредоточимся на том, как подключить нашу плату ESP32 к точке доступа, настроив её в режиме станции, также известном как режим STA/режим Wi-Fi-клиента. Давайте посмотрим, как это будет сделано.
Первым шагом является подключение заголовочного файла:
|
1 |
#include "esp_wifi.h" |
Конфигурация
Начнем с инициализации ресурса выделения Wi-Fi для драйвера Wi-Fi. Он отвечает за запуск задачи Wi-Fi.
|
1 |
esp_wifi_init(const wifi_init_config_t *config) |
Функция принимает один параметр config, который представляет собой указатель на уже инициализированную структуру конфигурации Wi-Fi. Обычно мы устанавливаем структуру конфигурации Wi-Fi в значение WIFI_INIT_CONFIG_DEFAULT() , чтобы инициализация конфигурации происходила со значениями по умолчанию. Это показано ниже:
|
1 |
wifi_init_config_t wifi_config = WIFI_INIT_CONFIG_DEFAULT(); |
Здесь wifi_init_config_t — это структура, обозначающая параметры конфигурации стека Wi-Fi, передаваемые в функцию esp_wifi_init().
Далее мы настроим режим Wi-Fi. Как упоминалось ранее, библиотека ESP-IDF Wi-Fi поддерживает несколько режимов работы Wi-Fi. Для установки режима Wi-Fi мы используем функцию esp_wifi_set_mode() и передаем в нее режим Wi-Fi в качестве параметра. По умолчанию режим установлен на station. Мы можем установить режим на station, soft-AP или оба (station + soft-AP). Параметр может принимать одно из трех значений:
- WIFI_MODE_STA (режим станции)
- WIFI_MODE_AP (для режима программной точки доступа)
- WIFI_MODE_APSTA (для режима станции + программной точки доступа)
|
1 |
esp_wifi_set_mode(wifi_mode_t mode) |
Запуск Wi-Fi
Для запуска Wi-Fi-соединения в заданных настройках вызывается функция esp_wifi_start(). В зависимости от настроенного режима, она сначала создает свой блок управления, а затем инициализирует этот режим.
|
1 |
esp_wifi_start(void) |
Наконец, для подключения платы ESP32, установленной в режиме станции, к точке доступа, мы используем функцию esp_wifi_connect(). Эта функция применима только в том случае, если настроен режим «станция» или «станция + программная точка доступа».
|
1 |
esp_wifi_connect(void) |
Особенности Wi-Fi на ESP32
ESP32 Wi-Fi поддерживает четыре виртуальных интерфейса Wi-Fi: STA, AP, Sniffer и Reserved. Более того, плата ESP32 может быть сконфигурирована в трех режимах: режим станции, режим программной точки доступа и одновременно режимы станции и программной точки доступа. Ниже мы привели еще несколько особенностей ESP32 Wi-Fi.
- Протокол ESP-NOW и режим дальней связи поддерживают передачу данных на расстояние до 1 км.
- Максимальная пропускная способность TCP по беспроводной сети составляет 20 Мбит/с.
- Кроме того, она обеспечивает максимальную пропускную способность UDP в беспроводной сети до 30 Мбит/с.
- В сочетании с различными стандартами безопасности, включая WPA/WPA2/WPA3/WPA2-Enterprise/WPA3-Enterprise/WAPI/WPS и DPP.
- IEEE 802.11b, IEEE 802.11g, IEEE 802.11n, а также API для настройки режима протокола.
- AMSDU, AMPDU, HT40, QoS, спящий режим модема, несколько антенн.
Подключение платы ESP32 к Wi-Fi-станции
Теперь давайте обсудим процесс подключения платы ESP32 к Wi-Fi-станции, который включает в себя в общей сложности 4 этапа:
- Фаза сканирования;
- Этап аутентификации;
- Этап ассоциации;
- Фаза четырехстороннего рукопожатия.
Давайте кратко обсудим эти этапы.
Фаза сканирования
s1.1: На этом этапе драйвер Wi-Fi начинает сканирование настроенной точки доступа. Именно тогда вызывается функция esp_wifi_connect().
s1.2: Если целевая точка доступа не обнаружена во время сканирования, произойдет событие Wi-Fi: WIFI_EVENT_STA_DISCONNECTED. Это приведет к появлению кода причины Wi-Fi: WIFI_EVENT_STA_DISCONNECTED.
Этап аутентификации
s2.1: Этап аутентификации начинается с отправки запроса на аутентификацию, после чего запускается таймер аутентификации для отслеживания этого запроса.
s2.2: Событие Wi-Fi: WIFI_EVENT_STA_DISCONNECTED произойдет, если таймер аутентификации истечет, а пакет ответа на запрос аутентификации еще не получен. Это приведет к коду причины Wi-Fi: WIFI_REASON_AUTH_EXPIRE.
s2.3: На этом этапе таймер аутентификации останавливается после получения пакета ответа на запрос аутентификации.
s2.4: В этом случае точка доступа не принимает пакет ответа аутентификации, что приводит к возникновению события Wi-Fi: WIFI_EVENT_STA_DISCONNECTED. Это приводит к коду причины Wi-Fi: WIFI_REASON_AUTH_FAIL.
Этап ассоциации
s3.1: Этот этап начинается с отправки запроса на установление связи, что активирует таймер установления связи.
s3.2: Событие Wi-Fi: WIFI_EVENT_STA_DISCONNECTED произойдет, если таймер установления соединения истечет, а пакет ответа на запрос установления соединения еще не получен. Это приведет к коду причины Wi-Fi: WIFI_REASON_ASSOC_EXPIRE.
s3.3: На этом этапе таймер установления соединения останавливается после получения пакета ответа на запрос об установлении соединения.
s3.4: В этом случае точка доступа не принимает пакет ответа на запрос подключения, что приводит к возникновению события Wi-Fi: WIFI_EVENT_STA_DISCONNECTED. Это приводит к коду причины сбоя Wi-Fi: WIFI_REASON_AUTH_FAIL.
Фаза четырехстороннего рукопожатия
s4.1: В этом случае, как только рукопожатие инициировано и таймер рукопожатия истекает, а сигнал 1/4 EAPOL не получен, возникает событие Wi-Fi: WIFI_EVENT_STA_DISCONNECTED. Это приводит к коду причины Wi-Fi: WIFI_REASON_HANDSHAKE_TIMEOUT.
s4.2: На этом этапе осуществляется приобретение 1/4 EAPOL.
s4.3: В этот момент станция отправляет ответ 2/4 EAPOL.
s4.4: В этом случае событие Wi-Fi: WIFI_EVENT_STA_DISCONNECTED возникает, когда сигнал 3/4 EAPOL не получен в течение времени ожидания таймера подтверждения. Это приводит к коду причины Wi-Fi: WIFI_REASON_HANDSHAKE_TIMEOUT.
s4.5: На этом этапе осуществляется приобретение 3/4 EAPOL.
s4.6: В этот момент станция отправляет ответ 4/4 EAPOL.
s4.7: Происходит событие Wi-Fi: WIFI_EVENT_STA_CONNECTED.
Пример работы ESP32 в режиме станции с использованием ESP-IDF
В режиме станции плата ESP32 подключается к сети Wi-Fi через маршрутизатор. Мы используем маршрутизатор для подключения плат ESP32 и получения доступа к локальной сети. Модуль ESP32 выступает в качестве клиента станции, а маршрутизатор настроен как точка доступа.
Создание примера проекта
Откройте VS Code и перейдите в меню View > Command Palette («Вид» > «Палитра команд»). Введите в строке поиска ESP-IDF: New Project (новый проект) и нажмите Enter.
Укажите название проекта и каталог. Мы назвали наш проект «ESP_IDF_WIFI_STA». Для платы ESP-IDF мы выбрали опцию custom board («Пользовательская плата»). В качестве целевой платформы ESP-IDF мы выбрали модуль ESP32. Нажмите кнопку ‘Choose Template’ («Выбрать шаблон»), чтобы продолжить.
В разделе Extension («Расширение») выберите опцию ESP-IDF:
На вкладке getting_started («Начало работы») для Wi-Fi мы нажмем на ‘station’ («станция»). Теперь нажмем ‘Create project using template station’ («Создать проект, используя шаблон станции«).
Вы получите уведомление о создании проекта. Чтобы открыть проект в новом окне, нажмите «Да».
Это открывает наш проект ESP_IDF_WIFI_STA, который мы создали во вкладке EXPLORER. Внутри папки проекта находится несколько папок. Это одинаково для всех проектов, которые вы будете создавать через ESP-IDF Explorer. В основной папке находится исходный код, то есть файл main.c будет находиться именно здесь.
Перейдите в main > station_example_main.c и откройте его.
Ниже приведён фрагмент кода. Этот пример демонстрирует функции Wi-Fi-станции по подключению к точке доступа.
Код подключения ESP32 к Wi-Fi (режим станции)
|
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
/* WiFi station Example This example code is in the Public Domain (or CC0 licensed, at your option.) Unless required by applicable law or agreed to in writing, this software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ #include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" #include "esp_wifi.h" #include "esp_event.h" #include "esp_log.h" #include "nvs_flash.h" #include "lwip/err.h" #include "lwip/sys.h" /* The examples use WiFi configuration that you can set via project configuration menu If you'd rather not, just change the below entries to strings with the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" */ #define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID #define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD #define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY /* FreeRTOS event group to signal when we are connected*/ static EventGroupHandle_t s_wifi_event_group; /* The event group allows multiple bits for each event, but we only care about two events: * - we are connected to the AP with an IP * - we failed to connect after the maximum amount of retries */ #define WIFI_CONNECTED_BIT BIT0 #define WIFI_FAIL_BIT BIT1 static const char *TAG = "wifi station"; static int s_retry_num = 0; 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:" IPSTR, IP2STR(&event->ip_info.ip)); s_retry_num = 0; xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } } void wifi_init_sta(void) { s_wifi_event_group = xEventGroupCreate(); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 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)); 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, }, }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); ESP_ERROR_CHECK(esp_wifi_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"); } /* 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); } 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(); } |
Обязательно укажите следующие переменные с собственными параметрами. Вам потребуется указать SSID и пароль вашей сети Wi-Fi в двойных кавычках. Кроме того, вы можете установить максимальное время повторной попытки, хотя по умолчанию оно равно 5.
|
1 2 3 |
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID #define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD #define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY |
Как работает код?
Для начала мы подключим необходимые библиотеки, включая библиотеки FreeRTOS для генерации задержек, создания задач и групп событий. Библиотека esp_wifi.h используется для включения Wi-Fi-соединения, esp_event.h — для мониторинга событий Wi-Fi, а esp_log.h — для ведения журналов.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
#include <string.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" #include "esp_wifi.h" #include "esp_event.h" #include "esp_log.h" #include "nvs_flash.h" #include "lwip/err.h" #include "lwip/sys.h" |
Укажите SSID и пароль вашей сети, к которой будет подключаться плата ESP32. В нашем случае мы указали SSID как «PTCL-08» и пароль как «44332211».
|
1 2 |
#define EXAMPLE_ESP_WIFI_SSID "PTCL-08" #define EXAMPLE_ESP_WIFI_PASS "44332211" |
Кроме того, мы установили максимальное количество повторных попыток равным 10.
|
1 |
#define EXAMPLE_ESP_MAXIMUM_RETRY 10 |
Далее мы объявляем переменную ‘s_wifi-event_group‘ для хранения созданной группы событий FreeRTOS. Эта группа событий FreeRTOS используется для оповещения о подключении к Wi-Fi.
|
1 |
static EventGroupHandle_t s_wifi_event_group; |
Затем мы определяем два бита для важных для нас событий Wi-Fi. К ним относятся бит, обозначающий успешное подключение к точке доступа Wi-Fi, и бит, обозначающий неудачное подключение к точке доступа Wi-Fi после истечения максимального количества попыток.
|
1 2 |
#define WIFI_CONNECTED_BIT BIT0 #define WIFI_FAIL_BIT BIT1 |
Этот код использует информационное логирование. Функция логирования принимает два аргумента. Первый аргумент — это тег, а второй — отформатированная строка. Поэтому эта глобальная переменная будет полезна при вызове функций ESP_LOGI(). Здесь «wifi station» — это тег, который будет использоваться при логировании.
|
1 |
static const char *TAG = "wifi station"; |
event_handler()
Затем у нас есть функция event_handler(), которая обрабатывает события Wi-Fi. Она выступает в качестве функции обратного вызова при возникновении события Wi-Fi или события IP.
Событие IP происходит, когда плата ESP32 подключается к нашей точке доступа, и маршрутизатор назначает ей IP-адрес. События IP могут быть одного из следующих типов. Но здесь мы используем только один — IP_EVENT_STA_GOT_IP.
|
1 2 3 4 5 6 7 8 9 10 11 |
/** IP event declarations */ typedef enum { IP_EVENT_STA_GOT_IP, /*!< station got IP from connected AP */ IP_EVENT_STA_LOST_IP, /*!< station lost IP and the IP is reset to 0 */ IP_EVENT_AP_STAIPASSIGNED, /*!< soft-AP assign an IP to a connected station */ IP_EVENT_GOT_IP6, /*!< station or ap or ethernet interface v6IP addr is preferred */ IP_EVENT_ETH_GOT_IP, /*!< ethernet got IP from connected AP */ IP_EVENT_ETH_LOST_IP, /*!< ethernet lost IP and the IP is reset to 0 */ IP_EVENT_PPP_GOT_IP, /*!< PPP interface got IP */ IP_EVENT_PPP_LOST_IP, /*!< PPP interface lost IP */ } ip_event_t; |
Во-первых, когда происходят события Wi-Fi (WIFI_EVENT и WIFI_EVENT_STA_START), мы подключаем ESP32 к точке доступа. Для этого мы используем функцию esp_wifi_connect() .
Если плата ESP32 не может подключиться к точке доступа в течение установленного максимального количества попыток, она снова пытается подключиться к точке доступа и регистрирует сообщение «повторная попытка подключения к точке доступа». Однако, если ESP32 не может установить соединение с точкой доступа после истечения максимального количества попыток, она регистрирует сообщение «сбой подключения к точке доступа» и устанавливает бит WIFI_FAIL_BIT. Теперь, если плата ESP32 успешно подключается к точке доступа, это означает, что произошли оба события IP (IP_EVENT и IP_EVENT_STA_GOT_IP). В этом случае она выводит IP-адрес в качестве результата. Кроме того, она также устанавливает бит WIFI_CONNECTED_BIT.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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:" IPSTR, IP2STR(&event->ip_info.ip)); s_retry_num = 0; xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); } } |
wifi_init_sta()
Функция wifi_init_sta() будет вызываться внутри функции app_main() для инициализации Wi-Fi в режиме станции для ESP32.
|
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
void wifi_init_sta(void) { s_wifi_event_group = xEventGroupCreate(); ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 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)); 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, }, }; ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); ESP_ERROR_CHECK(esp_wifi_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"); } /* 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); } |
Для начала создадим группу событий FreeRTOS для мониторинга соединения. Эта функция возвращает дескриптор группы событий.
|
1 |
s_wifi_event_group = xEventGroupCreate(); |
ESP-IDF предоставляет полезный макрос ESP_ERROR_CHECK(), который используется для проверки наличия или отсутствия ошибки. Если функция, переданная в него, не возвращает ESP_OK, то мы проверяем наличие ошибки и записываем её в лог.
Здесь мы инициализируем lwIP с помощью функции esp_netif_init() и создаём задачу IwIP, также известную как задача TCP/IP. lwIP — это стек библиотек TCP/IP, предоставляемый ESP-IDF, который используется для выполнения различных протоколов, таких как TCP, UDP, DHCP и т. д.
|
1 |
ESP_ERROR_CHECK(esp_netif_init()); |
Далее мы создаём цикл обработки событий по умолчанию, который позволяет отправлять системные события в задачу обработки событий.
|
1 |
ESP_ERROR_CHECK(esp_event_loop_create_default()); |
Кроме того, следующая строка используется для инициализации Wi-Fi по умолчанию в режиме станции. Этот API используется для инициализации, а также регистрации обработчиков событий для интерфейса по умолчанию, которым в нашем случае является станция. Он создает экземпляр сетевого интерфейса, связывающий драйвер Wi-Fi и стек TCP/IP. Когда станция находится в процессе подключения к точке доступа, различные процессы автоматически обрабатываются с помощью этой функции.
|
1 |
esp_netif_create_default_wifi_sta(); |
Затем мы инициализируем ресурс выделения Wi-Fi для драйвера Wi-Fi. Он отвечает за запуск задачи Wi-Fi. Он принимает единственный параметр cfg, который является указателем на уже инициализированную структуру конфигурации Wi-Fi, установленную в значение WIFI_INIT_CONFIG_DEFAULT(), так что инициализация конфигурации происходит со значениями по умолчанию. Здесь wifi_init_config_t — это структура, обозначающая параметры конфигурации стека Wi-Fi, которые передаются в функцию esp_wifi_init().
|
1 2 |
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); |
Далее мы создаём два обработчика событий: один с именем ‘instance_any_id’ для всех событий Wi-Fi, а другой с именем ‘instance_any_ip’ — для событий, когда станция получает IP-адрес.
|
1 2 |
esp_event_handler_instance_t instance_any_id; esp_event_handler_instance_t instance_got_ip; |
Далее, у нас есть два регистра для экземпляров обработчика событий, которые мы настроили. Таким образом, задача приложения может зарегистрироваться для обратного вызова, который будет прослушивать события для Wi-Fi и TCP/IP. Первое событие — «ESP_EVENT_ANY_ID», а второе — «IP_EVENT_STA_GOT_IP». Следовательно, она будет прослушивать все события Wi-Fi (ESP_EVENT_ANY_ID) и событие IP, когда станция получит свой IP-адрес (IP_EVENT_STA_GOT_IP). Таким образом, функция обратного вызова event_handler будет вызвана, если произойдет любое из этих двух событий.
|
1 2 3 4 5 6 7 8 9 10 |
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)); |
Другие события Wi-Fi, которые мы можем использовать в нашем коде, включают:
|
1 2 3 4 5 6 |
typedef enum { WIFI_EVENT_STA_CONNECTED, /**< ESP32 station connected to AP */ WIFI_EVENT_STA_DISCONNECTED, /**< ESP32 station disconnected from AP */ WIFI_EVENT_AP_START, /**< ESP32 soft-AP start */ WIFI_EVENT_AP_STOP, /**< ESP32 soft-AP stop */ } mdns_used_event_t; |
В этой части мы задаём SSID и пароль сети, к которой хотим подключить наш ESP32, а также назначаем параметры безопасности.
|
1 2 3 4 5 6 7 |
wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS, .threshold.authmode = WIFI_AUTH_WPA2_PSK, }, }; |
Кроме того, мы устанавливаем режим Wi-Fi как «станция». Для этого мы используем функцию esp_wifi_set_mode() и передаем в качестве параметра параметр WiFI_MODE_STA .
|
1 |
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); |
Затем мы назначаем SSID и пароль нашей сети. Таким образом, драйвер Wi-Fi настраивается с использованием учетных данных сети точки доступа и режима Wi-Fi. После этого мы запускаем Wi-Fi-соединение с заданными параметрами.
|
1 2 |
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); ESP_ERROR_CHECK(esp_wifi_start() ); |
На этом этапе в журнале информации появляется сообщение «wifi_init_sta finished». Процесс инициализации Wi-Fi в режиме станции завершен.
|
1 |
ESP_LOGI(TAG, "wifi_init_sta finished."); |
Далее приложение переходит в заблокированное состояние, ожидая установки одного из битов в группе событий. Это происходит после инициализации и запуска Wi-Fi. Приложение остается в заблокированном состоянии до тех пор, пока не будет установлено соединение Wi-Fi (контролируется битом WIFI_CONNECTED_BIT) или пока соединение Wi-Fi не будет разорвано в течение максимального количества попыток (контролируется битом WIFI_FAIL_BIT).
Если функция event_handler() устанавливает значение WIFI_CONNECTED_BIT, указывающее на успешное подключение ESP32 к точке доступа, то в информационном журнале будет указано, что соединение установлено с SSID и паролем указанной точки доступа. Если же функция event_handler() устанавливает значение WIFI_FAIL_BIT, указывающее на невозможность подключения ESP32 к точке доступа даже после достижения максимального количества попыток, то в информационном журнале будет указано, что соединение с SSID и паролем указанной точки доступа не удалось.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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"); } |
Кроме того, мы отменяем регистрацию двух обработчиков из цикла системных событий для IP_EVENT (базовое событие) и WIFI_EVENT (базовое событие). Функция esp_vent_handler_instance_unregister() принимает три параметра. Первый — это базовое событие. Второй — идентификатор события. Третий — объект экземпляра. Более того, мы также удаляем группу событий ‘s_wifi_event_group’ с помощью функции vEventGroupDelete(). Она была создана ранее с помощью вызова xEventGroupCreate().
|
1 2 3 |
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); |
app_main()
Внутри функции app_main() мы сначала инициализируем NVS, вызвав функцию nvs_flash_init(). Затем мы проверим, не содержит ли раздел NVS пустых страниц или содержит ли он данные в формате, отличном от текущей версии кода. Если хотя бы одно из этих условий выполняется, мы сотрём флэш-память NVS с помощью функции nvs_flash_erase() и инициализируем её заново.
Затем мы выведем в терминале “ESP_WIFI_MODE_STA” и вызовем функцию wifi_init_sta() для инициализации Wi-Fi в режиме станции.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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(); } |
Компиляция скетча
Для прошивки микросхемы введите следующую команду в последовательном терминале. Не забудьте заменить COM-порт на тот, через который подключена ваша плата.
|
1 |
idf.py -p COMX flash monitor |
После успешной прошивки кода вы сможете просмотреть все информационные журналы.
Сначала в терминале отображается сообщение «ESP_WIFI_MODE_STA». Затем следует «wifi_init_sta finished», что означает инициализацию Wi-Fi-станции. Далее можно просмотреть esp_netif_handlers, содержащий IP-адрес, маску и адрес шлюза. Затем в логе появляется сообщение о том, что Wi-Fi-станция получила IP-адрес, а затем и сам IP-адрес. Это показывает, что ESP32 успешно подключился к точке доступа. Наконец, можно увидеть SSID и пароль точки доступа, к которой подключилась плата.
