基于正点原子阿波罗F429开发板的LWIP应用(6)——SNTP功能和lwiperf测速

说在开头

        正点原子F429开发板主芯片采用的是STM32F429IGT6,网络PHY芯片采用的是LAN8720A(V1)和YT8512C(V2),采用的是RMII连接,PHY_ADDR为0;在代码中将会对不同的芯片做出适配。

        CubeMX版本:6.6.1;

        F4芯片组Pack包版本:STM32Cube FW_F4 V1.27.0;

        本实验代码以《基于正点原子阿波罗F429开发板的LWIP应用(3)——Netbiosns功能》一章的代码作为基础;

第一部分:SNTP功能实现

        SNTP的全称是“简单网络时间协议”,是一种由NTP协议改编而来的网络时间协议,主要用来同步因特网中的计算机时钟。

        在此实验中开发板做SNTP客户端,通过单播模式定期访问SNTP服务器获得准确的时间进而不断校准单片机的RTC。

        本次实验的工作逻辑如下:首先完成RTC和LWIP的初始化,在初始化完成后开始启动SNTP服务。在完成第一次SNTP授时后还是间隔1S从RTC读取时间并从串口打印出来。

代码修改(代码注释很详细我就不再讲解了)

1、 首先将"Middlewares/Third_Party/LwIP/src/apps/sntp/sntp.c"添加进工程“Application/User/LWIP/App”分组中;

2、在“LWIP/App”中新建“sntp_client.c ”、“sntp_client.h”2个文件并添加到工程“Application/User/LWIP/App”分组中,两个文件分别添加以下代码:

