FreeRTOS任务知识详解

news2024/11/19 1:39:12

前言

本篇文章旨在记录我学习FreeRTOS实时操作系统中,有关于Free RTOS的任务知识的记录。由于RTOS系统的核心就是任务管理,而且我们大多数人学习RTOS的初衷就是为了使用RTOS的多任务处理功能!

初步上手RTOS首先应该掌握的就是任务的创建、删除、挂起和恢复等操作。由此可见任务的重要性!

目录

前言

一、多任务系统是什么? 

二、FreeRTOS任务与协程

三、任务的特性 

四、协程(Co-routine)的特性

五、任务状态

NO.1 运行态 

NO.2 就绪态 

 NO.3 阻塞态

NO.4 挂起态 

任务状态之间的转换 

六、任务优先级 

七、FreeRTOS任务实现 

 八、任务控制块

 九、任务堆栈

十、结语 

一、多任务系统是什么? 

回想一下我们以前在使用51、AVR、STM32单片机裸机(未使用系统)的时候一般都是在main 函数里面用 while(1) 做一个大循环来完成所有的处理,即应用程序是一个无限的循环,循环中调用相应的函数完成所需的处理。有时候我们也需要中断中完成一些处理。

相对于多任务系统而言,这个就是单任务系统,也称作前后台系统,中断服务函数作为前台程序,大循环while(1)作为后台程序,如图所示:

前后台系统的实时性差,前后台系统各个任务(应用程序)都是排队等着轮流执行,不管你这个程序现在有多紧急,没轮到你就只能等着! 相当于所有任务(应用程序)的优先级都是一样的。但是前后台系统简单啊,资源消耗也少啊!在稍微大一点的嵌入式应用中前后台系统就明显力不从心了,此时就需要多任务系统出马了。


多任务系统会把一个大问题(应用)“分而治之”,把大问题划分成很多个小问题,逐步的把小问题解决掉,大问题也就随之解决了,这些小问题可以单独的作为一个小任务来处理。

这些小任务是并发处理的,注意,并不是说同一时刻一起执行很多个任务,而是由于每个任务执行的时间很短,导致看起来像是同一时刻执行了很多个任务一样。

多个任务带来了一个新的问题,究竟哪个任务先运行,哪个任务后运行呢?完成这个功能的东西在RTOS系统中叫做任务调度器

不同的系统其任务调度器的实现方法也不同,比如 FreeRTOS是一个抢占式的实时多任务系统,那么其任务调度器也是抢占式的,运行过程如图所示:

在图中,高优先级的任务可以打断低优先级任务的运行而取得CPU的使用权,这样就保证了那些紧急任务的运行。这样我们就可以为那些对实时性要求高的任务设置一个很高的优先级,比如自动驾驶中的障碍物检测任务等。

高优先级的任务执行完成以后重新把CPU的使用权归还给低优先级的任务,这个就是抢占式多任务系统的基本原理。

二、FreeRTOS任务与协程

在FreeRTOS中应用既可以使用任务,也可以使用协程(Co-Routine),或者两者混合使用。

但是任务和协程使用不同的API函数,因此不能通过队列(或信号量)将数据从任务发送给协程,反之亦然。协程是为那些资源很少的MCU准备的,其开销很小,但是FreeRTOS官方已经不打算再更新协程了。所以我在学习FreeRTOS的过程中也没有深究有关协程的知识。需要了解的小伙伴可以自己上网查一查。

三、任务的特性 

在使用RTOS的时候,一个实时应用可以作为一个独立的任务。每个任务都有自己的运行环境,不依赖于系统中其他的任务或者RTOS调度器。

任何一个时间点只能有一个任务运行,具体运行哪个任务是由RTOS调度器来决定的,RTOS调度器因此就会重复的开启、关闭每个任务。

任务不需要了解RTOS调度器的具体行为,RTOS调度器的职责是确保当一个任务开始执行的时候其上下文环境(寄存器值,堆栈内容等)和任务上一次退出的时候相同。

为了做到这一点,每个任务都必须有个堆栈,当任务切换的时候将上下文环境保存在堆栈中,这样当任务再次执行的时候就可以从堆栈中取出上下文环境,任务恢复运行。
 

上面的话很重要!!!!

上面的话很重要!!!!

上面的话很重要!!!!

综上,任务的特性是:

1、简单

2、没有使用权限

3、支持抢占

4、支持优先级

5、每个人任务都拥有堆栈导致了RAM使用量增大

6、如果使用抢占的话必须仔细考虑重入的问题

四、协程(Co-routine)的特性

