【FreeRTOS】任务管理

一、任务管理介绍

1.任务状态

1)调度器切换任务调度

2)任务是一个死循环,如果想要停止这个任务则会调用在函数最后写的delete函数进行自杀

1.就绪态

1)已经具备执行的能力,只等待调度器进行调度。

2)新创建的任务会默认设置为就绪态

2.运行态

1)表示此时任务正在运行,占用了CPU资源

2)是就绪任务优先级最高的运行

3.阻塞态

1)等待某一个时序或者中断的时候

2)等待延时,中断

3)已经从就绪列表中被删除

4.挂起态

1)任务被暂时停止,通过调用挂起函数(vTaskSuspend())可以把指定任务挂起,任务挂起后暂时不会运行,只有调用恢复函数(xTaskResume())才可以退出挂起状态

2)处于挂起态的任务对调度器而言是不可见的

5.挂起  VS  阻塞

挂起态与阻塞态的区别,当任务有较长的时间不允许运行的时候,我们可以挂起任务,这样子调度器就不会管这个任务的任何信息,直到调用恢复任务的 接口;而任务处于阻塞态的时候,系统还需要判断阻塞态的任务是否超时,是否可以解除阻塞。

2.任务状态转换

 1.运行<----->就绪

  1. 从运行态到就绪态的转换:
    当一个任务正在运行时(即处于运行态),如果发生了某个事件(如定时器超时、消息队列接收、信号量释放等),可能会导致该任务释放其占用的资源(如 CPU)并返回到就绪态。这种转换通常是由任务自身触发的,例如,当任务完成其当前工作后,它可能会释放它之前占用的资源并返回到就绪态,等待下一次调度器选择它运行。

此外,当一个更高优先级的任务准备就绪时,当前运行的任务可能会被抢占,从而导致当前任务从运行态转换到就绪态。这是基于优先级的抢占式调度的核心特性。

          2.从就绪态到运行态的转换:
当任务处于就绪态时,它已经准备好运行,但尚未获得 CPU 的使用权。从就绪态到运行态的转换是由调度器触发的。当调度器发现当前运行的任务已经完成其工作并释放了 CPU,或者有一个更高优先级的任务准备就绪时,调度器会选择一个优先级最高的就绪任务,并将其从就绪态转换到运行态。

这个过程涉及上下文切换,即保存当前运行任务的上下文(如寄存器状态、堆栈指针等),并恢复新任务的上下文。然后,新任务开始执行,从它上次停止的地方继续执行。

2.运行-->阻塞

当一个任务处于运行态时,它可能会因为等待某个资源或事件(如信号量、互斥量、消息队列中的消息等)而主动进入阻塞态。这通常发生在任务调用某些可能导致阻塞的API时,如xSemaphoreTake()xQueueReceive()等。

例如,如果一个任务尝试从一个空的消息队列中接收消息,并且该任务被配置为等待消息可用(阻塞接收),那么该任务将从运行态转换到阻塞态,并且会被加入到相应资源(在这个例子中是消息队列)的等待列表中。在阻塞态,任务会释放CPU,使得其他任务可以运行。

3.阻塞--->就绪

当任务所等待的资源或事件变得可用时,任务会从阻塞态转换到就绪态。这通常是由其他任务或中断服务例程(ISR)触发的。

例如,如果一个任务因为等待一个信号量而阻塞,当另一个任务释放该信号量时(通过调用xSemaphoreGive()),处于阻塞态的任务会被唤醒,并从信号量的等待列表中移除,转换到就绪态。此时,任务已经准备好再次运行,但是否能够立即运行取决于其优先级和其他任务的状态

4.就绪,运行,阻塞--->挂起

从运行态到挂起态

当任务处于运行态时,可以通过调用vTaskSuspend()函数来将其挂起。这将导致当前运行的任务立即释放CPU,并且其状态将从运行态转换到挂起态。挂起任务不会立即停止执行,而是在下一次上下文切换时停止。

