Продолжая работу по программированию микроконтроллера ESP8266 с использованием операционной системы реального времени FREEFTOS и, также продолжая тему передачи данных по беспроводной сети посредством протокола UDP, мы теперь попробуем принять данные с сервера. До сих пор мы пока только передавали пакеты с нашего клиента. Поэтому я добавил в мои программки для Android и для Windows ответы на наши пакеты. Программу для Windows я прикрепил внизу страницы, а приложение для Android достаточно будет просто обновить из Play Market. Сервер будет на 16-разрядное целое знаковое число отвечать подобным числом, но являющимся разностью числа 32767 и полученного числа. Также для того, чтобы нам нагляднее отследить пришедшие на наш клиент данные, мы к модулю ESP8266 Node MCU подключим символьный дисплей, и схема наша примет вид, как и в уроке 23
А проект мы сделаем из проекта прошлого урока с именем WIFI_STA_UDP_CLIENT_TX_RTOS, только подключим к нему нашу библиотеку для дисплея, например, из урока 23, и дадим нашему новому проекту имя WIFI_STA_UDP_CLIENT_RX_RTOS.
Откроем файл main.c и в функции user_init инициализируем наш дисплей
1 2 3 4 5 |
PIN_FUNC_SELECT (PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); i2c_mas_gpio_init(); I2C_MASTER_SDA_LOW_SCL_LOW(); LCD_ini(); LCD_SetPos(0,0); |
В файле wifi.h также подключим библиотеку дисплея
1 2 |
#include "gpio.h" #include "lcd.h" |
В файле wifi.c объявим структуру для очереди, а точнее тип структуры, и переменную данного типа
1 2 3 4 5 6 7 8 9 10 |
#include "wifi.h" //------------------------------------------------ typedef struct { unsigned char y_pos; char *str; } qData; //------------------------------------------------ xQueueHandle xQueue; //------------------------------------------------ |
Создадим функцию для задачи, которая будет отображать на дисплее числа, пришедшие с сервера, пока пустотелую
1 2 3 4 5 6 |
#define GPIO_LED 2 //------------------------------------------------ void ICACHE_FLASH_ATTR vLCDTask(void *pvParameters) { } //------------------------------------------------ |
В функции инициализации init_esp_wifi создадим очередь и задачу
1 2 3 |
stop_wifi_ap(); xQueue = xQueueCreate(10, sizeof(qData)); xTaskCreate(vLCDTask, "vLCDTask", 256, NULL, 2, NULL); |
В функции задачи отображения данных на дисплее vLCDTask возьмём из очереди готовую строку и отобразим её на дисплее
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void ICACHE_FLASH_ATTR vLCDTask(void *pvParameters) { portBASE_TYPE xStatus; qData xReceivedData; while(1) { xStatus = xQueueReceive(xQueue, &xReceivedData, 10000 /portTICK_RATE_MS); if (xStatus == pdPASS) { LCD_SetPos(0,xReceivedData.y_pos); LCD_String(xReceivedData.str); } } |
Для приёма данных с сервера и отправки их в функцию задачи дисплея нам желательно также создать отдельную задачу, поэтому добавим для неё функцию ниже функции vLCDTask
1 2 3 4 5 |
//------------------------------------------------ void ICACHE_FLASH_ATTR recv_task(void *pvParameters) { } //------------------------------------------------ |
В функции udp_task создадим нашу задачу
1 2 |
servaddr.sin_port = htons(SERVER_PORT); xTaskCreate(recv_task, "recv_task", 1024, (void*)&sockfd, 5, NULL); |
Также увеличим задержку между передачами пакетов в 10 раз, чтобы наш дисплей успевал отображать принятые с сервера в ответ на них числа
vTaskDelayUntil( &xLastWakeTime, ( 100 / portTICK_RATE_MS ) );
В функции задачи приёма пакетов recv_task с сервера объявим небольшой буфер, также создадим указатель целого типа на параметры, объявим переменную структуры очереди, небольшой строковый массив, а также проинициализируем позицию и указатель на строку, после чего добавим бесконечный цикл
1 2 3 4 5 6 7 8 9 10 11 |
void ICACHE_FLASH_ATTR recv_task(void *pvParameters) { char buf[10] = {}; int *sock = (int*) pvParameters; qData xLCDData; char str1[10]; xLCDData.y_pos = 1; xLCDData.str = str1; for(short i=0;;i++) { } |
В бесконечном цикле примем пакет с сервера, возьмём из него данные, преобразуем их в строку и отправим в очередь для отображении на дисплее
1 2 3 4 5 |
for(;;) { recv(*sock, buf, sizeof(buf), 0); snprintf(str1, sizeof(str1), "%6d", *(short*)buf); xQueueSendToBack(xQueue, &xLCDData, 0); |
Соберём код, прошьём контроллер, убедившись, что имя и ключ точки доступа в соответствующем хедер-файле правильные, также правильный IP и номер порта сервера, запустим сервер на смартфоне и, если всё правильно, то мы должны будем увидеть декриментирующиеся числа, пришедшие с сервера, на дисплее
Всё отлично работает.
Также мы можем теперь менять порт в приложении сервера. Попробуем его изменить и изменить его в заголовочном файле нашей программы. После этого также всё отлично передаётся и принимается.
Затем можно также проверить работу нашей программы и с сервером для Windows, в котором также теперь можно менять номер порта
Изменим IP-адрес и номер порта в программе и увидим, что у нас по-прежнему всё работает.
Итак, на данном занятии мы усовершенствовали свой клиент UDP, который теперь умеет также и принимать пакеты.
Всем спасибо за внимание!
Предыдущий урок Программирование МК ESP8266 Следующий урок
TCP UDP client-server for Android
QR-код на скачивание приложения:
Модуль ESP NodeMCU можно купить здесь: Модуль ESP NodeMCU
Различные модули ЕSP8266 можно приобрести здесь Модули ЕSP8266
Дисплей LCD 20×4 можно приобрести здесь Дисплей LCD 20×4
Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004
Смотреть ВИДЕОУРОК (нажмите на картинку)
помогите переписать программу точнее добавить функцию