基于STM32的FreeRTOS学习之任务基础知识(六)

2023-05-16

记录一下,方便以后翻阅~

RTOS系统的核心是任务管理,初学RTOS系统必须先掌握任务的创建、删除、挂起和恢复等操作。

1. 什么是多任务系统

玩裸机一般都是在main函数里用while(1)做一个死循环完成所有处理,同时再加一些中断完成一些特定的处理,这里中断服务函数叫前台程序,死循环叫后台程序,即前后台系统(单任务系统),如下图所示:
在这里插入图片描述
前后台系统的实时性差,所有任务的优先级都是一样的,没轮到你就只能等着!多任务系统就应运而生。RTOS系统有个任务调度器,不同系统的任务调度器的实现方法是不同的,FreeRTOS是一个抢占式的实时多任务系统:
在这里插入图片描述
上图中,高优先级的任务可以打断低优先级任务的运行而取得CPU的使用权,执行完成后重新把CPU使用权给低优先级任务,这就是抢占式多任务系统的基本原理。

2. 任务与协程

在FreeRTOS中应用既可以使用任务,也可以使用协程(Co-Routine),或者两者混用。任务和协程使用不同的API函数,因此不能通过队列(或信号量)将数据从任务发送给协程,反之亦然。目前FreeRTOS官方已经不再更新协程了,建议以后主要用任务。

2.1 任务(Task)的特性
任何一个时间点只能运行一个任务,具体运行哪个任务由RTOS调度器决定。RTOS调度器的职责是确保当一个任务开始执行的时候其上下文环境(寄存器、堆栈内容等)和任务上一次退出的时候相同。为了做到这一点,每个任务都必须有个堆栈。(本章不介绍协程的内容)
任务特性:
1)简单;
2)没有使用限制;
3)支持抢占;
4)支持优先级;
5)每个任务都拥有堆栈导致RAM使用量增大;
6)如果使用抢占的话必须考虑重入的问题。

2.2 任务状态
1)运行态
当一个任务正在运行时,称这个任务处于运行态。处于运行态的任务就是当前正在使用处理器的任务。

2)就绪态
就绪态的任务就是那些已经准备就绪(没有被阻塞或挂起),可以运行的任务,但是处于就绪态的任务还没有运行,因为有一个同优先级或更高优先级的任务正在运行!

3)阻塞态
若一个任务当前正在等待某个外部事件的话就称之为阻塞态,比如某个任务调用了函数 vTaskDelay()的话就会进入阻塞态,直到延迟周期完成。任务在等待队列、信号量、事件组、通知或互斥信号量的时候也会进入阻塞态。任务进入阻塞态会有一个超时时间,超过这个时间任务就会退出阻塞态,即使所等待的事件还没有来临!

4)挂起态
像阻塞态一样,任务进入挂起态后也不能被调度器调用进入运行态,但是进入挂起态的任务没有超时时间。任务进入和退出挂起态通过调用函数 vTaskSuspend()和 xTaskResume()。

任务状态之间的转换如下图:
在这里插入图片描述
2.3 任务优先级
每个任务都分配一个从0 ~ (configMAX_PRIORITIES-1)的优先级,configMAX_PRIORITIES在FreeRTOSConfig.h中有定义。

如果硬件平台支持类似计算前导零这样的指令(通过该指令选择下一个要运行的任务,Cortex-M处理器支持该指令),且宏configUSE_PORT_OPTIMISED_TASK_SELECTION也设置为1,那么宏configMAX_PRIORITIES不能超过32!即优先级不能超过32级。其他情况下可设置任意值,但考虑RAM的消耗,宏configMAX_PRIORITIES应设为一个满足应用的最小值。

优先级数字越低表示任务的优先级越低,0的优先级最低,configMAX_PRIORITIES-1的优先级最高。空闲任务的优先级为0。

FreeRTOS调度器确保处于就绪态或运行态的高优先级的任务获取处理器使用权,即处于就绪态的最高优先级的任务才会运行。当宏configUSE_TIME_SLICING为1时,多任务可共用一个优先级,数量不限。默认情况下宏configUSE_TIME_SLICING在FreeRTOS.h中定义为1,此时处于就绪态的优先级相同的任务会使用时间片轮转调度器获取运行时间。

