STM Урок 123. LAN87XX. LWIP. NETCONN. UDP. Соединяем три контролера. Часть 2



В предыдущей части нашего урока мы настроили проект для сервера, а также создали и написали проект для первого клиента и проверили работу соединения на практике.

 

Теперь поработаем со вторым клиентом. В качестве него будет ещё одна плата STM32F746G-DISCOVERY.

Отключим плату нашего первого клиента от ПК и подключим к независимому источнику, а плату 32F746G-DISCOVERY подключим к ПК, ну и. соответственно, также и к нашей сети (нажмите на картинку для увеличения изображения)

 

 

Проект для второго клиента мы создадим из проекта сервера, так как платы одни и те же. А имя данному проекту мы присвоим LAN8742_UDP_CLIENT_NETCONN. От проекта для первого клиента имя данного проекта отличается циферкой в маркировке микросхемы.

Запустим наш проект в Cube MX и перейдём в Configuration. Настроим сначала MAC-адрес в конфигурации сетевого интерфейса. Данные адреса не могут быть одинаковыми в одной сети

 

 

Теперь зайдём в LWIP и немного поменяем сетевой адрес

 

 

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

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

Первым делом — оформление экрана

 

TFT_DisplayString(0, 10, (uint8_t *)"UDP Client", CENTER_MODE);

 

 

Удалим глобальную структуру, предназначенную для сокета

 

typedef struct struct_sock_t {

  uint16_t y_pos;

  uint16_t port;

} struct_sock;

 

Также удалим и переменные данной структуры

 

struct_sock sock01, sock02;

 

Вместо этого добавим структуру для соединения и создадим переменную данной структуры

 

  } struct_out;

typedef struct struct_conn_t {

  uint32_t conn;

  uint32_t buf;

} struct_conn;

struct_conn conn01;

 

Из функции задачи соединения udp_thread удалим пока всё тело.

 

 

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

 

//---------------------------------------------------------------

static void send_thread(void *arg)

{

  struct_conn *arg_conn;

  struct_out *qstruct;

  struct netconn *conn;

  struct netbuf *buf;

  uint32_t syscnt = 0;

  arg_conn = (struct_conn*) arg;

  conn = (void*)arg_conn->conn;

  for(;;)

  {

    syscnt = osKernelSysTick();

    buf = netbuf_new();

    netbuf_alloc(buf, 4);

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

    netconn_send(conn,buf);

    netbuf_delete(buf);

    qstruct = osMailAlloc(strout_Queue, osWaitForever);

    qstruct->y_pos = 60;

    sprintf(qstruct->str,"%16lu",syscnt);

    osMailPut(strout_Queue, qstruct);

    osMailFree(strout_Queue, qstruct);

    osDelay(1000);

  }

}

//---------------------------------------------------------------

 

Также ниже функции udp_thread добавим функцию обратного вызова, реагирующую на приём пакетов, также полностью аналогичную той, которую мы использовали в первом клиенте

 

//---------------------------------------------------------------

void udp_receive_callback(struct netconn* conn, enum netconn_evt evt, u16_t len)

{

  struct_out *qstruct;

  uint32_t syscnt;

  unsigned short port;

  err_t recv_err;

  struct netbuf *buf;

  if(evt==NETCONN_EVT_RCVPLUS)

  {

    recv_err = netconn_recv(conn, &buf);

    if (recv_err == ERR_OK)

    {

      port = netbuf_fromport(buf);

      qstruct = osMailAlloc(strout_Queue, osWaitForever);

      qstruct->y_pos = 100;

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

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

      osMailPut(strout_Queue, qstruct);

      osMailFree(strout_Queue, qstruct);

      netbuf_delete(buf);

    }

  }

}

//---------------------------------------------------------------

 

Создадим прототип для данной функции

 

void TaskStringOut(void const * argument);

void udp_receive_callback(struct netconn* conn, enum netconn_evt evt, u16_t len);

 

Теперь добавим тело нашей функции, также аналогичное телу функции проекта первого клиента

 

static void udp_thread(void *arg)

{

  err_t err;

  struct netconn *conn;

  ip_addr_t DestIPaddr;

  TFT_SetTextColor(LCD_COLOR_BLUE);

  conn = netconn_new_with_callback(NETCONN_UDP,udp_receive_callback);

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

  if (conn!= NULL)

  {

    err = netconn_bind(conn, NULL, 1551);

    if (err == ERR_OK)

    {

      err = netconn_connect(conn, &DestIPaddr, 8);

      if (err == ERR_OK)

      {

        conn01.conn = conn;

        sys_thread_new("send_thread1", send_thread, (void*)&conn01, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );

      }

    }

    else

    {

      netconn_delete(conn);

    }

  }

  for(;;)

  {

    osDelay(1);

  }

}

 

Из функции задачи по умолчанию  удалим весь пользовательский код до бесконечного цикла и добавим создание задачи для соединения

 

/* USER CODE BEGIN 5 */

sys_thread_new("udp_thread1", udp_thread, NULL, DEFAULT_THREAD_STACKSIZE, osPriorityNormal );

/* Infinite loop */

 

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

 

 

Всё у нас отлично передаётся и принимается. Независимо друг от друга работают два соединения UDP.

Таким образом, сегодня мы создали клиент UDP с применением операционной системы FreeRTOS и интерфейса NETCONN, а также испытали его на двух различных платах, причём в работе одновременно обоих клиентов.

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

 

 

Предыдущая часть Программирование МК 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 не будет опубликован. Обязательные поля помечены *

*