FreeRTOS入门(02):任务基础使用与说明

news2024/11/25 4:38:39

文章目录

  • 目的
  • 创建任务
  • 任务调度
  • 任务控制
    • 延时函数
    • 任务句柄
    • 获取与修改任务优先级
    • 删除任务
    • 挂起与恢复任务
    • 强制任务离开阻塞状态
  • 空闲任务
  • 总结

目的

任务(Task)是FreeRTOS中供用户使用的最核心的功能,本文将介绍任务创建与使用相关的基础内容。

创建任务

创建任务主要使用 xTaskCreate 这个函数:

// 创建成功会返回pdPASS(1),失败通常返回errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(-1),即内存不足
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,                 // 任务函数
                        const char * const pcName,                 // 任务名称
                                                                   // 长度由FreeRTOSConfig.h中configMAX_TASK_NAME_LEN定义
                        const configSTACK_DEPTH_TYPE usStackDepth, // 该任务栈深度(栈大小),对于32位架构一个深度为四字节
                        void * const pvParameters,                 // 传递给任务的参数
                        UBaseType_t uxPriority,                    // 任务优先级,值越大优先级越高
                                                                   // 最大值为FreeRTOSConfig.h中configMAX_PRIORITIES - 1
                        TaskHandle_t * const pxCreatedTask )       // 任务句柄,后续可以用过该句柄来操作任务

任务需要使用 vTaskStartScheduler(); 来调度运行,通常将该行语句放在程序主循环前面,正常情况下程序将在这里无限循环。

下面是个基础的创建和使用任务的演示,使用CH32V307的FreeRTOS项目模板方式创建项目,替换 main.c 为下面内容:

#include "debug.h"
#include "FreeRTOS.h" // 引入头文件
#include "task.h"     // 引入头文件

/* Task1相关参数与任务处理函数 */
void task1_task(void *pvParameters)
{
    while(1)
    {
        printf("TickCount: %u\r\n", xTaskGetTickCount()); // 打印FreeRTOS时间刻
        vTaskDelay(250); // FreeRTOS的延时函数
                         // FreeRTOSConfig.h中configTICK_RATE_HZ为500,即每2ms调度一次
                         // 所以这里的延时时间是 250 * 2 = 500ms
    }
}

/* 主函数 */
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	SystemCoreClockUpdate();
	Delay_Init();
	USART_Printf_Init(115200);

	xTaskCreate(task1_task, "task1", 256, NULL, 5, NULL); // 创建一个任务

    vTaskStartScheduler(); // 任务调度,任务将在这里根据情况开始运行,程序将在这里无序循环

	while(1){} // 程序不会运行到这里
}

在这里插入图片描述

同一个任务的函数可以用来创建不同的任务,因为默认情况下不同任务有不同的堆栈:

#include "debug.h"
#include "FreeRTOS.h" // 引入头文件
#include "task.h"     // 引入头文件

/* Task1相关参数与任务处理函数 */
void task(void *pvParameters)
{
    const char *pcTaskText = pvParameters;
    while(1)
    {
        printf("%s\r\n", pcTaskText);
        vTaskDelay(500);
    }
}

/* 主函数 */
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	SystemCoreClockUpdate();
	Delay_Init();
	USART_Printf_Init(115200);

	xTaskCreate(task, "task1", 256, "task 1 run", 5, NULL); // 创建一个任务
	xTaskCreate(task, "task2", 256, "task 2 run", 5, NULL); // 创建一个任务

    vTaskStartScheduler(); // 任务调度,任务将在这里根据情况开始运行,程序将在这里无序循环

	while(1){} // 程序不会运行到这里
}

在这里插入图片描述

任务也可以动态的创建:

#include "debug.h"
#include "FreeRTOS.h" // 引入头文件
#include "task.h"     // 引入头文件

/* Task2相关参数与任务处理函数 */
void task2(void *pvParameters){
    while(1)
    {
        printf("task 2 run.\r\n");
        vTaskDelay(500);
    }
}

