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

2023-11-02

一、任务创建和删除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();          //开启任务调度

三、总结

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

5.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;
}

修改完成后,程序运行正常。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS学习笔记—任务创建和删除 的相关文章

  • 【模板】一维前缀和与一维差分

    文章目录 1 一维前缀和 1 1 求解一维前缀和数组 1 2 区间查询 2 一维差分 2 1 定义 2 2 区间修改 2 3 初始化 前缀和是一种极其优秀的线性结构 也是一种重要的思想 能极大地降低区间查询的时间复杂度 为了方便 涉及到前缀
  • PyCharm 集成安装PyQt5及其工具(Qt Designer、PyUIC)

    注意 本文基于Python3 搭建Qt5 环境 进行相关工具完善总结 Qt Designer 安装 一 点击菜单栏 File 弹出下拉框 选择 Setting 弹出设置界面 在设置界面中选择 Tools External Tools 该部分
  • Xilinx Vivado开发环境之Timing Constraints的使用

    引言 随着设计复杂度和调用IP丰富度的增加 在调试时序约束的过程中 用户常常会对除了顶层约束外所涉及的繁杂的时序约束感到困惑而无从下手 举个例子 XDC里面并没有指定set false path 为什么有些路径在分析时忽略了 我怎么去定位这
  • 2021电赛资源及经验总结

    电赛总结 苦逼的电赛终于结束 人生很难得的一次经历 非常值得总结和怀念 为此特写一篇文章 本文章目的在于为广大电赛小白和电赛老白提供资源和经验上的帮助 如果需要电赛资源或者有任何问题的可以联系我 微信 wpt666aaa 或QQ 20367
  • 为Nginx申请和使用Let‘s Encrypt的SSL免费证书

    文章目录 一 certbot是什么 二 获取SSL免费证书 2 1 部署certbot 2 2 获取证书 2 3 配置证书 三 更新证书 一 certbot是什么 我们申请和使用Let s Encrypt的免费HTTPS证书 就需要一个证书
  • CSS中英文换行问题

    1 word break break all 只对英文起作用 以字母作为换行依据 2 word wrap break word 只对英文起作用 以单词作为换行依据 3 white space pre wrap 只对中文起作用 强制换行 4

