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

2024-05-02 16:20

本文主要是介绍【STM32F407+CUBEMX+FreeRTOS+lwIP之UDP记录】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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;

效果

在这里插入图片描述

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

这篇关于【STM32F407+CUBEMX+FreeRTOS+lwIP之UDP记录】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/954664

相关文章

国内环境搭建私有知识问答库踩坑记录(ollama+deepseek+ragflow)

《国内环境搭建私有知识问答库踩坑记录(ollama+deepseek+ragflow)》本文给大家利用deepseek模型搭建私有知识问答库的详细步骤和遇到的问题及解决办法,感兴趣的朋友一起看看吧... 目录1. 第1步大家在安装完ollama后,需要到系统环境变量中添加两个变量2. 第3步 “在cmd中

Spring Retry 实现乐观锁重试实践记录

《SpringRetry实现乐观锁重试实践记录》本文介绍了在秒杀商品SKU表中使用乐观锁和MybatisPlus配置乐观锁的方法,并分析了测试环境和生产环境的隔离级别对乐观锁的影响,通过简单验证,... 目录一、场景分析 二、简单验证 2.1、可重复读 2.2、读已提交 三、最佳实践 3.1、配置重试模板

在 Spring Boot 中使用异步线程时的 HttpServletRequest 复用问题记录

《在SpringBoot中使用异步线程时的HttpServletRequest复用问题记录》文章讨论了在SpringBoot中使用异步线程时,由于HttpServletRequest复用导致... 目录一、问题描述:异步线程操作导致请求复用时 Cookie 解析失败1. 场景背景2. 问题根源二、问题详细分

关于Spring @Bean 相同加载顺序不同结果不同的问题记录

《关于Spring@Bean相同加载顺序不同结果不同的问题记录》本文主要探讨了在Spring5.1.3.RELEASE版本下,当有两个全注解类定义相同类型的Bean时,由于加载顺序不同,最终生成的... 目录问题说明测试输出1测试输出2@Bean注解的BeanDefiChina编程nition加入时机总结问题说明

将sqlserver数据迁移到mysql的详细步骤记录

《将sqlserver数据迁移到mysql的详细步骤记录》:本文主要介绍将SQLServer数据迁移到MySQL的步骤,包括导出数据、转换数据格式和导入数据,通过示例和工具说明,帮助大家顺利完成... 目录前言一、导出SQL Server 数据二、转换数据格式为mysql兼容格式三、导入数据到MySQL数据

关于rpc长连接与短连接的思考记录

《关于rpc长连接与短连接的思考记录》文章总结了RPC项目中长连接和短连接的处理方式,包括RPC和HTTP的长连接与短连接的区别、TCP的保活机制、客户端与服务器的连接模式及其利弊分析,文章强调了在实... 目录rpc项目中的长连接与短连接的思考什么是rpc项目中的长连接和短连接与tcp和http的长连接短

Oracle查询优化之高效实现仅查询前10条记录的方法与实践

《Oracle查询优化之高效实现仅查询前10条记录的方法与实践》:本文主要介绍Oracle查询优化之高效实现仅查询前10条记录的相关资料,包括使用ROWNUM、ROW_NUMBER()函数、FET... 目录1. 使用 ROWNUM 查询2. 使用 ROW_NUMBER() 函数3. 使用 FETCH FI

Python MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

Servlet中配置和使用过滤器的步骤记录

《Servlet中配置和使用过滤器的步骤记录》:本文主要介绍在Servlet中配置和使用过滤器的方法,包括创建过滤器类、配置过滤器以及在Web应用中使用过滤器等步骤,文中通过代码介绍的非常详细,需... 目录创建过滤器类配置过滤器使用过滤器总结在Servlet中配置和使用过滤器主要包括创建过滤器类、配置过滤

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6