/* Task1相关参数与任务处理函数 */
void task1(void *pvParameters)
{
    volatile size_t i = 0; // 使用volatile关键词防止编译器优化
    while(1)
    {
        printf("task 1 run.\r\n");
        i++;
        if (i == 3) {                                        // task1执行3次后
            xTaskCreate(task2, "task2", 256, NULL, 5, NULL); // 动态创建任务
        }
        vTaskDelay(1000);
    }
}

/* 主函数 */
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	SystemCoreClockUpdate();
	Delay_Init();
	USART_Printf_Init(115200);

	printf("FreeRTOS Kernel Version:%s\r\n",tskKERNEL_VERSION_NUMBER); // 打印FreeRTOS内核版本号
	xTaskCreate(task1, "task1", 256, NULL, 5, NULL); // 创建一个任务

    vTaskStartScheduler(); // 任务调度,任务将在这里根据情况开始运行,程序将在这里无序循环

	while(1){} // 程序不会运行到这里
}

在这里插入图片描述

除了使用 xTaskCreate 创建任务,还有一些其它方法可以创建任务,主要是一些使用静态内存分配方式创建任务的方法,目前来说除非要求非常高的场合,一般没必要使用这些方式。

任务调度

通常来说FreeRTOS使用时都会用到一个定时器(常用SysTick),定时器定时产生中断,FreeRTOS每次中断时累加系统时间 Tick (就是前面例子中使用 xTaskGetTickCount() 获取的内容),并检查和调度任务运行。

FreeRTOSConfig.h 文件中 configTICK_RATE_HZ 参数用于设置系统中断频率。在上面项目中默认值为 500 ,表示每秒中断 500 次,即每秒 Tick 值加 500 ,每两次调度发生间隔为 2ms ,这 2ms 其实就是每次被调度到执行的任务工作的时间。

任务在OS中各个阶段通常使用下面状态转换图表示:
在这里插入图片描述
Running 即表示当前正在运行的任务; Ready 表示已经准备好但没有时间可以分配给它运行的任务; Blocked 表示正在等待时间或者其它资源可用的任务(比如前面的vTaskDelay方法就会使任务进入Blocked状态); Suspended 主要是手动使用函数挂起的任务。

除了手动创建的任务,系统还有个空闲任务(优先级为0),在没有用户任务执行的适合空闲任务将会执行。空闲任务中会进行一些资源释放等操作,通常开发是最好保证空闲任务能够定期被调度到。

这里有一个问题,如果当前有多个任务处于就绪状态( Ready ),那么应该调度哪个任务执行?

在上面项目的默认设定下:

  • configUSE_PREEMPTION = 1 (在 FreeRTOSConfig.h 文件中定义)
    可以抢占,多任务同时就绪时最高优先级任务将执行;
  • configUSE_TIME_SLICING = 1 (没有主动定义,默认值为1)
    轮流执行,多个同优先级的项目将轮流交替执行;
  • configUSE_TICKLESS_IDLE = 0 (没有主动定义,默认值为0)
  • configIDLE_SHOULD_YIELD = 0 (在 FreeRTOSConfig.h 文件中定义)
    空闲任务不让出时间;

除了上面的调度逻辑,还有一个逻辑是在运行 vTaskStartScheduler(); 语句前添加的任务,高优先级的会先运行,同优先级的后添加的将先运行。

任务控制

任务创建后可以通过一些函数来控制任务状态,主要可以实现改变任务优先级、删除任务、挂起与恢复任务、阻塞任务等功能。

需要注意的是下面出现的任务控制功能可能并不会在相关函数执行后立即生效(比如任务删除自身),这种情况下需要等到下一次任务调度或是空闲任务执行后才会真正生效。

延时函数

前面例子中有出现延时函数,FreeRTOS提供了延时函数主要有下面两种:

// 从进入vTaskDelay函数到函数返回总时间至少为xTicksToDelay个系统Tick时间
void vTaskDelay(const TickType_t xTicksToDelay)

