FreeRTOS学习笔记—任务创建和删除

这篇具有很好参考价值的文章主要介绍了FreeRTOS学习笔记—任务创建和删除。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


🎀 文章作者:二土电子

🌸 关注文末公众号获取其他资料和工程文件!

🐸 期待大家一起学习交流!


一、任务创建和删除API函数

FreeRTOS 的任务创建和删除相关的API函数有下面几个

  • xTaskCreate()
    使用动态的方法创建一个任务
  • xTaskCreateStatic()
    使用静态的方法创建一个任务
  • xTaskCreateRestricted()
    创建一个使用 MPU 进行限制的任务,相关内存使用动态内存分配
  • vTaskDelete()
    删除一个任务

MPU意思是Memory Protect Unit,即为存储保护单元,它是位于存储器内部的一个可编程的区域,定义了存储器的属性和存储器的访问权限。这里就不再对MPU做深入了解了。

1.1 xTaskCreate()函数

由于该函数是动态方法创建任务,因此它的任务内存需要使用“pvPortMalloc”去申请。所以在使用该函数创建任务时,对应的“configSUPPORT_DYNAMIC_ALLOCATION”宏定义要打开。

#define configSUPPORT_DYNAMIC_ALLOCATION        1                       //支持动态内存申请

下面来看一下xTaskCreate()函数的各个参数

BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,
							const char * const pcName,
							const uint16_t usStackDepth,
							void * const pvParameters,
							UBaseType_t uxPriority,
							TaskHandle_t * const pxCreatedTask )
  • pxTaskCode
    任务函数
  • pcName
    任务名字。任务名字不能超过“configMAX_TASK_NAME_LEN”
  • usStackDepth
    任务堆栈大小。需要注意的是,实际的任务堆栈大小是该值 * 4字节,在上一篇已经介绍过了。其中空闲任
    务的任务堆栈大小为“configMINIMAL_STACK_SIZE”
  • pvParameters
    传递给任务函数的参数
  • uxPriotiry
    任务优先级。范围是0~ configMAX_PRIORITIES-1
  • pxCreatedTask
    任务句柄。任务创建成功以后会返回此任务的任务句柄,这个句柄其实就是任务的任务堆栈。此参数就用来保存这个任务句柄。其他 API 函数可能会使用到这个句柄。任务句柄通俗来讲,就是任务的标识,用来区分是哪个任务。

该函数有两种返回值

  • pdPASS
    任务创建成功
  • errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
    导致任务创建失败(通常可能是任务堆内存不足)

1.2 xTaskCreateStatic()函数

该函数是使用静态方法创建任务,需要将“configSUPPORT_STATIC_ALLOCATION”宏定义打开。该函数有以下参数

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 )
  • pxTaskCode
    任务函数
  • pcName
    任务名字。任务名字不能超过“configMAX_TASK_NAME_LEN”
  • usStackDepth
    任务堆栈大小。,由于是静态方法创建任务,所以任务堆栈由用户给出,一般是个数组,该参数值就是这个数组的大小
  • pvParameters
    传递给任务的参数
  • uxPriotiry
    任务优先级。范围是0~ configMAX_PRIORITIES-1
  • puxStackBuffer
    任务堆栈。一般为数组。数组类型要为 StackType_t 类型
  • pxTaskBuffer
    任务控制块

该函数的返回值如下

  • NULL
    任务创建失败(puxStackBuffer 或 pxTaskBuffer 为 NULL 的时候会导致这个错误的发生)
  • 其他值
    任务创建成功,返回任务的任务句柄

1.3 vTaskDelete()函数

使用任务删除函数时,需要开启“INCLUDE_vTaskDelete”宏定义。

删除一个用函数 xTaskCreate()或者 xTaskCreateStatic0创建的任务,被删除了的任务不再存在,也就是说再也不会进入运行态。任务被删除以后就不能再使用此任务的句柄。

