STM Урок 122. LAN87XX. LWIP. NETCONN. UDP. Соединяем два контролера



Продолжаем работать со стеком протоколов LWIP с интерфейсом NETCONN и теперь мы попробуем подключить к нашей плате другую плату — STM32F4-Discovery вместе с платой расширения DIS-BB. Причём на этой плате будет по-прежнему использоваться в качестве клиента интерфейс RAW. Другими словами, мы попробуем соединить сразу два урока — урок 118 и урок 120. Тем самым мы организуем обмен информацией без использования ПК.

Начнём с сервера.

Проект мы создадим из проекта урока 120 LAN8742_UDP_SERVER_NETCONN и назовём его LAN87XX_UDP_SERVER.

Откроем проект в Cube MX и немного подправим настройки LWIP в разделе Key Options, чтобы они были одинаковые с настройками в клиенте

 

 

 

 

 

Сохраним настройки, сгенерируем проект для System Workbench, откроем его там, уберём отладочные настройки при их наличии, а также изменим уровень оптимизации на 1.

Откроем файл main.c, закомментируем там неизвестные компилятору строки для настройки видеоускорителя и попробуем собрать проект.

Если всё нормально, то приступим к некоторым правкам проекта.

Передавать мы будем на наш сервер 4-байтные величины, поэтому возьмём её из буфера, добавив сначала для этого локальную переменную в функцию задач наших сокетов udp_thread

 

struct_sock *arg_sock;

uint32_t syscnt = 0;

 

Затем далее в теле той же функции заберём данную величину из полученного буфера

 

qstruct->y_pos = arg_sock->y_pos;

syscnt = *(uint32_t*) buf->p->payload;

 

Выведем на дисплей данную величину, а также и порт отправителя, исправив соответствующий код далее

 

sprintf(qstruct->str,"%5u %-20s",port, (char*) buf->p->payload);

sprintf(qstruct->str,"%5u %10lu",port, syscnt);

 

Разделим её на 1000, чтобы передать назад клиенту. Просто передавать то же самое — это как-то больше похоже на эхо, а если мы изменим величину и передадим её уже изменённую, то это будет как-бы отдельная передача вновь сформированного буфера

 

sprintf(qstruct->str,"%5u %10lu",port, syscnt);

syscnt /= 1000;

 

Уберём вставку пробела, он нам не нужен

 

//Пробел вместо переноса строки

qstruct->str[5 + strlen((char*) buf->p->payload)] = ' ';

 

 

Отправим назад в буфер изменённую 32-битную величину

 

syscnt /= 1000;

pbuf_take(buf->p, (void *) &syscnt, 4);

 

Отобразим после отправки данных клиенту на дисплее отправленную величину с номером порта нашего сервера

 

  netbuf_delete(buf);

  osDelay(1);

  qstruct->y_pos = arg_sock->y_pos + 40;

  sprintf(qstruct->str,"%5u %7lu",arg_sock->port, syscnt);

  osMailPut(strout_Queue, qstruct);

  osMailFree(strout_Queue, qstruct);

}

 

Думаю, что вы заметили, что мы перед тем, как отправить информацию на дисплей, вставили задержку. Она нужна для того, чтобы дать менее приоритетной задаче вывода на дисплей выполниться до конца, так как мы ей только что в очереди уже отправили данные. Одного системного кванта для этого вполне достаточно. Иначе без этой задержки мы увидим только нижнюю строку.

Соберём код и прошьём контроллер.

С сервером вроде всё, переходим к клиенту.

Мы подключим к нашей четвёртой Discovery небольшой символьный дисплей LCD1602, чтобы там тоже видеть информацию о содержимом отправленных и принятых пакета

 

 

Соединим наши платы сетевым кабелем, Плату сервера подключим от независимого источника питания, а плату клиента подключим к ПК.

Проект сделаем из проекта урока 118 LAN8720_UDP_CLIENT_RAW и дадим ему имя LAN87XX_UDP_CLIENT.

Откроем проект в Cube MX и для начала включим I2C для подключения дисплея

 

 

Переопределим ножки для удобства подключения к плате DIS-BB

 

 

Перейдём в Configuration и убедимся в правильной настройке данной шины

 

 