// 从pxPreviousWakeTime系统时间开始至少经过xTimeIncrement个系统时间
BaseType_t xTaskDelayUntil(TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement)
void vTaskDelayUntil(TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement)
// 上面函数中需要用到的系统时间 pxPreviousWakeTime 可以使用下面两个函数获取
TickType_t xTaskGetTickCount(void) // 在普通任务中使用
TickType_t xTaskGetTickCountFromISR(void) // 在中断服务程序中使用

通常来说如果想要设置任务每次执行完成到下次开始执行的延时可以使用第一种延时方式;如果想要任务每次开始执行时间间隔相等那就需要使用第二种方式(周期性任务)。

任务句柄

下面的各种任务控制功能都需要用到任务句柄。任务句柄可以理解为一个结构体,用来保存任务相关的各种内容,所以我们可以通过它来控制指定的任务。

任务句柄类型是 TaskHandle_t ,可以使用下面方式在创建任务时获得:

TaskHandle_t Task_Handler; // 声明任务句柄对象

int main(void)
{
    xTaskCreate(task_func, "name", 256, NULL, 5, &Task_Handler); // 创建任务并获得任务句柄
}

除了在创建时获得任务句柄,也可以使用下面函数获得已创建的任务的任务句柄:

// 获取当前任务任务句柄
// FreeRTOSConfig.h中INCLUDE_xTaskGetCurrentTaskHandle 设置为1才能使用
TaskHandle_t xTaskGetCurrentTaskHandle(void)

// 通过任务名称获取任务句柄
// FreeRTOSConfig.h中INCLUDE_xTaskGetHandle设置为1才能使用
TaskHandle_t xTaskGetHandle(const char *pcNameToQuery)

获取与修改任务优先级

获取与修改任务优先级主要由下面函数进行操作:

// 获取任务优先级
UBaseType_t uxTaskPriorityGet(const TaskHandle_t xTask) // 在普通任务中使用
UBaseType_t uxTaskPriorityGetFromISR(const TaskHandle_t xTask) // 在中断服务程序中使用

// 设置任务优先级
void vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority)

// xTask可以填入NULL,表示执行该函数的任务自身
// uxNewPriority为欲设的任务优先级,值越大优先级越高,最大值为FreeRTOSConfig.h中configMAX_PRIORITIES - 1

删除任务

可以使用下面函数来删除任务:

void vTaskDelete(TaskHandle_t xTaskToDelete)
// xTaskToDelete可以填入NULL,表示执行该函数的任务自身

挂起与恢复任务

挂起与恢复任务主要由下面函数进行操作:

// 挂起任务
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
// xTaskToSuspend可以填入NULL,表示执行该函数的任务自身

// 恢复任务
void vTaskResume(TaskHandle_t xTaskToResume) // 在普通任务中使用
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume) // 在中断服务程序中使用
// 通常恢复任务只能恢复别人,自己不能恢复自己(因为已经被挂起了)

// 暂停所有任务调度
void vTaskSuspendAll(void)
// 恢复所有任务调度
BaseType_t xTaskResumeAll(void)

强制任务离开阻塞状态

强制任务离开阻塞状态主要就下面函数进行操作:

BaseType_t xTaskAbortDelay(TaskHandle_t xTask)
// 如果xTask不在阻塞状态则返回pdFAIL,否则返回pdPASS

空闲任务

FreeRTOS调度器启动时,会自动创建空闲任务,以确保始终存在一个能够运行的任务。空闲任务处于最低优先级(0),以确保如果有更高的优先级应用程序任务处于准备就绪状态时空闲任务不会占用任何CPU时间。

空闲任务负责释放删除自身的任务的内存。除了这个功能,空闲任务还可以有一个由用户实现具体功能的钩子函数 void vApplicationIdleHook(void),该函数会在每次空闲任务运行时被调用。

要使用空闲任务钩子函数,需要在 FreeRTOSConfig.h 文件中定义 configUSE_IDLE_HOOK 值为 1 ,然后实现钩子函数:

void vApplicationIdleHook(void) {
	// TDOD
}

