Ну вот, наконец-то, дошли мы до той темы, к которой стремились и ради чего начинался цикл уроков по контроллерам ESP8266 — это приём и передача данных при помощи возможностей ESP8266 по беспроводной сети Wi-Fi.
Я думаю, что все знают, что это за тип сети и для чего она применяется.
Напомню лишь, что Wi-Fi — это протокол передачи данных, осуществляемой без применения проводов, физического уровня.
Как именно передаются данные по сети и как они подготавливаются, как заворачиваются в протоколы различного уровня, мы также очень хорошо знаем. Кто не помнит, напомню — смотрите уроки 40, 41, 44, 45, 46, 47, 48, 49, 50, 51, 52 по программированию контроллеров AVR, а также аналогичные уроки по контроллерам STM32. В данных уроках мы очень подробно рассмотрели многие протоколы всех уровней модели OSI. Те же самые протоколы будут использоваться и здесь, причём нам особо не придётся их программировать вручную, но знать, как они устроены, для чего нужны, мы обязаны, чтобы избежать ошибок при передаче данных, а также, если они и возникнут, то оперативно их устранить. И рассмотренных нами протоколов нам не потребуется протокол физического уровня Ethernet, его заменит протокол Wi-Fi.
Мы пока подробно не будем изучать протокол Wi-Fi, так как с ним работает наш контроллер аппаратно, но режимы работы мы должны знать. И знакомится с их разновидностями мы будем постепенно.
А пока мы должны знать, что наш контроллер ESP8266 поддерживает три основных режима работы — станция (Station mode или кратко STA), программная точка доступа (SoftAP), а также смешанный — Station + SoftAP.
Самым простым из этих режимов является первый — режим станции.
Режим станции (STA) — это такой режим, в котором контроллер не создает собственную сеть, а подключается к любой существующей сети Wi-Fi, например, к существующей локальной сети или к другому устройству, работающему в режиме точки доступа (AP).
На данном уроке мы настроим режим станции и попробуем подключиться к существующей точке доступа, например к роутеру, который раздаёт Wi-Fi по дому. Роутер от просто точки доступа отличается тем, что трафик, идущий от станций, подключенных к нему, он транслирует во внешнюю сеть и наоборот.
Пока воспользуемся возможностями SDK, то есть не будем лезть глубоко в дебри аппаратной части. Всему своё время.
Схема у нас будет простейшая — отладочная плата, подключенная к USB компьютера
Весь процесс соединения с точкой доступа и вхождение в различные стадии соединения мы будем отслеживать с помощью терминальной программы с помощью UART.
Проект наш выполнен из проекта прошлого урока с именем OS_TIMER и назван WIFI_STA.
Откроем наш проект в Eclipse и в файле main.c подключим библиотеку для работы с UART
1 2 |
#include "gpio.h" #include "driver/uart.h" |
В функции user_init сконфигурируем UART
1 2 3 4 |
void ICACHE_FLASH_ATTR user_init() { // Configure the UART uart_init(BIT_RATE_115200, BIT_RATE_115200); |
После небольшой задержки переведём строку в терминальной программе, чтобы отделить вывод следующих сообщений
1 2 3 |
gpio_output_set(0, 0, (1 << LED), 0); ets_delay_us(100000); os_printf("\r\n"); |
Вызовем функцию SDK, с помощью которой установим режим работы устройства в качестве станции
1 2 |
os_printf("\r\n"); wifi_set_opmode_current(STATION_MODE); |
Добавим функцию пока с пустым телом, которая будет вызываться через определённые промежутки времени по программному таймеру
1 2 3 4 5 6 |
static uint8_t led_state=0; //------------------------------------------------------ static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg) { } //------------------------------------------------------ |
А подобную функцию для обработки событий от программного таймера с именем timer_func_user удалим вместе с телом.
В функции user_init() в функции инициализации программного таймера, соответственно, изменим имя функции в параметре
os_timer_setfn(&os_timer01, (os_timer_func_t *)wifi_check_ip, NULL);
Также изменим третий параметр в вызове функции старта таймера. Теперь здесь будет ноль, так как запускать таймер мы будем однократно. Также увеличим период срабатывания
os_timer_arm(&os_timer01, 1000, 0);
Добавим локальную переменную структуры для настроек Wi-Fi соединения
1 2 3 |
void ICACHE_FLASH_ATTR user_init() { struct station_config stationConf; |
Забьём нулями всю память, зарезервированную под переменную структуры
1 2 |
wifi_set_opmode_current(STATION_MODE); os_memset(&stationConf, 0, sizeof(struct station_config)); |
В файле user_config.h добавим логин и пароль для соединения с точкой доступа
1 2 3 4 5 |
#define __USER_CONFIG_H__ //---------------------------------------------------------- #define WIFI_CLIENTSSID "ASUS444" #define WIFI_CLIENTPASSWORD "12345678" //---------------------------------------------------------- |
У вас, соответственно, данные будут свои, я также ввожу временные данные, затем я их из соображений безопасности опять изменю.
В функции user_init() файла main.c занесём наши настройки в поля структуры
1 2 3 |
os_memset(&stationConf, 0, sizeof(struct station_config)); os_sprintf(stationConf.ssid, "%s", WIFI_CLIENTSSID); os_sprintf(stationConf.password, "%s", WIFI_CLIENTPASSWORD); |
Применим данные настройки с помощью функции SDK
1 2 |
os_sprintf(stationConf.password, "%s", WIFI_CLIENTPASSWORD); wifi_station_set_config_current(&stationConf); |
Мы должны помнить, что данные настройки применятся только на время действия нашей программы, в память FLASH они не пропишутся, для этого есть уже другая функция.
После запуска таймера вызовем функцию соединения с точкой доступа
1 2 |
os_timer_arm(&os_timer01, 1000, 0); wifi_station_connect(); |
Объявим и проинициализируем две глобальные переменные — одну для хранения состояния соединения с точкой доступа, а другую — пользовательскую
1 2 3 |
static uint8_t led_state=0; static uint8_t wifiStatus = STATION_IDLE; static uint8_t connectStatus = 0; |
В функции wifi_check_ip добавим переменную структуры соединения сетевого уровня
1 2 3 |
static void ICACHE_FLASH_ATTR wifi_check_ip(void *arg) { struct ip_info ipConfig; |
Произведём деинициализацию таймера
1 2 |
struct ip_info ipConfig; os_timer_disarm(&os_timer01); |
Узнаем состояние соединения с точкой доступа
1 2 |
os_timer_disarm(&os_timer01); wifiStatus = wifi_station_get_connect_status(); |
Если состояние будет указывать на то, что IP-адрес получен, а также сетевой адрес ненулевой, то проинициализируем и запустим таймер, только с интервалом в 2 секунды и вывеем соответствующее сообщение в терминальную программу. Также у наше условие будет иметь и противный случай
1 2 3 4 5 6 7 8 9 10 |
wifiStatus = wifi_station_get_connect_status(); if (wifiStatus == STATION_GOT_IP && ipConfig.ip.addr != 0) { os_timer_setfn(&os_timer01, (os_timer_func_t *)wifi_check_ip, NULL); os_timer_arm(&os_timer01, 2000, 0); os_printf("STATION WIFI CONNECTED\r\n"); } else { } |
Начнём обрабатывать противный случай. В нем будет несколько условных конструкций.
Если пароль не совпал, то выведем соответствующее сообщение в терминальную программу и попытаемся соединиться повторно
1 2 3 4 5 6 7 |
else { if(wifi_station_get_connect_status() == STATION_WRONG_PASSWORD) { os_printf("STATION_WRONG_PASSWORD\r\n"); wifi_station_connect(); } |
Подобным образом поступим, если не будет найдена точка доступа
1 2 3 4 5 6 7 |
wifi_station_connect(); } else if(wifi_station_get_connect_status() == STATION_NO_AP_FOUND) { os_printf("STATION_NO_AP_FOUND\r\n"); wifi_station_connect(); } |
То же самое проделаем при неудачном соединении
1 2 3 4 5 6 7 |
wifi_station_connect(); } else if(wifi_station_get_connect_status() == STATION_CONNECT_FAIL) { os_printf("STATION_CONNECT_FAIL\r\n"); wifi_station_connect(); } |
В другом случае, не относящемся к вышеперечисленным установим переменной величину, соответствующую состоянию покоя
1 2 3 4 5 6 |
wifi_station_connect(); } else { os_printf("STATION_IDLE\r\n"); } |
Не выходя из тела противного состояния верхнего уровня, проинициализируем наш таймер и запустим его, установив период в полсекунды
1 2 3 4 |
os_printf("STATION_IDLE\r\n"); } os_timer_setfn(&os_timer01, (os_timer_func_t *)wifi_check_ip, NULL); os_timer_arm(&os_timer01, 500, 0); |
Соберём код, прошьём контроллер и через некоторое время в терминальной программе, если всё правильно, мы получим соответствующее сообщение об удачном соединении с точкой доступа
Теперь мы можем спокойно передавать и принимать данные, с точкой доступа мы соединены, и сетевой адрес получен, также давайте для того, чтобы каждые 2 секунды не было сообщения об удачном сетевом соединении, а было только однажды, немного переработаем ветку условия, где мы это выводим.
Если наша пользовательская переменная в нуле, то мы только тогда выводим сообщение, поэтому перенесём его вывод в данное условие, а также в этом же теле выставим нашу переменную в единицу
1 2 3 4 5 6 |
os_timer_arm(&os_timer01, 2000, 0); if(connectStatus == 0) { os_printf("STATION WIFI CONNECTED\r\n"); connectStatus = 1; } |
А в противном случае мы изменим состояние ножки, к которой подключен светодиод
1 2 3 4 5 6 7 |
connectStatus = 1; } else { led_state = (led_state==0) ? 1 : 0; GPIO_OUTPUT_SET(LED, led_state); } |
Также в противном случае верхнего уровня мы обнулим пользовательский статус
1 2 3 4 5 6 |
GPIO_OUTPUT_SET(LED, led_state); } } else { connectStatus = 0; |
Вот теперь, скорей всего, у нас вывод сообщения об удачном соединении будет только однажды, а именно в момент нашего соединения, а вернее не позже чем через 2 секунды после его установления.
Проверим это
Так и есть — сообщение теперь выводится только один раз, также, думаю, если произойдут какие-то проблемы с соединением, то потом после удачного соединения, у нас также сообщение выведется только один раз. А после вывода сообщения у нас только медленно мигает светодиод, что будет свидетельствовать о наличии соединения в данный момент нашей станции с точкой доступа.
Давайте проверим соединение с помощью пинга
Как видим, всё пингуется и пакеты проходят отлично. Только вот период великоват. Это всё потому, что наш контроллер находится в одном из режимов пониженного энергопотребления.
Давайте исправим данную ситуацию. Для этого в функции user_init() включим режим полноправной работы модуля
1 2 |
wifi_station_set_config_current(&stationConf); wifi_set_sleep_type(NONE_SLEEP_T); |
Теперь мы видим, что отклик происходит гораздо быстрее
Итак, на данном уроке мы научились конфигурировать беспроводное соединение в режиме станции, что позволило нам организовать стабильное соединение с точкой доступа, получив при этом сетевой адрес, что, как я думаю, уже немало.
Всем спасибо за внимание!
Предыдущий урок Программирование МК 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 (нажмите на картинку)
Добавить комментарий