嵌入式FreeRTOS学习八,xTaskCreate创建任务的细节以及恢复中断任务实现

2023-05-16

一.创建任务函数xTaskCreate

任务也不是很复杂的东西,任务也就是一个函数xTaskCreate。简单得说,创建一个任务,你得提供它的执行函数,你得提供它的栈的大小,函数的执行空间,函数的优先级等重要的条件。因为任务在运行中,任务函数有调用关系,有局部变量,这些都保存在任务的栈里面;任务有可能被切换,有可能被暂停,这时候CPU寄存器中断现场数据都保存在栈里面。

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
                        const char * const pcName, 
/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                        const configSTACK_DEPTH_TYPE usStackDepth,
                        void * const pvParameters,
                        UBaseType_t uxPriority,
                        TaskHandle_t * const pxCreatedTask )

参数说明:
(1)TaskFunction_t   : typedef   void   (*TaskFunction_t)( void * );    函数指针
(2)const  char  *  const  pcName  :  任务名字
(3)configSTACK_DEPTH_TYPE   :   #define  configSTACK_DEPTH_TYPE   uint16_t   是无符号的2字节数值,表示栈的深度大小,实际由malloc函数分配大小
(4)void  *  const  pvParameters  :是要传入的参数
(5)UBaseType_t   uxPriority   :    typedef  unsigned   short   UBaseType_t;  是一个无符号的整形数,表示优先级的大小,数值越大优先级越大
(6)TaskHandle_t  *  const   pxCreatedTask :这里面有一个TCB结构体指针,传出去的参数

 

TCB_t的全称为Task Control Block,也就是任务控制块,这个结构体包含了一个任务所有的信息,但是源代码中存在大量的条件配置选项,以下屏蔽掉的都是可以通过条件来配置的选项,通过条件来决定哪些定义使用或者不用,暂时不需要用到这些,对条件配置项进行屏蔽,TCB最主要的参数在上面它的定义以及相关变量的解释如下

typedef struct tskTaskControlBlock             
    {
        // 这里栈顶指针必须位于TCB第一项是为了便于上下文切换操作,详见xPortPendSVHandler中任务切换的操作。
        volatile StackType_t    *pxTopOfStack;    

       
        // 表示任务状态,不同的状态会挂接在不同的状态链表下
        ListItem_t            xStateListItem;    
        // 事件链表项,会挂接到不同事件链表下
        ListItem_t            xEventListItem;        
        // 任务优先级,数值越大优先级越高
        UBaseType_t            uxPriority;            
        // 指向堆栈起始位置,这只是单纯的一个分配空间的地址,可以用来检测堆栈是否溢出
        StackType_t            *pxStack;            
        // 任务名
        char                pcTaskName[ configMAX_TASK_NAME_LEN ];

/*
//以下屏蔽掉的都是可以通过条件来配置的选项,通过条件来决定哪些定义使用或者不用,暂时不需要用到这 
//些,屏蔽掉,TCB最主要的参数在上面
//#####################################################################################

        // MPU相关暂时不讨论
        #if ( portUSING_MPU_WRAPPERS == 1 )
            xMPU_SETTINGS    xMPUSettings;        
        #endif
        // 指向栈尾,可以用来检测堆栈是否溢出
        #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
            StackType_t        *pxEndOfStack;        
        #endif

        // 记录临界段的嵌套层数
        #if ( portCRITICAL_NESTING_IN_TCB == 1 )
            UBaseType_t        uxCriticalNesting;    
        #endif
        // 跟踪调试用的变量
        #if ( configUSE_TRACE_FACILITY == 1 )
            UBaseType_t        uxTCBNumber;        
            UBaseType_t        uxTaskNumber;        
        #endif
        // 任务优先级被临时提高时,保存任务原本的优先级
        #if ( configUSE_MUTEXES == 1 )
            UBaseType_t        uxBasePriority;        
            UBaseType_t        uxMutexesHeld;
        #endif
        // 任务的一个标签值,可以由用户自定义它的意义,例如可以传入一个函数指针可以用来做Hook    函数调用
        #if ( configUSE_APPLICATION_TASK_TAG == 1 )
            TaskHookFunction_t pxTaskTag;
        #endif

        // 任务的线程本地存储指针,可以理解为这个任务私有的存储空间
        #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
            void            *pvThreadLocalStoragePointers[     configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
        #endif

        // 运行时间变量
        #if( configGENERATE_RUN_TIME_STATS == 1 )
            uint32_t        ulRunTimeCounter;    
        #endif

        // 支持NEWLIB的一个变量
        #if ( configUSE_NEWLIB_REENTRANT == 1 )
            struct    _reent xNewLib_reent;
        #endif
        // 任务通知功能需要用到的变量
        #if( configUSE_TASK_NOTIFICATIONS == 1 )
            // 任务通知的值 
            volatile uint32_t ulNotifiedValue;
            // 任务通知的状态
            volatile uint8_t ucNotifyState;
        #endif
        // 用来标记这个任务的栈是不是静态分配的
        #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) 
            uint8_t    ucStaticallyAllocated;         
        #endif

        // 延时是否被打断
        #if( INCLUDE_xTaskAbortDelay == 1 )
            uint8_t ucDelayAborted;
        #endif
        // 错误标识
        #if( configUSE_POSIX_ERRNO == 1 )
            int iTaskErrno;
        #endif
//###################################################################################
*/
    } tskTCB;
    typedef tskTCB TCB_t;