如果此任务是使用动态方法创建的,也就是使用函数 xTaskCreate()创建的,那么在此任务被删除以后此任务之前申请的堆栈和控制块内存会在空闲任务中被释放掉,因此当调用函数 vTaskDelete()删除任务以后,必须给空闲任务一定的运行时间。

只有那些由内核分配给任务的内存才会在任务被删除以后自动的释放掉,用户分配给任务的内存需要用户自行释放掉,比如某个任务中用户调用函数 pvPotMalloc()分配了 500 字节的存,那么在此任务被删除以后用户也必须调用函数 vPortFree()将这 500 字节的内存释放掉,否则会导致内存泄露。

该函数的输入参数如下,无返回值

  • xTaskToDelete
    要删除的任务的任务句柄。如果在某函数中需要调用该函数删除自身,那么该参数写NULL即可。

二、任务创建和删除(动态方法)

下面根据正点原子提供的一个实验项目,学习一下上面任务创建与删除函数的使用。

2.1 任务要求

创建三个任务,分别是start_task,task1_task,task2_task,这三个任务的功能如下

  • start_task
    用来创建其他两个任务
  • task1_task
    此任务运行5次以后,调用任务删除函数vTaskDelete()删除task2_task。该任务也会控制LED0闪烁
  • task2_task
    该任务控制LED1的闪烁

2.2 程序设计

裸机状态下的主程序如下

int main(void)
{ 	 
	Med_Mcu_Iint();   // 系统初始化
	
	while (1)
	{
		// 具体处理
	}
}

使用操作系统时,首先要创建任务

void xxx_task (void *pxCreatedTask);   // 任务函数

int main (void)
{
	Med_Mcu_Iint();   // 系统初始化
	
    //创建任务
    xTaskCreate((TaskFunction_t )pxTaskCode,            //任务函数
                (const char*    )pcName,                //任务名称
                (uint16_t       )usStackDepth,          //任务堆栈大小
                (void*          )pvParameters,          //传递给任务函数的参数
                (UBaseType_t    )uxPriority,            //任务优先级
                (TaskHandle_t*  )&pxCreatedTask);       //任务句柄 
}

void xxx_task (void *pxCreatedTask)
{
    while1{
    }
}

有了上面的框架,只需要给参数赋值即可。对于任务堆栈,任务优先级等参数,可以用宏定义的方式写。需要注意的是,优先级0不能使用。因为空闲任务需要使用优先级0。在开启任务调度器时,会自动创建一个空闲任务,该任务的任务优先级为优先级0。最高优先级也不可以使用。因为使用软件定时器时,系统需要有一个定时器任务来维护这个软件定时器。这个定时器任务的任务优先级是最高优先级。

2.2.1 创建开始任务

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		120  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task (void *pxCreatedTask);

//创建任务
xTaskCreate((TaskFunction_t )start_task,            //任务函数
            (const char*    )"start_task",          //任务名称
            (uint16_t       )START_STK_SIZE,        //任务堆栈大小
            (void*          )NULL,                  //传递给任务函数的参数
            (UBaseType_t    )START_TASK_PRIO,       //任务优先级
            (TaskHandle_t*  )&StartTask_Handler);   //任务句柄
void start_task (void *pxCreatedTask)
{
	//创建任务1
    xTaskCreate((TaskFunction_t )taks1_task,            //任务函数
                (const char*    )"taks1_task",          //任务名称
                (uint16_t       )TASK1_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )TASK1_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&TASK1Task_Handler);   //任务句柄
								
		//创建任务2
    xTaskCreate((TaskFunction_t )taks2_task,            //任务函数
                (const char*    )"taks2_task",          //任务名称
                (uint16_t       )TASK2_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )TASK2_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&TASK2Task_Handler);   //任务句柄 
		
		// 开始任务只需要执行一次,执行完成后删除即可
		vTaskDelete(StartTask_Handler); //删除开始任务
}

