FreeRTOS-任务基础知识

2023-05-16

(一)多任务系统

1. 单任务系统

在使用C51系列、STM32等单片机进行裸机编程时,大都在main函数中写一个while或者for死循环函数,用来无限轮询任务函数。很多时候会加入硬件中断来完成一些功能处理。相对于多任务系统来说,这种轮询系统就是单任务系统,也称作前后台系统。中断服务函数为前台系统,轮询为后台系统。
图1 前后台系统
前后台系统的缺点:实时性差;除中断之外的所有任务都排队轮流执行,处理器的性能好的话,轮询的速度就会快些,要是处理器性能比较差并且代码很多的话,系统就会比较慢。优点:系统简单、消耗资源小。

2. 多任务系统

多任务系统会将任务并发处理(不意味着同一时刻能够多任务一起执行,并且MCU就一个核),由于每个任务所占用的CPU时间很短,可以看做是多任务在一起执行。在RTOS中任务调度器起了关键性的作用,负责任务的调度。FreeRTOS是一个抢占式的实时多任务系统,其任务调度器也是抢占式的。具体运行过程如下图所示:
图2 抢占式多任务系统

3. FreeRTOS任务与协程

在FreeRTOS中任务和协程均可使用,但两者使用的是不同的API函数,因此不能通过队列(或信号量)将数据从任务发送给协程,反之依然。协程是专门为资源很少的MCU准备的。

(1)任务特性

在RTOS中,每一个任务都有自己的运行环境,不依赖于系统中的其它任务或者RTOS调度器。任何一个时间点,只能同时运行一个任务。任务调度器的主要任务是决定哪个任务运行。任务调度器确保一个任务的开始执行时的系统环境(寄存器值,堆栈内容等)和上一次任务退出时保持一致。因此,每个任务都有堆栈,用于保存任务切换时的上下文环境。

任务特性:
  • 简单。
  • 没有使用限制。
  • 支持抢占。
  • 支持优先级。
  • 每个任务都拥有堆栈导致RAM使用量增大。
  • 如果使用抢占的话,必须仔细考虑重入问题。

(2)协程特性

协程与任务在概念上是相似的,但存在一下几点不同:

  • 堆栈的使用 -
    所有的协程使用同一个堆栈,比任务消耗更小的RAM。
  • 调度器和优先级
    协程使用合作式调度器,但可以在抢占式调度其中使用协程。
  • 宏实现
    协程是通过宏定义来实现的。
  • 使用限制
    为了降低对RAM的消耗做了很多的限制。

(3)任务状态

- 运行态
任务正在运行的状态。

- 就绪态
处于就绪态的任务(没有被阻塞或挂起)是已经准备就绪、可以运行的任务,但还没有正式运行,主要由于当前系统正在运行的同一优先级或者更高优先级的任务。

- 阻塞态
任务当前正在等待某个外部事件时,就处于阻塞态。例如,某任务调用vTaskDelay()函数,进入阻塞态,等待延时完成。任务在等待队列、信号量、事件组、通知或互斥信号量时也会进入阻塞态。任务进入阻塞态会有一个超时时间,当超过这个超时时间,任务就会退出阻塞态,即使等待的事件还没有触发。

- 挂起态
任务进入挂起态后不能被任务调度器调用进入运行态,且没有超时时间。任务进入和退出挂起态通过调用函数vTaskSuspend()和xTaskResume()。

任务状态之间的转换如下图所示:
在这里插入图片描述

(4)任务优先级

每个任务都可以分配一个从 0 ~ (configMAX_PRIORITIES - 1) 的优先级。configMAX_PRIORITIES 宏定义在FreeRTOSConfig.h头文件中有定义。一般情况下configMAX_PRIORITIES 可以设置为任意值,但是考虑到RAM的消耗,最好设置为一个满足应用的最小值。
注意:如果硬件平台支持类似计算前导零这样的指令(可以通过该指令选择下一个要运行的任务),并且宏configUSE_PORT_OPTIMISED_TASK_SELECTION也设置为1后,那么宏configMAX_PRIORITIES 不能超过32,即优先级不能超过32级。
优先级数字越小表示的优先级越低,0的优先级最低,configMAX_PRIORITIES - 1的优先级最高。空闲任务的优先级最低,为0.
处于就绪态的最高优先级的任务才会运行。当宏configUSE_TIME_SLICING定义为1时,多个任务可以共用一个优先级,数量不限;此时处于就绪态的同优先级任务,会使用时间片轮转调度器,获取运行时间。