2.4 任务实现
在使用FreeRTOS的过程中,要用函数xTaskCreate()或xTaskCreateStatic()创建任务,两个函数的第一个参数pxTaskCode,就是这个任务的任务函数。任务函数是完成本任务工作的函数。比如做个流水灯的任务,那么这个流水灯的程序就是任务函数实现的。任务函数代码模板如下:

void vATaskFunction(void *pvParameters)  // 任务函数名,其返回值一定要为void类型,即无返回值。任务参数也是void指针类型!
{
	for(;;)                              // 任务具体执行过程是一个循环,也可用while(1)
	{
		--任务应用程序--                 // 任务代码,要干的具体的活
		vTaskDelay();                    // FreeRTOS的延时函数(不一定要用),只要能让FreeRTOS发生任务切换的API函数都可以,比如信号量、队列等,甚至直接调用任务调度器。
	}
	vTaskDelete(NULL);                   // 任务函数一般不允许跳出循环,如果一定要跳出循环的话,在跳出循环后一定要调用vTaskDelete(NULL)删除此任务!
}

2.5 任务控制块
FreeRTOS每个任务都有一些属性需要存储,FreeRTOS把这些属性集合到一起用一个结构体表示,这个结构体称任务控制块:TCB_t,在使用函数xTaskCreate()创建任务时就会自动的给每个任务分配一个任务控制块。此结构体在task.c文件里定义如下:

/* Task control block.  A task control block (TCB) is allocated for each task, and stores task state information, including a pointer to the task's context (the task's run time environment, including register values) */
typedef struct tskTaskControlBlock
{	
	volatile StackType_t	*pxTopOfStack;	   // 任务堆栈栈顶
	#if ( portUSING_MPU_WRAPPERS == 1 )        // MPU相关设置
		xMPU_SETTINGS	xMPUSettings;		
	#endif
	ListItem_t			xStateListItem;	       // 状态列表项
	ListItem_t			xEventListItem;		   // 事件列表项
	UBaseType_t			uxPriority;			   // 任务优先级
	StackType_t			*pxStack;			   // 任务堆栈起始地址
	char				pcTaskName[ configMAX_TASK_NAME_LEN ];     // 任务名字
	#if ( portSTACK_GROWTH > 0 )
		StackType_t		*pxEndOfStack;		   // 任务堆栈栈底
	#endif
	#if ( portCRITICAL_NESTING_IN_TCB == 1 )
		UBaseType_t		uxCriticalNesting;	   // 临界区嵌套深度
	#endif
	#if ( configUSE_TRACE_FACILITY == 1 )
		UBaseType_t		uxTCBNumber;		   // trace或debug时用
		UBaseType_t		uxTaskNumber;		
	#endif
	#if ( configUSE_MUTEXES == 1 )
		UBaseType_t		uxBasePriority;		   // 任务基础优先级,优先级反转时用
		UBaseType_t		uxMutexesHeld;         // 任务获取到的互斥信号量个数
	#endif
	#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
	#if ( configUSE_NEWLIB_REENTRANT == 1 )  
		struct	_reent xNewLib_reent;         // 定义一个newlib结构体变量
	#endif
	#if( configUSE_TASK_NOTIFICATIONS == 1 )  // 任务通知相关变量 
		volatile uint32_t ulNotifiedValue;    // 任务通知值
		volatile uint8_t ucNotifyState;       // 任务通知状态
	#endif
	#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )  // 标记任务时动态创建还是静态创建,静态创建变量为pdTURE,反之为pdFALSE
		uint8_t	ucStaticallyAllocated; 		
	#endif
	#if( INCLUDE_xTaskAbortDelay == 1 )
		uint8_t ucDelayAborted;
	#endif
} tskTCB;
// 新版本FreeRTOS任务控制块重命名为TCB_t,本质还是tskTCB,主要为了兼容就版本
typedef tskTCB TCB_t;

2.6 任务堆栈
任务调度器在进行任务切换的时候会将当前任务的现场(CPU寄存器值等)保存在此任务的任务堆栈中,等到此任务下次运行时就会先用堆栈中保存的值来恢复现场,恢复现场后任务就会接着上次中断的地方开始运行。
创建任务的时候需要给任务指定堆栈,如果使用的函数xTaskCreate()创建任务,那么任务堆栈就会由函数xTaskCreate()自动创建,如果使用函数xTaskCreateStatic()创建任务就需要自行定义任务堆栈,然后堆栈首地址作为函数的参数puxStackBuffer传递给函数,如下:

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     )