从就绪态到挂起态

如果任务处于就绪态,同样可以通过调用vTaskSuspend()函数来将其挂起。一旦任务被挂起,它将不再参与调度器的调度,即使它的优先级比其他就绪任务高。

从阻塞态到挂起态

当任务处于阻塞态(等待某个资源或事件),并且该资源或事件尚未变得可用时,任务也可以被挂起。这通常是通过调用vTaskSuspend()函数实现的。在这种情况下,任务将保持其阻塞状态,但同时也会被挂起。一旦任务被挂起,即使资源或事件变得可用,任务也不会被唤醒。

从挂起态的恢复

要从挂起态恢复任务,可以使用vTaskResume()函数。这将把任务从挂起态转换回就绪态(如果任务原本处于就绪态或运行态被挂起),或者从阻塞态转换回阻塞态(如果任务原本因为等待资源或事件而被挂起)。当任务从挂起态恢复时,它将重新参与调度器的调度,并有可能在下一次上下文切换时获得CPU使用权。

二、常用API函数

1.任务挂起函数

1.vTaskSuspend

1)任务被挂起就不会获得CPU的使用权

2)无论任务当前处于什么状态,只要调用挂起函数就都可以进入挂起状态

3)如果这个传入的参数是NULL就表示挂起自己

2.vTaskSuspendAll 

1)这意味着一旦调用此函数,除了正在运行的任务(调用 vTaskSuspendAll() 的任务)之外,其他所有任务都将被暂停,不会获得 CPU 的使用权。

2)中断服务例程(ISR)不受 vTaskSuspendAll() 的影响。即使所有任务都被挂起,中断仍然可以正常响应和处理。

3)使用 xTaskResumeAll() 来恢复所有被 vTaskSuspendAll() 暂停的任务的调度。

4)如果系统配置了时间片轮转(task time slicing),vTaskSuspendAll() 也会暂停时间片的切换。

5)这个函数可以嵌套使用,但是如果调用多少次vTaskSuspendAll()就要调用多少次xTaskResumeAll()来恢复【如果你调用了vTaskSuspendAll() n 次,你就需要调用xTaskResumeAll() n 次来恢复所有任务的调度。

2.任务挂起恢复 

1.vTaskResume

1)任务的恢复就让挂起的任务重新回到就绪状态

2)此函数不能用于中断函数中恢复任务挂起

2.xTaskResumeFromISR

1)在中断里面对任务挂起的恢复操作

2)

 3.任务删除

1.vTaskDelete

1)如果要删除自己,就传入“NULL”

2)如果要删除其他用户则传入对应的句柄即可

3)要使用这个函数,则要先将这个“INCLUDE_vTaskDelete”置为1

4)我们要在删除任务之前,先将这个任务拥有的这个内存先删除,在删除这个任务。要不然这个任务所占的空间不会自动删除,容易造成内存泄漏

4.任务延时函数

1.vTaskDelay

2.vTaskDelayUntil

3.  vTaskDelay    和    vTaskDelayUntil

  1. 延时方式

    • vTaskDelay是一个相对延时函数,它使任务进入挂起态,直到至少等待指定的Tick Interrupt(滴答中断)次数。换句话说,它是从调用vTaskDelay函数开始,延时指定的时间后任务才会重新进入就绪态。
    • vTaskDelayUntil则是一个绝对延时函数,它会使任务等待到指定的绝对时刻后才会变为就绪态。这意味着任务会等待到指定的时间点,而不是等待某个数量的Tick Interrupt。
  2. 精度和任务执行

    • vTaskDelayUntil的精度通常比vTaskDelay高,因为它基于绝对时间进行延时。
    • 在某些情况下,使用vTaskDelayUntil的任务不会丢失执行,而vTaskDelay可能会导致任务丢失执行。例如,当高优先级的任务长时间占用CPU时,使用vTaskDelay的任务可能会错过其预定的执行时间。
  3. 使用场景

    • vTaskDelay适用于需要相对延时的场景,例如,当你想要任务在执行某个操作后等待一段时间再继续执行时。
    • vTaskDelayUntil则适用于需要任务在特定时间点执行的场景,例如,定时任务或需要在特定时间间隔内执行的任务。

