В предыдущей части нашего урока мы настроили проект для сервера, а также создали и написали проект для первого клиента и проверили работу соединения на практике.
Теперь поработаем со вторым клиентом. В качестве него будет ещё одна плата 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 Следующий урок
Отладочную плату можно приобрести здесь STM32F746G-DISCOVERY
Отладочную плату можно приобрести здесь STM32F4-DISCOVERY
Модуль LAN можно приобрести здесь: LAN8720
Плату расширения можно приобрести здесь: STM32F4DIS-BB
Переходник I2C to LCD можно приобрести здесьI2C to LCD1602 2004
Смотреть ВИДЕОУРОК (нажмите на картинку)
Добавить комментарий