随机推荐

  • springboot读取静态json文件数据

    springboot读取静态json文件数据 json数据如下 code 1 data avatar https randy168 com 1533262153771 gif name admin roles admin data inde
  • 华为认证之HCIP-Video Conference

    目录 Wireshark抓包工具介绍 1 1 Wireshark的界面组成 1 2 Wireshark的基本操作 H 323协议体系 2 1 H 323协议基础 2 2 会议调度信令流程 2 3 常见故障定位分析 SIP协议原理 3 1 概
  • tensorflow自定义激活函数

    前言 因为研究工作的需要 要更改激活函数以适应自己的网络模型 但是单纯的函数替换会训练导致不能收敛 这里还有些不清楚为什么 希望有人可以给出解释 查了一些博客 发现了解决之道 下面将解决过程贴出来供大家指正 1 背景 之前听某位老师提到说t
  • 摄像头参数介绍 ———— 信噪比(SNR)

    文章目录 介绍 计算 提升 方法1 增加曝光时间 方法2 多帧图像平均 方法3 像素融合Binning 方法4 使用QE更高的摄像头 方法5 使用像元尺寸更大的摄像头 方法6 去噪 介绍 信噪比 英文名称叫做SNR或S N SIGNAL N
  • git日常工作中常用指令

    git常用日常开发指令 引言 常用git指令 引言 日常开发中 无论是多人开发还是一个人开发 都需要一个好的代码管理仓库 于是掌握git常用的日常开发指令非常重要 常用git指令 重命名本地分支 不需要切换到其它分支下 git branch
  • 蓝桥杯算法训练VIP-比赛安排

    题目 题目链接 题解 DFS 本题我们要开两个标记数组 flag数组是个二维数组 用于标记某两只队伍是否进行过比赛了 另一是一维数组vis 用于标记某只队伍是否比过赛 两个数组的作用范围不同 vis数组只在每一行中有效 每到下一行时 vis
  • freeimage例子资料整理

    关于freeimage的一些实例代码 对学习freeimage很有帮助 about freeimage http www pudn com downloads169 sourcecode graph texture mapping deta
  • Kettle中“排序记录”的使用

    排序记录 作用很简单 就是对字段进行排序 一般很都是配合 去除重复记录 和 记录集连接 使用的 这里就简单介绍下排序记录的使用 核心对象 gt 转换 gt 排序记录 将 排序记录 拖拽到转换页面 配置参数 选择排序字段 data2 然后选择
  • HTML特殊字符符号大全

    HTML常用特殊字符 只要你认识了 HTML 标记 你便会知道特殊字符的用处 HTML 原代码 显示结果 描述 lt lt 小于号或显示标记 gt gt 大于号或显示标记 amp 可用于显示其它特殊字符 quot 引号 reg 已注册 co
  • C++ day2

    https note youdao com s BGiSQ9uwhttps note youdao com s BGiSQ9uw 封装一个结构体 结构体中包含一个私有数组 用来存放学生的成绩 包含一个私有变量 用来记录学生个数 提供一个公有
  • 范式建模和维度建模区别

    范式建模是只一份文件 维度建模是只一类文件
  • POJ1338~~~~~~丑数(经典dp)

    include
  • Android实战经验之图像处理及特效处理的集锦(总结版)

    1 Android学习笔记进阶之在图片上涂鸦 能清屏 2 Android学习笔记之详细讲解画圆角图片 3 Android学习笔记进阶20之得到图片的缩略图 4 Android学习笔记进阶19之给图片加边框 5 Android学习笔记进阶18
  • mac下hive-1.2.2-src版本的编译

    文章目录 1 下载 1 下载 官网 https github com apache hive 2 导入IDEA 进行编译 mvn clean install Phadoop 2 dist DskinpTests Dhadoop 23 ver
  • 软件测试自学怎么学?

    很多朋友想要入行软件测试 但是都不知道该怎么学 抽个时间简单的给大家说下 对于0基础的朋友 应该怎么去学习软件测试 学习软件测试有2条路可以选 1 最省事的当然是找个靠谱的培训机构去培训啦 你就什么都不用想了 跟着培训结构认真的学习就行了
  • shell 如何判断某个文件名以某个字符开头

    问题 shell 如何判断某个文件名以某个字符开头 解决 var cn get the length of me 1 parameter 1 传要判断的文件名字 var 1 isCN false var 0 2 取var子串 从第0个字符起
  • unity2019中虚拟按钮的使用

    版本 unity2019 4 12f1 Visual Studio2019 1 window栏加入Vuforia Engine AR 此时可以正常使用AR相机了 2 利用vuforia码 建立一个空物体showcube 然后在空物体上加入V
  • Pywin32:Python库的简介、安装和使用攻略

    Pywin32 Python库的简介 安装和使用攻略 Pywin32是Python的一个强大而广泛使用的库 它提供了访问Windows API的接口 以实现处理Windows系统资源的功能 如窗口管理 注册表操作 消息传递等等 这里我们将为
  • 遗传算法解决TSP问题

    一 背景 遗传算法是基于自然选择和自然遗传机制的一种随机搜索算法 具有良好的并行性和全局寻优能力 能够自适应地调整搜索方向 这是一种相对来说比较简单的算法 因为它不需要问题求解者具备非常完备的问题领域知识 它能够通过类似生物体繁殖后代的机制
  • FreeRTOS学习笔记—任务创建和删除

    文章目录 一 任务创建和删除API函数 1 1 xTaskCreate 函数 1 2 xTaskCreateStatic 函数 1 3 vTaskDelete 函数 二 任务创建和删除 动态方法 2 1 任务要求 2 2 程序设计 2 2