=========================================================================

二.创建任务的具体内部细节

以简单的任务创建函数为例,这里分别创建了三个简单任务vTask1,vTask2,vTask3

void vTask1( void *pvParameters )
{    /* 任务函数的主体一般都是无限循环 */
	for( ;; )
	{
		flagIdleTaskrun = 0;
		flagTask1run = 1;
		flagTask2run = 0;
		flagTask3run = 0;
		/* 打印任务的信息 */
		printf("T1\r\n");				
    }
}
void vTask2( void *pvParameters )
{	
	/* 任务函数的主体一般都是无限循环 */
	for( ;; )
	{
		flagIdleTaskrun = 0;
		flagTask1run = 0;
		flagTask2run = 1;
		flagTask3run = 0;
		/* 打印任务的信息 */
		printf("T2\r\n");				
	}
}

void vTask3( void *pvParameters )
{	
	const TickType_t xDelay5ms = pdMS_TO_TICKS( 5UL );		
	
	/* 任务函数的主体一般都是无限循环 */
	for( ;; )
	{
		flagIdleTaskrun = 0;
		flagTask1run = 0;
		flagTask2run = 0;
		flagTask3run = 1;
		/* 打印任务的信息 */
		printf("T3\r\n");				
		// 如果不休眠的话, 其他任务无法得到执行
		vTaskDelay( xDelay5ms );
	}
}
//主函数的实现
int main( void )
{
	prvSetupHardware();	
	xTaskCreate(vTask1, "Task 1", 1000, NULL, 0, NULL);
	xTaskCreate(vTask2, "Task 2", 1000, NULL, 0, NULL);
	xTaskCreate(vTask3, "Task 3", 1000, NULL, 2, NULL);
    /* 启动调度器 */
	vTaskStartScheduler();
    /* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
	return 0;
}

三.TCB任务结构体在RAM内存中的存在

下面的图中,将一整个tsTaskControlBlock结构体代码数据放入RAM内存中,表示出在内存中分配一个TCB结构体的效果(只画图表示效果,实际上可能不完全一样);可以看到,在RAM内存中分配的栈空间保存的数据有:

栈顶指针pxTopOfStack;  指向划分出来的内存空间的最后一个数据保存的位置
状态链表xStateListItem;
事件链表 xEventListItem;    
任务优先级 uxPriority;         
指向堆栈起始位置指针 pxStack;指向划分出来的内存空间的起始地址位置          
任务名 pcTaskName[ configMAX_TASK_NAME_LEN ];

 =========================================================================

四.任务函数创建时栈空间分配和大小的问题

//任务创建函数
xTaskCreate(vTask1, "Task 1", 1000, NULL, 0, NULL);

在创建这个任务的时候,传进来的参数是保存在哪里呢?首先看传进来的栈的大小这个参数1000,这时需要弄明白两个问题。第一是栈是从哪里分配?第二是栈的大小怎么确定?

第一个问题栈是从哪里分配?栈其实就是一块空闲的内存,FreeRTOS的heap2.cpp文件中关于是定义了一个巨大的全局数组ucHeap,这个数组没人使用,作为一块空闲的内存,在以后的栈的空间的分配就从这个巨大的数组里面划分可用的内存,来给某个任务当做栈来使用,如上图所示;由宏定义可知数组的大小为17*1024个字节。

第二个问题,例子中栈的大小怎么确定?可以根据程序员出入的值的大小进行分配,例子中划分出1000*4字节的内存,然后内存的起始空间保存在pxStack指针中。

 =========================================================================

五.任务函数创建时函数指针和参数保存问题和作用

//任务创建函数
xTaskCreate(vTask1, "Task 1", 1000, NULL, 0, NULL);

第一个参数是函数指针xTaskCreat其实就是函数的地址addrF,当我们想要去启动这个任务,或者调用这个函数的时候,我们可以让CPU中的R15寄存器,也就是PC寄存器的值等于函数的地址。addrF即可。

第四个参数是随着函数传入的参数值,通常保存在R0寄存器中。

=========================================================================

六.任务处于暂停的状态恢复运行

系统从定义的全局数组ucHeap中分配可用的空间给任务函数xTaskCreate使用,例子中分配了1000*4的内存空间,pxStack指向内存开始的地址位置,pxTopOfStack指向内存中最后一个数据保存的位置。

我们在创建任务的时候,任务函数xTaskCreate已经创建了这部分内存,帮我们修改了RAM内存里面的内容,在TCB结构体里面,我们没有看到传入的参数和函数指针,其实任务函数已经把这些值写入了CPU内存中的R15和R0等寄存器,以便恢复任务时使用。

刚创建任务的时候,任务还没有运行,属于某种暂停状态,当任务被中断,系统将当前任务的寄存器入栈进行现场保护,其中包括R15函数返回地址,R0参数等;然后开始运行中断任务,中断任务结束,则开始恢复RAM内存中栈里面的各种寄存器现场,从R15函数返回地址开始执行,跳转回上一个被中断的任务,继续执行。如上图所示。

 

 

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

嵌入式FreeRTOS学习八,xTaskCreate创建任务的细节以及恢复中断任务实现 的相关文章

  • YOLOv3网络结构分析以及工作流程

    注意 xff1a 本文章有很多图 xff0c 但是都是YOLOv3的结构图 xff0c 只是每张图表达出的信息都各有特色 xff0c 可将这些结构图结合起来 xff0c 能更好的理解 1 Darknet 53 模型结构 在论文中虽然有给网络
  • Qt中QDebug的使用

    QDebug类为调试信息 debugging information 提供输出流 它的声明在 lt QDebug gt 中 xff0c 实现在Core模块中 将调试或跟踪信息 debugging or tracing information
  • Ubuntu18.04安装教程——超详细的图文教程

    电脑配置 xff1a 名称 xff1a Lenovo 拯救者Y7000P 处理器 xff1a i7 10750H 内存 xff1a 32G 固态 xff1a 1TB 显卡 xff1a RTX2060 6G 一 准备工作 本文以 Ubuntu
  • Ubuntu18.04启动后无法进入桌面修复方法(图文)

    引言 xff08 吐槽可略过 xff09 xff1a Ubuntu是应用广泛的Linux操作系统 xff0c 特别是在机器学习应用中 xff0c 通过调用NVIDIA显卡的GPU进行计算和研究的主要平台之一 但是由于NV显卡的存在 xff0
  • VINS-Course代码解析——run_euroc前端数据处理

    vins mono总框架如下 xff1a 主要分为三大块 xff1a 我们先从主函数 main 入手 xff1a 主函数中有三个线程 xff0c 读取完数据集和配置文件的路径后就会进入这三个线程 xff0c 如下图 xff1a thd Ba
  • Gazebo11的更新与安装

    Melodic自带的Gazebo版本过低 xff0c 建议升级 Gazebo安装见gazebo官网 需注意以下四点 删除gazebo9以及相关插件选用Alternative installation step by step的安装方式 xf
  • XTDrone目标检测

    编译Darkent ROS 方法一 xff1a xff08 推荐 xff09 直接clone xff0c 记得加 recurse submodules xff0c 防止文件缺失 cd span class token operator sp
  • C++求解N个数的最大公约数、最小公倍数

    一 2个数的最大公约数 span class token comment 辗转相除法 span span class token keyword int span span class token function gcd span spa
  • 子序列个数——动态规划

    题目 xff1a 统计一个字符串中全部不同的子序列的个数 思路 xff1a 动态规划求解 令 f i 61 前 i 个元素中包含的全部子序列的个数 那么状态转移方程分为下面两种情况 xff1a 当第 i 个元素在前面 i 1 个字符中没有出
  • 字符串中特定子序列出现的次数(动态规划)

    题目 xff1a 给定一个字符串 xff0c 求子序列 cwbc 出现的次数 思路 xff1a 动态规划 令 dp i j 表示前 i 个字符中匹配了字符串 cwbc 中前 j 位 xff08 j 61 1 2 3 4 xff09 的个数
  • VMware ubuntu虚拟机无法上网的解决办法(笔记本连接WIFI情况)

    文章目录 一 虚拟机网络配置 一 虚拟机网络配置 1 设置Ubuntu网络适配器的网络连接方式为NAT模式 2 还原虚拟机网络配置 还原一下默认设置 3 window网络适配器设置适配器允许网络共享 4 Ubuntu启用联网 xff0c 连
  • ubuntu在树梅派上之VNC

    启动vncserver vncserver span class token operator span geometry 1600x900 杀死第一个桌面 vncserver span class token operator span
  • Sourcetree介绍及使用

    Sourcetree是一个操作简单但功能强大的免费Git客户端管理工具 xff0c 可应用在Windows和Mac平台 Sourcetree的安装 xff1a 1 从Sourcetree Free Git GUI for Mac and W
  • javascript创建一个基于数组的栈结构

    栈是一种遵从后进先出 xff08 LIFO xff09 原则的有序集合 新添加或待删除的元素都保存在栈的同 一端 xff0c 称作栈顶 xff0c 另一端就叫栈底 在栈里 xff0c 新元素都靠近栈顶 xff0c 旧元素都接近栈底 栈拥有以
  • Ubuntu16.04+RealsenseT265跑通VINS-Fusion

    一 提前条件 系统版本 xff1a ubuntu16 04 43 ROS xff08 kinetic xff09 默认已经掌握了ubuntu系统下的基本命令以及ROS的基本操作 二 realsenseT265的SDK测试 官方网站https
  • Why Kubernetes ,我对Kubernetes的理解

    去年换工作后 xff0c 开始真正在生产环境中接触容器与Kubernetes 边恶补相关知识的同时 xff0c 也想把学到的内容和自己的理解整理出来 学习的途径包括k8s官方文档 书籍 极客时间专栏及网上各种博文 所涉及一些摘抄或描述 xf
  • Kubernetes的几种主流部署方式01-minikube部署

    综述 Kubernetes集群的组件众多 xff0c 要部署一套符合生产环境的集群不是一件容易的事 好在随着社区的快速发展 xff0c 特别是在它成为事实上的容器编排标准以后 xff0c 基本所有的主流云平台都完全支持Kubernetes
  • Kubernetes 1.14版本的亮点新功能

    部分翻译自https sysdig com blog whats new kubernetes 1 14 Kubernetes 1 14的亮点新功能 xff1a 支持Windows容器服务可以通过kubeadm动态地创建一个高可用集群将ku
  • Kubernetes的几种主流部署方式02-kubeadm部署1.14版本高可用集群

    在上篇文章minikube部署中 xff0c 有提到Minikube部署Kubernetes的核心就是Kubeadm xff0c 这篇文章来详细说明下Kubeadm原理及部署步骤 写这篇文章的时候 xff0c Kubernetes1 14刚
  • Kubectl常用命令详解

    要使用和维护Kubernetes集群 xff0c 最常用且直接的方式 xff0c 就是使用自带的命令行工具Kubectl 这里梳理下常用的子命令及参数 xff0c 方便查找参考 参考文档 xff1a Overview of kubectlk

随机推荐