(5)任务实现

在FreeRTOS中,使用xTaskCreate()或者xTaskCreateStatic()两个函数来创建任务。FreeRTOS官方任务函数模板:

void vATaskFunction(void *pvParameters)
{
	for( ; ; )
	{
		/*
			任务应用程序
		*/
		vTaskDelay();
	}
	/*
		不能从任务函数中返回或者退出,从任务函数中返回或退出的话就会调用configASSERT(),前提是定义了configASSERT()。
		如果一定要从任务函数中退出的话,一定要调用函数vTaskDelete(NULL)来删除次任务。
	*/
	vTaskDelete(NULL);
}
  • 任务函数无返回值,且无传入参数;任务函数名可以根据实际应用定义。
  • 任务应用程序放在一个死循环中执行,可以是for( ; ; ),也可以是while(1)。
  • 死循环中是当前任务真正执行的功能
  • vTaskDelay()函数在这里的主要功能是引发任务调度器切换任务;只要是能引起任务切换的函数均可以的,例如请求信号量、队列,甚至可以直接调用任务调度器。
  • 任务函数一般不允许跳出死循环,如果一定要跳出,则在跳出后一定要调用vTaskDelete(NULL)函数删除此任务。

(6)任务控制块(任务句柄)

FreeRTOS的每个任务都有一些属性需要存储,FreeRTOS把这些属性集合到了一起,用了一个结构体来表示,这个结构体叫做任务句柄:TaskHandle_t,在调用任务创建函数时,会自动给每个任务分配一个任务控制块。在新版本中使用的是TaskHandle_t,本质上是tskTaskControlBlock结构体。

typedef struct tskTaskControlBlock 			/* The old naming convention is used to prevent breaking kernel aware debuggers. */
{
	volatile StackType_t	*pxTopOfStack;	/*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */

	#if ( portUSING_MPU_WRAPPERS == 1 )
		xMPU_SETTINGS	xMPUSettings;		/*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
	#endif

	ListItem_t			xStateListItem;	/*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
	ListItem_t			xEventListItem;		/*< Used to reference a task from an event list. */
	UBaseType_t			uxPriority;			/*< The priority of the task.  0 is the lowest priority. */
	StackType_t			*pxStack;			/*< Points to the start of the stack. */
	char				pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */

	#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
		StackType_t		*pxEndOfStack;		/*< Points to the highest valid address for the stack. */
	#endif

	#if ( portCRITICAL_NESTING_IN_TCB == 1 )
		UBaseType_t		uxCriticalNesting;	/*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
	#endif

	#if ( configUSE_TRACE_FACILITY == 1 )
		UBaseType_t		uxTCBNumber;		/*< Stores a number that increments each time a TCB is created.  It allows debuggers to determine when a task has been deleted and then recreated. */
		UBaseType_t		uxTaskNumber;		/*< Stores a number specifically for use by third party trace code. */
	#endif

	#if ( configUSE_MUTEXES == 1 )
		UBaseType_t		uxBasePriority;		/*< The priority last assigned to the task - used by the priority inheritance mechanism. */
		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;	/*< Stores the amount of time the task has spent in the Running state. */
	#endif

	#if ( configUSE_NEWLIB_REENTRANT == 1 )
		/* Allocate a Newlib reent structure that is specific to this task.
		Note Newlib support has been included by popular demand, but is not
		used by the FreeRTOS maintainers themselves.  FreeRTOS is not
		responsible for resulting newlib operation.  User must be familiar with
		newlib and must provide system-wide implementations of the necessary
		stubs. Be warned that (at the time of writing) the current newlib design
		implements a system-wide malloc() that must be provided with locks.

		See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
		for additional information. */
		struct	_reent xNewLib_reent;
	#endif

	#if( configUSE_TASK_NOTIFICATIONS == 1 )
		volatile uint32_t ulNotifiedValue;
		volatile uint8_t ucNotifyState;
	#endif

	/* See the comments in FreeRTOS.h with the definition of
	tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
	#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
		uint8_t	ucStaticallyAllocated; 		/*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
	#endif

	#if( INCLUDE_xTaskAbortDelay == 1 )
		uint8_t ucDelayAborted;
	#endif

	#if( configUSE_POSIX_ERRNO == 1 )
		int iTaskErrno;
	#endif

} tskTCB;

/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
below to enable the use of older kernel aware debuggers. */
typedef tskTCB TCB_t;

在task.h中有如下定义:

/**
 * task. h
 *
 * Type by which tasks are referenced.  For example, a call to xTaskCreate
 * returns (via a pointer parameter) an TaskHandle_t variable that can then
 * be used as a parameter to vTaskDelete to delete the task.
 *
 * \defgroup TaskHandle_t TaskHandle_t
 * \ingroup Tasks
 */
struct tskTaskControlBlock; /* The old naming convention is used to prevent breaking kernel aware debuggers. */
typedef struct tskTaskControlBlock* TaskHandle_t;

(7)任务堆栈

任务堆栈的存在保证了FreeRTOS能够正确的恢复一个任务。任务堆栈负责保存任务调度器在进行任务切换时的现场(CPU寄存器值等),等到该任务下次运行时,使用堆栈中的值来恢复现场,保证任务能够在上次停止的地方接着运行下去。
任务创建时需要制定任务堆栈。动态创建任务和静态创建任务直接会影响到堆栈的创建。使用xTaskCreate()函数动态创建任务时,任务堆栈会由函数自动创建。使用xTaskCreateStatic()函数静态创建任务时,需要自定定义任务堆栈,然后以堆栈首地址作为函数的参数puxStackBuffer 传递给函数。

TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,
									const char * const pcName,		/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
									const uint32_t ulStackDepth,
									void * const pvParameters,
									UBaseType_t uxPriority,
									StackType_t * const puxStackBuffer,
									StaticTask_t * const pxTaskBuffer )