2.2.2 创建任务1和任务2

关于任务1和任务2的一些宏定义,这里就不再详细列出来了,下面是任务1和任务2的函数

void taks1_task (void *pxCreatedTask)
{
	u8 task1Cunt = 0;   // 任务1运行次数计数变量
	
	while (1)
	{
		task1Cunt = task1Cunt + 1;   // task1运行次数加1
		
		Med_Led_StateReverse(LED0);   // LED0状态取反
		vTaskDelay(500);   // 延时500ms
		
		// 运行5次后
		if (task1Cunt >= 5 && TASK2Task_Handler != NULL)
		{
			// 删除任务2
			vTaskDelete(TASK2Task_Handler);
			TASK2Task_Handler = NULL;
		}
	}
}
void taks2_task (void *pxCreatedTask)
{
	while (1)
	{
		Med_Led_StateCtrl(LED1,LED_ON);   // 点亮LED1
		vTaskDelay(200);   // 延时200ms
		
		Med_Led_StateCtrl(LED1,LED_OFF);   // 熄灭LED1
		vTaskDelay(800);   // 延时800ms
	}
}

需要注意的是,在删除任务时,需要判断一下要删除任务的任务句柄是否为无效(NULL)。

2.2.3 开启任务调度器

vTaskStartScheduler();          //开启任务调度

三、总结

在其他任务中删除另一个任务,可能会有很多后遗症,所以删除时最好是任务子自删除。

3.1 删除任务后任务句柄不是NULL

最初删除任务2的程序如下

// 运行5次后
if (task1Cunt >= 5)
{
	// 删除任务2
	vTaskDelete(TASK2Task_Handler);
}

发现在运行5次任务1之后,程序就卡住了。打断点发现,程序卡在了删除任务2那里。一直在删除任务2。在删除任务2之前加入判断,判断任务2的任务句柄是否为NULL。

// 运行5次后
if (task1Cunt >= 5 && TASK2Task_Handler != NULL)
{
	// 删除任务2
	vTaskDelete(TASK2Task_Handler);
}

发现程序依旧会卡在删除任务2这里。用Debug查看删除任务2后任务2的任务句柄的值。发现在删除任务2之后,任务2的任务句柄依旧是有值的。冲浪后发现,大家也遇到了这种情况。同时,也学到了一种简单粗暴的处理方法。在删除任务后,将被删除任务的任务句柄修改为NULL。

// 运行5次后
if (task1Cunt >= 5 && TASK2Task_Handler != NULL)
{
	// 删除任务2
	vTaskDelete(TASK2Task_Handler);
	TASK2Task_Handler = NULL;
}

修改完成后,程序运行正常。文章来源地址https://www.toymoban.com/news/detail-520319.html

