【学习日记】【FreeRTOS】任务句柄、任务控制块TCB、任务栈、任务、就绪表详解

写在前面

本文是对FreeRTOS中任务句柄、任务控制块TCB、任务栈、任务、就绪表详解。

一、裸机和RTOS中函数存储位置详解

  • 左图为裸机开发时 RAM 的使用情况,右图是使用了 FreeRTOS 后 RAM 的使用情况(图片来自野火)。
    在这里插入图片描述
  • 无论是裸机开发还是FreeRTOS,程序都需要存放在RAM中以便执行。不过,在裸机开发环境下,程序员需要手动管理和分配内存,而在FreeRTOS中,操作系统会自动管理内存。

二、什么是任务句柄

任务句柄(Task Handle)是在 FreeRTOS 中用于标识和引用任务的数据类型。每个创建的任务都会分配一个唯一的任务句柄,通过该句柄可以对任务进行操作和管理。

任务句柄是一个指向任务控制块(Task Control Block,TCB)的指针。任务控制块是 FreeRTOS 中用于描述和管理任务的数据结构,包含了任务的状态、优先级、堆栈等信息。

使用任务句柄,可以通过 FreeRTOS 提供的 API 函数对任务进行操作,例如挂起(suspend)、恢复(resume)、删除(delete)任务,或者查询任务的状态等。另外,任务句柄还可以用于任务通信和同步的机制,例如向任务发送信号量或消息。

在创建任务时,通过调用 FreeRTOS 提供的任务创建函数(例如 xTaskCreate())可以获取到相应任务的句柄。你可以将该句柄保存在一个变量中,以便后续对该任务进行操作或引用。

例如,以下示例演示了如何创建一个任务并获取其句柄:

// 创建任务
TaskHandle_t xTaskHandle;
xTaskCreate(taskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTaskHandle);

// 使用任务句柄进行操作
vTaskSuspend(xTaskHandle);  // 挂起任务
vTaskResume(xTaskHandle);   // 恢复任务
vTaskDelete(xTaskHandle);   // 删除任务

在上述示例中,xTaskCreate() 函数创建了一个名为 “Task” 的任务,并将该任务的任务句柄保存在 xTaskHandle 变量中。然后,我们可以使用任务句柄对任务进行挂起、恢复和删除操作。

任务句柄提供了一种有效的方式来管理和操作 FreeRTOS 中的任务。通过使用任务句柄,可以方便地对任务进行控制和监视。

三、概念图解

在这里插入图片描述

四、函数详解

1.任务创建 static void prvInitialiseNewTask(…)

  • 这个函数用于创建新的任务,其中的 “prv” 表示该函数是一个私有函数,只用于内部处理和初始化新任务的操作。对于外部使用者来说,应该使用公开的 API 函数来创建和管理任务,而不是直接调用 “prvInitialiseNewTask”。
  • 这个函数被 TaskHandle_t xTaskCreateStatic() 函数调用
  • 函数源代码如下:
static void prvInitialiseNewTask( 	TaskFunction_t pxTaskCode,              /* 任务入口 */
									const char * const pcName,              /* 任务名称,字符串形式 */
									const uint32_t ulStackDepth,            /* 任务栈大小,单位为字 */
									void * const pvParameters,              /* 任务形参 */
									TaskHandle_t * const pxCreatedTask,     /* 任务句柄 */
									TCB_t *pxNewTCB )                       /* 任务控制块指针 */

{
	StackType_t *pxTopOfStack;
	UBaseType_t x;	
	
	/* 获取栈顶地址 */
	pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
	//pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
	/* 向下做8字节对齐 */
	pxTopOfStack = ( StackType_t * ) ( ( ( uint32_t ) pxTopOfStack ) & ( ~( ( uint32_t ) 0x0007 ) ) );	

	/* 将任务的名字存储在TCB中 */
	for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
	{
		pxNewTCB->pcTaskName[ x ] = pcName[ x ];

		if( pcName[ x ] == 0x00 )
		{
			break;
		}
	}
	/* 任务名字的长度不能超过configMAX_TASK_NAME_LEN */
	pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';

    /* 初始化TCB中的xStateListItem节点 */
    vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
    /* 设置xStateListItem节点的拥有者 */
	listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
    
    
    /* 初始化任务栈 */
	pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );   


	/* 让任务句柄指向任务控制块 */
    if( ( void * ) pxCreatedTask != NULL )
	{		
		*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
	}
}
  • 获取栈顶地址:
pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );

