FreeRTOS多任务

lcysts
7
2025-08-03

创建多任务

我们还是以上节课的多任务点灯为例,讲解使用FreeRTOS如何创建多个可以并行执行的任务

static inline IRAM_ATTR BaseType_t xTaskCreate(
                            TaskFunction_t pvTaskCode,
                            const char * const pcName,     /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                            const uint32_t usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask) 

我们可以使用xTaskCreate函数创建一个新的任务,该函数有如下参数:

  • pvTaskCode:创建的任务需要执行的逻辑,为一个函数,该函数返回值必须为void,只有一个参数,参数类型必须为void*

  • pcName:任务的名称,一个字符串,自己定义,主要为了方便排查问题;

  • usStackDepth:给任务分配的最大堆栈大小,比如2048,单位是字节,这个值需要根据任务复杂度来选择,一般简单的任务,2048~4096范围的值就足够,如果该任务需要处理的逻辑确实比较繁重,可以适当增大,比如8192

  • pvParameters:传递给任务的参数,类型是void*;

  • uxPriority:任务优先级,一个数字,取值范围为[0, 24],数字越大,优先级越高

  • pxCreatedTask:用于接收该任务的句柄,后续对该任务的操作,需要基于该句柄完成

我们基于上述函数,创建多任务点灯程序

#include <Arduino.h>

#define LED1 23 // 控制第一颗LED灯的引脚
#define LED2 22 // 控制第二颗LED灯的引脚

TaskHandle_t task1;
TaskHandle_t task2;

void handle_led1(void *ptr)
{
  pinMode(LED1, OUTPUT);
  char *param = (char *)ptr;
  Serial.print(param);
  Serial.println(" started");
  while (1)
  {
    digitalWrite(LED1, HIGH);
    vTaskDelay(1000);
    digitalWrite(LED1, LOW);
    vTaskDelay(1000);
  }
  vTaskDelete(NULL);
}

void handle_led2(void *ptr)
{
  pinMode(LED2, OUTPUT);
  char *param = (char *)ptr;
  Serial.print(param);
  Serial.println(" started");
  while (1)
  {
    digitalWrite(LED2, HIGH);
    vTaskDelay(3000);
    digitalWrite(LED2, LOW);
    vTaskDelay(3000);
  }
  vTaskDelete(NULL);
}

void setup()
{
  Serial.begin(115200);
  xTaskCreate(handle_led1, "task1", 2048, (void *)"led1", 1, &task1);
  xTaskCreate(handle_led2, "task2", 2048, (void *)"led2", 1, &task2);

  //vTaskDelete(task1);
  //vTaskDelete(task2);
}

void loop()
{
}

任务绑定CPU

如果我们需要将创建的任务分配到指定的CPU上运行,则可以使用如下函数实现:

BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pvTaskCode,
const char * const pcName,
const uint32_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pvCreatedTask,
const BaseType_t xCoreID);

该函数的作用和上节课介绍的xTaskCreate基本一致,只是它多了一个绑定到CPU的功能,函数前面几个参数功能一样,最后一个参数:

  • xCoreID:需要将任务分配到的CPU编号,esp32可选编号为01,也可以指定常量tskNO_AFFINITY,表示随机分配,查看源码可知xTaskCreate内部调用的也是这个函数,只不过传入的CPU编号为tskNO_AFFINITY

接下来我们改造上面的代码,使用xTaskCreatePinnedToCore函数创建任务,并将它绑定到1号CPU:

#include <Arduino.h>

void echo(void *ptr)
{
    while (1)
        {
            Serial.println(xPortGetCoreID());
        }
    vTaskDelete(NULL);
}

void setup()
{
    Serial.begin(115200);
    xTaskCreatePinnedToCore(echo, "echo", 2048, nullptr, 1, NULL, 1);
}

void loop()
{
}

动物装饰