个人名片:
🎓作者简介:嵌入式领域优质创作者
🌐个人主页:妄北y📞个人QQ:2061314755
💌个人邮箱:[mailto:2061314755@qq.com]
📱个人微信:Vir2025WBY🖥️个人公众号:科技妄北
🖋️本文为妄北y原创佳作,独家首发于CSDN🎊🎊🎊
💡座右铭:改造世界固然伟大,但改造自我更为可贵。
专栏导航:
妄北y系列专栏导航:
物联网嵌入式开发项目:大学期间的毕业设计,课程设计,大创项目,各种竞赛项目,全面覆盖了需求分析、方案设计、实施与调试、成果展示以及总结反思等关键环节。📚💼💡
QT基础入门学习:对QT的基础图形化页面设计进行了一个简单的学习与认识,利用QT的基础知识进行了翻金币小游戏的制作。🛠️🔧💭
Linux基础编程:初步认识什么是Linux,为什么学Linux,安装环境,进行基础命令的学习,入门级的shell编程。🍻🎉🖥️
深耕Linux应用开发:分享Linux的基本概念、命令行操作、文件系统、用户和权限管理等,网络编程相关知识,TCP/IP 协议、套接字(Socket)编程等,可以实现网络通信功能。常见开源库的二次开发,如libcurl、OpenSSL、json-c、freetype等💐📝💡
Linux驱动开发:Linux驱动开发是Linux系统不可或缺的组成部分,它专注于编写特殊的程序——驱动程序。这些程序承载着硬件设备的详细信息,并扮演着操作系统与硬件间沟通的桥梁角色。驱动开发的核心使命在于确保硬件设备在Linux系统上顺畅运作,同时实现与操作系统的无缝集成,为用户带来流畅稳定的体验。🚀🔧💻
Linux项目开发:Linux基础知识的实践,做项目是最锻炼能力的一个学习方法,这里我们会学习到一些简单基础的项目开发与应用,而且都是毕业设计级别的哦。🤸🌱🚀
非常期待与您一同在这个广阔的互联网天地里,携手探索知识的海洋,互相学习,共同进步。🌐💫🌱 熠熠星光,照亮我们的成长之路
✨✨ 欢迎订阅本专栏,对专栏内容任何问题都可以随时联系博主,共同书写属于我们的精彩篇章!✨✨
文章介绍:
📚本篇文章将深入剖析FreeRTOS学习的精髓与奥秘,与您一同分享相关知识!🎉🎉🎉
若您觉得文章尚可入目,期待您能慷慨地送上点赞、收藏与分享的三连支持!您的每一份鼓励,都是我创作路上源源不断的动力。让我们携手并进,共同奔跑,期待在顶峰相见的那一天,共庆辉煌!🚀🚀🚀
🙏衷心感谢大家的点赞👍、收藏⭐和评论✍️,您的支持是我前进的动力!
目录:
目录:
一、系统配置文件
二、FreeRTOSConfig.h文件
三、“INCLUDE”开始的宏
3.1 介绍
3.2 FreeRTOS可选函数配置
四、"config" 开始的宏
4.1 FreeRTOS基础配置配置选项
4.2 FreeRTOS与内存申请有关配置选项
4.3 FreeRTOS与钩子函数有关的配置选项
4.4 FreeRTOS与运行时间和任务状态收集有关的配置选项
4.5 FreeRTOS与协程有关的配置选项
4.6 FreeRTOS与软件定时器有关的配置选项
4.7 FreeRTOS与中断、中断服务函数有关的配置选项
4.7.1 中断优先设置
4.7.2 中断服务设置:
一、系统配置文件
在实际应用FreeRTOS时,我们常常需要根据具体需求对其进行配置,而不同架构的MCU在使用时也会有不同的配置要求。
FreeRTOS的系统配置文件是FreeRTOSConfig.h,用户可以通过这个配置文件来进行FreeRTOS的定制和设置,因此它是一个非常关键的文件。
主要对FreeRTOSConfig.h文件、“INCLUDE”开始的宏、“config”开始的宏进行分析介绍。
二、FreeRTOSConfig.h文件
FreeRTOS的配置主要是通过在FreeRTOSConfig.h文件中使用“#define”语句来定义各种宏实现的。
在FreeRTOS的官方示例中,每个项目都包含一个FreeRTOSConfig.h文件,我们在使用时可以参考这个文件,甚至可以直接复制和粘贴其中的内容来进行配置。
三、“INCLUDE”开始的宏
3.1 介绍
在FreeRTOS中,使用以“INCLUDE”开头的宏来控制不同API函数的可用性是一种常见的配置方法。这些宏允许开发者根据具体的需求来启用或禁用特定的功能,从而减小最终生成的代码大小,或根据硬件资源的限制来优化系统性能。
当你在FreeRTOS的配置文件中(通常是`FreeRTOSConfig.h`)看到类似于`#define INCLUDE_vTaskPrioritySet 1`或`#define INCLUDE_vTaskPrioritySet 0`的定义时,这意味着:
如果设置为`1`,则表示可以使用`vTaskPrioritySet()`函数。这使得可以在运行时调整任务的优先级。
如果设置为`0`,则表示禁用`vTaskPrioritySet()`函数,系统将不允许通过该API调整任务的优先级。
在文件tasks.c 中有相关代码介绍:
在这个例子中,如果`INCLUDE_vTaskPrioritySet`被定义为`1`,那么`vTaskPrioritySet`函数的实现会包含在编译中。反之,如果定义为`0`,则该函数及其实现将被编译器忽略。
这种方法使得FreeRTOS能够在不同的应用场景中灵活适应,例如在资源受限的嵌入式系统中,开发者可以通过简单的宏定义来裁剪掉不需要的功能,从而减小内存占用和提高效率。
3.2 FreeRTOS可选函数配置
/***************************************************************************************************************/
/* FreeRTOS可选函数配置选项 */
/***************************************************************************************************************/
#define INCLUDE_xTaskGetSchedulerState 1 // 包含获取调度器状态的函数
#define INCLUDE_vTaskPrioritySet 1 // 包含设置任务优先级的函数
#define INCLUDE_uxTaskPriorityGet 1 // 包含获取任务优先级的函数
#define INCLUDE_vTaskDelete 1 // 包含删除任务的函数
#define INCLUDE_vTaskCleanUpResources 1 // 包含清理任务资源的函数
#define INCLUDE_vTaskSuspend 1 // 包含挂起任务的函数
#define INCLUDE_vTaskDelayUntil 1 // 包含延迟到特定时间的函数
#define INCLUDE_vTaskDelay 1 // 包含延迟执行的函数
#define INCLUDE_eTaskGetState 1 // 包含获取任务状态的函数
#define INCLUDE_xTimerPendFunctionCall 1 // 包含挂起定时器函数调用的函数
INCLUDE_xTaskGetSchedulerState: 允许获取当前调度器的状态,通常用于检查调度器是否正在运行。
INCLUDE_vTaskPrioritySet: 允许修改已创建任务的优先级,可以在任务运行时动态调整其执行优先级。
INCLUDE_uxTaskPriorityGet: 允许获取指定任务的优先级,便于在需要时检查或记录任务优先级。
INCLUDE_vTaskDelete: 允许从调度器中删除一个已创建的任务,释放其占用的资源。
INCLUDE_vTaskCleanUpResources: 在任务被删除时调用,负责清理任务相关的资源,确保系统资源不泄漏。
INCLUDE_vTaskSuspend: 允许挂起(暂停)一个正在运行的任务,可以用于控制任务的执行。
INCLUDE_vTaskDelayUntil: 允许任务延迟执行直到特定的时间点,适合需要定时执行的任务。
INCLUDE_vTaskDelay: 允许任务延迟执行一段时间,通常用于控制任务的执行频率。
INCLUDE_eTaskGetState: 允许获取指定任务的当前状态(例如:运行、就绪、挂起等)。
INCLUDE_xTimerPendFunctionCall: 允许挂起一个函数调用并在定时器服务任务中调用,适合需要延迟执行的函数。
这些宏定义通常是在FreeRTOS或者类似实时操作系统的配置文件中使用,用于启用或禁用特定的任务管理功能。
四、"config" 开始的宏
“config”开始的宏和“NCLUDE”开始的宏一样,都是用来完成FreeRTOS的配置和裁剪的,接下来我们就看一下这些“config”开始的宏。
4.1 FreeRTOS基础配置配置选项
/***************************************************************************************************************/
/* FreeRTOS基础配置配置选项 */
/***************************************************************************************************************/
#define configUSE_PREEMPTION 1 //1使用抢占式内核,0使用协程
#define configUSE_TIME_SLICING 1 //1使能时间片调度(默认式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 //1启用特殊方法来选择下一个要运行的任务
//一般是硬件计算前导零指令,如果所使用的
//MCU没有这些硬件指令的话此宏应该设置为0!
#define configUSE_TICKLESS_IDLE 0 //1启用低功耗tickless模式
#define configUSE_QUEUE_SETS 1 //为1时启用队列
#define configCPU_CLOCK_HZ (SystemCoreClock) //CPU频率
#define configTICK_RATE_HZ (1000) //时钟节拍频率,这里设置为1000,周期就是1ms
#define configMAX_PRIORITIES (32) //可使用的最大优先级
#define configMINIMAL_STACK_SIZE ((unsigned short)130) //空闲任务使用的堆栈大小
#define configMAX_TASK_NAME_LEN (16) //任务名字字符串长度
#define configUSE_16_BIT_TICKS 0 //系统节拍计数器变量数据类型,
//1表示为16位无符号整形,0表示为32位无符号整形
#define configIDLE_SHOULD_YIELD 1 //为1时空闲任务放弃CPU使用权给其他同优先级的用户任务
#define configUSE_TASK_NOTIFICATIONS 1 //为1时开启任务通知功能,默认开启
#define configUSE_MUTEXES 1 //为1时使用互斥信号量
#define configQUEUE_REGISTRY_SIZE 8 //不为0时表示启用队列记录,具体的值是可以
//记录的队列和信号量最大数目。
#define configCHECK_FOR_STACK_OVERFLOW 0 //大于0时启用堆栈溢出检测功能,如果使用此功能
//用户必须提供一个栈溢出钩子函数,如果使用的话
//此值可以为1或者2,因为有两种栈溢出检测方法。
#define configUSE_RECURSIVE_MUTEXES 1 //为1时使用递归互斥信号量
#define configUSE_MALLOC_FAILED_HOOK 0 //1使用内存申请失败钩子函数
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1 //为1时使用计数信号量
这段代码是FreeRTOS操作系统的配置选项。这些选项用于调整FreeRTOS内核的行为,以适应特定应用程序的需求。下面是对各个配置项的详细介绍:
configUSE_PREEMPTION: 设置为1时,启用抢占式调度;设置为0时,使用协作式调度。抢占式内核允许更高优先级的任务打断低优先级任务。
configUSE_TIME_SLICING: 设置为1时,启用时间片调度。时间片调度允许同一优先级的任务在时间片结束后切换。
configUSE_PORT_OPTIMISED_TASK_SELECTION: 启用特别优化的任务选择方法。依赖于MCU的硬件特性。不支持硬件指令的MCU应将其设为0。
configUSE_TICKLESS_IDLE: 设置为1时,启用无滴答低功耗模式,有助于降低功耗。
configUSE_QUEUE_SETS: 设置为1时,启用队列集功能,允许将多个队列组合在一起,简化任务间的通信。
configCPU_CLOCK_HZ: 定义CPU的主频,通常使用系统核心时钟的值。
configTICK_RATE_HZ: 定义系统节拍的频率。设置为1000表示每秒产生1000个节拍(1毫秒一个节拍)。
configMAX_PRIORITIES: 定义可用的最大优先级数。将其设置为32,表示可以定义32个优先级的任务。
configMINIMAL_STACK_SIZE: 定义空闲任务的堆栈大小,单位为字节。
configMAX_TASK_NAME_LEN: 定义任务名称字符串的最大长度。
configUSE_16_BIT_TICKS: 设置为1时使用16位无符号整形作为系统节拍计数器,设置为0时使用32位无符号整形。
configIDLE_SHOULD_YIELD: 如果设置为1,空闲任务会放弃CPU使用权给同优先级的其他任务。
configUSE_TASK_NOTIFICATIONS: 设置为1时启用任务通知功能,允许任务间通过通知进行同步。
configUSE_MUTEXES: 设置为1时,启用互斥信号量,以保护共享资源。
configQUEUE_REGISTRY_SIZE: 如果不为0,启用队列注册功能,定义可以记录的队列和信号量的最大数量。
configCHECK_FOR_STACK_OVERFLOW: 大于0时启用堆栈溢出检测,用户需要实现相应的钩子函数。可设置为1(对每个任务进行检查)或2(对所有任务进行检查)。
configUSE_RECURSIVE_MUTEXES: 设置为1时,启用递归互斥信号量,允许同一任务多次获得同一互斥信号量。
configUSE_MALLOC_FAILED_HOOK: 设置为1时,启用内存分配失败的钩子函数,用于处理内存分配失败的情况。
configUSE_APPLICATION_TASK_TAG: 启用应用程序任务标签功能,允许开发者给任务添加标签以便于管理。
configUSE_COUNTING_SEMAPHORES: 设置为1时,启用计数信号量,允许多任务资源共享。
这些配置选项使得FreeRTOS的行为能够灵活调整,以适应不同的应用需求和硬件环境。根据具体的应用场景和系统资源,开发者可以选择合适的配置来优化系统的性能和资源管理。
4.2 FreeRTOS与内存申请有关配置选项
在FreeRTOS中,configAPPLICATION_ALLOCATED_HEAP
是一个配置宏,用于决定堆内存的分配方式。当你将其定义为1时,堆内存的管理将由用户自行设置,而不是由FreeRTOS自动分配。
在这种情况下,用户需要在自己的代码中提供一个足够大的内存块,并将其传递给FreeRTOS进行使用。
在不同的堆实现文件中(如 heap_1.c
, heap_2.c
, heap_3.c
, heap_4.c
, heap_5.c
),FreeRTOS 提供了多种内存管理方式,以适应不同的应用需求。每种实现的具体细节和特性可能会有所不同,用户可以根据需要选择合适的实现。
例如,如果用户选择了 heap_4.c
,通常会在文件中看到类似如下的定义:
在这个示例中,ucHeap
数组就是用户定义的堆内存区域,FreeRTOS 将使用这个区域进行动态内存分配。具体的堆内存大小可以根据实际需求来进行调整,例如通过修改 configTOTAL_HEAP_SIZE
的值。
/***************************************************************************************************************/
/* FreeRTOS与内存申请有关配置选项 */
/***************************************************************************************************************/
#define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持动态内存申请
#define configTOTAL_HEAP_SIZE ((size_t)(20*1024)) //系统所有总的堆大小
1.configSUPPORT_DYNAMIC_ALLOCATION
:
- 这个宏用于启用或禁用动态内存分配支持。
- 值为
1
表示支持动态内存分配,意味着可以使用如pvPortMalloc
和vPortFree
这样的API来动态分配和释放内存。- 如果将其设置为
0
,则禁用动态内存分配,系统将只使用静态内存分配。2.
configTOTAL_HEAP_SIZE
:
- 这个宏定义了系统中可用的总堆内存大小。
- 在这个例子中,堆的大小被设置为20KB(即20480字节)。
- 确保堆的大小足够大,以满足任务、队列、信号量等对象的动态内存需求。
4.3 FreeRTOS与钩子函数有关的配置选项
/***************************************************************************************************************/
/* FreeRTOS与钩子函数有关的配置选项 */
/***************************************************************************************************************/
#define configUSE_IDLE_HOOK 0 //1,使用空闲钩子;0,不使用
#define configUSE_TICK_HOOK 0 //1,使用时间片钩子;0,不使用
1. configUSE_IDLE_HOOK:
- 定义:
#define configUSE_IDLE_HOOK 0
- 含义:这个配置选项决定了是否使用空闲钩子(Idle Hook)。空闲钩子是在系统空闲时(即没有任务需要执行时)调用的函数。
- 值为0:表示不使用空闲钩子。这意味着当系统空闲时,不会调用任何用户定义的空闲钩子函数。
- 值为1:表示使用空闲钩子。如果设置为1,用户需要定义一个名为
vApplicationIdleHook
的函数,该函数将在系统空闲时被调用。2. configUSE_TICK_HOOK:
- 定义:
#define configUSE_TICK_HOOK 0
- 含义:这个配置选项决定了是否使用时间片钩子(Tick Hook)。时间片钩子是在每个系统时钟节拍(Tick)发生时调用的函数。
- 值为0:表示不使用时间片钩子。这意味着在每个时钟节拍时,不会调用任何用户定义的时间片钩子函数。
- 值为1:表示使用时间片钩子。如果设置为1,用户需要定义一个名为
vApplicationTickHook
的函数,该函数将在每个时钟节拍时被调用。
4.4 FreeRTOS与运行时间和任务状态收集有关的配置选项
/***************************************************************************************************************/
/* FreeRTOS与运行时间和任务状态收集有关的配置选项 */
/***************************************************************************************************************/
#define configGENERATE_RUN_TIME_STATS 0 //为1时启用运行时间统计功能
#define configUSE_TRACE_FACILITY 1 //为1启用可视化跟踪调试
#define configUSE_STATS_FORMATTING_FUNCTIONS 1 //与宏configUSE_TRACE_FACILITY同时为1时会编译下面3个函数
//prvWriteNameToBuffer(),vTaskList(),
//vTaskGetRunTimeStats()
1. configGENERATE_RUN_TIME_STATS:
- 该选项设置为1时,启用运行时间统计功能。这意味着系统会收集每个任务的运行时间信息,这对于性能分析和调试非常有用。
2. configUSE_TRACE_FACILITY:
- 设置为1时,启用可视化跟踪调试功能。这允许使用FreeRTOS的跟踪工具来监控任务状态和系统行为,从而更容易进行调试和性能优化。
3.configUSE_STATS_FORMATTING_FUNCTIONS:
- 当configUSE_TRACE_FACILITY也为1时,该选项设置为1会编译一些特定的函数,用于格式化和输出任务状态和运行时间统计信息。这些函数包括:
prvWriteNameToBuffer()
: 用于将任务名称写入缓冲区。vTaskList()
: 生成一个包含所有任务状态的列表。vTaskGetRunTimeStats()
: 获取任务的运行时间统计信息。
4.5 FreeRTOS与协程有关的配置选项
/***************************************************************************************************************/
/* FreeRTOS与协程有关的配置选项 */
/***************************************************************************************************************/
#define configUSE_CO_ROUTINES 0 //为1时启用协程,启用协程以后必须添加文件croutine.c
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) //协程的有效优先级数目
1. configUSE_CO_ROUTINES:
- 这个配置项用于启用或禁用协程功能。
- 当设置为1时,表示启用协程功能,此时必须将
croutine.c
文件添加到项目中。- 当设置为0时,表示禁用协程功能,协程相关的代码不会被编译和使用。
2. configMAX_CO_ROUTINE_PRIORITIES:
- 这个配置项定义了协程可以使用的优先级数量。
- 在这个例子中,
configMAX_CO_ROUTINE_PRIORITIES
被设置为2,表示协程可以使用两个不同的优先级。- 优先级数量越多,系统可以更灵活地管理不同协程的执行顺序,但也会增加系统的复杂性和开销。
4.6 FreeRTOS与软件定时器有关的配置选项
/***************************************************************************************************************/
/* FreeRTOS与软件定时器有关的配置选项 */
/***************************************************************************************************************/
#define configUSE_TIMERS 1 //为1时启用软件定时器
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1) //软件定时器优先级
#define configTIMER_QUEUE_LENGTH 5 //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2) //软件定时器任务堆栈大小
1. configUSE_TIMERS:
- 这是一个布尔值,可以设置为1(启用)或0(禁用)。将其设置为1时,FreeRTOS将启用软件定时器功能。软件定时器能够在特定时间间隔后调用回调函数,非常适用于需要定时执行的任务。
2. configTIMER_TASK_PRIORITY:
- 该选项定义了软件定时器任务的优先级。它通常设置为
configMAX_PRIORITIES - 1
,这意味着软件定时器任务的优先级将是所有可用优先级中的最高之一。选择合适的优先级可以确保定时器能够及时处理任务,同时不会对其他实时任务造成干扰。3. configTIMER_QUEUE_LENGTH:
- 这个选项定义了软件定时器队列的长度。在此例中,队列长度为5。这意味着可以有最多5个软件定时器同时排队等待处理。根据应用的需要,可能需要调整这个值,以便能够容纳更多的定时器请求或减少内存使用。
4. configTIMER_TASK_STACK_DEPTH:
- 这个选项定义了软件定时器任务的堆栈大小。在这个例子中,它被设置为
configMINIMAL_STACK_SIZE * 2
,通常情况下,软件定时器任务并不需要非常大的堆栈,但为了安全起见,使用两倍的最小堆栈大小是一个常见的做法。
4.7 FreeRTOS与中断、中断服务函数有关的配置选项
/***************************************************************************************************************/
/* FreeRTOS与中断有关的配置选项 */
/***************************************************************************************************************/
#ifdef __NVIC_PRIO_BITS
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 //中断最低优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 //系统可管理的最高中断优先级
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/***************************************************************************************************************/
/* FreeRTOS与中断服务函数有关的配置选项 */
/***************************************************************************************************************/
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#endif /* FREERTOS_CONFIG_H */
4.7.1 中断优先设置
#ifdef __NVIC_PRIO_BITS #define configPRIO_BITS __NVIC_PRIO_BITS #else #define configPRIO_BITS 4 #endif
__NVIC_PRIO_BITS
是一个宏,表示具体硬件平台上可用的中断优先级位数。如果该宏已定义,则使用其值;如果未定义,则默认使用 4 位(即可以有 16 个优先级)。
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 // 中断最低优先级 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 // 系统可管理的最高中断优先级
configLIBRARY_LOWEST_INTERRUPT_PRIORITY
定义了中断的最低优先级,这里设为 15。configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
定义了 FreeRTOS 内核允许的最高中断优先级,这里设为 5。此优先级以下的中断可以安全地调用 FreeRTOS 的 API。
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) ) #define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
configKERNEL_INTERRUPT_PRIORITY
和configMAX_SYSCALL_INTERRUPT_PRIORITY
计算出内核和系统调用的中断优先级,这两个值基于之前定义的优先级进行位移计算,以便与硬件平台的优先级配置相匹配。
4.7.2 中断服务设置:
#define xPortPendSVHandler PendSV_Handler #define vPortSVCHandler SVC_Handler
xPortPendSVHandler
和vPortSVCHandler
分别定义了 PendSV 和 SVC 中断服务例程的处理函数。FreeRTOS 使用这两个中断来进行任务切换和系统调用。
这段配置代码主要用于设置 FreeRTOS 中与中断相关的优先级和中断处理程序。通过合理的优先级设置,可以确保系统在处理中断时的稳定性与高效性,避免高优先级的中断影响实时操作。
📝大佬觉得本文有所裨益,不妨轻点一下👍给予鼓励吧!
❤️❤️❤️本人虽努力,但能力尚浅,若有不足之处,恳请各位大佬不吝赐教,您的批评指正将是我进步的动力!😊😊😊
💖💖💖若您认为此篇文章对您有所帮助,烦请点赞👍并收藏🌟,您的支持是我前行的最大动力!
🚀🚀🚀任务在默默中完成,价值在悄然间提升。让我们携手共进,一起加油,迎接更美好的未来!🌈🌈🌈