FreeRTOS的任务详解、创建与删除

目录

1、任务详解

1.1 什么是任务?

1.2 任务的特点

1.3 任务的状态

1.4 任务的优先级

1.5 任务的堆和栈

2、任务的创建与删除

2.1 相关API

2.2 函数解析

2.2.1 xTaxkCreate()

2.2.2 xTaskCreateStatic()

2.2.3 vTaskDelete()

3、实战案例

3.1 创建两个任务

3.2 配置LED引脚

3.3 相关代码


1、任务详解

1.1 什么是任务?

任务可以理解为进程/线程,创建一个任务,就会在内存开辟一个空间。

比如: 玩游戏、陪女朋友,都可以视为任务;Windows 系统中的 MarkText 、谷歌浏览器、记事本,都是任务。

在 FreeROTS 中,任务可以分配不同的优先级,并按照优先级进行调度。当一个任务没有工作可以做时,操作系统会将 CPU 时间分配给另一个优先级更高的任务,以确保系统的正常运行。

1.2 任务的特点

  1. 简单
  2. 没有使用限制
  3. 支持抢占
  4. 支持优先级
  5. 每个任务都拥有堆栈导致了 RAM 使用量增大
  6. 如果使用抢占的话的必须仔细的考虑重入的问题 

1.3 任务的状态

  • 运行态

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

  • 就绪态

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

  • 阻塞态

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

  • 挂起态

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

任务状态之间的转换如图

1.4 任务的优先级

每个任务都可以分配一个从0~(configMAX_PRIORITIES-1) 的优先级, configMAX_PRIORITIES 在文件 FreeRTOSConfig.h 中有定义,一共设置了32个优先级。

注意:数字越大,优先级约高,0为最低优先级

1.5 任务的堆和栈

FreeRTOS 之所以能正确的恢复一个任务的运行就是因为有任务堆栈在保驾护航,任务调度器在进行任务切换的时候会将当前任务的现场(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 )

2、任务的创建与删除

2.1 相关API

                                函数名称                                 函数作用
xTaskCreate()动态方式创建任务
xTaskCreateStatic()静态方式创建任务
vTaskDelete()删除任务

动态创建任务与静态创建任务的区别:动态创建任务的堆栈由系统分配,而静态创建任务的堆栈由用户自己传递(分配)。 通常情况下使用动态方式创建任务。

2.2 函数解析

2.2.1 xTaxkCreate()

此函数用来创建一个任务,任务需要 RAM 来保存与任务有关的状态信息(任务控制块),任务也需要一定的 RAM 来作为任务堆栈。如果使用函数xTaskCreate()来创建任务的话那么这些所需的 RAM就会自动的从FreeRTOS的堆中分配,因此必须提供内存管理文件,默认我们使用heap_4.c 这个内存管理文件,而且宏 configSUPPORT_DYNAMIC_ALLOCATION 必须为 1

新创建的任务默认就是就绪态的如果当前没有比它更高优先级的任务运行那么此任务就会立即进入运行态开始运行,不管在任务调度器启动前还是启动后,都可以创建任务。此函数也是我们以后经常用到的。

1. pxTaskCode:指向任务函数的指针,任务必须实现为永不返回(即连续循环);

2. pcName:任务的名字,主要是用来调试,默认情况下最大长度是16;

3. pvParameters:指定的任务栈的大小;

4. uxPriority:任务优先级,数值越大,优先级越大;

5. pxCreatedTask:用于返回已创建任务的句柄可以被引用。

                        返回值                      描述                
pdPASS任务创建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY任务创建失败

官方案例:

/* Task to be created. */
void vTaskCode( void * pvParameters )
{/* The parameter value is expected to be 1 as 1 is passed in thepvParameters value in the call to xTaskCreate() below.configASSERT( ( ( uint32_t ) pvParameters ) == 1 );for( ;; ){/* Task code goes here. */}
}
/* Function that creates a task. */
void vOtherFunction( void )
{BaseType_t xReturned;TaskHandle_t xHandle = NULL;/* Create the task, storing the handle. */xReturned = xTaskCreate(vTaskCode, /* Function that implements the task. */"NAME", /* Text name for the task. */STACK_SIZE, /* Stack size in words, not bytes. */( void * ) 1, /* Parameter passed into the task. */tskIDLE_PRIORITY,/* Priority at which the task is created. */&xHandle ); /* Used to pass out the created task's handle. */if( xReturned == pdPASS ){/* The task was created. Use the task's handle to delete the task. */vTaskDelete( xHandle );}
}
2.2.2 xTaskCreateStatic()