协程是为那些资源很少的MCU而做的,但是随着MCU的飞速发展,性能越来越强大,现在协程几乎很少用到了!

在一些资料中我了解到,FreeRTOS目前还没有把协程移除的计划,但是FreeRTOS是绝对不会再更新和维护协程了,因此协程大家了解一下就行了。在概念上协程和任务是相似的,但是有如下根本上的不同:


1、堆栈使用
所有的协程使用同一个堆栈(如果是任务的话每个任务都有自己的堆栈),这样就比使用任务消耗更少的RAM。
2、调度器和优先级
协程使用合作式的调度器,但是可以在使用抢占式的调度器中使用协程。

3、宏实现
协程是通过宏定义来实现的。

4、使用限制
为了降低对RAM的消耗做了很多的限制。

五、任务状态

FrreRTOS中的任务状态共有四种,故FreeRTOS的任务永远都是处于这四种状态中的一种。

NO.1 运行态 

当一个任务正在运行时,那么就说这个任务处于运行态,处于运行态的任务就是当前正在使用处理器的任务。

如果使用的是单核处理器的话那么不管在任何时刻永远都只有一个任务处于运行态。

NO.2 就绪态 

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

 NO.3 阻塞态

如果一个任务当前正在等待某个外部事件的话就说它处于阻塞态,比如说如果某个任务调用了函数vTaskDelay()的话就会进入阻塞态,直到延时周期完成。

任务在等待队列、信号量、事件组、通知或互斥信号量的时候也会进入阻塞态。

任务进入阻塞态会有一个超时时间,当超过这个超时时间任务就会退出阻塞态,即使所等待的事件还没有来临!

NO.4 挂起态 

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


任务状态之间的转换 

六、任务优先级 

每个任务都可以分配一个从0 ~ (configMAX_PRIORITIES-1)的优先级﹐configMAX_PRIORITIES在文件 FreeRTOSConfig.h中有定义,之前我的文章中带大家了解FreeRTOS系统配置的时候已经讲过了。

如果所使用的硬件平台支持类似计算前导零这样的指令(可以通过该指令选择下一个要运行的任务,Cortex-M处理器是支持该指令的),并且宏configUSE_PORT_OPTIMISED_TASK_SELECTION也设置为了 1,那么宏configMAX_PRIORITIES不能超过32!也就是优先级不能超过32级。

其他情况下宏configMAX_PRIORITIES可以为任意值,但是考虑到RAM的消耗,宏 configMAX_PRIORITIES最好设置为一个满足应用的最小值。


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


FreeRTOS调度器确保处于就绪态或运行态的高优先级的任务获取处理器使用权,换句话说就是处于就绪态的最高优先级的任务才会运行。

当宏configUSE_TIME_SLICING定义为1的时候多个任务可以共用一个优先级,数量不限。默认情况下宏 configUSE_TIME_SLICING在文件FreeRTOS.h中已经定义为1。此时处于就绪态的优先级相同的任务就会使用时间片轮转调度器获取运行时间。

七、FreeRTOS任务实现 

在使用FreeRTOS的过程中,我们要使用函数 xTaskCreate()或xTaskCreateStatic()来创建任务,这两个函数的第一个参数pxTaskCode,就是这个任务的任务函数。什么是任务函数?

任务函数就是完成本任务工作的函数。我这个任务要干嘛?要做什么?要完成什么样的功能都是在这个任务函数中实现的。比如我要做个任务,这个任务要点个流水灯,那么这个流水灯的程序就是任务函数中实现的。FreeRTOS官方给出的任务函数模板如下:

(1)、任务函数本质也是函数,所以肯定有任务名什么的,不过这里我们要注意:任务函数的返回类型一定要为void类型,也就是无返回值,而且任务的参数也是void指针类型的!任务函数名可以根据实际情况定义。


(2)、任务的具体执行过程是一个大循环,for(; ; )就代表一个循环,作用和 while(1)一样,笔者习惯用while(1)。


(3)、循环里面就是真正的任务代码了,此任务具体要干的活就在这里实现!


(4)、FreeRTOS的延时函数,此处不一定要用延时函数,其他只要能让FreeRTOS发生任务切换的API函数都可以,比如请求信号量、队列等,甚至直接调用任务调度器。只不过最常用的就是FreeRTOS的延时函数。


(5)、任务函数一般不允许跳出循环,如果一定要跳出循环的话在跳出循环以后一定要调用函数 vTaskDelete(NULL) 删除此任务!
FreeRTOS的任务函数和UCOS的任务函数模式基本相同的,不止 FreeRTOS,其他RTOS的任务函数基本也是这种方式的。

 八、任务控制块

