Продолжаем программирование микроконтроллера ESP8266 с использованием операционной системы реального времени FREEFTOS.
На данном уроке мы также продолжим тему беспроводной передачи данных и попробуем настроить наш модуль в режиме программной точки доступа (SOFTAP). После этого мы можем создавать подключение с узлами, настроенными в режиме станции, пытающимися подключиться к нашему модулю. Также мы попытаемся с помощью настройки DHCP раздать нашим станциям IP-адреса.
Схема наша остаётся без изменений – отладочная плата, подключенная к USB компьютера
Проект за основу мы возьмём с прошлого занятия с именем WIFI_STA_RTOS и присвоим ему новое имя WIFI_AP_RTOS.
Откроем наш проект в среде Eclipse и в файле конфигурации user_config.h добавим имя нашей точки доступа, пароль подключения к ней, её сетевой адрес, шлюз, сетевую маску, а также начало и окончание пула адресов, выделяемых подключаемым станциям
1 2 3 4 5 6 7 8 |
#define WIFI_CLIENTPASSWORD "12345678" #define WIFI_APSSID "ESP8266_AP" #define WIFI_APPASSWORD "12345678" #define WIFI_AP_IP "192.168.0.1" #define WIFI_AP_GW "192.168.0.1" #define WIFI_AP_NETMASK "255.255.255.0" #define WIFI_AP_IP_CLIENT_START "192.168.0.100" #define WIFI_AP_IP_CLIENT_END "192.168.0.105" |
Данные станции мы удалять не будем, так как наш проект будет универсальным и сможет работать как в режиме станции, так и точки доступа.
В файле wifi.c ниже функции set_on_station_disconnect добавим функции, получающие указатели на функции соединения станции с нашей точкой доступа, а также разрыва соединения
1 2 3 4 5 6 7 8 9 10 |
//------------------------------------------------ void ICACHE_FLASH_ATTR set_on_client_connect(wifi_state_cb_t cb){ on_client_connect = cb; } //------------------------------------------------ void ICACHE_FLASH_ATTR set_on_client_disconnect(wifi_state_cb_t cb) { on_client_disconnect = cb; } //------------------------------------------------ |
Ниже функции on_wifi_disconnect добавим функцию-обработчик соединения станции с нашей точкой доступа
1 2 3 4 5 6 7 8 9 |
//------------------------------------------------ LOCAL void ICACHE_FLASH_ATTR on_wifi_client_connect() { os_printf("on_wifi_client_connect();\n"); uint32 station_num = wifi_softap_get_station_num(); os_printf("number station: %d\n", station_num); GPIO_OUTPUT_SET(GPIO_LED, 0); } //------------------------------------------------ |
В данной функции мы выведем соответствующее сообщение в терминальную программу, затем узнаем количество подключенных станций, впоследствии также выведя об этом соответствующее сообщение в терминальную программу и зажжём наш светодиод.
Ниже этой функции добавим функцию-обработчик разъединения станции с точкой доступа
1 2 3 4 5 6 7 8 9 |
//------------------------------------------------ LOCAL void ICACHE_FLASH_ATTR on_wifi_client_disconnect() { os_printf("client disconnect\n"); uint32 station_num = wifi_softap_get_station_num(); os_printf("number station: %d\n", station_num); if (!station_num) GPIO_OUTPUT_SET(GPIO_LED, 1); } //------------------------------------------------ |
Данная функция подобна предыдущей, только выводит она уже сообщение в терминальную программу об отсоединении станции, и если у нас подсоединённых станций не осталось, то есть их количество равно 0, то мы погасим светодиод.
Из тела функции инициализации init_esp_wifi удалим данные строки
set_on_station_connect(on_wifi_connect);
set_on_station_disconnect(on_wifi_disconnect);
А вместо них мы зарегистрируем наши 2 функции, которые мы только что добавили
1 2 |
set_on_client_connect(on_wifi_client_connect); set_on_client_disconnect(on_wifi_client_disconnect); |
В функции-обработчике событий wifi-соединения wifi_event_handler_cb исправим ошибку в кейсе EVENT_SOFTAPMODE_STACONNECTED, так как мы там вместо on_client_connect проверяли on_station_connect
Ниже функции старта станции start_wifi_station добавим функцию старта точки доступа, в теле которой для начала объявим переменную типа структуры ip_info, также целочисленную переменную для адреса и два символьных массива для IP-адреса и MAC-адреса
1 2 3 4 5 6 7 8 9 |
//------------------------------------------------ bool ICACHE_FLASH_ATTR start_wifi_ap(const char * ssid, const char * pass) { struct ip_info ipinfo; uint32_t ip; char ip_char[15]; char macaddress[17]; } //------------------------------------------------ |
Добавим символьный массив для MAC-адреса
1 2 |
struct ip_info ipinfo; uint8 macadr[6]; |
Попытаемся установить режим точки доступа, если не получится, то выйдем из функции со статусом false
1 2 3 4 5 6 |
uint8 macadr[6]; if(!wifi_set_mode(SOFTAP_MODE)) { os_printf("Failed to enable Access Point mode!\n"); return false; } |
Объявим переменную типа указателя на структуру и выделим для такой переменной память
1 2 3 |
return false; } struct softap_config *config = (struct softap_config *)zalloc(sizeof(struct softap_config)); |
Вернёмся в функцию start_wifi_ap и получим MAC-адрес модуля, а затем запишем его в переменную
1 2 |
struct softap_config *config = (struct softap_config *)zalloc(sizeof(struct softap_config)); wifi_get_macaddr(SOFTAP_IF, macaddr); |
Запросим данные о состоянии точки доступа и сохраним их в переменную структуры
1 2 |
wifi_get_macaddr(SOFTAP_IF, macaddr); wifi_softap_get_config(config); |
Очистим память в данной переменной под имя точки доступа и запишем туда данное имя
1 2 3 |
wifi_softap_get_config(config); memset(config->ssid, 0, sizeof(config->ssid)); sprintf(config->ssid, WIFI_APSSID); |
Аналогично поступим и с паролем
1 2 3 |
sprintf(config->ssid, WIFI_APSSID); memset(config->password, 0, sizeof(config->password)); sprintf(config->password, WIFI_APPASSWORD); |
Проверим, что у нас включился режим точки доступа, и если это так, то сначала выведем соответствующее сообщение в терминальную программу
1 2 3 4 5 |
sprintf(config->password, WIFI_APPASSWORD); if (wifi_get_opmode() == SOFTAP_MODE) { os_printf("SOFTAP_MODE\n"); } |
Не выходя из тела данного условия, проинициализируем также номер канала, на котором будет работать наша точка доступа, режим шифрования, максимальное количество подключаемых станций, а также режим видимости, и затем запишем наши настройки в модуль с помощью специальной функции, передав ей нашу переменную типа структуры в качестве параметра
1 2 3 4 5 6 |
os_printf("SOFTAP_MODE\n"); config->authmode = AUTH_WPA_WPA2_PSK; config->channel = 7; config->max_connection = 255; config->ssid_hidden = 0; wifi_softap_set_config(config); |
Выйдем из условия и ещё раз убедимся, что у нас режим точки доступа и, если это так, то заберём конфигурацию опять в нашу переменную config
1 2 3 4 5 6 |
wifi_softap_set_config(config); } if (wifi_get_opmode() == SOFTAP_MODE) { wifi_softap_get_config(config); } |
Также в теле данного условия выведем наши настройки в терминальную программу
1 2 3 4 5 6 7 8 |
wifi_softap_get_config(config); os_printf("OPMODE: %u, SSID: %s, PASSWORD: %s, CHANNEL: %d, AUTHMODE: %d, MACADDRESS: %02x:%02x:%02x:%02x:%02x:%02x\n", wifi_get_opmode(), config->ssid, config->password, config->channel, config->authmode, macadr[0],macadr[1],macadr[2],macadr[3],macadr[4],macadr[5]); |
Выйдя из тела условия, освободим память, выделенную под переменную структуры
1 2 3 |
macaddress); } free(config); |
Включим полноправный режим без пониженного энергопотребления
1 2 |
free(config); wifi_set_sleep_type(NONE_SLEEP_T); |
Остановим DHCP-сервер
1 2 |
wifi_set_sleep_type(NONE_SLEEP_T); wifi_softap_dhcps_stop(); |
Занесём в переменную структуры ipinfo значения IP-адреса, шлюза и сетевой маски нашего DHCP-сервера
1 2 3 4 5 6 7 8 9 10 |
wifi_softap_dhcps_stop(); snprintf(ip_char, sizeof(ip_char), "%s", WIFI_AP_IP); ip = ipaddr_addr(ip_char); memcpy(&ipinfo.ip, &ip, 4); snprintf(ip_char, sizeof(ip_char), "%s", WIFI_AP_GW); ip = ipaddr_addr(ip_char); memcpy(&ipinfo.gw, &ip, 4); snprintf(ip_char, sizeof(ip_char), "%s", WIFI_AP_NETMASK); ip = ipaddr_addr(ip_char); memcpy(&ipinfo.netmask, &ip, 4); |
Сохраним всё это в модуль
1 2 |
memcpy(&ipinfo.netmask, &ip, 4); wifi_set_ip_info(SOFTAP_IF, &ipinfo); |
Аналогичным образом настроим пул адресов для станций
1 2 3 4 5 6 7 8 9 |
wifi_set_ip_info(SOFTAP_IF, &ipinfo); struct dhcps_lease dhcp_lease; snprintf(ip_char, sizeof(ip_char), "%s", WIFI_AP_IP_CLIENT_START); ip = ipaddr_addr(ip_char); memcpy(&dhcp_lease.start_ip, &ip, 4); snprintf(ip_char, sizeof(ip_char), "%s", WIFI_AP_IP_CLIENT_END); ip = ipaddr_addr(ip_char); memcpy(&dhcp_lease.end_ip, &ip, 4); wifi_softap_set_dhcps_lease(&dhcp_lease); |
Запустим DHCP-сервер, установим режим с максимальной скоростью передачи данных и вернём true
1 2 3 4 5 |
wifi_softap_set_dhcps_lease(&dhcp_lease); wifi_softap_dhcps_start(); if(wifi_get_phy_mode() != PHY_MODE_11N) wifi_set_phy_mode(PHY_MODE_11N); return true; |
Ниже функции stop_wifi_ap добавим аналогичную функцию остановки станции
1 2 3 4 5 6 7 8 9 10 11 12 13 |
//------------------------------------------------ bool ICACHE_FLASH_ATTR stop_wifi_station() { WIFI_MODE mode = wifi_get_opmode(); mode &= ~STATION_MODE; if(!wifi_set_mode(mode)) { os_printf("Failed to disable STA mode!\n"); return false; } return true; } //------------------------------------------------ |
Тело функции подобно телу предыдущей функции, только отключаем мы режим станции.
В функции инициализации удалим следующую строку
stop_wifi_ap();
Вместо неё остановим станцию
1 |
stop_wifi_station(); |
В файле main.c в функции user_init удалим вот эту строку
start_wifi_station(WIFI_CLIENTSSID, WIFI_CLIENTPASSWORD);
Вместо неё запустим режим точки доступа, не забыв предварительно добавить на данную функцию прототип в заголовочном файле
1 |
start_wifi_ap(WIFI_APSSID, WIFI_APPASSWORD); |
Соберём код, прошьём контроллер и попытаемся соединиться с нашей точкой доступа со смартфона
Светодиод загорелся
Также в терминальной программе мы видим, что станция с точкой доступа соединилась и количество станций теперь 1
Попробуем соединиться с точкой доступа с другого смартфона
Почему-то, независимо от настройки пула, адреса назначились начальные — 2 и 3. Ну это не страшно и некритично.
Светодиод продолжает светиться и количество станций теперь 2
Отсоединимся в одном сматрфоне, количество станций теперь 1
Отключим второй, количество соединений — 0 и светодиод не светится
Итак, на данном занятии нам удалось настроить наш модуль в режиме точки доступа, используя при этом операционную систему FreeRTOS.
Всем спасибо за внимание!
Предыдущий урок Программирование МК ESP8266 Следующий урок
Модуль ESP NodeMCU можно купить здесь: Модуль ESP NodeMCU
Различные модули ЕSP8266 можно приобрести здесь Модули ЕSP8266
Переходник USB to TTL можно приобрести здесь ftdi ft232rl
Многофункциональный переходник JTAG UART FIFO SPI I2C можно приобрести здесь CJMCU FT232H USB к JTAG UART FIFO SPI I2C
Логический анализатор 16 каналов можно приобрести здесь
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Спасибо за уроки! Изучаю, грызу гранит науки.
Здравствуйте, спасибо за уроки, очень хороший материал.
Извините мемного за не в тему. Но у меня вопрос. У меня не получилось запустить точку доступа на nonOS. Вроде всё правильно. но вайфай сети просто нет. при использовании среды ардуино все создаётся.
Позскажите где я чтото упустил. не хочу захламлять тут, скажите куда можно код скинуть
Что бы заработал диапазон адресов DHCP, надо еще сделать dhcp_lease.enable = TRUE