使用此函数创建的任务所需的RAM需要用户来提供 。

如果要使用此函数的话需要将宏configSUPPORT_STATIC_ALLOCATION定义为1。

	StackType_t StartTaskStack[START_STK_SIZE];			//任务堆栈xTaskCreateStatic((TaskFunction_t	)start_task,		//任务函数(const char* 	)"start_task",		    //任务名称(uint32_t 		)START_STK_SIZE,	//任务堆栈大小(void* 		  	)NULL,				//传递给任务函数的参数(UBaseType_t 	)START_TASK_PRIO, 	    //任务优先级(StackType_t*   )StartTaskStack,	    //任务堆栈(StaticTask_t*  )&StartTaskTCB);	    //任务控制块vTaskStartScheduler();          //开启任务调度 

函数返回值就是任务句柄

2.2.3 vTaskDelete()
void vTaskDelete(TaskHandle_t xTaskToDelete);

只需将待删除的任务句柄传入该函数,即可将该任务删除。

当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)。

任务被删除以后就不能再使用此任务的句柄:如果此任务是使用动态方法创建的,也就是使用函数 xTaskCreate()创建的,那么在此任务被删除以后,此任务之前申请的堆栈和控制块内存会在空闲任务中被释放掉,因此当调用函数 vTaskDelete()删除任务以后必须给空闲任务一定的运行时间。

用户分配给任务的内存需要用户自行释放掉:比如某个任务中用户调用函数 pvPortMalloc()分配了 500 字节的内存,那么在此任务被删除以后用户也必须调用函数 vPortFree()将这 500 字节的内存释放掉,否则会导致内存泄露

3、实战案例

这里创建两个任务进行点灯,其中两个任务对应的点灯速率不同。

3.1 创建两个任务

这里直接讲述使用Cubemx创建任务的操作,关于FreeRTOS移植到STM32F103C8T6可查看上一篇文章FreeRTOS介绍-CSDN博客

点击Middleware找到FreeRTOS,点击Task and Queues

进行创建任务配置

配置任务1

配置任务2

3.2 配置LED引脚

查看板子原理图,得到LED的引脚编号

引脚配置

3.3 相关代码

打开freertos.c

//找到设置的任务函数名称,在其中的循环中进行代码改写
void StartTaskLED1(void const * argument)
{for(;;){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);osDelay(500);}
}void StartTaskLED2(void const * argument)
{for(;;){HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);osDelay(1000);}
}

最终LED1以500ms闪烁,LED2以1s闪烁。

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

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

相关文章

JavaSwing课程设计-实现一个计算器程序

通过JavaSwing技术来实现计算器小程序,效果如下。 源码下载链接 源码下载 博主承诺真实有效,私信可提供支持

Android广播demo(系统广播,自定义广播)

