基于esp32官方demo :helloworld工程 进行修改测试。
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, //任务执行函数
const char * const pcName, //任务名字符串
unsigned short usStackDepth,//任务分配堆栈深度,实际占用字节数为:深度 x 4Byte
void *pvParameters,//向任务传递的参数
UBaseType_t uxPriority,//任务优先级,0为最低优先级,2优先级高于1
TaskHandle_t *pxCreatedTask //任务句柄
);
void vTaskSuspend( TaskHandle_t pxTaskToSuspend //被挂起的任务句柄
);
void vTaskResume( TaskHandle_t pxTaskToResume );
句柄为空时,挂起当前任务,其他函数也同样适用。
void vTaskSuspendAll( void );//挂起任务调度器
BaseType_t xTaskResumeAll( void );//恢复调度器 返回值:pdTRUE 和 pdFALSE
void vTaskList( char *pcWriteBuffer //输出任务列表字符串
);

State
Stack
表示任务剩余可用堆栈空间
Num
相当于任务ID
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask //任务句柄
);
结果会随程序执行过程变化,该函数要比 vTaskList 函数占用系统资源少的多。
头文件: components/esp_system/include/esp_task_wdt.h
esp_err_t esp_task_wdt_init(const esp_task_wdt_config_t *config); //初始化任务看门狗,并加入IDLE任务,在系统启动时已调用
esp_err_t esp_task_wdt_deinit(void);//从看门狗列表移除IDLE任务,并关闭任务看门狗
esp_err_t esp_task_wdt_add(TaskHandle_t task_handle); //添加任务到看门狗列表
esp_err_t esp_task_wdt_delete(TaskHandle_t task_handle);//从看门狗列表移除任务
esp_err_t esp_task_wdt_reset(void);//喂狗
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
while (1)
{
printf("hello world in the mytask1\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, NULL);
printf("Hello world!\n");
}
效果:
Hello world!
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
主程序打印hello world 后,mytask1开始打印。
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
while (1)
{
printf("hello world in the mytask1\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t myTastHandle1 = NULL;
xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, &myTastHandle1);
printf("Hello world!\n");
vTaskDelay(10000 / portTICK_PERIOD_MS);//等待10s
if (myTastHandle1 != NULL)
{
vTaskDelete(myTastHandle1);//删除任务
}
}
效果:
Hello world!
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
mytask1任务执行10s后退出
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
int i = 0;
while (1)
{
printf("hello world in the mytask1\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (i > 10)
{
vTaskDelete(NULL);
}
i++;
}
}
void app_main(void)
{
xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, NULL);
printf("Hello world!\n");
}
效果:
Hello world!
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
hello world in the mytask1
任务执行多次后删除
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
typedef struct a_struct
{
int iMem1;
char *iMem2;
} xStruct;
void mytask1(void *pvParameter)
{
int *p;
int i = 0;
p = (int *)pvParameter;
while (1)
{
printf("mytask1: testNumber = %d\n", *p);
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (i > 2)
{
*p = 1;
vTaskDelete(NULL);
}
i++;
}
}
void mytask2(void *pvParameter)
{
int *p;
int i = 0;
p = (int *)pvParameter;
while (1)
{
printf("mytask2: testArray = {%d,%d,%d,%d}\n", *p, *(p + 1), *(p + 2), *(p + 3));
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (i > 2)
{
*(p + 3) = 1;
vTaskDelete(NULL);
}
i++;
}
}
void mytask3(void *pvParameter)
{
xStruct *p;
int i = 0;
p = (xStruct *)pvParameter;
while (1)
{
printf("mytask3: testStruct: iMem1 =%d, iMem2 = %s }\n", p->iMem1, p->iMem2);
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (i > 2)
{
p->iMem1 = 1;
p->iMem2 = "TEST STRUCT STRING";
vTaskDelete(NULL);
}
i++;
}
}
void mytask4(void *pvParameter)
{
int *p;
int i = 0;
p = (int *)pvParameter;
while (1)
{
printf("mytask4: str = %s\n", (char *)*p);
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (i > 2)
{
*p = (int)&"I am Michael";
vTaskDelete(NULL);
}
i++;
}
}
void app_main(void)
{
int testNumber = 5; //已测试全局或局部变量,都可双向传递
int testArray[] = {0, 2, 5, 8};
xStruct testStruct;
testStruct.iMem1 = 5,
testStruct.iMem2 = "test struct string";
char *str = "I am Hong";
int strAddr = (int)str;
xTaskCreate(mytask1, "mytask1", 1024 * 5, (void *)&testNumber, 1, NULL); //注意,传入的int型变量需取地址 &
xTaskCreate(mytask2, "mytask2", 1024 * 5, (void *)testArray, 1, NULL);
xTaskCreate(mytask3, "mytask3", 1024 * 5, (void *)&testStruct, 1, NULL);
xTaskCreate(mytask4, "mytask4", 1024 * 5, (void *)&strAddr, 1, NULL); //注意传入的是一个整型变量,该变量存放字符串指针
while (1)
{
printf("app_main: testNumber = %d\n", testNumber);
printf("app_main: testArray = {%d,%d,%d,%d}\n", testArray[0], testArray[1], testArray[2], testArray[3]);
printf("app_main: testStruct: iMem1 =%d, iMem2 = %s }\n", testStruct.iMem1, testStruct.iMem2);
printf("app_main: str = %s\n", (char *)strAddr);
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
}
效果:
mytask1: testNumber = 5
app_main: testNumber = 5
mytask2: testArray = {0,2,5,8}
mytask3: testStruct: iMem1 =5, iMem2 = test struct string }
mytask4: str = I am Hong
app_main: testArray = {0,2,5,8}
app_main: testStruct: iMem1 =5, iMem2 = test struct string }
app_main: str = I am Hong
mytask1: testNumber = 5
mytask2: testArray = {0,2,5,8}
mytask3: testStruct: iMem1 =5, iMem2 = test struct string }
mytask4: str = I am Hong
mytask1: testNumber = 5
mytask2: testArray = {0,2,5,8}
mytask3: testStruct: iMem1 =5, iMem2 = test struct string }
mytask4: str = I am Hong
mytask1: testNumber = 5
mytask2: testArray = {0,2,5,8}
mytask3: testStruct: iMem1 =5, iMem2 = test struct string }
mytask4: str = I am Hong
app_main: testNumber = 1
app_main: testArray = {0,2,5,1}
app_main: testStruct: iMem1 =1, iMem2 = TEST STRUCT STRING }
app_main: str = I am Michael
app_main: testNumber = 1
app_main: testArray = {0,2,5,1}
app_main: testStruct: iMem1 =1, iMem2 = TEST STRUCT STRING }
app_main: str = I am Michael
app_main: testNumber = 1
app_main: testArray = {0,2,5,1}
app_main: testStruct: iMem1 =1, iMem2 = TEST STRUCT STRING }
app_main: str = I am Michael
app_main: testNumber = 1
app_main: testArray = {0,2,5,1}
app_main: testStruct: iMem1 =1, iMem2 = TEST STRUCT STRING }
app_main: str = I am Michael
演示了4个任务,分别传入了int、数组、结构体、字符串,并在任务结束前修改传入参数,主线程均能够反馈任务中对变量的修改。
需要注意:字符串只能单向传入,我这边为了实现双向传送的效果,在task4中实际上传入的是一个存放了字符串指针的整型变量。
configMAX_PRIORITIES 定义了系统最大优先级,通过查找确认为25。
需要注意:该定义在多个文件夹下的 FreeRTOSConfig.h文件,我们使用的是esp_additions文件夹下的。