在这里插入图片描述

必须确保钩子函数不能调用任何可能导致空闲任务阻塞的 API 函数 (例如,vTaskDelay () ,或带有阻塞时间的队列或信号量函数 )

空闲钩子函数比较常用的功能有下面一些:

  • 将 CPU 置于省电模式;
  • 测量空闲时间计算 CPU 占用率;
  • 执行一些低优先级,但需要长时间执行的任务;

总结

FreeRTOS中任务的基础使用还是比较简单的。实际项目中通常会有多个任务,任务间多数时候会需要配合工作,这些时候就需要用到 队列、信号量、互斥量 等功能了,这些内容将在后面的文章中进行介绍。

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

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

相关文章

QT入门Containers之QTabWidget

目录 一、QTabWidget界面相关 1、布局介绍 2、更改选项卡的名字 3、设置关闭图标 4、代码测试新增页面在构造函数中添加 5、添加图标 6、常用设置 此文为作者原创,创作不易,转载请标明出处! 一、QTabWidget界面相关 1、布局介绍 选项…

MySQL 数据库基础命令

MySQL 基础命令 一.了解数据库 1、了解数据库对象 1.表: 用于以有组织方式存储数据。以行和列的格式包含数据。 2.索引: 是内部表结构,MySQL 用它基于一列或多列的值来提供对表中各行的快速访问。 3.视图: 是虚拟表&#…

Netcat安装与使用(nc)

Netcat安装与使用1.Netcat简介1.1.Netcat安装1.1.1.安装整体流程1.1.1.1.安装依赖1.1.1.2.安装Netcat1.1.1.3.配置环境变量1.1.1.4.测试1.2.Netcat基本功能1.3.Netcat常用参数2.Netcat用法2.1.前期准备2.2.banner相关信息抓取2.3.端口扫描2.3.1.扫描指定端口2.3.2.扫描指定端口…

springboot启动图案的修改方法

目录 一、springboot项目启动原图 二、如何修改为你心意的图片 1、首先在resource下创建banner.txt这是默认的名字 2、在banner.txt文件中加入你自己的配置 3、生成的图案 4、推荐几个生成的网址 5、修改字符颜色 6、控制Banner的是否开启、输出位置 第一种: …

yarn的global安装命令不生效

问题 yarn全局安装某个依赖完成之后,但依赖没有生效,一般有两种情况导致的。 解决思路 1.yarn命令问题 yarn在全局安装某个依赖时,global要紧接在yarn之后,然后才是add yarn global add xxxx如果出现global在add之后&#xff…

JAVASE半天速通集锦(only 40点,查找and复习必看)

JAVASE 以下内容根据【尚硅谷】7天搞定Java基础,Java零基础极速入门 视频简单总结而成 所谓变量就是可以改变的向量存储;标识符即标识数据的符号——变量名:只有下划线和$,预定义关键字或保留字不给用 基本数据类型 byte 8,sho…

诚邀您体验人工智能AI

近期,人工智能(AI)领域动作频频,OPENAI公司Chat GPT的出现,标志着人工智能的研究与应用已经进入了一个崭新的发展阶段,国内腾讯、阿里巴巴、百度、易网、国外微软、谷歌、苹果、IBM、Amazon,等互…

数据结构---顺序表

专栏:数据结构 个人主页:HaiFan. 专栏简介:从零开始,数据结构!! 顺序表前言接口实现SListInit初始化和SListDestory销毁SListPrint打印表中的元素SListCheckCapacity检查表中空间SListPushBack尾插和SListP…

【项目设计】高并发内存池(一)[项目介绍|内存池介绍|定长内存池的实现]

🎇C学习历程:入门 博客主页:一起去看日落吗持续分享博主的C学习历程博主的能力有限,出现错误希望大家不吝赐教分享给大家一句我很喜欢的话: 也许你现在做的事情,暂时看不到成果,但不要忘记&…

IPVlan 详解