无论是创建动态任务(xTaskCreate())或者是静态任务(xTaskCreateStatic())都需要指定任务的堆栈大小。由于采用的uint32_t的类型,单位为4个字节,故实际的堆栈大小为定义数字的4倍。

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

FreeRTOS-任务基础知识 的相关文章

  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

    FreeRTOS内核是高度可定制的 使用配置文件FreeRTOSConfig h进行定制 每个FreeRTOS应用都必须包含这个头文件 用户根据实际应用来裁剪定制FreeRTOS内核 这个配置文件是针对用户程序的 而非内核 因此配置文件一般
  • FreeRTOS快速上手

    FreeRTOS使用 一 源码下载和移植文件提取 1 1 源码下载 在网站https sourceforge net projects freertos 可以找到freertos最新的源码 1 2 移植文件提取 根据第一步 我们会得到一个f
  • FreeRTOS简述和移植文档

    FreeRTOS简述和移植文档 文章目录 FreeRTOS简述和移植文档 1 前言 2 FreeRTOS简述 1 概述 2 实现 3 主要特色 4 支持平台 3 移植FreeRTOS 4 最后 1 前言 目前由于IOT的飞速发展 针对单片机
  • FreeRTOS学习笔记(3、信号量、互斥量的使用)

    FreeRTOS学习笔记 3 信号量 互斥量的使用 前言 往期学习笔记链接 学习工程 信号量 semaphore 两种信号量的对比 信号量的使用 1 创建信号量 2 give 3 take 4 删除信号量 使用计数型信号量实现同步功能 使用
  • 【FreeRTOS】多任务创建

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • 【FreeRTOS开发问题】FreeRTOS内存溢出

    FreeRTOS内存溢出 如下图所示 FreeRTOS编译完成后可以看到 系统提示无法分配内存到堆 Objects Template axf Error L6406E No space in execution regions with A
  • ZYNQ中FreeRTOS中使用定时器

    使用普通的Timer中断方式时 Timer中断可以正常运行 但是UDP通信进程无法启动 其中TimerIntrHandler是中断服务程序 打印程序运行时间与从BRAM中读取的数据 void SetupInterruptSystem XSc
  • FreeRTOS_中断

    传送门 博客汇总帖 传送门 Cortex M3 中断 异常 传送门 Cortex M3笔记 基础 笔记内容参考 正点原子的FreeRTOS开发手册 cortex m3权威指南 Cortex M3和Cortex M4权威指南等 文中stm32
  • 基于HAL库的FREERTOS-----------三.队列

    一 队列简介 在实际的应用中 常常会遇到一个任务或者中断服务需要和另外一个任务进行 沟通交流 这个 沟通交流 的过程其实就是消息传递的过程 在没有操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式 但是如果在使用操作系统的应用中用
  • FreeRTOS临界段和开关中断

    http blog sina com cn s blog 98ee3a930102wg5u html 本章教程为大家讲解两个重要的概念 FreeRTOS的临界段和开关中断 本章教程配套的例子含Cortex M3内核的STM32F103和Co
  • FreeRTOS学习(三)开关中断

    声明及感谢 跟随正点原子资料学习 在此作为学习的记录和总结 环境 keil stm32f103 背景知识 Cotex M3的NVIC最多支持240个IRQ 中断请求 1个不可屏蔽 NMI 1个Systick 滴答定时器 Cortex M处理
  • FreeRTOS之事件

    FreeRTOS之事件 声明 本人按照正点原子的FreeRTOS例程进行学习的 欢迎各位大佬指责和批评 谢谢 一 事件定义 事件 事件集 与高数上的集合意义差不多 事件啊 其实是实现任务间通信的机制 主要用于实现多任务间的同步 但是事件类型
  • FreeRTOS学习笔记(8)---- 软件定时器

    使用FreeRTOS软件定时器需要在文件FreeRTOSConfig h先做如下配置 1 configUSE TIMERS 使能软件定时器 2 configTIMER TASK PRIORITY 定时器任务优先级 3 configTIMER
  • 【FreeRTOS 事件】任务通知事件

    普通任务通知事件创建创建及运行 参阅安富莱电子demo define BIT 0 1 lt lt 0 define BIT 1 1 lt lt 1 static TaskHandle t xHandleTaskUserIF NULL sta
  • FreeRTOS轻量级同步--任务通知

    1 简介 在FreeRTOS的配置参数中的configUSE TASK NOTIFICATIONS宏打开 一般RTOS会默认打开 如图1所示 图1 notify宏开关 RTOS在创建任务时 会创建一个32位的通知值ulNotifiedVal
  • 单片机通信数据延迟问题排查

    1 问题说明 笔者在最近的项目中 发现系统的响应延迟较高 经过排查 排除了单片机运行卡死的问题 2 原因分析 具体排查过程这里就不细致说明了 直接给出排查后原因 任务执行周期规划不合理 导致freertos队列发送接收到的命令有延迟 为了便
  • FreeRTOS临界段

    1 临界段 在访问共享资源时不希望被其他任务或者中断打断的代码 这段要执行的代码称为临界段代码 2 设置临界段的目的 保护共享资源 例如 全局变量 公共函数 不可重入函数 函数里面使用 了一些静态全局变量 malloc 等 保护外设的实时性
  • 如何更改 FreeRTOS 中任务的最大可用堆大小?

    我通过以下方式在任务中创建元素列表 l dllist pvPortMalloc sizeof dllist dlllist 有 32 字节大 我的嵌入式系统有 60kB SRAM 所以我希望系统可以轻松处理我的 200 个元素列表 我发现在
  • 防止GCC LTO删除函数

    我使用 GCC ARM Embedded 和 FreeRTOS FreeRTOS具有的功能vTaskSwitchContext 仅在某些情况下使用 内联汇编代码 问题是 当我使用LTO时 GCC不考虑内联汇编代码并认为该函数没有被使用 因此
  • 有关 CMake 错误的问题:没有为目标提供源

    我正在尝试使用 cmake 和 eclipse 将 FreeRtos 添加到我的项目中 但出现错误 我运行的是 debian 10 我的 cmake 版本是 3 13 4 cmake 的文件可以在以下位置找到这个 git 仓库 https