堆栈大小:
不管用xTaskCreate()还是xTaskCreateStatic()创建任务都需要制定任务堆栈大小。任务堆栈的数据类型为StackType_t, StackType_t本质上是uint32_t,在portmacro.h中有定义:

#define portSTACK_TYPE   uint32_t
#define portBASE_TYPE    long
typedef portSTACK_TYPE   StackType_t;
typedef long             BaseType_t;
typedef unsigned long    UBaseType_t;

可以看出StackType_t类型的变量为4个字节,那么任务的实际堆栈大小是所定义的4倍。

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

基于STM32的FreeRTOS学习之任务基础知识(六) 的相关文章

  • 使用k-近邻算法识别手写数字。

    在之前的文章中介绍了k 近邻算法的原理知识并且用Python实现了一个分类器 xff0c 而且完成了一个简单的优化约会网站配对效果的实例 在 机器学习实战 中有关kNN的后一部分内容就是一个手写识别系统 xff0c 可以识别手写的0 9的数
  • 在Ubuntu14.04不能添加PPA源到apt源的问题解决方法

    在Ubuntu14 04使用apt get 更新Git 时 xff0c 需要更新apt源 xff0c 添加一个带有最新Git的源 xff0c 如下命令 xff1a sudo add apt repository ppa git core p
  • 单片机的操作本质【以STM32系列为例】

    单片机的操作本质 摘要寄存器的本质单片机的操作本质操作寄存器的方法 摘要 本文档是笔者学习野火F103视频 课时5 至 课时7 的总结 视频链接 xff1a https study 163 com course introduction 1
  • 《视觉SLAM进阶:从零开始手写VIO》第一讲作业

    目录 1 视觉与IMU融合之后有何优势 xff1f 2 有哪些常见的视觉 43 IMU融合方案 xff1f 有没有工业界应用的例子 xff1f 3 在学术界 xff0c VIO研究有哪些新进展 xff1f 有没有将学习方法应用到VIO的例子
  • GPS坐标与UTM坐标的转换

    1 简介 1 1 消息 gps common定义了两个通用消息 xff0c 供GPS驱动程序输出 xff1a gps common GPSFix和gps common GPSStatus 在大多数情况下 xff0c 这些消息应同时发布 xf
  • NVIDIA Jetson TX2使用笔记(一):开机设置

    0 写在前面 由于项目需要 xff0c 使用 NVIDIA Jetson TX2作为硬件开发平台 xff0c 在此记录使用方法和遇到的问题 NVIDIA Jetson TX2是英伟达的嵌入式开发套件 xff0c 可以进行视觉计算 xff0c
  • ORB-SLAM2的安装与运行

    0 背景简介 ORB SLAM是西班牙Zaragoza大学的Raul Mur Artal编写的视觉SLAM系统 他的论文 ORB SLAM a versatile andaccurate monocular SLAM system 34 发
  • Ubuntu14.04升级cmake版本的方法

    在Ubuntu14 04用以下命令默认安装的cmake版本为2 8 x xff0c 有时我们需要更高版本的cmake xff0c 所以需要升级 span class hljs built in sudo span apt get insta
  • 在TX2上配置ORB-SLAM2错误总结

    Pangolin 错误描述 usr lib gcc aarch64 linux gnu 5 aarch64 linux gnu libGL so undefined reference to 96 drmFreeDevice 解决方法 cd
  • docker镜像迁移/移植

    docker镜像迁移 移植 或者docker save 镜像名 版本号 o 路径 保存的包名 tar 通过这两个命令保存保存镜像 xff0c 下载到本地再上传到其他服务器 然后通过docker load lt 保存的包名 tar 完成镜像移
  • 安装并运行VINS-Mono

    0 A Robust and Versatile Monocular Visual Inertial State Estimator VINS Mono是单目视觉惯性系统的实时SLAM框架 它使用基于优化的滑动窗口配方来提供高精度的视觉惯性
  • 使用小觅双目-惯性相机运行VINS-Mono

    步骤 1 下载相机驱动MYNT EYE SDK 2 xff0c 然后make ros xff08 注意 xff1a 前面的Ubuntu安装也要操作 xff09 xff1b 2 安装VINS Mono xff1b 3 在MYNT EYE VI
  • 在TX2上安装VIINS-Mono——问题总结

    1 ceres solver 我们一般通过以下命令安装Eigen xff1a sudo apt get install libeigen3 dev 默认安装在 usr include eigen3 在CMakeList txt中一般用以下语
  • LeGO-LOAM初探:原理,安装和测试

    前言 最近要搞3D激光SLAM xff0c 先后测试了Autoware xff0c cartographer xff0c loam和LeGO LOAM 今天就带来LeGO LOAM的使用体验 Github xff1a https githu
  • IMU噪声标定——加速度计和陀螺仪的白噪声和零偏不稳定性

    前言 imu utils是一个用于分析IMU性能的ROS工具包 参考资料 Allan Variance Noise Analysis for Gyroscopesvectornav gyroscopeAn introduction to i
  • TF坐标变换

    文章目录 TF坐标变换TF功能包TF工具乌龟例程中的TF创建TF广播器创建TF监听器实现乌龟跟随运动 存在的问题总结参考 TF坐标变换 坐标变换是机器人学中一个非常基础 xff0c 同时也是非常重要的概念 机器人本体和机器人的工作环境中往往
  • Linux下目录文件的操作(opendir,readdir,closedir) 以及DIR,dirent,stat等结构体详解

    From http blog chinaunix net uid 27213819 id 3810699 html 注 xff1a 为什么要说 目录文件 xff1f 其实在linux中 目录也是一种 文件 xff0c 只是它的内容是上级的
  • 堆栈的工作原理

    声明 xff1a 以下均为个人收集的一些资料 xff0c 非原创 每一个使用c语言的都应该知道栈的重要性 xff0c 我们能够使用C C 43 43 语言写出诸多复杂的程序 xff0c 很大功劳一部分有归于栈的实现 xff0c 因为它可以帮
  • RTK+GPS提高定位精度原理解析(一个小白写给另一个小白系列)

    RTK 43 GPS提高定位精度原理解析 xff08 一个小白写给另一个小白系列 xff09 GPS定位原理回顾RTK基本概念RTK组成RTK传输差分示意RTK数据链接坐标转换RTK应用后记 我们在上一篇文章导航定位系统的原理解析 xff0
  • Python 嵌套函数中内部函数引用外部函数循环变量情况

    Python 嵌套函数中内部函数引用外部函数循环变量情况 Python中的嵌套函数也称为闭包 xff08 Closure xff09 有一个特点就是内部函数可以引用外部函数内的变量并且在外部函数返回后保存该引用变量的值 xff1b 但是如果

