【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

相关文章

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

MySQL 中查询 VARCHAR 类型 JSON 数据的问题记录

《MySQL中查询VARCHAR类型JSON数据的问题记录》在数据库设计中,有时我们会将JSON数据存储在VARCHAR或TEXT类型字段中,本文将详细介绍如何在MySQL中有效查询存储为V... 目录一、问题背景二、mysql jsON 函数2.1 常用 JSON 函数三、查询示例3.1 基本查询3.2

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

MySQL INSERT语句实现当记录不存在时插入的几种方法

《MySQLINSERT语句实现当记录不存在时插入的几种方法》MySQL的INSERT语句是用于向数据库表中插入新记录的关键命令,下面:本文主要介绍MySQLINSERT语句实现当记录不存在时... 目录使用 INSERT IGNORE使用 ON DUPLICATE KEY UPDATE使用 REPLACE

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

Spring Boot中定时任务Cron表达式的终极指南最佳实践记录

《SpringBoot中定时任务Cron表达式的终极指南最佳实践记录》本文详细介绍了SpringBoot中定时任务的实现方法,特别是Cron表达式的使用技巧和高级用法,从基础语法到复杂场景,从快速启... 目录一、Cron表达式基础1.1 Cron表达式结构1.2 核心语法规则二、Spring Boot中定

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

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

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

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