栈顶 = 栈起始地址 + 栈大小 -1

  • 获取到的栈顶地址需要做 8 字节对齐
pxTopOfStack = ( StackType_t * ) ( ( ( uint32_t ) pxTopOfStack ) & ( ~( ( uint32_t ) 0x0007 ) ) );

~ 是按位取反运算符。它会反转操作数的每一位,将所有的0变为1,将所有的1变为0。

在给定的代码中,~ 运算符用于创建一个掩码,该掩码在对齐操作中用于清除特定位的值。

( ~( ( uint32_t ) 0x0007 ) )

在这里,0x0007 是一个表示二进制数 0000 0111 的十六进制数,它具有最低的3位都是1,其他位都是0。通过 ~ 运算符对 0x0007 进行按位取反,得到的掩码就是所有最低的3位都是0,其他位都是1。

这样,当掩码与 pxTopOfStack 进行按位与操作时,最低的3位将被清零,而其他位将保持不变,pxTopOfStack 变量就被更新为按照8字节对齐的地址。

通常,在某些特定的编程环境中,需要按照特定的内存对齐要求来访问数据。这段代码将 pxTopOfStack 指针变量按照8字节对齐,以满足特定的对齐要求。

2.初始化任务栈 StackType_t *pxPortInitialiseStack(…)

通过栈顶指针对整个栈进行初始化,分为自动加载内容和手动加载内容。

  • 代码如下:
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
    /* 异常发生时,自动加载到CPU寄存器的内容 */
	pxTopOfStack--;
	*pxTopOfStack = portINITIAL_XPSR;	                                    /* xPSR的bit24必须置1 */
	pxTopOfStack--;
	*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK;	/* PC,即任务入口函数 */
	pxTopOfStack--;
	*pxTopOfStack = ( StackType_t ) prvTaskExitError;	                    /* LR,函数返回地址 */
	pxTopOfStack -= 5;	/* R12, R3, R2 and R1 默认初始化为0 */
	*pxTopOfStack = ( StackType_t ) pvParameters;	                        /* R0,任务形参 */
    
    /* 异常发生时,手动加载到CPU寄存器的内容 */    
	pxTopOfStack -= 8;	/* R11, R10, R9, R8, R7, R6, R5 and R4默认初始化为0 */

	/* 返回栈顶指针,此时pxTopOfStack指向空闲栈 */
    return pxTopOfStack;
}

在这里插入图片描述

3.初始化任务就绪列表

任务就绪列表的定义

任务就绪列表(Task Ready List)是用于存储当前准备就绪状态的任务的数据结构。

任务就绪列表是一个由多个优先级队列组成的数据结构,其中每个优先级队列维护了相同优先级的就绪任务。通过任务就绪列表,操作系统可以快速找到具有最高优先级的就绪任务,并将其调度到正在运行的任务。

当一个任务变为就绪状态时,它将被插入到适当的就绪列表中,而当一个任务被调度执行时,它将从就绪列表中被移除。

每个列表中存储相同优先级的任务,最大支持256个优先级,也就是最大有256个列表。

  • 定义5个优先级的任务就绪列表的代码:
#define configMAX_PRIORITIES		            ( 5 )	//最大列表数量

/* 任务就绪列表 */
List_t pxReadyTasksLists[ configMAX_PRIORITIES ];	//定义了5个任务就绪列表

任务就绪列表的初始化

循环调用列表初始化函数 vListInitialise() 进行初始化即可。

  • 代码如下:
/* 初始化任务相关的列表 */
void prvInitialiseTaskLists( void )
{
    UBaseType_t uxPriority;
    
    
    for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
	{
		vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );	//初始化每个就绪列表
	}
}

五、任务创建与初始化方法

1.定义任务栈大小,并定义任务栈存放任务上下文

//定义任务栈
#define TASK1_STACK_SIZE                    20
StackType_t Task1Stack[TASK1_STACK_SIZE];

2.定义任务控制块TCB

//定义任务控制块
TCB_t Task1TCB;

3.定义任务句柄(用于指向TCB)

//定义任务句柄
TaskHandle_t Task1_Handle;

4.定义任务函数并声明

void Task1_Entry( void *p_arg );

//定义任务函数(无限循环不返回)
void Task1_Entry(void *p_arg)
{
	
	for(;;){
		//此处书写任务代码
		
	}
}

5.在main函数中,初始化所有的任务就绪列表

prvInitialiseTaskLists();	//初始化所有的任务就绪列表

6.在main函数中,创建任务,并使任务句柄指向TCB

