【STM32F407+CUBEMX+FreeRTOS+lwIP之UDP记录】

发布于:2024-04-26 ⋅ 阅读:(24) ⋅ 点赞:(0)

基本信息

正点原子F407探索者开发板
cubemx v6.10.0
STM32Cube FM_f4 v1.28.0
8720A

cubemx配置

GPIO

在这里插入图片描述

NVIC

在这里插入图片描述
在这里插入图片描述

RCC

在这里插入图片描述

SYS

在这里插入图片描述

ETH

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

FREERTOS

这个按需配置
在这里插入图片描述

lwIP

这个按需配置

8720A可以选下图中这个,其他为适配的可以生成代码后自己修改

UDP(SOCKET)

本地端口是本地对外开放的端口
远程端口目标IP的端口

一些定义

#include <lwip/sockets.h>
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/api.h"
#include "lwip/udp.h"
#include "queue.h"

osThreadId_t led_TaskHandle;
const osThreadAttr_t led_Task_attributes = {
  .name = "led_Task",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) (osPriorityNormal-10),
};
void Start_led_Task(void *argument);


#ifdef lwip_socket_udp_base
osThreadId_t socket_udp_TaskHandle;
const osThreadAttr_t socket_udp_Task_attributes = {
  .name = "socket_udp_Task",
  .stack_size = 128 * 8,
  .priority = (osPriority_t) (osPriorityNormal-9),
};
void Start_socket_udp_Task(void *argument);
#define LWIP_DEMO_PORT 8081
#define LWIP_DEMO_RX_BUFSIZE         200    /* 最大接收数据长度 */
//#define IP_ADDR   "192.168.123.92"		/* 单播 一对一*/
socklen_t sock_fd;                     /* 定义一个Socket接口 */
struct sockaddr_in local_info;         /* 定义Socket地址信息结构体 */
/* 接收数据缓冲区 */
uint8_t g_lwip_demo_recvbuf[LWIP_DEMO_RX_BUFSIZE];

osThreadId_t lwip_recv_TaskHandle;
const osThreadAttr_t lwip_recv_Task_attributes = {
  .name = "lwip_recv_Task",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) (osPriorityNormal-9),
};
/* 显示消息队列的数量 */
#define DISPLAYMSG_Q_NUM    20              /* 显示消息队列的数量 */
QueueHandle_t g_display_queue;              /* 显示消息队列句柄 */

创建led任务

led_TaskHandle = osThreadNew(Start_led_Task, NULL, &led_Task_attributes);

lwIP初始化后UDP、接收、队列

void StartDefaultTask(void *argument)
{
  /* init code for LWIP */
  MX_LWIP_Init();
  /* USER CODE BEGIN StartDefaultTask */
	taskENTER_CRITICAL();           /* 进入临界区 */
	socket_udp_TaskHandle = osThreadNew(Start_socket_udp_Task, NULL, &socket_udp_Task_attributes);
	lwip_recv_TaskHandle = osThreadNew(lwip_recv_Task, NULL, &lwip_recv_Task_attributes);
	g_display_queue = xQueueCreate(DISPLAYMSG_Q_NUM,200);/* 创建消息Message_Queue,队列项长度是200长度 */
	taskEXIT_CRITICAL();            /* 退出临界区 */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);	//ticks
  }
  /* USER CODE END StartDefaultTask */
}

udp配置

void Start_socket_udp_Task(void *argument){

	/* 发送数据内容 */
	char g_lwip_demo_sendbuf[] = "ALIENTEK DATA \r\n";
	memset(&local_info, 0, sizeof(struct sockaddr_in)); /* 将服务器地址清空 */
    local_info.sin_len = sizeof(local_info);
    local_info.sin_family = AF_INET;                    /* IPv4地址 */
    local_info.sin_port = htons(LWIP_DEMO_PORT);        /* 设置端口号 */
    local_info.sin_addr.s_addr = htons(INADDR_ANY);     /* 设置本地IP地址 */
	
	
	sock_fd = socket(AF_INET,SOCK_DGRAM,0);/* 建立一个新的socket连接 */
	if (sock_fd < 0)
    {
        printf("socket failed!\n");
    }
	int ret = bind(sock_fd,(struct sockaddr *)&local_info, sizeof(struct sockaddr_in));/* 建立绑定 */
	if (ret < 0)
    {
        printf(" bind error!\n ");
    }
	while(1){
		local_info.sin_addr.s_addr = inet_addr(IP_ADDR);                /* 需要发送的远程IP地址 */
		sendto(sock_fd,                                         /* scoket */
                  (char *)g_lwip_demo_sendbuf,                        /* 发送的数据 */
                  sizeof(g_lwip_demo_sendbuf), 0,                     /* 发送的数据大小 */
                  (struct sockaddr *)&local_info,                   /* 接收端地址信息 */ 
                  sizeof(local_info));                              /* 接收端地址信息大小 */
		vTaskDelay(400);
		LL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
	}
}