三、任务的设计要点

1.中断服务函数

1)在中断函数中不能执行挂起任务

2)不允许执行任何会阻塞运行的API接口函数

3)保持精简短小

4)只能做标记,标记触发其他函数

5)中断过长,会影响其他函数的运行

2.普通任务

1)因为任务是死循环的,所以这里一定要有阻塞的机会,才可以跳转到其他任务

2)将紧急任务的优先级设计较高

3.空闲任务

1)任务创建的时候自动创建空闲任务

2)空闲任务中也不要编写会阻塞运行的API函数

3)主要用于释放资源

4.任务执行时间

1)时间---->任务执行的周期时间,任务需要的时间长短

2)一般来说:处理时间更短的任务优先级要设置的越(因为这样对运行时间长的任务来说根本不值得一提)

四、例子

#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"


//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define LED1_TASK_PRIO		2
//任务堆栈大小	
#define LED1_STK_SIZE 		50  
//任务句柄
TaskHandle_t LED1Task_Handler;
//任务函数
void led1_task(void *pvParameters);

//任务优先级
#define LED2_TASK_PRIO		3
//任务堆栈大小	
#define LED2_STK_SIZE 		50  
//任务句柄
TaskHandle_t LED2Task_Handler;
//任务函数
void led2_task(void *pvParameters);

//任务优先级
#define KEY_TASK_PRIO		4
//任务堆栈大小	
#define KEY_STK_SIZE 		50  
//任务句柄
TaskHandle_t KEYTask_Handler;
//任务函数
void key_task(void *pvParameters);


/*******************************************************************************
* 函 数 名         : main
* 函数功能		   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
int main()
{
	SysTick_Init(72);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
	LED_Init();
	KEY_Init();
	USART1_Init(115200);
	
	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
      
    //创建LED1任务
    xTaskCreate((TaskFunction_t )led1_task,     
                (const char*    )"led1_task",   
                (uint16_t       )LED1_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LED1_TASK_PRIO,
                (TaskHandle_t*  )&LED1Task_Handler); 
				
	//创建LED2任务
    xTaskCreate((TaskFunction_t )led2_task,     
                (const char*    )"led2_task",   
                (uint16_t       )LED2_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LED2_TASK_PRIO,
                (TaskHandle_t*  )&LED2Task_Handler);

	//创建KEY任务
    xTaskCreate((TaskFunction_t )key_task,     
                (const char*    )"key_task",   
                (uint16_t       )KEY_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )KEY_TASK_PRIO,
                (TaskHandle_t*  )&KEYTask_Handler);
				
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
} 

//LED1任务函数
void led1_task(void *pvParameters)
{
    while(1)
    {
        LED1=0;
        vTaskDelay(200);
        LED1=1;
        vTaskDelay(800);
    }
}

//LED2任务函数
void led2_task(void *pvParameters)
{
    while(1)
    {
        LED2=0;
        vTaskDelay(800);
        LED2=1;
        vTaskDelay(200);
    }
}

//KEY任务函数
void key_task(void *pvParameters)
{
    u8 key=0;
	
	while(1)
    {
		key=KEY_Scan(0);
		if(key==KEY_UP_PRESS)
		{
			printf("挂起LED任务!\n");
			vTaskSuspend(LED2Task_Handler);/* 挂起LED任务 */
			printf("挂起LED任务成功!\n");
		}
		else if(key==KEY1_PRESS)
		{
			printf("恢复LED任务!\n");
			vTaskResume(LED2Task_Handler);/* 恢复LED任务!*/
			printf("恢复LED任务成功!\n");
		}
		//将本任务进行挂起
		vTaskDelay(20);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统前后端分离项目

