• FreeRTOS学习笔记-任务


    工程模板

    基于esp32官方demo :helloworld工程 进行修改测试。

    关键函数说明

    创建任务(xTaskCreate)

    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 //任务句柄
    						);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 堆栈深度: 实际堆栈大小之所以要乘以4字节,我理解跟处理器总线位宽有关系,esp32是32位CPU,即4Byte,因此乘以4Byte
    • 优先级: 最大优先级为:(configMAX_PRIORITIES-1),configMAX_PRIORITIES参数不宜过大,避免浪费RAM。

    挂起和恢复任务(vTaskSuspend、vTaskResume)

    void vTaskSuspend( TaskHandle_t pxTaskToSuspend //被挂起的任务句柄
    );
    void vTaskResume( TaskHandle_t pxTaskToResume );
    
    • 1
    • 2
    • 3

    句柄为空时,挂起当前任务,其他函数也同样适用

    挂起和恢复任务调度

    • 挂起任务调度器后,当前任务独占CPU,直到恢复调度;
    • 主要在某些关键代码在执行过程中不能被打断时使用;
    • 调度器挂起期间,当前任务不能调用FreeRTOS相关的API;
    • 需要注意独占时间不能超过任务看门狗超时时间,任务看门狗超时默认配置为5s。
    void vTaskSuspendAll( void );//挂起任务调度器
    BaseType_t xTaskResumeAll( void );//恢复调度器 返回值:pdTRUE 和 pdFALSE
    
    • 1
    • 2

    任务列表

    void vTaskList( char *pcWriteBuffer //输出任务列表字符串
    );
    
    • 1
    • 2

    在这里插入图片描述
    State

    • X 表示任务正在执行
    • B 任务被阻塞
    • R 任务Ready
    • S 任务被挂起
    • D 任务被删除

    Stack
    表示任务剩余可用堆栈空间
    Num
    相当于任务ID

    获取任务可用堆栈(uxTaskGetStackHighWaterMark)

    UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask //任务句柄
    );
    
    • 1
    • 2

    结果会随程序执行过程变化,该函数要比 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);//喂狗
    
    • 1
    • 2
    • 3
    • 4
    • 5

    课程演示

    创建任务

    #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");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    效果:

    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);//删除任务
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    效果:

    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");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    效果:

    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110

    效果:

    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");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    效果:

    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    效果

    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);
    
    • 1

    效果:

    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    效果

    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++;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    效果

    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);
        
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    效果

    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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    效果

    mytask1: calc start
    ···························(非打印信息,表示等待一段时间)
    mytask1: calc over
    mytask2: hello world
    mytask2: hello world
    mytask2: hello world
    mytask2: hello world

    任务1计算过程中未调度其他任务,独占cpu,待计算完成后恢复调度。

    任务列表(vTaskList)

    使用前下面几个配置项需要被使能,使能以下配置会增加系统资源消耗,建议谨慎使用。
    在这里插入图片描述

    #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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    效果
    在这里插入图片描述
    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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    效果:
    任务中有打印:app_main: task1_stack = 320
    任务中无打印:app_main: task1_stack = 592

    任务看门狗定时器(Task Watchdog Timer)

    任务看门狗默认超时时间5s,也就是说5s不喂狗就会触发看门狗。
    在这里插入图片描述

    触发IDLE任务看门狗

    #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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    效果
    任务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调用,有两种方法:

    • 当修改任务1的优先级为0,与IDLE同级时,就不会触发看门狗;
    • 在任务1循环中增加阻塞函数,如:
    vTaskDelay(10 / portTICK_PERIOD_MS);
    
    • 1

    添加任务到看门狗列表

    #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);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    效果

    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

  • 相关阅读:
    如何使用java实现第三方支付
    【算能】sail的python-pcie的编译时候,报错:
    Learning to Enhance Low-Light Image via Zero-Reference Deep Curve Estimation
    刷题日常计~JS①
    纯钧(ChunJun,原名FlinkX)框架学习
    多线程模块 | java中的各种锁
    【JavaSE】类和对象 (二) —— 封装、包以及 static 关键字
    Java日期格式化:避免YYYY引发的时间异常
    Linux权限
    使用vue-cli搭建SPA项目及使用和路由及路由嵌套的使用
  • 原文地址:https://blog.csdn.net/ai_ljh/article/details/126723733