将从队列收到的消息打印出来

void Start_led_Task(void *argument){
	uint8_t buffer[200];
	while(1){
		LL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
		vTaskDelay(500);
		if (xQueueReceive(g_display_queue,&buffer,portMAX_DELAY))
		{
			printf("%s\n",buffer);
			memset(buffer,0,200);       /* 清除缓冲区 */
		}
	}
}
void lwip_recv_Task(void *argument){
	BaseType_t lwip_err;
	
	struct sockaddr_in sender;/*存放发送方信息*/
    int sender_len = sizeof(sender);/*发送方信息长度*/
	
	while(1){
		memset(g_lwip_demo_recvbuf, 0, sizeof(g_lwip_demo_recvbuf));
//		recv(sock_fd, (void *)g_lwip_demo_recvbuf, sizeof(g_lwip_demo_recvbuf), 0);/*这个只有通信数据*/
		recvfrom(sock_fd, (void *)g_lwip_demo_recvbuf, sizeof(g_lwip_demo_recvbuf), 0,(struct sockaddr*)&sender,(socklen_t *)&sender_len);/*这个只有通信数据、还有发送方信息*/
		lwip_err = xQueueSend(g_display_queue,&g_lwip_demo_recvbuf,0);
		if (lwip_err == errQUEUE_FULL)
		{
			printf("队列Key_Queue已满,数据发送失败!\r\n");
		}else{
			/*IP*/
			printf("%s %d \n", inet_ntoa(sender.sin_addr), ntohs(sender.sin_port));/*打印发送放IP和端口*/
		}
		vTaskDelay(10);
	}
}

效果

在这里插入图片描述

UDP广播(SOCKET)

#define IP_ADDR   "192.168.123.255"		/* 广播所有设备255.255.255.255 通常只在本地网络中使用*/

效果

在这里插入图片描述
在这里插入图片描述

UDP组播(SOCKET)

添加一些定义

/* 组播D类IP:224.0.0.0至239.255.255.255 */
/* 多播/组播 IP 地址 */
#define GROUP_IP "224.0.1.0"
/* 多播信息 */
struct ip_mreq_t
{
    struct ip_mreq mreq;            /* 多播信息控制块 */
    socklen_t mreq_len;             /* 多播信息长度 */
};
struct ip_mreq_t mreq_info;

bind后加这个

/*组播 LWIP_IGMP为1*/
	mreq_info.mreq.imr_multiaddr.s_addr = inet_addr(GROUP_IP);     /* 多播组 IP 地址设置 */
    mreq_info.mreq.imr_interface.s_addr = htonl(INADDR_ANY);       /* 待加入多播组的 IP 地址 */
    mreq_info.mreq_len = sizeof(struct ip_mreq);
	/* 添加多播组成员(该语句之前,socket 只与 某单播IP地址相关联 执行该语句后 将与多播地址相关联) */
    ret = setsockopt(sock_fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq_info.mreq,mreq_info.mreq_len);
    if (ret < 0)
    {
        printf("setsockopt failed !");
    }
    else
    {
        printf("setsockopt success\n");
    }

切到组播IP,发送数据

local_info.sin_addr.s_addr = inet_addr(GROUP_IP); /* 组播ip */
sendto(sock_fd,                                         /* scoket */
                  (char *)g_lwip_demo_sendbuf,                        /* 发送的数据 */
                  sizeof(g_lwip_demo_sendbuf), 0,                     /* 发送的数据大小 */
                  (struct sockaddr *)&local_info,                   /* 接收端地址信息 */ 
                  sizeof(local_info));                              /* 接收端地址信息大小 */
		vTaskDelay(400);
		LL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);

cubemx注意以下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

ethernetif.c

netif初始化前添加

netif->flags |=NETIF_FLAG_IGMP;/*组播*/

PHY初始化前添加

HAL_ETH_GetMACFilterConfig(&heth,&g_eth_macfilterconfig_handler);
	g_eth_macfilterconfig_handler.ReceiveAllMode = ENABLE;
	g_eth_macfilterconfig_handler.PassAllMulticast =ENABLE;
	HAL_ETH_SetMACFilterConfig(&heth,&g_eth_macfilterconfig_handler);

这个定义到外面

	ETH_MACFilterConfigTypeDef g_eth_macfilterconfig_handler;

效果

在这里插入图片描述

可参考正点原子和野火的手册