随机推荐

  • Git查看版本改动—— git diff

    HEAD 表示当前版本 xff0c 也就是最新的提交 上一个版本就是 HEAD xff0c 上上一个版本就是 HEAD xff0c 往上100个版本写100个 比较容易数不过来 xff0c 所以写成 HEAD 100 HEAD 2 相当于
  • PyQt5编程-鼠标事件

    处理鼠标事件的频率不低于键盘事件 包括按下 松开鼠标按键 xff1b 移动鼠标到特定区域或离开特定区域 xff1b 更改鼠标指针的形状 xff0c 等等 1 按下 松开鼠标按键 按下并释放鼠标按钮时 xff0c 将调用以下方法 xff1a
  • latex 正文设置为双栏,图片如何占两栏

    xff08 1 xff09 插入一栏图片时 xff0c 使用的是 xff1a begin figure end figure 96 xff08 2 xff09 插入双栏图片时 xff0c 需在figure的上标中加入星号 begin fig
  • VIO松耦合和紧耦合对比

    松耦合 xff08 结果级融合 xff09 xff1a 两个独立的运动估计过程中分别处理视觉和惯性测量的信息 xff0c 最终将他们的输出 xff08 位置和姿态 xff09 融合作为结果 紧耦合 xff08 特征级融合 xff09 xff
  • zed2相机运行VINS-mono

    zed2相机标定请参考专栏前面博文 xff01 一 zed2相机运行VINS mono 1 下载VINS mono mkdir p vins ws src cd vins ws src git clone https github com
  • C语言指针笔试题

    1 我们先来看第一段代码和它的输出 span class token keyword int span span class token function main span span class token punctuation spa
  • Gazebo 官网教程学习笔记--Model Editor

    终端打开Gazebo Gui 界面 然后快捷键CTRL 43 M 打开 Model Editor xff0c 或者在edit 下选择model editor 界面如下 1 工具栏 包含用于编辑模型的工具 2 调色板 也称为左面板 有两个选项
  • 《大厂算法面试》小书

    算法面试是大多数小伙伴的弱势 xff0c 但是大厂几乎都会考算法 xff0c 如果在面试过程中不刻意准备一下算法 xff0c 很大概率被挂 其实对于前端和移动端来说 xff0c 算法要求的并不是很高 xff0c 只要把一些常见的算法题刷完
  • ROS通信架构上——Topic和Msg

    Topic 异步通信方式 Node间通过publish subscribe机制通信 相关的命令 xff1a rostopic rostopic list 列出当前所有topicrostopic info topic name 显示某个top
  • Type-C显示器是什么,Type-C显示器的5大优势

    在显示器领域内 xff0c USB Type C接口还处于发展阶段 xff0c 目前已经在新推出的一些高端显示器和旗舰显示器中有配置 USB Type C接口的出现 xff0c 将会形成以显示器为核心的桌面解决方案 xff0c 用户可以把任
  • SLAM综述

    SLAM综述 前言一 概述二 Lidar SLAM激光雷达传感器激光雷达SLAM系统 xff08 Lidar SLAM System xff09 2D SLAM3D SLAM深度学习与激光雷达Feature amp Detection xf
  • VisionPro使用 C# 开发

    VisionPro 常用控件的说明 工具设置窗体 CogPMAlignEditV2 模版匹配设置窗体控件 CogPMAlignEditV2 Subject 工具关联对象 如 xff1a CogPMAlignEditV2 Subject 61
  • rosdep update 失败及解决办法

    一 问题 reading in sources list data from etc ros rosdep sources list d Hit https raw githubusercontent com ros rosdistro m
  • 在STM32上运行ROS节点——rosserial&stm32开发及调试方法

    近期接手了一些ROS机器人项目 xff0c 这里将开发中遇到的问题和解决方法记录下来 stm32强大的外设资源为机器人底层设备控制带来了极大的便利 xff0c 本文简述借助rosserial项目在stm32中运行ROS节点的方法 基本原理
  • 动态存储区、静态存储区、堆和栈的区别

    C c 43 43 程序经过编译连接后形成的二进制映像文件 xff0c 这文件包含 xff1a 栈 xff0c 堆 xff0c 数据段 xff08 只读数据段 xff0c 已经初始化读写数据段 xff0c 未初始化数据段即BBS xff09
  • kubemini-基础使用

    起始 minikube 是一个本地的 k8s 专注于为 k8s 创建一个简单的学习和开发环境 你只需要一个 Docker 或者类似兼容的 容器 xff0c 或者一个虚拟机环境 xff0c k8s 只需要一个单独的命令 xff1a minik
  • 详解信号量和互斥锁之间的区别和联系

    一 xff1a 信号量与互斥锁之间的区别 xff1a 1 xff1a 互斥量用于线程的互斥 xff0c 信号线用于线程的同步 这是互斥量和信号量的根本区别 xff0c 也就是互斥和同步之间的区别 2 xff1a 互斥量值只能为0 1 xff
  • python基础学习(十二)——python中代码的执行顺序以及if __name__ ==‘__main__‘作用和原理

    xff08 1 xff09 代码执行顺序 python程序是顺序执行的 xff0c Python中首先执行最先出现的非函数定义和非类定义的没有缩进的代码 python程序执行时 按照自上而下的顺序 xff1a 首先执行没有缩进的代码 xff
  • c学习--不同c文件中的同名全局变量及同名函数53

    如果在不同的c文件中定义了同名的全局变量 xff0c 则它们会占用相同的内存空间 xff0c 而且编译链接时不会报错 xff01 这可以参考全局变量的内存初始化顺序 对于局部变量而言 xff0c 内存分配的顺序和代码的顺序是一样的 全局变量
  • 基于STM32的FreeRTOS学习之任务基础知识(六)

    记录一下 xff0c 方便以后翻阅 RTOS系统的核心是任务管理 xff0c 初学RTOS系统必须先掌握任务的创建 删除 挂起和恢复等操作 1 什么是多任务系统 玩裸机一般都是在main函数里用while 1 做一个死循环完成所有处理 xf