ESP32之FreeRTOS--任务的创建和运行


前言

参考文献:官方资料

FreeRTOS类似于UCOS,关于前面的基础就不所了,直接看如何将系统运用到ESP32中去。


提示:以下是本篇文章正文内容

一、创建任务和删除函数

FreeRTOS最基本的功能就是任务管理:创建和删除任务

1.xTaskCreate()

函数原型

static inline IRAM_ATTR BaseType_t xTaskCreate(
			TaskFunction_t pvTaskCode, // 任务函数
			const char * const pcName,//任务名称,没什么用
			const uint32_t usStackDepth,//任务堆栈大小
			void * const pvParameters,//传递给 任务函数的参数
			UBaseType_t uxPriority,//任务优先级
			TaskHandle_t * const pvCreatedTask//任务句柄
			)
	{
		return xTaskCreatePinnedToCore( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pvCreatedTask, tskNO_AFFINITY );
	}

此函数用来创建一个任务,任务需要RAM来保存与任务有关的状态信息(任务控制块),任务也需要一定的RAM来作为任务堆栈。所需的RAM会自动从FreeRTOS的堆中分配。

2.xTaskCreateStatic()

此函数和xTaskCreate()功能一样,但是需要的RAM需要用户来提供

3.xTaskCreateRestricted()

此函数和xTaskCreate()功能一样,但是此函数要求所使用的MCU有MPU(内存保护单元)

4.vTaskDelete()

函数原型

void vTaskDelete( TaskHandle_t xTaskToDelete ) PRIVILEGED_FUNCTION;
使用任务句柄删除指定的任务,若删除任务本身传入NULL即可

用于删除创建的任务

注:
1.从RTOS 实时内核管理中移除任务,要删除的任务将从就绪,封锁,挂起,事件列表中移除

2.任务被删除后就不复存在,也不会再进入运行态, 空闲任务负责释放内核分配给已删除任务的内存

3.只有内核为任务分配的内存空间才会在任务被删除后由空闲任务自动回收,任务自己占用的内存或资源需要由应用程序自己显式地释放

eg:创建三个任务,并在串口打印出来

#include <Arduino.h>

// 任务1
#define TASK1_TASK_PRIO  1          // 任务优先级
#define TASK1_STK_SIZE   1024        // 任务堆栈大小
TaskHandle_t Tasks1_TaskHandle; // 任务句柄
void task1(void *pvParameters); //任务函数

// 任务2
#define TASK2_TASK_PRIO  1        // 任务优先级
#define TASK2_STK_SIZE   1024        // 任务堆栈大小
TaskHandle_t Tasks2_TaskHandle; // 任务句柄
void task2(void *pvParameters); //任务函数

// 任务3
#define TASK3_TASK_PRIO  1          // 任务优先级
#define TASK3_STK_SIZE   1024        // 任务堆栈大小
TaskHandle_t Tasks3_TaskHandle; // 任务句柄
void task3(void *pvParameters); //任务函数

void setup()
{
    Serial.begin(115200);
    // 创建任务
	
    xTaskCreate(task1, "task1_task",TASK1_STK_SIZE,NULL,TASK1_TASK_PRIO,NULL); 

    xTaskCreate(task2, "task2_task",TASK2_STK_SIZE,NULL,TASK2_TASK_PRIO,NULL);

    xTaskCreate(task3, "task3_task",TASK3_STK_SIZE,NULL,TASK3_TASK_PRIO,NULL);
    vTaskStartScheduler(); //启动调度
}
void loop() 
{

}


void task1(void *pvParameters)
{
    while(true)
    {
        Serial.println("task1 runing........");
        vTaskDelay(100/portTICK_PERIOD_MS); //等待1s
    }
}

void task2(void *pvParameters)
{
    while(true)
    {
        Serial.println("task2 runing........");
        vTaskDelay(100/portTICK_PERIOD_MS); //等待1s
    }
    
}
void task3(void *pvParameters)
{
     while(true)
    {
        Serial.println("task3 runing........");
        vTaskDelay(100/portTICK_PERIOD_MS); //等待1s
    }
}

结果
在这里插入图片描述

二、任务函数和任务控制块TCB

1.任务函数模板

使用xTaskCreate()创建任务之后,该函数的第一个参数就是pxTaskCode,也就是我们定义任务函数的函数名,任务函数就是实现任务工作的函数,模板如下

void vATaskFunction(void *pvParameters)
{
    for(;;)
    {
        --任务应用程序--
        vTaskDelay();    
    }
    vTaskDelete(NULL);
}

1.任务函数的本质也是函数,函数名根据情况而定,但是函数的返回类型必须是void类型,函数的参数也必须是viod指针类型

2.任务具体的执行过程是一个大循环,for(;;)或者while(true)都可以

