В данной статье мы рассмотрим как установить статический IP-адрес для вашей платы разработки ESP32. Мы будем использовать пример скетча, предоставленный ESP-IDF, и объясним API, используемые для назначения статических IP-адресов. Фиксированный IP-адрес решает проблему изменения IP-адреса или назначения нового IP-адреса маршрутизатором при каждой перезагрузке платы ESP32. Например, если вы используете веб-сервер или веб-клиент на ESP32, наличие статического/фиксированного IP-адреса будет полезно. Вы можете следовать этому руководству, чтобы назначить статический/фиксированный IP-адрес с помощью ESP-IDF.

Также ранее на нашем сайте мы рассматривали установку статического IP-адреса на ESP32 с помощью Arduino IDE.
Пример для установки статического IP-адреса на ESP32
Мы будем использовать пример скетча, загруженный на GitHub по следующей ссылке ( https://github.com/espressif/esp-idf/tree/master/examples/protocols/static_ip ).
В этом примере используются примеры ESP-IDF из вкладки «Протоколы» под названием «static_ip».
Откройте VS Code и перейдите в меню View > Command Palette. Введите в строке поиска ESP-IDF: New Project и нажмите Enter.
Укажите название проекта и каталог. Мы назвали наш проект «ESP_IDF_STATIC_IP». Для платы ESP-IDF мы выбрали опцию custom board («Пользовательская плата»). В качестве целевой платформы ESP-IDF мы выбрали модуль ESP32. Нажмите кнопку ‘Choose Template’ («Выбрать шаблон»), чтобы продолжить.
В разделе Extension («Расширение») выберите опцию ESP-IDF:
На вкладке get-started («Начало работы») мы щелкнем по пункту «sample_project». Затем нажмем ‘Create project using template sample_project’ («Создать проект, используя шаблон sample_project»).
Вы получите уведомление о создании проекта. Чтобы открыть проект в новом окне, нажмите «Да».
Это откроет созданный нами проект во вкладке «Проводник». Внутри папки проекта находится несколько папок. Это относится ко всем проектам, которые вы будете создавать с помощью ESP-IDF Explorer. Создайте новый файл с именем «Kconfig.projbuild» в основной папке. Скопируйте файл из этого места в созданный файл.
Конфигурация проекта
Для начала перейдём к menuconfig. Щёлкните по значку, показанному ниже. Откроется редактор конфигурации ESP-IDF SDK.
Прокрутите вниз и откройте Example Configuration (пример конфигурации). Здесь мы можем установить параметры конфигурации для этого примера в соответствии с нашими потребностями. Это включает в себя SSID Wi-Fi, пароль Wi-Fi, максимальное количество попыток, статический IP-адрес, статическую маску подсети, статический адрес шлюза, выбор DNS-сервера и включение проверки разрешения DNS. Здесь вы можете увидеть, что по умолчанию ESP-IDF использует максимальное количество попыток равное 5, статический IP-адрес 192.168.4.2, статическую маску подсети 255.255.255.0, статический адрес шлюза 192.168.4.1 и DNS-сервер в качестве адреса шлюза.
Вы можете изменить эти параметры по своему усмотрению, а затем нажать кнопку «Сохранить», расположенную вверху. Установите следующие параметры:
- SSID сети Wi-Fi, пароль сети Wi-Fi, максимальное количество попыток подключения.
- Статический IP-адрес.
- Статический адрес маски подсети.
- Статический адрес шлюза.
- В разделе «Выбор DNS-сервера» вы можете выбрать либо «Использовать адрес шлюза в качестве DNS-сервера», либо «Установить значение DNS-сервера вручную».
- Если вы выберете вариант настройки DNS-сервера вручную, вам будет предложено указать адрес основного DNS-сервера и адрес резервного DNS-сервера.
- Вы можете установить флажок «Включить проверку разрешения DNS» и указать имя хоста для разрешения.
Мы присвоим нашей плате ESP32 статический IP-адрес 192.168.4.1, который является адресом по умолчанию.

Код для установки статического IP-адреса на ESP32
В папке main находится исходный код, то есть файл main.c будет находиться здесь. Внутри main.c мы напишем наш программный код. Перейдите в main > main.c и откройте его. Здесь мы определим функции и программный код. Скопируйте код по этой ссылке.
Это наш файл main.c.
|
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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
/* Static IP 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 <netdb.h> #include "nvs_flash.h" /* The examples use 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_WIFI_SSID CONFIG_EXAMPLE_WIFI_SSID #define EXAMPLE_WIFI_PASS CONFIG_EXAMPLE_WIFI_PASSWORD #define EXAMPLE_MAXIMUM_RETRY CONFIG_EXAMPLE_MAXIMUM_RETRY #define EXAMPLE_STATIC_IP_ADDR CONFIG_EXAMPLE_STATIC_IP_ADDR #define EXAMPLE_STATIC_NETMASK_ADDR CONFIG_EXAMPLE_STATIC_NETMASK_ADDR #define EXAMPLE_STATIC_GW_ADDR CONFIG_EXAMPLE_STATIC_GW_ADDR #ifdef CONFIG_EXAMPLE_STATIC_DNS_AUTO #define EXAMPLE_MAIN_DNS_SERVER EXAMPLE_STATIC_GW_ADDR #define EXAMPLE_BACKUP_DNS_SERVER "0.0.0.0" #else #define EXAMPLE_MAIN_DNS_SERVER CONFIG_EXAMPLE_STATIC_DNS_SERVER_MAIN #define EXAMPLE_BACKUP_DNS_SERVER CONFIG_EXAMPLE_STATIC_DNS_SERVER_BACKUP #endif #ifdef CONFIG_EXAMPLE_STATIC_DNS_RESOLVE_TEST #define EXAMPLE_RESOLVE_DOMAIN CONFIG_EXAMPLE_STATIC_RESOLVE_DOMAIN #endif /* 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 = "static_ip"; static int s_retry_num = 0; static esp_err_t example_set_dns_server(esp_netif_t *netif, uint32_t addr, esp_netif_dns_type_t type) { if (addr && (addr != IPADDR_NONE)) { esp_netif_dns_info_t dns; dns.ip.u_addr.ip4.addr = addr; dns.ip.type = IPADDR_TYPE_V4; ESP_ERROR_CHECK(esp_netif_set_dns_info(netif, type, &dns)); } return ESP_OK; } static void example_set_static_ip(esp_netif_t *netif) { if (esp_netif_dhcpc_stop(netif) != ESP_OK) { ESP_LOGE(TAG, "Failed to stop dhcp client"); return; } esp_netif_ip_info_t ip; memset(&ip, 0 , sizeof(esp_netif_ip_info_t)); ip.ip.addr = ipaddr_addr(EXAMPLE_STATIC_IP_ADDR); ip.netmask.addr = ipaddr_addr(EXAMPLE_STATIC_NETMASK_ADDR); ip.gw.addr = ipaddr_addr(EXAMPLE_STATIC_GW_ADDR); if (esp_netif_set_ip_info(netif, &ip) != ESP_OK) { ESP_LOGE(TAG, "Failed to set ip info"); return; } ESP_LOGD(TAG, "Success to set static ip: %s, netmask: %s, gw: %s", EXAMPLE_STATIC_IP_ADDR, EXAMPLE_STATIC_NETMASK_ADDR, EXAMPLE_STATIC_GW_ADDR); ESP_ERROR_CHECK(example_set_dns_server(netif, ipaddr_addr(EXAMPLE_MAIN_DNS_SERVER), ESP_NETIF_DNS_MAIN)); ESP_ERROR_CHECK(example_set_dns_server(netif, ipaddr_addr(EXAMPLE_BACKUP_DNS_SERVER), ESP_NETIF_DNS_BACKUP)); } 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_CONNECTED) { example_set_static_ip(arg); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { if (s_retry_num < EXAMPLE_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, "static 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_t *sta_netif = esp_netif_create_default_wifi_sta(); assert(sta_netif); 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, sta_netif, &instance_any_id)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, sta_netif, &instance_got_ip)); wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_WIFI_SSID, .password = EXAMPLE_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_WIFI_SSID, EXAMPLE_WIFI_PASS); } else if (bits & WIFI_FAIL_BIT) { ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", EXAMPLE_WIFI_SSID, EXAMPLE_WIFI_PASS); } else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); } #ifdef CONFIG_EXAMPLE_STATIC_DNS_RESOLVE_TEST struct addrinfo *address_info; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int res = getaddrinfo(EXAMPLE_RESOLVE_DOMAIN, NULL, &hints, &address_info); if (res != 0 || address_info == NULL) { ESP_LOGE(TAG, "couldn't get hostname for :%s: " "getaddrinfo() returns %d, addrinfo=%p", EXAMPLE_RESOLVE_DOMAIN, res, address_info); } else { if (address_info->ai_family == AF_INET) { struct sockaddr_in *p = (struct sockaddr_in *)address_info->ai_addr; ESP_LOGI(TAG, "Resolved IPv4 address: %s", ipaddr_ntoa((const ip_addr_t*)&p->sin_addr.s_addr)); } #if CONFIG_LWIP_IPV6 else if (address_info->ai_family == AF_INET6) { struct sockaddr_in6 *p = (struct sockaddr_in6 *)address_info->ai_addr; ESP_LOGI(TAG, "Resolved IPv6 address: %s", ip6addr_ntoa((const ip6_addr_t*)&p->sin6_addr)); } #endif } #endif /* 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(); } |
Как работает код?
Для начала мы подключим необходимые библиотеки, включая библиотеки FreeRTOS для генерации задержек и создания задач, esp_wifi.h для включения Wi-Fi-соединения, esp_event.h для мониторинга событий Wi-Fi и esp_log.h в качестве библиотеки для ведения журналов.
|
1 2 3 4 5 6 7 8 9 10 |
#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 <netdb.h> #include "nvs_flash.h" |
Затем мы определили переменные, которые составляют примеры параметров конфигурации, которые мы установили ранее. Эти переменные будут обращаться к значениям, которые мы задали ранее в menuconfig, поэтому значения уже определены. Однако, если вы хотите определить эти параметры в файле main.c, то укажите их в двойных кавычках. Например: #define EXAMPLE_WIFI_SSID “PTCL-08”
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#define EXAMPLE_WIFI_SSID CONFIG_EXAMPLE_WIFI_SSID #define EXAMPLE_WIFI_PASS CONFIG_EXAMPLE_WIFI_PASSWORD #define EXAMPLE_MAXIMUM_RETRY CONFIG_EXAMPLE_MAXIMUM_RETRY #define EXAMPLE_STATIC_IP_ADDR CONFIG_EXAMPLE_STATIC_IP_ADDR #define EXAMPLE_STATIC_NETMASK_ADDR CONFIG_EXAMPLE_STATIC_NETMASK_ADDR #define EXAMPLE_STATIC_GW_ADDR CONFIG_EXAMPLE_STATIC_GW_ADDR #ifdef CONFIG_EXAMPLE_STATIC_DNS_AUTO #define EXAMPLE_MAIN_DNS_SERVER EXAMPLE_STATIC_GW_ADDR #define EXAMPLE_BACKUP_DNS_SERVER "0.0.0.0" #else #define EXAMPLE_MAIN_DNS_SERVER CONFIG_EXAMPLE_STATIC_DNS_SERVER_MAIN #define EXAMPLE_BACKUP_DNS_SERVER CONFIG_EXAMPLE_STATIC_DNS_SERVER_BACKUP #endif #ifdef CONFIG_EXAMPLE_STATIC_DNS_RESOLVE_TEST #define EXAMPLE_RESOLVE_DOMAIN CONFIG_EXAMPLE_STATIC_RESOLVE_DOMAIN #endif |
Далее мы объявляем переменную '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(). Здесь «static ip» — это тег, который будет использоваться при логировании.
|
1 |
static const char *TAG = "static_ip"; |
Настройка DNS-сервера и статического IP-адреса
Функция example_set_dns_server() отвечает за установку DNS-сервера путем вызова функции esp_netif_set_dns_info(). Функция esp_netif_set_dns_info() принимает три параметра. Первый параметр — это дескриптор экземпляра esp-netif. Второй параметр — это тип DNS-сервера (ESP_NETIF_DNS_MAIN, ESP_NETIF_DNS_BACKUP, ESP_NETIF_DNS_FALLBACK), который необходимо установить. Третий параметр — это адрес DNS-сервера, который необходимо установить.
|
1 2 3 4 5 6 7 8 9 10 |
static esp_err_t example_set_dns_server(esp_netif_t *netif, uint32_t addr, esp_netif_dns_type_t type) { if (addr && (addr != IPADDR_NONE)) { esp_netif_dns_info_t dns; dns.ip.u_addr.ip4.addr = addr; dns.ip.type = IPADDR_TYPE_V4; ESP_ERROR_CHECK(esp_netif_set_dns_info(netif, type, &dns)); } return ESP_OK; } |
Функция example_set_static_ip() назначает статический IP-адрес. Сначала она останавливает DHCP-клиент, если он включен для данного интерфейса, используя функцию esp_netif_dhcpc_stop(), которая принимает в качестве параметра дескриптор экземпляра esp-netif. Если функция esp_netif_dhcpc_stop() не возвращает ESP_OK, она выводит в терминал сообщение «Не удалось остановить DHCP-клиент». После этого она обращается к значениям статического IP-адреса, статической маски подсети и статического адреса шлюза, уже определенным пользователем, и вызывает функцию esp_netif_set_ip_info(). Эта функция используется для установки статического IP-адреса на интерфейсе. Функция принимает два параметра. Первый параметр — это дескриптор экземпляра esp-netif, а второй — информация об IP-адресе, установленном на конкретном интерфейсе. Если все пройдет успешно, терминал выведет статический IP-адрес, маску подсети и адрес шлюза.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
static void example_set_static_ip(esp_netif_t *netif) { if (esp_netif_dhcpc_stop(netif) != ESP_OK) { ESP_LOGE(TAG, "Failed to stop dhcp client"); return; } esp_netif_ip_info_t ip; memset(&ip, 0 , sizeof(esp_netif_ip_info_t)); ip.ip.addr = ipaddr_addr(EXAMPLE_STATIC_IP_ADDR); ip.netmask.addr = ipaddr_addr(EXAMPLE_STATIC_NETMASK_ADDR); ip.gw.addr = ipaddr_addr(EXAMPLE_STATIC_GW_ADDR); if (esp_netif_set_ip_info(netif, &ip) != ESP_OK) { ESP_LOGE(TAG, "Failed to set ip info"); return; } ESP_LOGD(TAG, "Success to set static ip: %s, netmask: %s, gw: %s", EXAMPLE_STATIC_IP_ADDR, EXAMPLE_STATIC_NETMASK_ADDR, EXAMPLE_STATIC_GW_ADDR); ESP_ERROR_CHECK(example_set_dns_server(netif, ipaddr_addr(EXAMPLE_MAIN_DNS_SERVER), ESP_NETIF_DNS_MAIN)); ESP_ERROR_CHECK(example_set_dns_server(netif, ipaddr_addr(EXAMPLE_BACKUP_DNS_SERVER), ESP_NETIF_DNS_BACKUP)); } |
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() .
Если произошли события Wi-Fi WIFI_EVENT и WIFI_EVENT_STA_CONNECTED, то будет вызвана функция example_set_static_ip(arg). Это назначит плате ESP32 статический IP-адрес. Если плата 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 22 23 |
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_CONNECTED) { example_set_static_ip(arg); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { if (s_retry_num < EXAMPLE_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, "static 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 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 |
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_t *sta_netif = esp_netif_create_default_wifi_sta(); assert(sta_netif); 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, sta_netif, &instance_any_id)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, sta_netif, &instance_got_ip)); wifi_config_t wifi_config = { .sta = { .ssid = EXAMPLE_WIFI_SSID, .password = EXAMPLE_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_WIFI_SSID, EXAMPLE_WIFI_PASS); } else if (bits & WIFI_FAIL_BIT) { ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", EXAMPLE_WIFI_SSID, EXAMPLE_WIFI_PASS); } else { ESP_LOGE(TAG, "UNEXPECTED EVENT"); } #ifdef CONFIG_EXAMPLE_STATIC_DNS_RESOLVE_TEST struct addrinfo *address_info; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int res = getaddrinfo(EXAMPLE_RESOLVE_DOMAIN, NULL, &hints, &address_info); if (res != 0 || address_info == NULL) { ESP_LOGE(TAG, "couldn't get hostname for :%s: " "getaddrinfo() returns %d, addrinfo=%p", EXAMPLE_RESOLVE_DOMAIN, res, address_info); } else { if (address_info->ai_family == AF_INET) { struct sockaddr_in *p = (struct sockaddr_in *)address_info->ai_addr; ESP_LOGI(TAG, "Resolved IPv4 address: %s", ipaddr_ntoa((const ip_addr_t*)&p->sin_addr.s_addr)); } #if CONFIG_LWIP_IPV6 else if (address_info->ai_family == AF_INET6) { struct sockaddr_in6 *p = (struct sockaddr_in6 *)address_info->ai_addr; ESP_LOGI(TAG, "Resolved IPv6 address: %s", ip6addr_ntoa((const ip6_addr_t*)&p->sin6_addr)); } #endif } #endif /* 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()); |
Кроме этого, функция esp_netif_create_default_wifi_sta() используется для инициализации Wi-Fi по умолчанию в режиме станции. Этот API используется для инициализации, а также регистрации обработчиков событий для интерфейса по умолчанию, которым в нашем случае является станция. Он создает экземпляр сетевого интерфейса, связывающий драйвер Wi-Fi и стек TCP/IP. Когда станция находится в процессе подключения к точке доступа, различные процессы автоматически обрабатываются с помощью этой функции.
|
1 2 |
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta(); assert(sta_netif); |
Затем мы инициализируем ресурс выделения 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, sta_netif, &instance_any_id)); ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, sta_netif, &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-адрес, маску и адрес шлюза. Затем в логе появляется информация о статическом IP-адресе 192.168.4.2 , присвоенном плате. Это показывает, что ESP32 успешно подключился к точке доступа и получил статический IP-адрес.
4 просмотров