文章目录简介Ipvlan2同节点 Ns 互通Ns 内与宿主机 通信第三种方法Ns 到节点外部结论Ipvlan31. 同节点 Ns 互通Ns 内与宿主机 通信Ns 内到外部网络总结源码分析ipvlan 收包流程收包流程主要探讨使用 ipvlan 为 cni 通过虚拟网卡的实现。简介 ipvlan 和 macvlan 类似&#xff0c…

深度学习入门(六十七)循环神经网络——注意力机制

深度学习入门(六十七)循环神经网络——注意力机制前言循环神经网络——注意力机制课件心理学注意力机制注意力机制是显式地考虑随意线索非参注意力池化层Nadaraya-Watson 核回归:总结教材(注意力提示)1 生物学中的注意…

数据库系统:2. 关系数据库

更好的阅读体验\huge{\color{red}{更好的阅读体验}}更好的阅读体验 文章目录2.1 关系数据结构及形式化定义2.1.1 关系域笛卡尔积关系码三类关系基本关系的性质2.1.2 关系模式2.1.3 关系数据库2.1.4 关系模型的存储结构2.2 关系操作2.2.1 基本的关系操作2.2.2 关系数据语言的分类…

[visual studio]中,关于如何 【调试】 的问题 及 技巧

我们都知道,不会调试的程序员不是一个合格的程序员。 在初学阶段,由于对于语法的不熟悉,我们可能会写出很多语法错误,无法通过编译,编译器会报错,这种错误很好修改。 但是,随着我们不断敲代码…

当面试官问“你的SQL能力怎么样”时,怎么回答才不会掉进应聘陷阱?

在某平台看到一个比较实际的问题,在这里分享给职场新人。 SQL已经是职场最常用的一种编程语言,所以应聘技术或非技术岗位,都可能会被问道一个问题:你的SQL能力怎么样? 对于职场新人来说(SQL高手可以无视下…

JavaScript事件循环

大厂面试题分享 面试题库后端面试题库 (面试必备) 推荐:★★★★★地址:前端面试题库一、异步执行原理1. 单线程的JavaScript我们知道,JavaScript是一种单线程语言,它主要用来与用户互动,以及操…

50-Jenkins-Lockable Resources插件实现资源锁定

Lockable Resources插件实现资源锁定前言安装插件使用插件资源配置Pipeline中使用前言 用来阻止多个构建在同一时间试图使用同一个资源。这里的资源可能是一个节点、一个代理节点、一组节点或代理节点的集合,或者仅仅是一个用于上锁的名字。如果指定的资源没有在全…

ASP.NET MVC | 创建应用程序

目录 首先 NO.1 No.2 App_Data 文件夹 Content 文件夹 Controllers 文件夹 Models 文件夹 Views 文件夹 Scripts 文件夹 最后 首先 一步一步的来,电脑上需要安装vs2019软件,版本高低无所谓,就是功能多少而已。 长这样的&#xff0…

无公网IP如何外网异地登录访问电商进销存系统?

电商进销存系统软件是电商企业必备的重要软件之一。 集订单管理、货品管理、采购管理等功能于一体,主要帮助广大电商用户实现准确、高效的订单处理及精细化的仓储管理。 电商进销存系统软件一般采用B/S结构,用户可在异地访问系统、查看货品库存及管理订…

第五期(2022-2023)传统行业云原生技术落地调研——金融篇 现已开启

随着数字化浪潮的来临,云原生技术正在改变着各行各业,通过IT变革驱动业务创新发展,促进企业自身以及产业生态的转型升级。 因此,灵雀云联合云原生技术实践联盟(CNBPA)和行业内头部厂商F5,共同发…

小黑子的线性代数:第一章

线代从入门到入土:一小黑子的线代系列:第一章1. 行列式1.1 二阶行列式1.2 三阶行列式1.3 小结2. 全排列与逆序数2.1 全排列2.2 逆序数3. 对换4. n阶行列式的定义5. 余子式和代数余子式6. 行列式的性质6.1 转置行列式6.2 对换变号6.3 提取公因子6.4 行列式…