3.在循环里面实现我们真正要做的事情的程序

4.调用vTaskDelay(),任务从运行态进入阻塞态,转而去执行其他任务,这里一定不用使用delay, 一般只要能让任务发送调度就可以,比如信号量,队列,任务调度器都可

5.任务函数一般不允许跳出循环

2.TCB

每个任务都有一些属性要求存储,任务控制块就是实现的该功能的,在使用xTaskCreak()创建任务的时候,会自动的给每个任务分配一个TCB,

主要有一些属性
在这里插入图片描述
在这里插入图片描述

三、延时函数

1.vTaskDelay()

函数原型

void vTaskDelay( const TickType_t xTicksToDelay ) PRIVILEGED_FUNCTION;

在UCOSIII延时函数有三种模式:相对模式,周期模式和绝对模式,
在FreeRTOS中,vTaskDelay()就是相对延时函数,而vTaskDelayUnitl()就是绝对延时函数。

参数xTicksToDelay 是以心跳周期为单位,每个‘1’代表15ms,延时的时间一般大于0,否则直接使用**任务调度函数portYIELD()**进行任务调度(注:延时函数里面调用了任务调度的函数)

如果看过UCOS源码的都知道,调用了该延时函数,任务就相当于挂起,会被从就绪列表中删除,然后会被添加到时基列表,当延时时间到就会重新添加到就绪列表

实时操作系统的两大列表就是时基列表和就绪列表
有兴趣的大佬可以看这篇UCOS的介绍:UCOSiii源码阅读

2.vTaskDelayUntil()

函数原型

void vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) PRIVILEGED_FUNCTION;

延时的绝对时间,应用于按照一定频率运行的任务

该处使用的url网络请求的数据。


3.系统时钟节拍

简单说一下,xTickCount就是该系统的系统时钟节拍计数器,每个定时器中断中xTickCount就会加一,实现函数如下:

BaseType_t xTaskIncrementTick( void ) PRIVILEGED_FUNCTION;

判断任务延时时间结束与否,也是在这里完成的

四、任务挂起和恢复函数

在这里插入图片描述
有时我们需要暂停某个任务,这时就需要用到任务挂起和任务恢复

1.vTaskSuspend()

函数原型

void vTaskSuspend( TaskHandle_t xTaskToSuspend ) PRIVILEGED_FUNCTION;

用于将某个任务设置为挂起状态,进入挂起状态后,只有使用vTaskResume和xTaskResumeFromISR才会进入运行态

如果传入参数为NULL,表示挂起任务本身,可以传入其他任务句柄挂起其他任务,xTaskGetHandle()可根据任务名称获取某个任务的任务句柄

2.vTaskResume()

函数原型

void vTaskResume( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;

将一个任务从挂起状态恢复到就绪态,只有挂起的任务次才可以使用该函数

3.xTaskResumeFromISR()

函数原型

BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION;

用于在中断服务函数中恢复一个任务

其他一些于任务有关的相关函数
在这里插入图片描述

总结

提示:这里对文章进行总结:

对于ESP32FreeRTOS教程,你可以参考以下步骤: 1. 首先,确保你已经安装了ESP32的开发环境,包括ESP-IDF(ESP32 IoT Development Framework)相应的工具链。 2. 了解FreeRTOS的基本概念特性。FreeRTOS是一个用于嵌入式系统的开源实时操作系统,它提供了任务管理、时间管理、内存管理等功能,可以帮助你更好地组织管理ESP32上的任务。 3. 创建一个FreeRTOS任务。在ESP-IDF中,你可以使用FreeRTOS API创建管理任务。你可以定义任务函数,并使用xTaskCreate函数创建一个任务。例如,你可以创建一个LED闪烁的任务任务函数中通过控制GPIO实现LED的闪烁。 4. 理解任务优先级调度。FreeRTOS通过任务优先级来确定任务的执行顺序。较高优先级的任务将在较低优先级的任务之前执行。你可以使用vTaskPrioritySet函数设置任务的优先级,并通过vTaskDelay函数实现任务之间的时间延迟。 5. 学习任务通信同步机制。在多任务系统中,任务之间需要进行通信同步。FreeRTOS提供了多种机制来实现这些功能,例如队列、信号量、事件组等。你可以根据具体的需求选择合适的机制来实现任务之间的数据传递同步操作。 6. 调试测试。在开发过程中,你可能会遇到一些问题,例如任务死锁、内存泄漏等。ESP-IDF提供了一些调试工具功能来帮助你定位解决这些问题,例如FreeRTOS的跟踪功能内存泄漏检测工具。 希望以上步骤对你有所帮助!如果你需要更详细的教程或有其他问题,请随时提问。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Super.Bear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值