目录 一.jdk安装 二.tomcat安装 三.MySQL安装 四.nginx安装 五.Nginx负载均衡tomcat 六.前端部署 一.jdk安装 1. 上传jdk安装包 jdk-8u151-linux-x64.tar.gz 进入opt目录&#xff0c;将安装包拖进去 2. 解压安装包 这里需要解压到usr/local目录下&#xff0c;在这里新建一个…

python程序设计基础:异常处理结构与程序调试、测试

第八章&#xff1a;异常处理结构与程序调试、测试 简单地说,异常是指程序运行时引发的错误,引发错误的原因有很多例如除零、下标越界、文件不存在、网络异常、类型错误、名字错误、字典键错误、磁盘空间不足,等等。 如果这些错误得不到正确的处理将会导致程序终止运行,而合理…

HuggingFists系统功能介绍(1)--系统概述

HuggingFists是一款低代码AI应用工具&#xff0c;力图发展为LangChain的低代码平替工具。HuggingFists发起于数由科技的Sengee数据科学计算框架&#xff0c;因此其界面风格继承了数据科学工具的很多特征。有别于完全基于LangChain衍生出的低代码工具Flowise&#xff0c;其风格更…

YOLO如何训练自己的模型

目录 步骤 一、打标签 二、数据集 三、跑train代码出模型 四、跑detect代码出结果 五、详细操作 步骤 一、打标签 &#xff08;1&#xff09;在终端 pip install labelimg &#xff08;2&#xff09;在终端输入labelimg打开 如何打标签&#xff1a; 推荐文章&#xf…

2.23 Day05

#include "mywidget.h" #include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget) {ui->setupUi(this);//居中ui->label02->setAlignment(Qt::AlignCenter);ui->Edit1->setAlignment(Qt::Alig…

协程源码 launch 流程跟踪学习

为了更深入学习协程的底层实现原理&#xff0c;了解协程线程切换的根本本质。也为了以后在工作中可以根据不同的需求场景&#xff0c;更加随心所欲的使用不同的协程。 今天通过 launch 跟踪一下协程的执行流程。 fun getData() {Trace.beginSection("getData");Log.…

knife4j springboot3使用

简介 在日常开发中&#xff0c;写接口文档是我们必不可少的&#xff0c;而Knife4j就是一个接口文档工具&#xff0c;可以看作是Swagger的升级版&#xff0c;但是界面比Swagger更好看&#xff0c;功能更丰富 使用 我使用的是springboot3.2.3 knife4j 4.3.0,knife4j 4.4版本有…

RK3568平台开发系列讲解(Linux系统篇)字符设备驱动:主设备和次设备

🚀返回专栏总目录 文章目录 一、主设备和次设备的概念二、设备号的分配和释放沉淀、分享、成长,让自己和他人都能有所收获!😄 字符设备通过字符(一个接一个的字符)以流方式向用户程序传递数据,就像串行端口那样。字符设备驱动通过/dev目录下的特殊文件公开设备的属性和…

dolphinscheduler单机版部署教程

文章目录 前言一、安装准备1. 安装条件2. 安装jdk3. 安装MySQL 二、安装dolphinscheduler1. 下载并解压dolphinscheduler2. 修改配置文件2.1 修改 dolphinscheduler_env.sh 文件2.2 修改 application.yaml 文件 3. 配置mysql数据源3.1 修改MySQL安全策略3.2 查看数据库3.3 创建…

UE5 文字游戏(1) 仅UI截图转换为texture2d(适用于window端)

目录 需求 思路 1.截图并读取到本地 2.本地读取图片并转换为纹理2d 效果展示 找了好多的解决办法&#xff0c;都不管用。这个算是折中的。 需求 将当前的用户控件&#xff08;ui&#xff09;截图下来&#xff0c;并赋值到一个texture2d上。 我的需求&#xff1a;文字游戏…

golang通过http访问外部网址