#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
while (1)
{
printf("hello world in the mytask1\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
UBaseType_t task1_Priority;
TaskHandle_t myTastHandle1 = NULL;
xTaskCreate(mytask1, "mytask1", 1024, NULL, 50, &myTastHandle1);
task1_Priority = uxTaskPriorityGet(myTastHandle1);
printf("app_main: task1_Priority = %d\n", task1_Priority);
printf("app_main: Hello world!\n");
}
效果:
app_main: task1_Priority = 24
hello world in the mytask1
app_main: Hello world!
hello world in the mytask1
hello world in the mytask1
最大优先级配置为25-1,因此设置50无效,被限制为24.
相同优先级任务采用时间片机制,使每个任务都能得以运行,并且先创建先运行。
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
while (1)
{
printf("mytask1: hello world\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void mytask2(void *pvParameter)
{
while (1)
{
printf("mytask2: hello world\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
UBaseType_t task1_Priority, task2_Priority;
TaskHandle_t myTastHandle1 = NULL;
TaskHandle_t myTastHandle2 = NULL;
xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, &myTastHandle1);
xTaskCreate(mytask2, "mytask2", 1024, NULL, 1, &myTastHandle2);
task1_Priority = uxTaskPriorityGet(myTastHandle1);
task2_Priority = uxTaskPriorityGet(myTastHandle2);
printf("app_main: task1_Priority = %d task2_Priority = %d \n", task1_Priority, task2_Priority);
}
效果
app_main: task1_Priority = 1 task2_Priority = 1
mytask1: hello world
mytask2: hello world
mytask1: hello world
提高任务2的优先级别:
xTaskCreate(mytask2, "mytask2", 1024, NULL, 2, &myTastHandle2);
效果:
app_main: task1_Priority = 1 task2_Priority = 2
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
while (1)
{
printf("mytask1: hello world\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void mytask2(void *pvParameter)
{
while (1)
{
printf("mytask2: hello world\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
UBaseType_t task1_Priority, task2_Priority;
TaskHandle_t myTastHandle1 = NULL;
TaskHandle_t myTastHandle2 = NULL;
xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, &myTastHandle1);
xTaskCreate(mytask2, "mytask2", 1024, NULL, 2, &myTastHandle2);
task1_Priority = uxTaskPriorityGet(myTastHandle1);
task2_Priority = uxTaskPriorityGet(myTastHandle2);
printf("app_main: task1_Priority = %d task2_Priority = %d \n", task1_Priority, task2_Priority);
/*******2s后提高任务1的优先级************/
vTaskDelay(2000 / portTICK_PERIOD_MS);
vTaskPrioritySet(myTastHandle1, 3);
task1_Priority = uxTaskPriorityGet(myTastHandle1);
task2_Priority = uxTaskPriorityGet(myTastHandle2);
printf("app_main: task1_Priority = %d task2_Priority = %d \n", task1_Priority, task2_Priority);
}
效果
app_main: task1_Priority = 1 task2_Priority = 2
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
app_main: task1_Priority = 3 task2_Priority = 2
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
主程序等待2s,并修改优先级后,任务1先运行
在任务1中修改自身优先级仍然有效:
void mytask1(void *pvParameter)
{
int i = 0;
while (1)
{
printf("mytask1: hello world\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (i == 2)
vTaskPrioritySet(NULL, 3);
i++;
}
}
效果
app_main: task1_Priority = 1 task2_Priority = 2
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask1: hello world
mytask2: hello world
app_main: task1_Priority = 3 task2_Priority = 2
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world

阻塞态具有超时机制,挂起态没有。
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
while (1)
{
printf("mytask1: hello world\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void mytask2(void *pvParameter)
{
while (1)
{
printf("mytask2: hello world\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t myTastHandle1 = NULL;
TaskHandle_t myTastHandle2 = NULL;
xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, &myTastHandle1);
xTaskCreate(mytask2, "mytask2", 1024, NULL, 2, &myTastHandle2);
/*****挂起任务1,等待2s后恢复********/
vTaskSuspend(myTastHandle1);
vTaskDelay(2000 / portTICK_PERIOD_MS);
vTaskResume(myTastHandle1);
}
效果
mytask2: hello world
mytask2: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
printf("mytask1: calc start \n");
/******调度器挂起期间,不能调用RTOS任何API,包括printf也不行 会直接导致系统出错 *******/
vTaskSuspendAll();
for (int i = 0; i < 3000; i++) //没用9999是因为循环时间超过5s,会触发任务看门狗
{
for (int j = 0; j < 9999; j++)
{
;
}
}
xTaskResumeAll();
printf("mytask1: calc over \n");
vTaskDelete(NULL);
}
void mytask2(void *pvParameter)
{
while (1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("mytask2: hello world\n");
}
}
void app_main(void)
{
TaskHandle_t myTastHandle1 = NULL;
TaskHandle_t myTastHandle2 = NULL;
// IDLE任务优先级为0,优先级如果大于IDLE,并长时间独占CPU,会触发任务看门狗
xTaskCreate(mytask1, "mytask1", 1024, NULL, 0, &myTastHandle1);
xTaskCreate(mytask2, "mytask2", 1024, NULL, 0, &myTastHandle2);
}
效果
mytask1: calc start
···························(非打印信息,表示等待一段时间)
mytask1: calc over
mytask2: hello world
mytask2: hello world
mytask2: hello world
mytask2: hello world
任务1计算过程中未调度其他任务,独占cpu,待计算完成后恢复调度。
使用前下面几个配置项需要被使能,使能以下配置会增加系统资源消耗,建议谨慎使用。

#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
printf("mytask1: calc start \n");
vTaskSuspendAll();
for (int i = 0; i < 3000; i++)
{
for (int j = 0; j < 9999; j++)
{
;
}
}
xTaskResumeAll();
printf("mytask1: calc over \n");
vTaskDelete(NULL);
}
void mytask2(void *pvParameter)
{
while (1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
printf("mytask2: hello world\n");
}
}
void app_main(void)
{
TaskHandle_t myTastHandle1 = NULL;
TaskHandle_t myTastHandle2 = NULL;
char taskListStr[512];
xTaskCreate(mytask1, "mytask1", 1024, NULL, 0, &myTastHandle1);
xTaskCreate(mytask2, "mytask2", 1024, NULL, 0, &myTastHandle2);
vTaskDelay(3000 / portTICK_PERIOD_MS);
vTaskList(taskListStr);
printf("Name State Priority Stack Num CPUID\n");
printf("*******************************************************\n");
printf("%s", taskListStr);
}
效果

CPUID为-1 表示当前任务未绑定CPUID
任务1已被删除,因此不在当前列表中
任务堆栈可预设较大值,然后通过以下代码获取可用堆栈大小,再修正配置值。
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
while (1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
//printf("mytask1: hello world\n");
}
}
void app_main(void)
{
UBaseType_t task1_stack;
TaskHandle_t myTastHandle1 = NULL;
xTaskCreate(mytask1, "mytask1", 1024, NULL, 0, &myTastHandle1);
while (1)
{
task1_stack = uxTaskGetStackHighWaterMark(myTastHandle1);
printf("app_main: task1_stack = %d\n", task1_stack);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
效果:
任务中有打印:app_main: task1_stack = 320
任务中无打印:app_main: task1_stack = 592
任务看门狗默认超时时间5s,也就是说5s不喂狗就会触发看门狗。

#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
void mytask1(void *pvParameter)
{
while (1)
;
}
void app_main(void)
{
xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, NULL);
}
效果
任务1优先级高于IDLE(优先级为0),达到5s超时还未切换IDLE时触发看门狗。从调试信息看出,cpu1当前运行任务为mytask1。
E (10306) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (10306) task_wdt: - IDLE (CPU 1)
E (10306) task_wdt: Tasks currently running:
E (10306) task_wdt: CPU 0: IDLE
E (10306) task_wdt: CPU 1: mytask1
E (10306) task_wdt: Print CPU 0 (current core) backtrace
如何让IDLE调用,有两种方法:
vTaskDelay(10 / portTICK_PERIOD_MS);
#include
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_task_wdt.h"
void mytask1(void *pvParameter)
{
while (1)
{
printf("mytask1: hello world\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void mytask2(void *pvParameter)
{
esp_task_wdt_add(NULL);//添加当前任务到任务看门狗列表
while (1)
{
printf("mytask2: hello world\n");
vTaskDelay(1000 / portTICK_PERIOD_MS);
esp_task_wdt_reset();//喂狗
}
}
void app_main(void)
{
xTaskCreate(mytask1, "mytask1", 1024, NULL, 1, NULL);
xTaskCreate(mytask2, "mytask2", 1024, NULL, 1, NULL);
}
效果
mytask1: hello world
mytask2: hello world
mytask2: hello world
mytask1: hello world
mytask2: hello world
两个任务正常运行,当屏蔽任务2中的喂狗函数时,每5s触发一次看门狗,并打印:
E (40306) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (40306) task_wdt: - mytask2 (CPU 0/1)
E (40306) task_wdt: Tasks currently running:
E (40306) task_wdt: CPU 0: IDLE
E (40306) task_wdt: CPU 1: IDLE
E (40306) task_wdt: Print CPU 0 (current core) backtrace