//任务创建函数的函数原型:
TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,           /* 任务入口 */
					            const char * const pcName,           /* 任务名称,字符串形式 */
					            const uint32_t ulStackDepth,         /* 任务栈大小,单位为字 */
					            void * const pvParameters,           /* 任务形参 */
					            StackType_t * const puxStackBuffer,  /* 任务栈起始地址 */
					            TCB_t * const pxTaskBuffer );         /* 任务控制块指针 */

//创建任务,并使任务句柄指向TCB
Task1_Handle = xTaskCreateStatic(Task1_Entry,
						"Task1",
						TASK1_STACK_SIZE,
						NULL,
						Task1Stack,
						&Task1TCB);

7.将任务控制块中的任务项插入一个就绪列表中

vListInsert(&pxReadyTasksLists[1], &Task1TCB.xStateListItem);

后记

如果您觉得本文写得不错,可以点个赞激励一下作者!
如果您发现本文的问题,欢迎在评论区或者私信共同探讨!
共勉!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Rust】Rust学习 第四章认识所有权

第四章认识所有权 所有权&#xff08;系统&#xff09;是 Rust 最为与众不同的特性&#xff0c;它让 Rust 无需垃圾回收&#xff08;garbage collector&#xff09;即可保障内存安全。因此&#xff0c;理解 Rust 中所有权如何工作是十分重要的。 4.1 所有权 所有运行的程序都…

python-02(入门基础篇2——基本常见语法)

python-02&#xff08;入门基础篇2——基本常见语法&#xff09; 1. 逻辑判断词1.1 布尔类型1.1.1 python为False的情况 1.2 逻辑判断词 not 2. for 语句2.1 语法结构2.2 例子2.2.1 例子1——循环迭代字符串2.2.2 例子2——进行数值循环2.2.2.1 简单循环&#xff08;结合range函…

Kafka入门,保姆级教学

文章目录 Kafka概念消息中间件对比消息中间件对比-选择建议Kafka常用名词介绍Kafka入门1. Kafka安装配置2.Kafka生产者与消费者关系3.Kafka依赖4.生产者发消息5.消费者接受消息6.Kafka高可用性设计6.1集群Kafka备份机制(Reolication) 7.kafka生产者详解7.1 发送类型7.2参数详解…

ChatGPT已闯入学术界,Elsevier推出AI工具

2022年11月&#xff0c;OpenAI公司发布了ChatGPT&#xff0c;这是迄今为止人工智能在现实世界中最重要的应用之一。 当前&#xff0c;互联网搜索引擎中出现了越来越多的人工智能&#xff08;AI&#xff09;聊天机器人&#xff0c;例如谷歌的Bard和微软的Bing&#xff0c;看起来…

Java中VO,BO,PO,DO,DTO的区别

术语解释&#xff1a; VO&#xff08; View Object&#xff09;&#xff1a;显示层对象&#xff0c;通常是Web向模板渲染引擎层传输的对象。 BO&#xff08; Business Object&#xff09;&#xff1a;业务对象。 由Service层输出的封装业务逻辑的对象。 DO&#xff08; Data…

chatGLM 本地部署(windows+linux)

chatGLM算是个相对友好的模型&#xff0c;支持中英文双语的对话交流&#xff0c;清华出的 我的教程无需特别的网络设置&#xff0c;不过部分情况因为国内网络速度慢&#xff0c;需要反复重复 chatGLM github地址 一、硬件需求 N卡8G显存以上&#xff0c;最好16G以上&#xff…

openGauss学习笔记-36 openGauss 高级数据管理-TRUNCATE TABLE语句

文章目录 openGauss学习笔记-36 openGauss 高级数据管理-TRUNCATE TABLE语句36.1 语法格式36.2 参数说明36.3 示例 openGauss学习笔记-36 openGauss 高级数据管理-TRUNCATE TABLE语句 清理表数据&#xff0c;TRUNCATE TABLE用于删除表的数据&#xff0c;但不删除表结构。也可以…

【网络模块】数传DTU(USR-DR150)进行MQTT通讯

文章目录 [TOC] 准备资料软件硬件硬件接线 USR-CAT1 V1.1.4配置 USR-DR15X 是一款有人物联网推出的“口红DTU”&#xff0c;也称为超小体积导轨式DTU&#xff0c;该产品具有体积小巧、集成SIM卡、蓝牙配置、导轨和挂耳安装方便的特征&#xff1b;Cat-1系列产品具备高速率、低延…

C++中的typeid

