目录
1、任务创建
2、任务删除
3、延迟函数
4、示例:
ESP32的SDK包中内置了FreeRTOS,在FreeRTOS中,线程(Thread)和任务(Task)的概念是相同的。每个任务就是一个线程,有着自己的一个程序
创建任务相当于创建分身,开启多任务后,你可以简单理解为你拥有了多个loop函数,这样每个函数就可以执行单独的功能
多任务的原理:
当操作系统使用某种任务调度策略允许多任务共享一个处理器时,虽然处理器在某一时刻只会给一件任务提供服务,因为调度机制保证不同任务之间的切换速度十分迅速,因此给人多个任务同时运行的错觉。
注意事项:
FreeRTOS 任务不允许以任何方式从实现函数中返回——它们绝不能有一
条”return”语句,也不能执行到函数末尾
一个任务函数可以用来创建若干个任务——创建出的任务均是独立的执行实例,拥
有属于自己的栈空间,以及属于自己的自动变量(栈变量),即任务函数本身定义的变量。
1、任务创建
任务由FreeRTOS中xTaskCreate()这个函数创建
BaseType_t xTaskCreate(
TaskFunction_t pxTaskCode, // 任务函数指针
const char * const pcName, // 任务名称
uint16_t usStackDepth, // 任务堆栈深度
void * const pvParameters, // 传递给任务的参数
UBaseType_t uxPriority, // 任务优先级
TaskHandle_t *pxCreatedTask // 创建任务的句柄
);
2、任务删除
void vTaskDelete(TaskHandle_t xTaskToDelete);
void vTaskToDelete(void *params){
// 任务操作...
vTaskDelete(NULL); // 删除自身
}
void anotherFunction(){
TaskHandle_t xTaskToDeleteHandle;
xTaskCreate(vTaskToDelete, "TaskToDelete", 200, NULL, 2, &xTaskToDeleteHandle);
// 在某个时刻决定删除这个任务
vTaskDelete(xTaskToDeleteHandle);
}
3、延迟函数
在Free RTOS中一般不会使用delay()延迟函数,主要由于delay()函数会对程序造成阻塞,是通过CPU做循环的方式来延时,CPU在延时中是做不了其他东西的,大大浪费了CPU的效率!而且非常危险!在free RTOS系统中常用的是两个函数,相对延迟vTaskDelay和绝对延迟
vTaskDelay()
vTaskDelay()函数的参数单位是系统时钟节拍(Tick)。这意味着当你调用vTaskDelay(2000)时,任务将会被挂起并等待2000个系统时钟节拍后才恢复执行。
系统时钟节拍(Tick)的时长取决于FreeRTOS的配置,具体是多少毫秒或微秒取决于configTICK_RATE_HZ宏的定义,该宏设定了FreeRTOS系统时钟的频率。计算单个时钟节拍的时长可以用公式:
\text{单个Tick的时长} = \frac{1}{\text{configTICK_RATE_HZ}} \text{秒}
例如,如果configTICK_RATE_HZ被定义为1000,那么每个Tick代表1毫秒;如果定义为100,则每个Tick代表10毫秒。因此,在调用vTaskDelay(2000)时,任务将暂停的时间为2000个Tick乘以单个Tick的时长。
ESP32 Arduino环境下,FreeRTOS的心跳频率(即系统时钟节拍频率 configTICK_RATE_HZ)默认通常是100Hz。这意味着每秒钟产生100个时钟节拍,每个节拍之间的时间间隔是10毫秒。因此,当你在ESP32的Arduino代码中使用 vTaskDelay() 函数时,给定的数值应当理解为相对于这个默认节拍频率的延时周期数。例如,vTaskDelay(1) 会导致任务延迟10毫秒。
vTaskDelay(Tick);
ESP32 Tick:单位ms
4、示例:
这里使用的是Platform io创建的,里面已经集成,无需添加该库文件。
#include <Arduino.h>
void task_LED(void *pxCreatedTask)
{
while (1)
{
printf("指示灯任务\n");
vTaskDelay(1000);
}
}
void task_button(void *pxCreatedTask)
{
while (1)
{
printf("按键任务\n");
vTaskDelay(2000);
}
}
// 调度任务
void init_task()
{
xTaskCreate(
task_LED, // 任务函数
"TaskReport", // 任务名
1024 * 10, // 任务栈,根据任务内使用的空间评估,例如任务中有一个10000个字节的数组,那空间最好选择10000+10000*50%
NULL, // 任务参数
1, // 任务优先级, with 3 (configMAX_PRIORITIES - 1) 是最高的,0是最低的.
NULL // 任务句柄
);
xTaskCreate(
task_button, // 任务函数
"TaskButton", // 任务名
1024 * 5, // 任务栈
NULL, // 任务参数
0, // 任务优先级, with 3 (configMAX_PRIORITIES - 1) 是最高的,0是最低的.
NULL // 任务句柄
);
}
void setup()
{
Serial.begin(9600);
init_task(); // 创建任务
printf("初始化开始\n");
}
void loop()
{
printf("main里面的循环\n");
vTaskDelay(2000);
}