不同项目之前,通过http访问,进行数据沟通 先设定一个接口,确认外部能访问到 PHP写一个接口 public function ceshi_return() {$data $this->request->param();$id $data[id];$res Db::name(user)->field(id,status,price,name)->where([id>$id])->find…

抖音视频抓取软件的优势|视频评论内容提取器|批量视频下载

抖音视频抓取软件在市场上的优势明显&#xff1a; 功能强大&#xff1a;我们的软件支持关键词搜索抓取和分享链接单一视频提取两种方式&#xff0c;满足用户不同的需求。同时&#xff0c;支持批量处理数据&#xff0c;提高用户获取视频的效率。 操作简单&#xff1a;我们的软件…

matlab|计及源荷不确定性的综合能源生产单元运行调度与容量配置随机优化模型

目录 1 主要内容 1.1 风光场景聚类 1.2 主模型程序结果 1.3 随机模型和确定性模型对比 1.4 有无储气对比 1.5 煤价灵敏性分析 1.6 甲烷价格灵敏性分析 2 部分程序 3 下载链接 1 主要内容 本程序复现《计及源荷不确定性的综合能源生产单元运行调度与容量配置两阶段随机…

OpenGL ES (OpenGL) Compute Shader 计算着色器是怎么用的?

OpenGL ES (OpenGL) Compute Shader 是怎么用的? Compute Shader 是 OpenGL ES(以及 OpenGL )中的一种 Shader 程序类型,用于在GPU上执行通用计算任务。与传统的顶点着色器和片段着色器不同,Compute Shader 被设计用于在 GPU 上执行各种通用计算任务,而不是仅仅处理图形…

前端导出下载文件后提示无法打开文件

问题 项目中的导出文件功能&#xff0c;导出下载后的文件打开提示如下&#xff1a; 原因 对返回的响应数据进行打印&#xff0c;发现响应数据为字符串格式&#xff0c;前期规划的后端返回数据应该 blob 对象的。后经排查后发现是请求头缺少了响应数据格式的配置&#xff0c;应…

SpringMVC 学习(六)之视图

目录 1 SpringMVC 视图介绍 2 JSP 视图 3 Thymeleaf 视图 4 FreeMarker 视图 5 XSLT 视图 6 请求转发与重定向 6.1 请求转发 (Forward) 6.2 重定向 (Redirect) 7 视图控制器 (view-controller) 1 SpringMVC 视图介绍 在 SpringMVC 框架中&#xff0c;视图可以是一个 J…

Python爬虫实战:图片爬取与保存

引言&#xff1a; 在本文中&#xff0c;我们将学习如何使用Python创建一个简单的图片爬虫。 我们将利用requests库来发送HTTP请求&#xff0c;BeautifulSoup库来解析HTML页面&#xff0c;以及os和shutil库来下载和保存图片。通过这个教程&#xff0c;你将学会如何爬取网…

神经网络2-卷积神经网络一文深度读懂

卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;是一类包含卷积计算且具有深度结构的前馈神经网络&#xff08;Feedforward Neural Networks&#xff09;&#xff0c;主要用于图像识别、语音识别和自然语言处理等任务&#xff0c;是深度学习&#xff0…

遗传算法(Genetic Algorithm,GA)求解不闭合多旅行商问题(提供MATLAB代码)

一、遗传算法&#xff08;GA&#xff09;介绍 遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;是一种模拟自然界生物进化过程的优化算法。它通过模拟生物的遗传、变异和选择等机制&#xff0c;来搜索问题的最优解。 遗传算法的基本思想是通过对候选解进行编…

基于虚拟力优化的无线传感器网络覆盖率matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 虚拟力优化算法 4.2 覆盖覆盖率计算 5.完整程序 1.程序功能描述 基于虚拟力优化的无线传感器网络覆盖率&#xff0c;仿真输出优化前后的网络覆盖率&#xff0c;覆盖率优化收敛迭代曲线…