FreeRTOS的每个任务都有一些属性需要存储,FreeRTOS把这些属性集合到一起用一个结构体来表示,这个结构体叫做任务控制块:TCB_t

在使用函数xTaskCreate()创建任务的时候就会自动的给每个任务分配一个任务控制块。在老版本的 FreeRTOS中任务控制块叫做tskTCB,新版本重命名为TCB_t,但是本质上还是tskTCB,此结构体在文件tasks.c中有定义,如下:

可以看出来FreeRTOS的任务控制块中的成员变量相比UCOSIⅢ要少很多,而且大多数与裁剪有关,当不使用某些功能的时候与其相关的变量就不参与编译,任务控制块大小就会进一步的减小。

 九、任务堆栈

FreeRTOS之所以能正确的恢复一个任务的运行就是因为有任务堆栈在保驾护航,任务调度器在进行任务切换的时候会将当前任务的现场(CPU寄存器值等)保存在此任务的任务堆栈中,等到此任务下次运行的时候就会先用堆栈中保存的值来恢复现场,恢复现场以后任务就会接着从上次中断的地方开始运行。


创建任务的时候需要给任务指定堆栈,如果使用的函数xTaskCreate()创建任务(动态方法)的话那么任务堆栈就会由函数xTaskCreate()自动创建,后面分析xTaskCreate()的时候会为大家提及。

如果使用函数xTaskCreateStatic()创建任务(静态方法)的话就需要程序员自行定义任务堆栈,然后堆栈首地址作为函数的参数puxStackBuffer传递给函数,如下:

(1)、任务堆栈需要用户定义,然后将堆栈首地址传递给这个参数

堆栈大小:


我们不管是使用函数xTaskCreate()还是xTaskCreateStatic()创建任务都需要指定任务堆栈大小。任务堆栈的数据类型为StackType_t,StackType_t本质上是uint32_t,在portmacro.h中有定义,如下:
可以看出 StackType_t类型的变量为4个字节,那么任务的实际堆栈大小就应该是我们所定义的4倍

十、结语 

好了,至此关于FreeRTOS任务的学习分享就结束了。相信我的分享的一定能给你带来比一样的收获!愿我们一起努力,为梦奔赴,砥砺前行!

冲!!!

冲!!!

冲!!!

​​​​​​​ 

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

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

相关文章

AlmaLinux上安装Docker

AlmaLinux上安装Docker 文章目录 AlmaLinux上安装Docker一、前言二、具体步骤1、Docker 下载更新系统包索引:添加Docker仓库:安装Docker引擎: 2、Docker服务启动启动Docker服务:设置Docker开机自启: 3、Docker 安装验证…

GitLab16.8配置webhooks、Jenkins2.4配置GitLab插件实现持续集成、配置宝塔面板实现持续部署

看本篇文章的前提是已经部署完GItlab和Jenkins服务器,已经可以手动构建成功,并且经过了很多次实践,对这两款软件基本熟悉。 建议大家按以下顺序看 前端自动化(其一)部署gitlab https://blog.csdn.net/weixin_45062076…

数据中心代理IP:最优性价比业务应用指南

数据中心代理IP在应对高速高并发的业务时,以独特的高速传输,游刃有余地应对多任务处理,适合于特定业务场景的高效加速。理性选用数据中心代理IP,可以为业务将迎来更加稳健和迅速的发展。今天,我们将揭示数据中心代理IP…

QT+VS实现Kmeans++

1、Kmeans的原理如下: (1)首先选取样本中任一数据点作为第一个聚类中心; (2)计算样本每一个数据点至现所有聚类中心的最近距离,并记录下来; (3)逐一挑选所…

ATT汇编

指令后缀 AT&T格式的汇编指令有不同的后缀 其中 b表示byte,字节 w表示word,字/两字节 l表示long,32位系统下的long是4字节 q表示quad,意味四重,表示4个字/8字节 寄存器用途 参见 AT&T的汇编世界 - Gemfield…

备战蓝桥杯----数据结构及STL应用(基础2)