到了这里,关于FreeRTOS学习笔记—任务创建和删除的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • (第48-59讲)STM32F4单片机,FreeRTOS【事件标志、任务通知、软件定时器、Tickless低功耗】【纯文字讲解】【】

    【吐血总结】FreeRTOS难点、Systick中断-滴答定时器、PendSV中断-任务切换、SVC中断-系统底层、时间片调度-时钟节拍【已完结】 (第1-8讲)STM32F4单片机,FreeRTOS基础知识总结【视频笔记、代码讲解】【正点原子】【原创】 (第9-10讲)STM32F4单片机,FreeRTOS任务创建和删除(动态方

    2024年02月01日
    浏览(65)
  • FreeRTOS学习之路,以STM32F103C8T6为实验MCU(序章——浅谈单片机以及FreeRTOS)

    学习之路主要为FreeRTOS操作系统在STM32F103(STM32F103C8T6)上的运用,采用的是标准库编程的方式,使用的IDE为KEIL5。 注意!!!本学习之路可以通过购买STM32最小系统板以及部分配件的方式进行学习,也可以通过Proteus仿真的方式进行学习。 后续文章会同时发表在个人博客(jaso

    2024年02月06日
    浏览(56)
  • STM32+FREERTOS任务堆栈大小

    在FREERTOS任务开发过程中,由于不知道具体需要分配多大的任务堆栈大小,就需要在开始开发阶段尽可能的多分配一些,不然在调试过程中会出现程序卡死或者数据通信异常的现象。 如何评估任务堆栈的分配大小问题,可以根据任务的规模以及所任务所需的数据空间大概进行

    2024年02月16日
    浏览(43)
  • STM32FreeRTOS任务通知(STM32cube高效开发)

    1、任务通知可模拟队列和信号量 任务通知是FreeRTOS另外一种进程间通信技术。不需要创建任何中间对象,可以直接从任务向任务或ISR向任务发送通知,传递一个通知值任务通知可以模拟二值信号量、计数信号量、或长度为1的消息队列,使用任务通知,一般效率更高,消耗内

    2024年03月13日
    浏览(49)
  • stm32 freertos多任务状态迁移,中断临界段,任务延时

    arm中SP,LR,PC寄存器以及其它所有寄存器以及处理器运行模式介绍 特权级与用户级的区别主要是某些寄存器能不能访问与修改: cortex M3/M4内核 特权级与用户级详解 Cortex-M3双堆栈MSP和PSP Cortex-M3双堆栈MSP和PSP M3内核何时使用MSP何时使用PSP? 特权级可以使用MSP 和PSP指针 用户级

    2024年02月12日
    浏览(57)
  • 【STM32】利用CubeMX对FreeRTOS用按键控制任务

    对于FreeRTOS中的操作,最常用的就是创建、删除、暂停和恢复任务。 此次实验目标: 1.创建任务一:LED1每间隔1秒闪烁一次,并通过串口打印 2.创建任务二:LED2每间隔0.5秒闪烁一次,并通过串口打印 3.创建任务三:通过KEY1实现对任务一的创建和删除。 按键按下以后如果有任

    2024年02月13日
    浏览(70)
  • FreeRTOS笔记【一】 任务的创建(动态方法和静态方法)

    函数 描述 xTaskCreate() 使用动态的方法创建一个任务 xTaskCreateStatic() 使用静态的方法创建一个任务 xTaskCreateRestricted() 创建一个使用MPU进行限制的任务,相关内存使用动态内存分配 vTaskDelete() 删除一个任务 使用  xTaskCreate()  函数是在 FreeRTOS 中创建任务的一种方法, 使用该函数

    2024年02月05日
    浏览(32)
  • STM32单片机入门学习笔记——MPU6050

    笔记整理自B站UP主江科大自化协教程《[10-2] MPU6050简介_哔哩哔哩_bilibili》,所用单片机也为教程推荐单片机。 如果芯片里再集成一个3轴的磁场传感器,测量XYZ轴的磁场强度,那就叫做9轴姿态传感器,如果再集成一个气压传感器,测量气压大小,那就叫做10轴姿态传感器,一

    2024年02月08日
    浏览(52)
  • FreeRTOS_Stm32F103系列单片机标准库移植

    链接:FreeRTOS 下面的教程是基于从github下载压缩包进行的,最好下载这个或者直接看3.1,从我百度网盘下载。如果是别的下载源也问题不大,大同小异。 此时我们需要下载以下两个仓库, 点进去按下面的步骤下载就行了,另一个也是这样下。 链接: FreeRTOS官网 打开链接我们

    2024年01月22日
    浏览(53)
  • STM32初学者入门FreeRTOS操作系统,多任务实时系统

            FreeRTOS(Free Real-Time Operating System)是一个开源的嵌入式实时操作系统,它专门设计用于在资源有限的嵌入式系统中运行。FreeRTOS提供了一些用于任务管理、调度、同步和通信的功能,使开发者能够轻松地创建可靠的嵌入式系统。 以下是FreeRTOS的一些特点和功能: 轻量

    2024年02月11日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包