随机推荐

  • 深度相机进行目标检测

    1 介绍 国外博客 xff0c 这个博客还行 xff0c 可以下载源码 CSDN 目标检测采用YOLOv5 xff0c 已经搭建好 相机采用realsense d435i 官网有文档 xff0c 示例代码 xff0c 工具等 看官网是最好的
  • 手眼标定[Realsense+大象机器人]

    踩坑 手眼标定的算法网上是比较多的 xff0c 但是很多都不好用 github上高赞的easy handeye xff0c 试了一下 xff0c 但是mycobot600没有提供moveit的配置 xff0c 而我ROS基础不是很好 xff
  • 在Linux上用docker部署项目

    在Linux上用docker部署项目 一 用xftp5或FileZilla连接服务器 二 用上面工具在服务器上创建一个文件夹 xff08 或者用命令行创建 xff09 上面是在 usr 下创建了docker文件夹 xff0c 用来放需要更新
  • idea集成docker最新

    一 安装docker 1 卸载旧版本 sudo yum remove docker docker client docker client latest docker common docker latest docker latest l
  • docker命令删除容器和镜像

    1 查看所有正在运行容器 docker ps 2 停止容器 xff08 containerId是容器id xff09 docker stop containerId 3 删除容器 docker rm 容器id 4 查看镜像 docker i
  • 下拉多选框的实现

    这两天在写一个chrome插件 xff0c 需要在popup页使用下拉多选框 用select看起来非常原始 xff0c 多选还要按住ctrl键或者command键 html代码如下 xff1a span class token operat
  • 使用sed和awk分割部分文件内容

    目标 xff1a 文本的一部分内容 xff0c 需要进行比较 xff0c 其他的部分 xff0c 需要忽略掉 步骤 xff1a 1 cat 文件 xff1b 2 grep 起始 终止 字符串 xff1b 3 获取行数 xff1b 通过sed
  • docker安装、启动、卸载nginx,并配置修改nginx的配置文件

    一 第一种方式 1 使用docker 下载nginx 镜像 docker pull nginx 2 启动nginx docker run span class token operator span name nginx span clas
  • 更新docker镜像及容器,使用docker-compose命令

    第一种方法 xff1a docker stop 容器名或镜像id 下面一样 docker rm 容器名 docker rmi 镜像名 docker builder 镜像名 docker run d name 容器名 p 对外端口 内部端口
  • docker/overlay2磁盘占满——Linux定时清理docker日志脚本

    一 查看占用磁盘文件 df span class token operator span h 然后进入占用大的文件目录执行 du span class token operator span span class token operato
  • java3-5年面试题——数据库篇

    1 limit关键字从0到10与从100000到200000效率相差几个数量级 xff0c 为什么 xff1f 从100000到200000 这种分页查询方式会从数据库第一条记录开始扫描 xff0c 所以越往后 xff0c 查询速度越慢 x
  • java3-5年面试题——高级篇

    关于linux操作 xff1a 1 常用的文件操作命令 1 ls命令 xff1a 查看当前目录中的文件信息 ls span class token operator span a 查看所有文件列表 xff08 可查看隐藏文件 xff09 l
  • mysql行列转换

    一 行转列 建表语句 xff1a span class token keyword DROP span span class token keyword TABLE span span class token keyword IF span
  • Object Detection Api安装经测试后,出现“AlreadyExistsError: Another metric with the same name already exists.”

    在安装Object Detection Api后 xff0c 经过如下一行代码测试 xff1a span class token keyword from span object detection span class token pun
  • windows系统安装curl

    1 curl是什么 curl 是一种命令行工具 xff0c 作用是发出网络请求 xff0c 然后获取数据 xff0c 显示在 34 标准输出 34 xff08 stdout xff09 上面 安装教程 x1f447 xff1a 1 官网下载
  • 文件系统与LVM(mksf、mkswap、swapon、挂载、磁盘、UUID号)

    目录 mksfmkswapswapon挂载查看磁盘使用情况查看分区UUID号管理LVM逻辑卷 mksf 作用 创建文件系统 格式化 t 指定格式化文件类型 b 指定block大小 U 设置UUID号 mksf ext4 磁盘路径 格式化 m
  • 【踩坑记录】Slam-Gmapping建图失败--已解决

    目录 场景 仿真小车在Gazebo上进行Gmapping 步骤 xff1a 问题 xff1a 填坑过程 知识储备 解决办法 修改尝试 0 结论 0 odom由一个发布者发布 修改尝试 1 结论 1 odom信息由模型中的URDF决定 修改尝
  • 【踩坑记录】Gazebo启动慢,画面卡“Preparing your world”

    项目场景 xff1a ros kinetic 问题描述 xff1a 启动gazebo慢 xff0c 卡顿 xff0c 一直停留在Preparing your world的界面上 原因分析 xff1a gazebo在启动时需要将模型仿真出来
  • 【踩坑笔记】Linux系统无法启动,拷贝备份文件

    问题描述 xff1a Linux系统中安装输入法后 xff0c 重启后 xff0c 导致系统无法进入 xff0c 进入 recovery mode下的resume 也启动不了 xff0c 所以决定将需要的东西复制到U盘 解决方案 xff1a
  • FreeRTOS-任务基础知识

    xff08 一 xff09 多任务系统 1 单任务系统 在使用C51系列 STM32等单片机进行裸机编程时 xff0c 大都在main函数中写一个while或者for死循环函数 xff0c 用来无限轮询任务函数 很多时候会加入硬件中断来完成