上次我们讲了vector的大致内容,接下来让我们讲一下栈,队列吧! 什么是栈呢? 很简单,我们用的羽毛球桶就是,我们取的球,是最后放的,栈是一种先进后出的数据结构。 方法函数 s.push(…

Dubbo框架注册中心-Zookeeper搭建

Dubbo 是阿里巴巴公司开源的高性能、轻量级的Java RPC框架,致力于提供高性能。 Dubbo官网 本篇开始dubbo的第一篇,注册中心 ZooKeeper 环境搭建。 环境前置:由于Zookeeper是基于Java环境,必须安装有JDK。查看命令 java -version。…

蓝桥杯---九数组分数

1,2,3 ... 9 这九个数字组成一个分数,其值恰好为1/3,如何组法? 下面的程序实现了该功能,请填写划线部分缺失的代码。 注意,只能填写缺少的部分,不要重复抄写已有代码。不要填写任何多余的文字。 代码 public class _05九数组分数 {public static void test(int[] x){int a …

在WebSocket中使用Redis出现空指针异常解决方案

文章目录 在WebSocket中使用Redis1.问题描述2.原因3.解决步骤1.新建一个SpringUtil.java类,通过getBean的方法主动获取实例2.在WebSocketSingleServer.java中导入 在WebSocket中使用Redis 1.问题描述 在controller 和 service中都可以正常使用Redis,在…

03_Opencv简单实例演示效果和基本介绍

视频处理 视频分解图片 在后面我们要学习的机器学习中,我们需要大量的图片训练样本,这些图片训练样本如果我们全都使用相机拍照的方式去获取的话,工作量会非常巨大, 通常的做法是我们通过录制视频,然后提取视频中的每一帧即可! 接下来,我们就来学习如何从视频中获取信息 ubun…

JVM工作原理与实战(三十):堆内存状况的对比分析

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、堆内存状况的对比分析 1.正常情况 2.异常情况(内存泄漏) 二、产生内存溢出的原因 总结 前言 JVM作为Java程序的运行环境,其负责解释和执行字…

【Linux 内核源码分析】多核调度分析

多核调度 SMP(Symmetric Multiprocessing,对称多处理)是一种常见的多核处理器架构。它将多个处理器集成到一个计算机系统中,并通过共享系统总线和内存子系统来实现处理器之间的通信。 首先,SMP架构将一组处理器集中在…

【Fooocus 深度学习】SDXL,AIGC生图,源码解读

文章目录 使用通配符增加prompt多样性Fooocus的风格实现fooocus_expansionclip扩散采样参数 sigmasBrownianTreeNoiseSamplerPatchedjoint samplevae 使用通配符增加prompt多样性 prompt和negative_prompt都可以通过apply_wildcards函数来实现通配符替换,apply_wil…

初识K8S(Kubernetes )

一、概述 Kubernetes 是一个可移植、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态,其服务、支持和工具的使用范围相当广泛。(官网) Kuberne…

Windows 7 x64 SP1 安装 Google Chrome 109.0.5414.120 (正式版本) (64 位)

1 使用 IE 浏览器 输入网址 Google Chrome 网络浏览器得益于 Google 智能工具,Chrome 现在更易用、更安全、更快速。https://www.google.cn/chrome/,点击下载 Chrome。 2 点击 接受并安装。 3 提示。 4 保存。 5 双击 运行 ChromeSetup.exe。 6 等待安…

用于不对称卷积的验证参数的小程序

非对称卷积的特征图尺寸计算 此处只例举输入图像是正方形的情况。设输入图像尺寸为WxW,卷积核尺寸为ExF,步幅为S,Padding为P,卷积后的特征图尺寸为: 矩形卷积 如果输入图像是正方形,尺寸为WxW&#xff0c…

WSL2 Debian系统添加支持SocketCAN

本人最近在使用WSL2,Linux系统选择的是Debian,用起来很不错,感觉可以代替VMware Player虚拟机。 但是WSL2 Debian默认不支持SocketCAN,这就有点坑了,由于本人经常要使用SocketCAN功能,所以决定让Debian支持…

switch语句详解及底层实现原理

目录 switch 与 if else switch语句用法 switch底层汇编实现分析 switch原理总结 switch 与 if else if else是人工优化的,而switch则是编译器进行优化的 使用场合:命中样本一致,每个case命中概率一样,case的数据必须是线性…

内网安全:RDP WinRS WinRM SPN Kerberos 横向移动

目录 WinRM协议 RDP协议 域横向移动:RDP协议 RDP协议利用 一. 探针服务 二. 获取NTML Hash 明文密码 三. 连接执行 域横向移动:WinRM WinRS WinRM协议、WinRS命令利用 一. cs 内置端口扫描5985 二. 连接执行 三. 上线CS 四. CS插件横向移动…

日常学习之:vue + django + docker + heroku 对后端项目 / 前后端整体项目进行部署

文章目录 使用 docker 在 heroku 上单独部署 vue 前端使用 docker 在 heroku 上单独部署 django 后端创建 heroku 项目构建 Dockerfile设置 settings.pydatabase静态文件管理安全设置applicaiton & 中间件配置 设置 requirements.txtheroku container 部署应用 前后端分别部…