SOC-ESP32S3部分:11-任务创建
飞书文档https://x509p6c8to.feishu.cn/wiki/EH3owsPahisvl6kL6k3cqaQ3n0g 在我们学习单片机的时候,main函数入口中一般有一个while大循环在不停轮询,如果我们需要实现多种不同的业务,就需要用到状态机,根据不同时刻的要求执行不同的代码,虽然可以实现需求,但这种情况下代码是比较臃肿的。试想下,如果我们可以开启多个while循环,每个while循环负责不同的业务,这样实现复杂的业务是不是更容易了呢?
void main1(){while (1){//执行某些操作}
}void main2(){while (1){//执行某些操作}
}
在 FreeRTOS 中,任务(Task) 可以通俗地理解为一个独立的“小程序”或“小工人”,每个任务都有自己的工作内容和优先级,它们共同协作完成整个系统的功能。
1、任务是什么?
任务是一个独立的执行单元
每个任务就像一个小工人,负责完成特定的工作。例如:
- 一个任务负责读取传感器数据。
- 一个任务负责控制 LED 灯。
- 一个任务负责处理网络通信。
任务有自己的运行空间
每个任务都有自己的栈(Stack),用于存储临时变量和函数调用信息。任务之间是相互独立的,不会互相干扰。
任务可以同时运行
虽然 ESP32 是单核或双核处理器,但 FreeRTOS 通过快速切换任务,让多个任务看起来像是同时运行的(这叫做“并发”)。
假设我们有一个智能家居系统,需要完成以下功能:
- 读取温度传感器的数据。
- 根据温度控制风扇的开关。
- 将温度数据发送到云端。
我们可以创建 3 个任务:
任务 1:读取温度
每隔 1 秒读取一次温度传感器的数据,并将数据发送到队列中。
任务 2:控制风扇
从队列中读取温度数据,如果温度超过 30°C,打开风扇;否则关闭风扇。
任务 3:上传数据
从队列中读取温度数据,并通过 Wi-Fi 上传到云端。
2、如何实现多任务?
IDF默认是集成了实时操作系统FreeRTOS的,所以FreeRTOS相关接口我们都是可以用的。
但是需要注意的是,IDF的例程中,是不会单独对FreeRTOS通用的任务创建、任务通信等RTOS相关特性进行讲解,这部分我们可以参考FreeRTOS官方文档或者IDF API文档进行了解。
IDF freertos api :https://docs.espressif.com/projects/esp-idf/zh_CN/v5.4/esp32s3/api-reference/system/freertos_idf.html
freertos 官方api:https://www.freertos.org/zh-cn-cmn-s/Documentation/02-Kernel/04-API-references/01-Task-creation/01-xTaskCreate
那这节课,我们就来了解下FreeRTOS的多任务实现。
头文件
#include "freertos/task.h"BaseType_t xTaskCreate(TaskFunction_t pxTaskCode,const char *const pcName,const configSTACK_DEPTH_TYPE usStackDepth,void *const pvParameters,UBaseType_t uxPriority,TaskHandle_t *const pxCreatedTask
);
功能: xTaskCreate 函数用于创建一个新的 FreeRTOS 任务。该函数分配任务所需的内存,并初始化任务控制块(TCB),然后将任务添加到就绪列表中,等待调度器运行该任务。
参数:
pxTaskCode: 指向任务函数的指针。任务函数的原型必须为 void TaskFunction(void *pvParameters)。
pcName: 任务的名称,用于调试和日志记录。长度不能超过 configMAX_TASK_NAME_LEN 个字符。
usStackDepth: 任务堆栈的大小,以字为单位
pvParameters: 传递给任务函数的参数。
uxPriority: 任务的优先级。优先级值越高,任务的优先级越高。优先级值的范围通常是 0 到 configMAX_PRIORITIES - 1。
pxCreatedTask: 用于存储新创建任务的句柄。如果不需要任务句柄,可以传递 NULL。
返回值:
pdPASS: 任务创建成功。
如下方例程,我们在app_main中创建了两个任务task1和task2,创建成功后,我们可以看到app_main、task1、task2间隔运行的效果。
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"static const char *TAG = "MyModule";static void task1_func(void *arg)
{while (1){ESP_LOGI(TAG, "task1 run");vTaskDelay(1000 / portTICK_PERIOD_MS);}
}static void task2_func(void *arg)
{while (1){ESP_LOGI(TAG, "task2 run");vTaskDelay(1000 / portTICK_PERIOD_MS);}
}void app_main(void)
{// 创建任务,任务堆栈大小为 2048 字,优先级为 5xTaskCreate(task1_func, // 任务函数"task1_name", // 任务名称2048, // 堆栈大小(字)NULL, // 传递给任务的参数5, // 任务优先级NULL // 任务句柄);xTaskCreate(task2_func, // 任务函数"task2_name", // 任务名称2048, // 堆栈大小(字)NULL, // 传递给任务的参数5, // 任务优先级NULL // 任务句柄);int cnt = 0;while (1){ESP_LOGI(TAG, "app_main run: %d", cnt++);vTaskDelay(1000 / portTICK_PERIOD_MS);}
}
编译烧录后,运行效果如下: