STM32F407+CUBEMX+FreeRTOS+lwIP之UDP记录
- 基本信息
- cubemx配置
- GPIO
- NVIC
- RCC
- SYS
- ETH
- FREERTOS
- lwIP
- UDP(SOCKET)
- 效果
- UDP广播(SOCKET)
- 效果
- UDP组播(SOCKET)
- cubemx注意以下
- ethernetif.c
- 效果
- 可参考正点原子和野火的手册
基本信息
正点原子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;