【学习日记】【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);

后记

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【docker】设置 docker 国内镜像报错,解决方案

一、报错&#xff1a; [rootlocalhost ~]# systemctl restart docker Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.二、原因&#xf…

实现分布式事务:Java与MySQL的XA事务协调

目录 一、什么是XA事务 二、Java中的XA事务支持 三、MySQL的XA事务协调 四、注意事项和最佳实践 五、基于 java 语言的开发工具 六、小结 分布式事务是在跨多个数据库或服务之间保持一致性的重要机制。Java与MySQL的XA&#xff08;eXtended Architecture&#xff09;事务…

NPM包的安装、更新、卸载

目录 1、下载安装全局包 2、解决全局安装包时的EACCES权限错误 2.1 重新安装NPM 2.2 手动更改npm的默认目录 3、更新从注册表下载的包 3.1 更新本地包 3.2 更新全局安装的软件包 3.3 确定哪些全局包需要更新 3.4 更新单个全局包 3.5 更新所有全局安装的软件包 4、在项…

【ASP.NET MVC】使用动软(五)(13)

一、问题 前文完成的用户登录后的首页如下&#xff1a; 后续账单管理、人员管理等功能页面都有相同的头部&#xff0c;左边和下边&#xff0c;唯一不同的右边内容部分&#xff0c;所以要解决重复设计的问题。 二、解决方法——使用布局页 在Views上右键添加新建项&#xff…

多维时序 | MATLAB实现ZOA-CNN-BiGRU-Attention多变量时间序列预测

多维时序 | MATLAB实现ZOA-CNN-BiGRU-Attention多变量时间序列预测 目录 多维时序 | MATLAB实现ZOA-CNN-BiGRU-Attention多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.Matlab基于ZOA-CNN-BiGRU-Attention斑马优化卷积双向门控循环单元网络…

【云原生】Kubernetes控制器中DaemonSet与Job的使用

目录 DaemonSet 1 什么是 DaemonSet 2 使用 DaemonSet Job 1 什么是 Job 2 使用 Job 3 自动清理完成的 Job 控制器无法解决问题 DaemonSet 1 什么是 DaemonSet DaemonSet | Kubernetes DaemonSet 确保全部&#xff08;或者某些&#xff09;节点上运行一个 Pod 的副本…

eeglab(自用)

目录 1.加载、显示数据 2.绘制脑电头皮图 3.绘制通道光谱图 4.预处理工具 5.ICA去除伪迹 5. 提取数据epoch 1.加载、显示数据 观察事件值(Event values)&#xff1a;该数据集中包含2400个事件&#xff0c;每个事件指定了EEG.event结构的字段Type(类型)、position(位置)和…

检测新突破 | AlignDet:支持各类检测器自监督新框架(ICCV2023)

引言 论文链接&#xff1a;https://arxiv.org/abs/2307.11077 项目地址&#xff1a;https://github.com/liming-ai/AlignDet 这篇论文主要研究目标检测领域的自监督预训练方法。作者首先指出&#xff0c;当前主流的预训练-微调框架在预训练和微调阶段存在数据、模型和任务上的…

【技巧】如何设置Word文档部分内容“限制编辑”?

我们知道&#xff0c;Word文档可以设置“限制编辑”&#xff0c;也就是保护文档不被随意更改。 那如果只想保护文档中的部分内容&#xff0c;其他内容还是随意编辑更改&#xff0c;是否可以设置部分内容“限制编辑”&#xff1f;答案是可以的&#xff0c;下面小编来举例说明一…

uniapp 格式化时间刚刚,几分钟前,几小时前,几天前…

效果如图&#xff1a; 根目录下新建utils文件夹&#xff0c;文件夹下新增js文件&#xff0c;文件内容&#xff1a; export const filters {dateTimeSub(data) {if (data undefined) {return;}// 传进来的data必须是日期格式&#xff0c;不能是时间戳//将字符串转换成时间格式…

msvcp120.dll丢失的解决方法,Win11系统报错处理方法

在使用Windows11系统的时候&#xff0c;出现报错msvcp120.dll丢失我们需要怎么去修复它呢&#xff1f;msvcp120.dll是Windows操作系统中的一个重要的动态链接库文件&#xff0c;它包含了许多用于C程序的函数和类。然而&#xff0c;有时候我们可能会遇到msvcp120.dll丢失或损坏的…

UI美工设计的主要职责(合集)

UI美工设计的主要职责1 职责&#xff1a; 1、执行公司的规章制度及专业管理办法; 2、 负责重点项目的原型设计和产品流程设计、视觉设计&#xff0c;优化网站和移动端的设计流程和规范&#xff0c;制定产品 UI/UE规范及文档编写; 3、负责使用PS、AI、illustrator、MarkMan、…

matplotlib FormatStrFormatter设置坐标轴的标注为整数和小数【设置小数点的数目】

利用FormatStrFormatter 进行设置 1 设置为整数 import matplotlib.pyplot as plt from matplotlib.ticker import FormatStrFormatter# 创建一个图表 fig, ax plt.subplots()# 生成一些示例数据 x [1, 2, 3, 4, 5] y [1000, 2000, 3000, 4000, 5000]# 在 x 轴上设置刻度标…

【前端】CSS水平居中的6种方法

左右两边间隔相等的居中 文章目录 flex绝对定位margin:auto绝对定位margin:负值定位transformtext-align: center;margin: 0 auto;思维导图 flex display: flex;justify-content: center; <div classparent><div class"son"></div> </div>…

uni-app:实现点击按钮,进行数据累加展示(解决数据过多,导致出错)

效果 代码 核心代码 一、标签显示 <!-- 加载更多 --> <view class"load_more" v-if"info.length > pageNum * pageSize" tap"loadMore">加载更多 </view> v-if"info.length > pageNum * pageSize"&#xf…

辽宁线上3D三维虚拟工厂生产仿真系统应用场景及优势

工厂虚拟仿真是一种基于计算机技术和虚拟现实技术的数字化解决方案&#xff0c;它可以通过模拟工厂中的设备、流程和操作&#xff0c;来为工程师和操作人员提供了一个沉浸式的虚拟环境&#xff0c;帮助他们更好地了解和优化工厂生产过程。 工厂VR三维可视化技术为工业生产提供了…

ruby send call 的简单使用

refer: ruby on rails - What does .call do? - Stack Overflow Ruby使用call 可以调用方法或者proc m 12.method("") # > method gets the method defined in the Fixnum instance # m.class # > Methodm.call(3) #> 15 # 3 is passed inside the…

LeetCode150道面试经典题--验证回文串(简单)

1.题目 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&#xff0c;如果它是 回文串 &#xff0c;返回 true &#xff1b;否…

uniapp 微信小程序 封装公共的请求js(api版本)

一、新建api文件夹 在项目目录下创建api文件夹&#xff0c;内放files跟index.js文件夹&#xff0c;files文件夹内放每个页面对应的js请求接口 1、index.js /*** api接口的统一出口*/ const api {}; const requireComponent require.context(./files, false, /\.js$/) requi…

SpringCloud实用篇2——Nacos配置管理 Feign远程调用 Gateway服务网关

目录 1 Nacos配置管理1.1 统一配置管理1.1.1 在nacos中添加配置文件1.1.2 从微服务拉取配置 1.2 配置热更新1.2.1 方式一1.2.2 方式二&#xff08;推荐&#xff09; 1.3.配置共享 2 搭建Nacos集群2.1 集群结构图2.2 搭建集群2.2.1 初始化数据库2.2.2 下载nacos2.2.3 配置Nacos2…