精华内容
下载资源
问答
  • "FreeRTOS学习笔记——FreeRTOS任务创建和删除实验(动态方法)"博客所用代码
  • 1. FreeRTOS任务创建 FreeRTOS有两种方式创建任务,动态方法和静态方法,他们的区别就是动态创建任务所使用到的堆栈由系统自动分配,而静态创建任务所使用到的堆栈则要由程序员自己指定了。 1.1 动态方法 FreeRTOS...

    1. FreeRTOS任务创建

    FreeRTOS有两种方式创建任务,动态方法和静态方法,他们的区别就是动态创建任务所使用到的堆栈由系统自动分配,而静态创建任务所使用到的堆栈则要由程序员自己指定了。

    1.1 动态方法

    FreeRTOS动态方法创建任务的API是xTaskCreate,其函数原型如下:

    /* 动态方法创建任务的API */
    BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,				// 任务函数
                            const char * const pcName,				// 任务名称
                            const uint16_t usStackDepth,			// 堆栈大小,实际大小为4 * usStackDepth
                            void * const pvParameters,				// 传递给任务函数的参数
                            UBaseType_t uxPriority,					// 任务优先级
                            TaskHandle_t * const pxCreatedTask 		// 任务句柄(可以理解为就是该任务本身)
                          );
    

    参数介绍

    1. xTaskCreate: 该参数就是指向用户任务函数的指针。任务函数也是一个C函数而已,只不过任务函数没有返回值,函数参数是一个void型指针,任务函数里面通常是一个死循环,里面执行着用户想要实现的任务功能。任务函数原型:void task_function( void *pvParameters )

    2. pcName: 任务名称。这个参数不会被 FreeRTOS 使用,其只是单纯地用于辅助调试。应用程序可以通过定义常量 config_MAX_TASK_NAME_LEN 来定义任务名的最大长度——包括’\0’结束符。如果传入的字符串长度超过了这个最大值,字符串将会自动被截断。

    3. usStackDepth: 我们创建的每个任务,他们都有唯一属于自己的任务堆栈空间。usStackDepth 值用于告诉内核为该任务分配多大的栈空间,单位是字节。实际分配的大小为:4 * usStackDepth 字节。

    4. pvParameters: 传递给任务函数的参数。

    5. uxPriority: 任务优先级,FreeRTOS中任务优先级的取值范围是: 0 ~ (configMAX_PRIORITIES – 1),取值越大说明优先级越高。

      其中,configMAX_PRIORITIES 这个宏是由用户定义的常量,FreeRTOS并没有规定优先级的上限,但是我们在使用的时候,最好定义一个自己实际需要的大小,这样可以避免浪费内存。

    6. pxCreatedTask: 任务句柄。这个句柄将在 API 调用中对该创建出来的任务进行引用, 比如改变任务优先级, 或者删除任务。如果应用程序中不会用到这个任务的句柄,则 pxCreatedTask 可以被设为 NULL。

    返回值

    该API有两个返回值:

    1. pdTRUE,表明任务创建成功。
    2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY,表明任务创建失败。一般任务创建失败都是由于内存不足造成的。

    1.2 静态方法

    静态方法创建任务,需要用户自己指定任务堆栈和任务控制块,静态方法创建任务会比动态方法更复杂一些。静态方法创建任务函数原型如下:

    /* 静态方法创建任务的API,创建成功函数返回该任务句柄 */
    TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,			// 任务函数
    								const char * const pcName,			// 任务名称
    								const uint32_t ulStackDepth,		// 堆栈大小,由用户自己给出堆栈
    								void * const pvParameters,			// 传递给任务函数的参数
    								UBaseType_t uxPriority,				// 任务优先级
    								StackType_t * const puxStackBuffer,	// 任务堆栈
    								StaticTask_t * const pxTaskBuffer 	// 任务控制块
                                  );
    

    参数介绍(只介绍和动态方法不同的几个参数)

    1. usStackDepth: 任务堆栈大小,由于本函数是静态方法创建任务,所以任务堆栈由用户给出(一般是个用户定义一个数组),所以此参数就是这个数组的大小。
    2. puxStackBuffer: 任务堆栈,一般是用户定义的一个数组,数组类型要为StackType_t 类型。
    3. pxTaskBuffer: 任务控制块。

    返回值

    1. NULL: 表明任务创建失败,一般是 puxStackBuffer 或 pxTaskBuffer 用户定义的堆栈大小,任务控制块内存大小不足导致失败。

    2. 创建成功,返回该任务的任务句柄。

    2. FreeRTOS任务删除

    当我们觉得某个任务已经不需要时,FreeRTOS提供vTaskDelete()函数来删除任务自身或者其他任务,任务一旦被删除之后,相当于不存在了,后续也不可能进入运行态。

    如果删除的这个任务,是使用动态方法创建的,那么这个任务删除后,这个任务所用到的堆栈和任务控制块会被空闲任务自动回收。因此有一点很重要,那就是使用 vTaskDelete() 函数的任务千万不能把空闲任务的执行时间饿死,否则空闲任务得不到执行,那么被删除的任务内存也就回收不了了。

    另外,该任务的内存只有由内核自动分配的,才会由空闲任务自动回收。而那些由用户自己申请的内存,比如pvPortMalloc()申请的内存,在任务删除后,需要用户自己去释放这部分内存,内核是不会自动帮我们回收的。

    删除任务的函数原型如下:

    void vTaskDelete( xTaskHandle pxTaskToDelete );
    

    其中参数pxTaskToDelete为要删除的某个任务句柄,另外任务可以传入NULL来删除自身。

    3. FreeRTOS任务创建和删除代码示例

    我们来设计一个例子。

    1. 首先在main函数里创建优先级为1的任务1,当任务1运行的时候,以优先级2创建任务2。这时因为任务2的优先级最高,所以会马上得到执行。
    2. 任务2执行时,啥都不做,它只是把自己删除了(vTaskDelete传入NULL即可把自身删除)。
    3. 当任务2删除自身之后,任务1又成为了最高的优先级任务,任务1继续执行,这时需要调用vTaskDelay()函数来阻塞一小段时间,让空闲任务得以执行,从而回收被删除了的任务2的内存。
    4. 当任务1退出阻塞态后,再次成为就绪态中具有最高优先级的任务,因此会抢占空闲任务。任务1再次得以运行,如此往复下去。

    代码清单如下:

    #include <stdio.h>
    
    #include "bsp_usart.h"
    #include "FreeRTOS.h"
    #include "task.h"
    
    TaskHandle_t StartTask_Handler;			//task1任务句柄
    
    /* task2函数 */
    void task2(void *pvParameters)
    {	
    	for ( ; ; )
    	{
    		printf("task2 is running and about to delete itself\n");
    
    		vTaskDelete( NULL );		// 任务2把自己删除了
    	}
    }
    
    /* task1函数 */
    void task1(void *pvParameters)
    {	
    	for ( ; ; )
    	{
    		printf("task1 is running\n");
    
    		xTaskCreate( task2, "task2", 1000, NULL, 2, NULL );		// 创建任务2
    
    		vTaskDelay(1000);		// 延时1s,让空闲任务得以运行,从而回收被删除的任务2的内存
    	}
    }
    
    int main()
    {
    	USART_Config();		// 串口初始化
    
    	/* 创建任务1 */
        xTaskCreate((TaskFunction_t )task1,           	 	 //任务函数
                    (const char*    )"task1",          		 //任务名称
                    (uint16_t       )128,        			 //任务堆栈大小
                    (void*          )NULL,             		 //传递给任务函数的参数
                    (UBaseType_t    )1,       				 //任务优先级
                    (TaskHandle_t*  )StartTask_Handler);     //任务句柄
    				
        vTaskStartScheduler();          					 //开启任务调度
    }
    

    代码编译运行后,在串口助手上看到的运行结果如下:
    在这里插入图片描述
    和我们设计时分析的运行过程时一模一样的。为了更直观的了解这个例子的运行过程,可以看下面的任务运行的流程图:
    在这里插入图片描述

    展开全文
  • 174_FreeRTOS任务删除

    2019-11-30 10:05:01
    不知道是不是我工作比较特殊的原因,在我的工作经历中几乎没有什么删除Task的需求。不过,既然这是一个标准性的OS支持功能,还是来掌握一下。 先分析官方例子代码: 任务开始只创建了一个Task1,优先级是1。...

             不知道是不是我工作比较特殊的原因,在我的工作经历中几乎没有什么删除Task的需求。不过,既然这是一个标准性的OS支持功能,还是来掌握一下。

             先分析官方例子代码:

             任务开始只创建了一个Task1,优先级是1。之后,OS的调度器启动。

             在Task1中,打印一个字符串同时创建Task2,优先级是2,之后延迟100ms。这里有一个问题我也很想弄清楚,什么时候能够触发调度?会是系统Tick会触发调度器动作?其实有一个基础的概念我一直没弄清楚,也就是我现在模拟环境下的系统Tick究竟是多少?不过肯定的是,Task2肯定会有机会执行。

             Task2的设计算是很特别的,这个任务只执行一次?!没有一个死循环,因此从机理分析看,这个任务打印一个字符串之后,删除了当前任务。这里看得出,这个参数不一定是NULL,还可以是相应的Handle。之后,系统中只剩下了一个Task1,Task1肯定会获得执行机会。

             大致分析这么多,先看一下运行效果:

             直接感觉上,这个延时绝对不止100ms。从运行效果看,软件执行中Task的执行是交替的,因此从结果上分析,很可能调度器启动后任务的创建或者删除会触发一次任务调度!

             增加一个测试,Task1中的delay去掉之后会是什么效果?

             运行效果:

             软件运行到此,之后不再打印。不知道软件是运行到了什么地方去了?至少不是Task1,如果是屏幕应该还在打印,也不是Task2,不然Task2的信息会被打印出来。增加一个idle hook之后再看,再测试之前先保证了idle hook可以执行。

             之后,测试之前的软件,效果依然类似。也就是说,有一个Task应该吧idle task给饿死了。或者直接进入了某个故障状态。

             接下来,用了我不熟悉的VS断点调试发现,其实这个问题是因为heap空间被消耗完了。为了验证,我扩大了heap的大小。之后,测试效果如下:

             这个截图中出现了多次任务切换,但是,最终还是卡死了。但是可以看得出调度上的一个改进了,也在一定程度上验证了我自己的猜测。

    展开全文
  • FreeRTOS-删除任务笔记

    2020-04-13 13:46:29
    任务删除函数: void vTaskDelete( TaskHandle_t xTaskToDelete ) 1.获取要删除任务任务控制块 2. 把要删除任务从就绪列表中删除 3.判断要删除任务是否有等待事件发生,如果有的话从列表中删除。 4....

    任务删除函数:  void vTaskDelete( TaskHandle_t xTaskToDelete )

    1.获取要删除任务的任务控制块

    2. 把要删除的任务从就绪列表中删除

    3.判断要删除的任务是否有等待事件发生,如果有的话从列表中删除。

    4.如果要删除的任务是当前运行的任务时,把当前任务放到xTasksWaitingTermination 列表中,当下一次空闲任务运行的时候会把要删除任务的内存删除掉。uxDeletedTasksWaitingCleanUp意思是有多少个任务需要释放内存。

    5.如果闪出的任务不是当前运行的任务时,1.任务总数减1, 2.删除任务控制块, 3.更新下一个任务的阻塞时间

    6.如果任务调度器已经在运行,并且删除的任务是正在运行的任务,则进行一次任务切换。

    展开全文
  • FreeRTOS任务删除

    2018-10-04 01:06:17
    FreeRTOS任务删除并不常用,下面把有任务删除部分的代码贴出来: //************************************************************** // 具体任务函数 //函数名:Start_Task //*****************************...

    FreeRTOS的任务删除并不常用,下面把有任务删除部分的代码贴出来:

    //**************************************************************
    //                      具体任务函数
    //函数名:Start_Task
    //**************************************************************
    void Start_Task(void *pvParameters)
    {
    	//创建任务1:
        xTaskCreate((TaskFunction_t)    Task1,             //任务函数名
    				(const char *)      "Task1",           //任务名称(随便取)
    				(uint16_t)          TASK1_SIZE,        //任务堆栈大小
    				(void *)            NULL,              //任务参数,一般为空
    				(UBaseType_t)       TASK1_PRIO,        //任务优先级
    				(TaskHandle_t *)    &Task1_Handler);   //任务句柄
        //创建任务2:
        xTaskCreate((TaskFunction_t)    Task2,             //任务函数名
    				(const char *)      "Task2",           //任务名称(随便取)
    				(uint16_t)          TASK2_SIZE,        //任务堆栈大小
    				(void *)            NULL,              //任务参数,一般为空
    				(UBaseType_t)       TASK2_PRIO,        //任务优先级
    				(TaskHandle_t *)    &Task2_Handler);   //任务句柄
        
        vTaskDelete(Start_Task_Handler);                   //创建其它任务后,删除自己,参数为待删除任务的任务句柄
        //vTaskDelete(NULL);                               //如果任务在任务函数中删除自己,也可以将参数写为"NULL",就像这个里面一样。
    }
    

    下面我参照正点原子写的,里面有任务删除过程,上面那段代码就是摘自这个里面:

    #include "sys.h"
    #include "delay.h"
    #include "usart.h"
    #include "led.h"
    #include "FreeRTOS.h"
    #include "task.h"
    
    //本例程大体结构:
    //例程主要学习任务的动态创建,先是创建一个开始创建任务的任务,然后在这个任务里面又创建另外两个任务.
    //任务创建的步骤:
    //1、大体构思任务框架;
    //2、准备好任务创建函数:"xTaskCreate();"
    //3、将任务创建函数"xTaskCreate()"里面的参数都准备好填进去,
    //   任务参数就是:任务函数的函数名、任务名、堆栈、优先级、句柄;
    //4、编写任务的具体函数,函数体内搞个大循环,剩下的就是具体的功能了;
    //5、一切准备好后,开启任务调度器.
    
    
    //====================开始任务函数相关========================
    void Start_Task(void *pvParameters);//任务函数声明
    #define START_TASK_SIZE     120     //任务堆栈大小
    #define START_TASK_PRIO     1       //任务优先级,注意,优先级“0”不能用,这个是空闲任务的优先级,
                                        //空闲任务在开启任务调度器中会自动创建
                                        //还有一个软件定时器任务,这个任务优先级是最高的31,这个也不能用
    TaskHandle_t Start_Task_Handler;    //任务句柄
    
    //========================任务1相关========================
    void Task1(void *pvParameters);     //任务函数声明
    #define TASK1_SIZE     120          //任务堆栈大小
    #define TASK1_PRIO     2            //任务优先级,注意,优先级“0”不能用,这个是空闲任务的优先级,
                                        //空闲任务在开启任务调度器中会自动创建
                                        //还有一个软件定时器任务,这个任务优先级是最高的31,这个也不能用
    TaskHandle_t Task1_Handler;         //任务句柄
    
    //========================任务2相关========================
    void Task2(void *pvParameters);     //任务函数声明
    #define TASK2_SIZE     120          //任务堆栈大小
    #define TASK2_PRIO     3            //任务优先级,注意,优先级“0”不能用,这个是空闲任务的优先级,
                                        //空闲任务在开启任务调度器中会自动创建
                                        //还有一个软件定时器任务,这个任务优先级是最高的31,这个也不能用
    TaskHandle_t Task2_Handler;         //任务句柄
    
    
    
    int main(void)
    {
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
    	delay_init();	    				//延时函数初始化	  
    	uart_init(115200);					//初始化串口
    	LED_Init();		  					//初始化LED
        
        //创建任务:
        //(这个任务里面再去创建其它任务)
        xTaskCreate((TaskFunction_t)    Start_Task,             //任务函数名
    				(const char *)      "Start_Task",           //任务名称(随便取)
    				(uint16_t)          START_TASK_SIZE,        //任务堆栈大小
    				(void *)            NULL,                   //任务参数,一般为空
    				(UBaseType_t)       START_TASK_PRIO,        //任务优先级
    				(TaskHandle_t *)    &Start_Task_Handler);   //任务句柄
        
        vTaskStartScheduler();                                  //开启任务调度器
    }
    
    
    
    //**************************************************************
    //                      具体任务函数
    //函数名:Start_Task
    //**************************************************************
    void Start_Task(void *pvParameters)
    {
    	//创建任务1:
        xTaskCreate((TaskFunction_t)    Task1,             //任务函数名
    				(const char *)      "Task1",           //任务名称(随便取)
    				(uint16_t)          TASK1_SIZE,        //任务堆栈大小
    				(void *)            NULL,              //任务参数,一般为空
    				(UBaseType_t)       TASK1_PRIO,        //任务优先级
    				(TaskHandle_t *)    &Task1_Handler);   //任务句柄
        //创建任务2:
        xTaskCreate((TaskFunction_t)    Task2,             //任务函数名
    				(const char *)      "Task2",           //任务名称(随便取)
    				(uint16_t)          TASK2_SIZE,        //任务堆栈大小
    				(void *)            NULL,              //任务参数,一般为空
    				(UBaseType_t)       TASK2_PRIO,        //任务优先级
    				(TaskHandle_t *)    &Task2_Handler);   //任务句柄
        
        vTaskDelete(Start_Task_Handler);                   //创建其它任务后,删除自己,参数为待删除任务的任务句柄
        //vTaskDelete(NULL);                               //如果任务在任务函数中删除自己,也可以将参数写为"NULL",就像这个里面一样。
    }
    
    //**************************************************************
    //                      具体任务函数
    //函数名:Task1
    //**************************************************************
    void Task1(void *pvParameters)
    {
    	while(1)
        {
            LED0=~LED0;
            vTaskDelay(200);
        }
    }
    
    //**************************************************************
    //                      具体任务函数
    //函数名:Task2
    //**************************************************************
    void Task2(void *pvParameters)
    {
    	while(1)
        {
            LED1=~LED1;
            vTaskDelay(200);
        }
    }
    
    
    
    展开全文
  • FreeRtos的学习视频(FreeRtos任务删除,挂起和恢复)。对于学习FreeRtos的很有用。FreeRtos是当前物联网引用最多的操作系统
  • 关于FreeRTOS任务删除

    2019-12-01 10:31:06
    任务删除 当一个任务不需要了,可以选择将其删除任务删除了之后就无法再被调度器调度,进入运行态;任务占用的内存由空闲任务来进行释放,故调用的任务删除函数的API要保证空闲函数能够被调用,以进行内存回收,...
  • 6.1 任务创建和删除API 函数FreeRTOS 最基本的功能就是任务管理,而任务管理最基本的操作就是创建和删除任务FreeRTOS任务创建和删除API 函数如表6.1.1.1 所示:1、函数xTaxkCreate()此函数用来创建一个任务,...
  • 帮助一些刚入门学习FREERTOS的同学了解实时操作系统的问题,包括静态和动态的区别
  • FreeRTOS任务删除函数是一个条件编译函数。想要使用任务函数需要将宏INCLUDE_vTaskDelete定义为1。如果系统中的任务永远都不需要再运行了,那么就可以调用任务删除函数删除任务。 瞎哔哔谁都会,给我看代码。 #...
  • FreeRTOS支持任务动态创建与删除。在前面的实例中已经演示了任务的创建、参数传递、阻塞延时以及优先级调度,本次实例将实现任务删除。 1、硬件准备 NodeMCU ESP32-S V3.0开发板一块 数据线一条 2、软件准备 ...
  • FreeRTOS 任务管理之任务删除

    千次阅读 2016-06-30 16:35:18
    任务删除当一个任务不需要了,可以选择将其删除任务删除了之后就无法再被调度器调度,进入运行态;任务占用的内存由空闲任务来进行释放,故调用的任务删除函数的API要保证空闲函数能够被调用,以进行内存回收,...
  • 测试出删除后,状态回是删除标志 但是,定义了句柄没有创建任务时,状态是就绪,那就无法判断是不是创建了改任务。 最终还是使用正点原子方法将句柄等于NULL来判断。 ...*功能:删除一个任务 ...
  • 6.3 任务创建和删除实验(静态方法)6.3.1 实验程序设计1、实验目的上一小节我们讲了使用函数xTaskCreate()来创建任务,本...2、实验设计参考实验:FreeRTOS 实验6-1 FreeRTOS 任务创建和删除实验(动态方法)。3、实验...
  • FreeRTOS任务详解

    2021-09-07 10:33:03
    详细讲解freeRTOS任务
  • STM32CubeMX学习笔记——FreeRTOS_任务创建与删除Github简介任务创建可视化创建方式代码创建方式任务删除 Github ...
  • FreeRTOS 任务的 创建 、删除、挂起、恢复、例程实验例程
  • 任务删除 受博客限制,如果您想获得更好的阅读体验,请前往https://github.com/Nrusher/FreeRTOS-Book或者https://gitee.com/nrush/FreeRTOS-Book下载PDF版本阅读,如果您觉得本文不错也可前往star,以示对作者的...
  • FreeRTOS系列第10篇---FreeRTOS任务创建和删除

    万次阅读 多人点赞 2015-12-21 14:43:04
    FreeRTOS移植到Cortex-M3硬件平台的文章中,我们已经见过任务创建API,但那篇文章的重点在于如何移植FreeRTOS,本文将重点放在任务的创建和删除API函数上面。 任务创建和删除API函数位于文件task.c中,需要包含...
  • FreeRTOS动态创建任务删除任务

    千次阅读 2017-06-08 16:41:07
    #define Start_Stack_Size 120 //任务堆栈大小 #define Start_Task_Prio 1 //任务优先级 0和31分别是空闲任务和软件定时器优先级,用户不能用 TaskHandle_t Start_Task_Handle; //任务句柄 void Start_Task( ...
  • FreeRTOS空闲任务

    千次阅读 2019-03-01 09:58:15
    空闲任务在启动调度器的时候被创建 /* 启动调度器 */ void vTaskStartScheduler( void ) { BaseType_t xReturn; #if (configSUPPORT_STATIC_ALLOCATION == 1) { ...... } #else { /* 创建空闲任务 */ ...
  • FreeRTOS-任务信息查询

    2021-09-05 09:21:25
    FreeRTOS-任务信息查询 FreeRTOS中提供了很多函数可以用来获取相应的任务信息,这里我们会深入分析vTaskGetInfo()、uxTaskGetSystemState()和vTaskList()这三个函数以及它们之间的一些联系。FreeRTOS中的任务信息...
  • freertos 任务死机Sometimes our computers simply die due to unexpected hardware problems that are not our fault, so how do you locate and transfer ‘rare’ or hard to recreate files like scheduled ...
  • FreeRTOS-任务基础知识

    2020-12-13 10:50:29
    (一)多任务系统 1. 单任务系统 在使用C51系列、STM32等单片机进行裸机编程时,大都在main函数中写一个while或者for死循环函数,用来无限轮询任务函数。很多时候会加入硬件中断来完成一些功能处理。相对于多任务...
  • 3_vTaskDelete删除任务 如何删除一个任务? [[#4 删除任务例子]] 1.开启功能 修改配置文件:FreeRTOSconfig.h //引入任务删除 #define INCLUDE_vTaskDelete 1 2.函数接口 函数定义头文件:task.h void...
  • freeRTOS出现任务卡死的情况。

    千次阅读 2020-12-03 11:18:03
    整个freeRTOS工程项目创建了4个task任务。 我是先修改了BLE任务,修改完毕后运行正常;然后一步一步添加新的4G任务代码。发现只添加4G初始化代码,4个任务都正常,但是添加业务功能代码的时候,4个任务都卡死了(一...
  • 此程序为STM32F103 移植FreeRTOS系统工程源码,有需要可以学习参考,特别适合刚入门, 或者还没有入门的单片机开发者,可以提高代码开发周期,提升编程水平
  • 主要介绍FreeRTOS任务删除功能。通过分析函数vTaskDelete()剖析任务删除的原理,同时,对于该函数内部调用的函数也重点分析。
  • FreeRTOS任务简介

    2021-05-29 00:37:45
    一、FreeRTOS用途FreeRTOS一般被用于硬件设计上RAM大小存在一定限制(成本、资源、性能功耗比等)的平台之中,它是目前运用的比较多的实时操作系统之一。选用FreeRTOS作为项...
  • FreeRTOS 任务句柄(详解)

    千次阅读 2020-05-18 18:40:26
    为每个任务分配一个任务控制块(TCB), *并存储任务状态信息,包括指向任务上下文的指针 *(任务的运行时环境,包括寄存器值) */ 任务句柄,在FreeRTOS又叫任务控制块,包含创建任务的所有信息,所有删除任务就...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,651
精华内容 1,060
关键字:

freertos删除任务