Сохраним настройки, сгенерируем проект для System Workbench, откроем его там, уберём отладочные настройки при их наличии, а также изменим уровень оптимизации на 1.

 

 

Откроем файл main.c и попробуем собрать проект.

Если всё нормально, то начнём править также и этот проект.

Из проекта урока 115 NRF24_RX_02_LCD возьмём файлы для дисплея lcd.c и lcd.h и скопируем их в соответствующие папки нашего нового проекта.

Обновим дерево проекта.

Подключим библиотеку в файле main.c

 

#include "net.h"

#include "lcd.h"

 

Также в функции main() вызовем инициализацию дисплея, выдержав небольшое время перед ней, а также запуск таймера перенесём на последнее место, чтобы у нас не вызвались функции передачи пакетов до инициализации сетевого соединения. Получится в main() вот такой код

 

/* USER CODE BEGIN 2 */

udp_client_connect();

HAL_Delay(200);

LCD_ini();

HAL_TIM_Base_Start_IT(&htim2);

/* USER CODE END 2 */

 

В файле lcd.c изменим номер шины I2C

 

extern I2C_HandleTypeDef hi2c1;

 

В функции LCD_WriteByteI2CLCD тоже

 

HAL_I2C_Master_Transmit(&hi2c1,(uint16_t) 0x4E,buf,1,1000);

 

В файле net.h также подключим библиотеку для дисплея

 

#include "lwip/udp.h"

#include "lcd.h"

 

Перейдём в файл net.c и функции udp_client_connect изменим IP-адрес сервера

 

IP4_ADDR(&DestIPaddr, 192, 168, 1, 191);

 

Также изменим и номер порта

 

err= udp_connect(upcb, &DestIPaddr, 7);

 

Переходим в функцию udp_client_send и добавим там две локальные переменные

 

struct pbuf *p;

uint32_t gt;

uint16_t port;

 

Удалим функцию преобразования в строку

 

sprintf(str1,"%lu\r\n",HAL_GetTick());

 

Узнаем наш локальный порт

 

p = pbuf_alloc(PBUF_TRANSPORT, strlen(str1), PBUF_POOL);

port = upcb->local_port;

 

Узнаем количество прошедших системных тиков

 

if (p != NULL)

{

  gt = HAL_GetTick();

 

Положим их в буфер отправки пакета, изменив аргументы в соответствующей вызываемой функции

 

pbuf_take(p, (void *) &gt, 4);

 

Отобразим данное число на дисплее

 

pbuf_take(p, (void *) &gt, 4);

sprintf(str1,"%10lu", gt);

LCD_SetPos(0,0);

LCD_String(str1);

 

Перейдём в функцию приёма пакета udp_receive_callback и удалим оттуда формирование строки

 

strncpy(str1,p->payload,p->len);

str1[p->len]=0;

 

Сформируем её по-новому и отправим на дисплей

 

void udp_receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)

{

  sprintf(str1,"%5u %7lu", port, *(uint32_t*) p->payload);

  LCD_SetPos(0,1);

  LCD_String(str1);

 

Соберём код, прошьём контроллер и посмотрим результат на дисплеях клиента и сервера (нажмите на картинку для увеличения изображения)

 

 

Всё у нас отлично передаётся.

Таким образом, данный урок нам позволил соединить клиент и сервер, работающие по протоколу UDP посредством двух отладочных плат, на которых применён стек протоколов LWIP с различными интерфейсами. Это в дальнейшем может позволить с приличной скоростью передавать любые данные с контроллера на контроллер.

Всем спасибо за внимание!

 

 

Предыдущий урок Программирование МК STM32 Следующий урок

 

Исходный код сервера

Исходный код клиента

 

 

Отладочную плату можно приобрести здесь 32F746G-DISCOVERY

Отладочную плату можно приобрести здесь: STM32F4-DISCOVERY

Модуль LAN можно приобрести здесь: LAN8720

Плату расширения можно приобрести здесь: STM32F4DIS-BB

Дисплей LCD 16×2 можно приобрести тут: LCD 16×2

Переходник I2C to LCD1602 2004 можно приобрести здесь: I2C to LCD1602 2004

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

STM LAN87XX. LWIP. NETCONN. UDP. Соединяем два контролера

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*