1 系统广播demo 1.1 BootReceiver 的广播接收器类: import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast;public class BootReceiver extends BroadcastReceiver {Overridep…

JavaEE 多线程详细讲解(2)

1.线程不安全分析 (1)线程不安全的主要原因就是,系统的抢占式执行,对于内核设计者来说,这是非常方便的一个执行方式,但是这却却导致线程不安全的问题,也有不抢占执行的系统,但是这种…

存储或读取时转换JSON数据

一、 数据库类型 二、使用Hutool工具 存储时将数据转换为JSON数据 获取时将JSON数据转换为对象 发现问题: 原本数据对象是Address 和 Firend但是转换完成后数据变成了JSONArray和JSONObject 三、自定义TypeHandler继承Mybatis的BaseTypeHandler处理器 package …

STL速查

容器 (Containers) 图解容器 支持随机访问 stringarrayvectordeque支持支持支持支持 string 类 构造函数 string(); ------创建一个空的字符串 例如: string str;string(const char* s); ------使用字符串s初始化string(const string& str); ------拷贝构造 赋值操作…

欧拉角(Euler)和四元数(Quaternion)

欧拉角-Euler 欧拉角是三个角度参数,它们描述了一个物体围绕三个主轴X、Y和Z顺序旋转的情况。三个角分别对应于偏航(Yaw)、俯仰(Pitch)和翻滚(Roll)。 偏航(Yaw):绕Y轴的旋转&…

Android GPU渲染屏幕绘制显示基础概念(1)

Android GPU渲染屏幕绘制显示基础概念(1) Android中的图像生产者OpenGL,Skia,Vulkan将绘制的数据存放在图像缓冲区中,Android中的图像消费SurfaceFlinger从图像缓冲区将数据取出,进行加工及合成。 Surface…

OpenMVS学习笔记(一):WSL编译安装测试

1.CUDA和CUDNN安装 [1] WSL版本cuda安装: >> wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin >> sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600 >> wg…

Vue 数据校验

使用 插件 和 mixin进行数据校验 使用mixin 进行数据校验 <script>// plugin 插件 数据校验// 创建 vue实例const app Vue.createApp({data() {return{name:dell,age: 28}},methods: {handleClick() {this.show !this.show;}},// 数据校验 agerules: {age: {validat…

7个AI驱动的3D模型生成器

老子云AI生成3D模型https://www.laozicloud.com/aiModel 在快速发展的技术世界中&#xff0c;人工智能 (AI) 已经改变了游戏规则&#xff0c;尤其是在 3D 对象生成领域。 AI 驱动的 3D 对象生成器彻底改变了我们创建和可视化 3D 模型的方式&#xff0c;使该过程更加高效、准确…

Star-CCM+通过将所有部件创建一个区域的方式分配至区域后子区域的分离,子区域材料属性的赋值,以及物理连续体的创建方法介绍

前言 上次介绍了将零部件分配至区域的方法与各个方法之间的区别&#xff0c;本文将继续上次的讲解&#xff0c;将其中的“将所有部件分配至一个区域”的应用进行补充。 如下图所示&#xff0c;按照将所有部件创建一个区域的方式分配至区域后&#xff0c;在区域下就会有一个区域…

toB、toC、toD、B2B、C2C、O2O、B2C、P2P到底是什么?

toB、toC、toD到底是什么&#xff1f; toB&#xff08;Business&#xff09;&#xff1a;面向企业用户&#xff0c;例如OA办公系统 toC&#xff08;Consumer&#xff09;&#xff1a;主要是面向个人、客户&#xff0c;例如王者荣耀 toD&#xff08;Developer&#xff09;&…

WPF中ObservableCollection

在WPF&#xff08;Windows Presentation Foundation&#xff09;中&#xff0c;ObservableCollection<T> 是一个非常重要的类&#xff0c;它用于实现动态数据绑定功能。这个类位于 System.Collections.ObjectModel 命名空间中&#xff0c;是 ICollection<T>, IList…

初识微前端

微前端&#xff1a;微前端是一种软件架构模式&#xff0c;旨在解决大型前端应用程序开发和维护中的复杂性问题。它将前端应用程序拆分成更小的、独立的部分&#xff0c;每个部分可以由不同的团队开发、测试、部署和维护。这些独立的部分可以是单独的应用程序或者功能模块&#…

java:遍历目录文件

/*** 通过递归遍历目录下的所有内容&#xff0c;并把所有文件的绝对路径输出在控制台** 思路&#xff1a;* 1.根据给定的路径创建一个File对象* 2.定义一个方法&#xff0c;用于获取给定目录下所有内容&#xff0c;参数为第一步创建的file对象* 3.获取给定的File目录下的文件或…

若依集成mybatis-plus 超详细教程(亲测可用)

文章目录 简介步骤第一步第二步第三步第四步第五步第六步 使用QueryWrapperservice层impl 实现接口类层Mapper层 简介 话不多说 直接跟着下面的教程操作&#xff0c;如果有报错私信我&#xff0c;或者通过博文下面的微信名片加我微信&#xff0c;免费解答哦&#xff01; 步骤 …

代码随想录Day 42|Leetcode|Python|121. 买卖股票的最佳时机 ● 122.买卖股票的最佳时机II

121. 买卖股票的最佳时机 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从…

如何处理Django项目中表数据的排序问题

如何处理Django项目中表数据的按时间排序问题 当我们在写一些项目如购物平台 , 图书管理系统等都会不可避免的遇到排序问题 , 因为作者正在完成一个购物系统的项目 , 所以该文就以电商购物系统来举例说明 在utils文件夹中新建一个modle.py文件 , – utils文件夹主要存放一些非…

opencv图片的旋转-------c++

图片的旋转 /// <summary> /// 图片的旋转 /// </summary> /// <param name"img"></param> /// <param name"angle">旋转角度:正数&#xff0c;则表示逆时针旋转;负数&#xff0c;则表示顺时针旋转</param> /// <…

【吊打面试官系列】Java高并发篇 - 什么是线程调度器(Thread Scheduler)和时间分片(TimeSlicing )?

大家好&#xff0c;我是锋哥。今天分享关于 【什么是线程调度器(Thread Scheduler)和时间分片(TimeSlicing )&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; 什么是线程调度器(Thread Scheduler)和时间分片(TimeSlicing )&#xff1f; 线程调度器是一个操作系统…