/******************sntp_client.c文件代码**********************/
#include "sntp_client.h"#include "lwip/apps/sntp.h"
#include "time.h"
#include "rtc.h"/*1、中国国家授时中心NTP服务器“域名:ntp.ntsc.ac.cnIP:202.120.2.101 ---> 0X650278CA2、阿里云NTP服务器地址:域名:ntp.aliyun.comIP:110.75.8.1
*//*!
* @brief 设置 SNTP 的服务器地址,
* 		 加入多个 IP 以免某个 IP 获取不了时间
*        执行条件:无
*
* @retval: 无
*/
void set_sntp_server_list(void)
{uint32_t server_list[SNTP_MAX_SERVERS] =	{  0X650278CA,  //国家授时中心0x0B6C1978,0x0B0C5CB6,0x58066BCB,0xC51F70CA,0x521D70CA,0x820176CA,0x510176CA,};ip_addr_t sntp_server;for(int i = 0; i < SNTP_MAX_SERVERS; i++){sntp_server.addr = server_list[i];sntp_setserver(i, &sntp_server);  // 国家授时中心}
}/*!
* @brief Lwip 的 SNTP 初始化封装接口
*        执行条件:无
*
* @retval: 无
*/
void bsp_sntp_init(void)
{/*设置 SNTP 的获取方式SNTP_OPMODE_POLL             //单播模式,客户端主动发送获取时间请求SNTP_OPMODE_LISTENONLY       //组播模式,等待授时服务器主动发送更新时间请求(请求发送时间不确定)*/sntp_setoperatingmode(SNTP_OPMODE_POLL);//SNTP 初始化sntp_init();//加入授时中心的IP信息set_sntp_server_list();/*通过修改sntp_opts.h中的SNTP_UPDATE_DELAY宏定义的值来修改同步时间的间隔默认1小时——3600000,目前修改成1分钟:60000*/
}/*!
* @brief SNTP 获取时间戳的处理函数
*        执行条件:无
*
* @param [in] : sntp 获取的时间戳
*
* @retval: 无
*/
void sntp_set_time(uint32_t sntp_time)
{if(sntp_time == 0){printf("sntp_set_time: wrong!@@\n");return;}struct tm *time;sntp_time += (8 * 60 * 60); ///北京时间是东8区需偏移8小时time = localtime(&sntp_time);//RTC校准RTC_calibration((time->tm_year - 100), (time->tm_mon + 1), time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec, time->tm_wday);if(RTC_calibrate_flag == 0) RTC_calibrate_flag =1;//	printf("sntp_set_time: 20%d-%02d-%02d %d:%d:%d, 星期%d", \
//		time->tm_year - 100,
//		time->tm_mon + 1,
//		time->tm_mday,
//		time->tm_hour,
//		time->tm_min,
//		time->tm_sec,
//		(time->tm_wday==0 ? 7 : time->tm_wday));//星期需要注意:0表示周天,1-6表示周一到周六}/******************sntp_client.h文件代码**********************/
#ifndef __SNTP_CLIENT_H
#define __SNTP_CLIENT_H#include "main.h"void bsp_sntp_init(void);
void sntp_set_time(uint32_t sntp_time);
#endif

3、在“lwipopts.h”文件中添加以下内容:

#define LWIP_SNTP 											1
#define SNTP_MAX_SERVERS 								8
#include "sntp_client.h"
#define SNTP_SET_SYSTEM_TIME						sntp_set_time 	//定义 Lwip SNTP 的 处理函数
#define SNTP_UPDATE_DELAY								60000           //授时请求发送间隔:1分钟

4、rtc.c文件添加以下内容:

/******************rtc.c文件添加代码**********************/
void RTC_calibration(uint8_t year,uint8_t month,uint8_t day,uint8_t hour,uint8_t minute,uint8_t sec, uint8_t week)//RTC校准
{RTC_DateTypeDef sdatestructure;RTC_TimeTypeDef stimestructure;sdatestructure.Year    = year;//年 自2000开始,0x24表示24年sdatestructure.Month   = month;//月sdatestructure.Date    = day;//日sdatestructure.WeekDay = week;//星期if(HAL_RTC_SetDate(&hrtc,&sdatestructure,RTC_FORMAT_BIN) != HAL_OK){Error_Handler(); }stimestructure.Hours        = hour;stimestructure.Minutes      = minute;stimestructure.Seconds      = sec;stimestructure.TimeFormat = 0;stimestructure.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;stimestructure.StoreOperation = RTC_STOREOPERATION_RESET;if(HAL_RTC_SetTime(&hrtc,&stimestructure,RTC_FORMAT_BIN) != HAL_OK){Error_Handler();}
}void Get_time_info(uint8_t *info)
{RTC_DateTypeDef sdatestructureget;RTC_TimeTypeDef stimestructureget;uint8_t aShowTime[50] = {0};uint8_t aShowDate[50] = {0};/* Get the RTC current Time */HAL_RTC_GetTime(&hrtc, &stimestructureget, RTC_FORMAT_BIN);/* Get the RTC current Date */HAL_RTC_GetDate(&hrtc, &sdatestructureget, RTC_FORMAT_BIN);/* Display time Format : hh:mm:ss */info[0]   =  sdatestructureget.Year;//2000开始info[1] 	=	 sdatestructureget.Month;//1至12info[2]   =  sdatestructureget.Date;//1至31info[3]  	=  stimestructureget.Hours; info[4] 	=	 stimestructureget.Minutes;info[5] 	=  stimestructureget.Seconds;info[6]   =	 sdatestructureget.WeekDay;	//0至6表示周日到周六sprintf((char*)aShowTime,"%02d:%02d:%02d",stimestructureget.Hours, stimestructureget.Minutes, stimestructureget.Seconds);/* Display date Format : mm-dd-yy */sprintf((char*)aShowDate,"%02d-%02d-%02d,week=%d",sdatestructureget.Month, sdatestructureget.Date, 2000 + sdatestructureget.Year, sdatestructureget.WeekDay); printf("%s %s\n",aShowTime,aShowDate);
}/******************rtc.h文件添加代码**********************/
void RTC_calibration(uint8_t year,uint8_t month,uint8_t day,uint8_t hour,uint8_t minute,uint8_t sec, uint8_t week);
void Get_time_info(uint8_t *info);

5、main.c文件增加以下内容:

/******************main.c开头增加以下内容**********************/
uint8_t RTC_calibrate_flag = 0;//RTC校准标志位
uint8_t Internet_timeinfo[7] = { NULL };//网络时间中的:年 月 日 时 分 秒 星期	/******************main函数while(1)前增加以下内容**********************/
bsp_sntp_init();//SNTP初始化/******************main.h增加以下内容**********************/
extern uint8_t RTC_calibrate_flag;//RTC校准标志位
extern uint8_t Internet_timeinfo[7];

6、stm32f4xx_it.c文件增加以下内容:

/******************stm32f4xx_it.c开头增加以下内容**********************/
extern void Get_time_info(uint8_t *info);
uint16_t time_read_count = 0;/******************SysTick_Handler函数最后增加以下内容**********************/time_read_count++;if(time_read_count >= 1000){time_read_count = 0;if(RTC_calibrate_flag) Get_time_info(Internet_timeinfo);//从RTC获取时间}

至此就修改完成了,编译0警告0错误。烧录进开发板可以看到DS0一直闪烁,同时串口间隔1S打印RTC的时间,打印时间和串口接收的时间戳相差不超过1S钟,串口打印如下图:

第二部分:lwiperf测速实现

1、 首先将"Middlewares/Third_Party/LwIP/src/apps/lwiperf/lwiperf.c"添加进工程“Application/User/LWIP/App”分组中;

2、在“LWIP/App”中新建“speed_test.c ”、“speed_test.h”2个文件并添加到工程“Application/User/LWIP/App”分组中,两个文件分别添加以下代码:

/******************speed_test.c内容如下**********************/
#include "speed_test.h"#include "lwip.h"#include "lwip/apps/lwiperf.h"uint8_t info_buf[30];/* 报告状态 */
const char *report_type_str[] = 
{"TCP_DONE_SERVER",             /* LWIPERF_TCP_DONE_SERVER,*/"TCP_DONE_CLIENT",             /* LWIPERF_TCP_DONE_CLIENT,*/"TCP_ABORTED_LOCAL",           /* LWIPERF_TCP_ABORTED_LOCAL, */"TCP_ABORTED_LOCAL_DATAERROR", /* LWIPERF_TCP_ABORTED_LOCAL_DATAERROR, */"TCP_ABORTED_LOCAL_TXERROR",   /* LWIPERF_TCP_ABORTED_LOCAL_TXERROR, */"TCP_ABORTED_REMOTE",          /* LWIPERF_TCP_ABORTED_REMOTE, */"UDP_STARTED",                 /* LWIPERF_UDP_STARTED, */"UDP_DONE",                    /* LWIPERF_UDP_DONE, */"UDP_ABORTED_LOCAL",           /* LWIPERF_UDP_ABORTED_LOCAL, */"UDP_ABORTED_REMOTE"           /* LWIPERF_UDP_ABORTED_REMOTE */
};/* 当测试结束以后会调用此函数,此函数用来报告测试结果 */
/*** @brief       当测试结束以后会调用此函数,此函数用来报告测试结果* @param       无* @retval      无*/
static void lwiperf_report(void *arg,enum lwiperf_report_type report_type,const ip_addr_t *local_addr,u16_t local_port,const ip_addr_t *remote_addr,u16_t remote_port,u32_t bytes_transferred,u32_t ms_duration,u32_t bandwidth_kbitpsec)
{printf("-------------------------------------------------\r\n");if (((int)report_type < (sizeof(report_type_str)/sizeof(report_type_str[0]))) && local_addr && remote_addr){printf(" %s \r\n", report_type_str[report_type]);printf(" Local address : %u.%u.%u.%u ", ((u8_t *)local_addr)[0], ((u8_t *)local_addr)[1],((u8_t *)local_addr)[2], ((u8_t *)local_addr)[3]);printf(" Port %d \r\n", local_port);printf(" Remote address : %u.%u.%u.%u ", ((u8_t *)remote_addr)[0], ((u8_t *)remote_addr)[1],((u8_t *)remote_addr)[2], ((u8_t *)remote_addr)[3]);printf(" Port %d \r\n", remote_port);printf(" Bytes Transferred %d \r\n", (int)bytes_transferred);printf(" Duration (ms) %d \r\n", (int)ms_duration);printf(" Bandwidth (kbitpsec) %d \r\n", (int)bandwidth_kbitpsec);memset(info_buf,0,sizeof(info_buf));sprintf((char*)info_buf,"%u.%u.%u.%u",((u8_t *)local_addr)[0], ((u8_t *)local_addr)[1],((u8_t *)local_addr)[2], ((u8_t *)local_addr)[3]);           /* 显示动态IP地址 */printf("%s\n",info_buf);memset(info_buf,0,sizeof(info_buf));sprintf((char*)info_buf,"%d",local_port);                           /* 显示本地端口 */printf("%s\n",info_buf);memset(info_buf,0,sizeof(info_buf));sprintf((char*)info_buf,"%u.%u.%u.%u",((u8_t *)remote_addr)[0], ((u8_t *)remote_addr)[1],((u8_t *)remote_addr)[2], ((u8_t *)remote_addr)[3]);         /* 显示远程IP地址 */printf("%s\n",info_buf);memset(info_buf,0,sizeof(info_buf));sprintf((char*)info_buf,"%d",remote_port);              /* 显示远程IP端口 */printf("%s\n",info_buf);memset(info_buf,0,sizeof(info_buf));sprintf((char*)info_buf,"%d",(int)bytes_transferred/1024);   /* 转换速度 */printf("%s\n",info_buf);memset(info_buf,0,sizeof(info_buf));sprintf((char*)info_buf,"%d",(int)ms_duration);         /* 持续时间 */printf("%s\n",info_buf);memset(info_buf,0,sizeof(info_buf));sprintf((char*)info_buf,"%d",(int)bandwidth_kbitpsec);  /* 带宽 */printf("%s\n",info_buf);}else{printf(" IPERF Report error\r\n");}
}/*** @brief       lwip_demo实验入口* @param       无* @retval      无*/
void speed_test(void)
{lwiperf_start_tcp_server_default(lwiperf_report,NULL);
}/******************speed_test.h内容如下**********************/
#ifndef __SPEED_TEST_H
#define __SPEED_TEST_H#include "main.h"void speed_test(void);#endif

3、main.c文件增加以下内容:

/******************main.c开头增加以下内容**********************/
#include "speed_test.h"/******************main函数while(1)前增加以下内容**********************/
speed_test();

至此就修改完成了,编译0警告0错误。烧录进开发板串口打印模块IP。

之后运行JPerf 网络测速工具(会和实验源码一起分享),按下图操作即可进行测速:

测速完成后串口也会打印相关信息:

看到这个结果大家肯定会纳闷了,官方不是宣称开发板带的是百兆网络吗,为什么这里测出来才23M呢?那接下来就告诉大家该如何进行优化:在“lwipopts.h”文件中修改以下参数的值可以提升网速(没有就新增):

/* 堆内存的大小,如果需要更大的堆内存,那么设置高一点 */
#define MEM_SIZE (30*1024)
/* MEMP_NUM_PBUF: 设置内存池的数量 */
#define MEMP_NUM_PBUF 25
/* MEMP_NUM_UDP_PCB: UDP 协议控制块的数量. */
#define MEMP_NUM_UDP_PCB 4
/* MEMP_NUM_TCP_PCB: TCP 的数量. */
#define MEMP_NUM_TCP_PCB 8
/* MEMP_NUM_TCP_PCB_LISTEN: 监听 TCP 的数量. */
#define MEMP_NUM_TCP_PCB_LISTEN 2
/* MEMP_NUM_TCP_SEG: 同时排队的 TCP 的数量段. */
#define MEMP_NUM_TCP_SEG 150
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#define PBUF_POOL_SIZE          20
/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
#define PBUF_POOL_BUFSIZE       LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN)//1536
/* TCP 接收窗口 */
#define TCP_WND 								(20*TCP_MSS)

编译完成后再次测试,虽然没有达到100M,但也可以稳定在86M,欢迎大家继续优化并把优化好的参数分享在评论区:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/86401.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C:\Users\中文名修改为英文名

C:\Users\中文名修改为英文名 背景操作步骤 背景 买了台新电脑&#xff0c;初始化好不知道啥操作把自己的登录用户名改成了中文&#xff0c;有些安装的软件看见有中文直接就水土不服了。 操作步骤 以下称中文用户名为张三。 正常登录张三用户 进入用户管理页面修改用户名&a…

YOLOv12环境配置,手把手教你使用YOLOv12训练自己的数据集和推理(附YOLOv12网络结构图),全文最详细教程

文章目录 前言一、YOLOv12代码下载地址1.YOLOv12模型结构图 二、YOLO环境配置教程1.创建虚拟环境2.激活虚拟环境3.查询自己电脑可支持最高cuda版本是多少&#xff08;无显卡的同学可以跳过这个步骤&#xff09;4.pytorch安装5.验证 PyTorch GPU 是否可用&#xff08;没有显卡的…

ES6(ES2015)特性全解析

ES6&#xff08;ECMAScript 2015&#xff09;是 JavaScript 语言发展史上的一个重要里程碑&#xff0c;它引入了许多新的语法特性和功能&#xff0c;提升了代码的可读性、可维护性和开发效率。 1. 块级作用域变量&#xff1a;let 和 const ES6 引入了 let 和 const 关键字&am…

jvm 垃圾收集算法 详解

垃圾收集算法 分代收集理论 垃圾收集器的理论基础&#xff0c;它建立在两个分代假说之上&#xff1a; 弱分代假说&#xff1a;绝大多数对象都是朝生夕灭的。强分代假说&#xff1a;熬过越多次垃圾收集过程的对象就越难以消亡。 这两个分代假说共同奠定了多款常用的垃圾收集…

数字孪生+AR/VR的融合创新

目录 引言&#xff1a;工业元宇宙的兴起与技术基石数字孪生&#xff1a;工业元宇宙的数字底座 2.1 数字孪生的概念与关键要素 2.2 数字孪生在工业领域的应用 2.3 数字孪生的技术架构 (Mermaid Graph) AR/VR&#xff1a;工业元宇宙的沉浸式体验层 3.1 AR/VR 的概念与技术原理…

图解C#教程 第五版 第4章 类型、存储和变量 笔记

第4章 类型、存储和变量 笔记 4.1 C# 程序是一组类型声明 C程序是一组函数和数据类型&#xff0c;C程序是一组函数和类&#xff0c; 而C#程序是一组类型声明&#xff0c;具有如下特征&#xff1a; C# 程序或 DLL 的源代码是一组类型声明类型声明中必须有一个包含 Main 方法…

SpringBoot整合SSM

1. SSM整合步骤 今天带大家学习一下基于SpringBoot的SSM整合案例&#xff0c;话不多说&#xff0c;咱们开始&#xff0c;要实现SSM整合&#xff0c;有以下这么几步 导入依赖创建yml配置文件dao层静态页面测试类进行测试 1.1 导入依赖 <?xml version"1.0" enco…

多面体模型-学习笔记2

1&#xff09; 多面体模型被应用于解决程序变换问题&#xff0c;并有效地推动了程 序自动并行化等技术的发展。与传统的解决程序变换的方法相比&#xff0c;多面体模型 具有许多优势[5]。多面体模型提供了一种强大的抽象&#xff0c;将每个语句的动态语句执 行实例视作一个多面…

基于django+vue的健身房管理系统-vue

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.8数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat12开发软件&#xff1a;PyCharm 系统展示 会员信息管理 员工信息管理 会员卡类型管理 健身项目管理 会员卡管理 摘要 健身房管理…

【Linux系统】Linux环境变量:系统配置的隐形指挥官

。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量&#xff1a;setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…

Spring AI中使用ChatMemory实现会话记忆功能

文章目录 1、需求2、ChatMemory中消息的存储位置3、实现步骤1、引入依赖2、配置Spring AI3、配置chatmemory4、java层传递conversaionId 4、验证5、完整代码6、参考文档 1、需求 我们知道大型语言模型 &#xff08;LLM&#xff09; 是无状态的&#xff0c;这就意味着他们不会保…

Java 高级泛型实战:8 个场景化编程技巧

文章目录 一、通配符高级应用&#xff1a;灵活处理类型关系二、泛型方法与类型推断三、泛型类的嵌套使用四、受限泛型与边界条件五、泛型与反射结合六、泛型在函数式接口中的应用七、类型擦除与桥接方法八、自定义泛型注解总结 在Java编程中&#xff0c;泛型不仅是类型安全的保…

[蓝桥杯 2024 国 B] 立定跳远

问题描述 在运动会上&#xff0c;小明从数轴的原点开始向正方向立定跳远。项目设置了 n 个检查点 a1,a2,...,an且 ai≥ai−1>0。小明必须先后跳跃到每个检查点上且只能跳跃到检查点上。同时&#xff0c;小明可以自行再增加 m 个检查点让自己跳得更轻松。在运动会前&#xf…

2025年全国I卷数学压轴题解答

第19题第3问: b b b 使得存在 t t t, 对于任意的 x x x, 5 cos ⁡ x − cos ⁡ ( 5 x t ) < b 5\cos x-\cos(5xt)<b 5cosx−cos(5xt)<b, 求 b b b 的最小值. 解: b b b 的最小值 b m i n min ⁡ t max ⁡ x g ( x , t ) b_{min}\min_{t} \max_{x} g(x,t) bmi…

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…

解决网页导出PDF部分内容被遮挡问题

问题描述 以学习通为例&#xff0c;在使用CtrlP打印页面或截图时&#xff0c;固定侧边栏会遮挡部分内容&#xff0c;影响完整内容的获取。如下图所示&#xff1a; 解决办法 通过浏览器开发者工具临时移除固定侧边栏&#xff0c;具体步骤如下&#xff1a; 在目标页面右键点…

机器学习监督学习实战六:五种算法对新闻组英文文档进行文本分类(20类),词频统计和TF-IDF 转换特征提取方法理论和对比解析

本文主要介绍了20 Newsgroups数据集及其在文本分类任务中的应用。20 Newsgroups数据集包含约20,000篇新闻组文档&#xff0c;分为20个不同主题的新闻组&#xff0c;数据集被分为训练集和测试集。在数据预处理阶段&#xff0c;使用了CountVectorizer和TfidfVectorizer两种方法将…

易学探索助手-个人记录(十四)

项目背景 在大语言模型&#xff08;LLM&#xff09;完成指令微调&#xff08;SFT&#xff09;之后&#xff0c;虽然可以处理开放式问答任务&#xff0c;但在专业领域&#xff08;如《周易》&#xff09;仍面临知识更新滞后、事实性薄弱等问题。为此&#xff0c;本文介绍如何通…

从“人找政策”到“政策找人”:智能退税ERP数字化重构外贸生态

离境退税新政核心内容与外贸企业影响 &#xff08;一&#xff09;政策核心变化解析 退税商店网络扩容 新政明确鼓励在大型商圈、旅游景区、交通枢纽等境外旅客聚集地增设退税商店&#xff0c;并放宽备案条件至纳税信用M级企业。以上海为例&#xff0c;静安区计划新增1000家退…

Pandas 可视化集成:数据科学家的高效绘图指南

为什么选择 Pandas 进行数据可视化&#xff1f; 在数据科学和分析领域&#xff0c;可视化是理解数据、发现模式和传达见解的关键步骤。Python 生态系统提供了多种可视化工具&#xff0c;如 Matplotlib、Seaborn、Plotly 等&#xff0c;但 Pandas 内置的可视化功能因其与数据结…