2023年8月10日&#xff0c;周四下午 目录 概述typeid的用法用法1用法2用法3举例说明 概述 typeid是 C 中的运算符&#xff0c;用于获取表达式或类型的运行时类型信息。 它返回一个std::type_info对象&#xff0c;该对象包含有关类型的信息&#xff0c;例如类型的名称。 type…

Java正确的错误捕获姿态

理论概述 在Java中&#xff0c;捕获异常并且合理地处理或抛出异常是编写健壮和可靠代码的关键部分。但是有时候我们可能会对各种错误的捕获方法有点模棱两可&#xff0c;不知道怎么合适的去使用&#xff0c;这里作为基础知识我们做一个回顾巩固&#xff01;只有正确的开发方法…

Arcgis将一个shp依照属性表导出为多个shp

# -*- coding:utf-8 -*-import arcpy import osfrom arcpy import env#env.workspace "./" #自己设置路径shp rC:\Users\Administrator\Desktop\Lake\xxx.shp #shp文件路径outpath r"C:\Users\Administrator\Desktop\Lake\fenli" #输出结果路径with arc…

IP提取器对比器

需求&#xff1a; 一个html 页面 &#xff0c;有两个输入框 第一个输入框输入文本中包含多个ip&#xff0c;输入的ip是不规则的&#xff0c;需要使用正则表达式提取出 输入文本的ip地址 &#xff0c; 然后在第二个输入框中输入内容&#xff0c;并提取出内容的ip &#xff0c;如…

VR全景在建筑工程行业能起到哪些作用?

在建筑工程领域&#xff0c;数字化技术为行业的发展起到巨大的推动作用&#xff0c;虽然建筑施工行业主要是依赖于工人劳动力和施工设备&#xff0c;但是VR全景在该行业中方方面面都能应用&#xff0c;从设计建模到项目交付&#xff0c;帮助建筑师以及项目方更好的理解每个环节…

Go语言进阶

个人笔记&#xff0c;大量摘自Go语言高级编程、Go|Dave Cheney等 更新 go get -u all 在非go目录运行go install golang.org/x/tools/goplslatest更新go tools&#xff1a;在go目录运行go get -u golang.org/x/tools/...&#xff0c;会更新bin目录下的应用&#xff1b; 运行…

灰度非线性变换之c++实现(qt + 不调包)

本章介绍灰度非线性变换&#xff0c;具体内容包括&#xff1a;对数变换、幂次变换、指数变换。他们的共同特点是使用非线性变换关系式进行图像变换。 1.灰度对数变换 变换公式&#xff1a;y a log(1x) / b&#xff0c;其中&#xff0c;a控制曲线的垂直移量&#xff1b;b为正…

两个状态的马尔可夫链

手动推导如下公式。 证明&#xff1a; 首先将如下矩阵对角化&#xff1a; { 1 − a a b 1 − b } \begin {Bmatrix} 1-a & a \\ b & 1-b \end {Bmatrix} {1−ab​a1−b​} (1)求如下矩阵的特征值&#xff1a; { 1 − a a b 1 − b } { x 1 x 2 } λ { x 1 x 2 }…

数据结构——空间复杂度

3.空间复杂度 空间复杂度也是一个数学表达式&#xff0c;是对一个算法在运行过程中临时占用存储空间大小的量度 。 空间复杂度不是程序占用了多少bytes的空间&#xff0c;因为这个也没太大意义&#xff0c;所以空间复杂度算的是变量的个数。 空间复杂度计算规则基本跟实践复杂…

yolov5代码解读之yolo.py【网络结构】

​这个文件阿对于做模型修改、模型创新有很好大好处。 首先加载一些python库和模块&#xff1a; 如果要执行这段代码&#xff0c;直接在终端输入python yolo.py. yolov5的模型定义和网络搭建都用到了model这个类(也就是以下图片展示的东西)&#xff1a;&#xff08;以前代码没…

EasyPoi导出 导入(带校验)简单示例 EasyExcel

官方文档 : http://doc.wupaas.com/docs/easypoi pom的引入: <!-- easyPoi--><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><version>4.0.0</version></dep…

学习笔记-JVM-工具包(JVM分析工具)

常用工具 JDK工具 ① jps: JVM Process status tool&#xff1a;JVM进程状态工具&#xff0c;查看进程基本信息 ② jstat: JVM statistics monitoring tool &#xff1a; JVM统计监控工具&#xff0c;查看堆&#xff0c;GC详细信息 ③ jinfo&#xff1a;Java Configuration I…