当前位置: 首页 > article >正文

ESP32 freeRTOS笔记 参数传递、任务优先级

一、四种参数传递方式

1.1 整数传递

使用 (void *) 任何类型传递参数,通过地址传递给任务。

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

void myTask(void *pvPragma)
{
    int *getNum;
    getNum = (int *)pvPragma; //强转int类型指针
    printf("Task get num = %d\n",*getNum); //此处*为解地址符,解出地址存的东西
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    vTaskDelete(NULL);
}

int IntNum = 1;

void app_main(void)
{
    xTaskCreate(myTask, "mytask1", 2048, (void *)&IntNum, 1, NULL);    //取地址后传递参数
}

效果如下: 

1.2 数组

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

void myTask(void *pvPragma)
{
    int *pArrayNum;
    pArrayNum = (int *)pvPragma;
    printf("Task get num1 = %d\n", *pArrayNum);
    //因为是int类型指针 +1移动自动移动一个int
    printf("Task get num2 = %d\n", *(pArrayNum + 1)); //此处*为解地址符,解出地址存的东西
    printf("Task get num3 = %d\n", *(pArrayNum + 2));
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    vTaskDelete(NULL);
}

int testNum[] = {5, 6, 7};

void app_main(void)
{
    //数组本来就是地址 直接传递 不加&
    xTaskCreate(myTask, "mytask1", 2048, (void *)testNum, 1, NULL);    
}

效果如下:  

1.3 结构体

和整数传递很像,只不过换成了结构体,任务函数也是强转成结构体指针。

#include <stdio.h>
#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 num1;
    int num2;
} xstruct;//xstruct=struct A_struct,不清楚时查看struct和typedef struct的区别
xstruct testnum = {5,6};
void mytask(void *pvParam)
{
    xstruct *p;                             //声明一个结构体指针类型的变量,
    p = (xstruct *)pvParam;                 // 因为这里参数传的都是地址,将参数强制转化为相同的类型,取得输入参数的地址
    printf("I get testnum num1 = %d\n", p->num1); 
    printf("I get testnum num2 = %d\n", p->num2); 
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    vTaskDelete(NULL);
}
//-------------------------------------------------------
void app_main(void)
{
    xTaskCreate(mytask, "mytask1", 2048, (void *)&testnum, 1, NULL);
}

效果如下:  

1.4 字符串

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

static const char *ptest = "hello world";


void mytask(void *pvParam)
{
    char *p;                            
    p = (char *)pvParam;                 
    printf("I get message = %s\n", p); 
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    vTaskDelete(NULL);
}

void app_main(void)
{
    xTaskCreate(mytask, "mytask1", 2048, (void *)ptest, 1, NULL);
}

效果如下:  

二、Task 任务优先级

2.1 任务优先级简介

FreeRTOS 中任务优先级数字越大,优先级越高。

引用 RTOS 官方手册RTOS task priorities in FreeRTOS for pre-emptive and co-operative real time operation

也就是 configMAX_PRIORITIES 是当前项目中允许的最大优先级。

在下路径中可以找到这个宏定义,其中在 esp-idf 代码中(非项目代码,应该是模板代码路径),FreeRTOSConfig.h 文件保存了这个的默认值。 

2.2 使用 uxTaskPriorityGet()

函数原型:

UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask );
//参数: xTask: 要查找的任务的任务句柄。
//返回值: 获取到的对应的任务的优先级。 

对于 esp32 默认的 configMAX_PRIORITIES 是 25。但是如果我们创建优先级的时候将优先级设置为 25 以上。比如下文的 41。

#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_spi_flash.h"

static const char *ptest = "hello world";

void mytask(void *pvParam)
{
    char *p;                            
    p = (char *)pvParam;                 
    printf("I get message = %s\n", p); 
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    vTaskDelete(NULL);
}

void app_main(void)
{
    UBaseType_t iPriority = 0;
    TaskHandle_t pxTask = NULL;

    xTaskCreate(mytask, "mytask1", 2048, (void *)ptest, 41, &pxTask);

    iPriority = uxTaskPriorityGet(pxTask);
    printf("iPriority = %d\n",iPriority);
}

2.3 使用 vTaskPrioritySet() 

vTaskPrioritySet() 可以设置任务的优先级。如果设置的优先级高于当前执行任务的优先级,则上下文切换将在此函数返回之前发生。

void app_main(void)
{
    TaskHandle_t pxTask = NULL;
    UBaseType_t iPriority = 0;

    xTaskCreate(myTask1, "mytask1", 2048, (void *)ptest, 1,&pxTask);
    xTaskCreate(myTask2, "mytask2", 2048, (void *)ptest, 4, NULL);
    
    vTaskPrioritySet(pxTask,3);

    iPriority = uxTaskPriorityGet(pxTask);
    printf("Task1 iPriority = %d\n",iPriority);
}

 

三、Task 堆栈设置和调试

3.1 显示任务详细信息 vTaskList()

通过 vTaskList来协助分析操作系统当前 task 状态,以帮助优化内存,帮助定位栈溢出问题。

void vTaskList( char *pcWriteBuffer );
parameterdescription
pcWriteBuffer保存任务状态信息表的存储区,须足够大
return

pcWriteBuffe 表中信息:

说明定义
Name创建任务的时候给任务分配的名字
State任务的状态信息,X:运行态,B:阻塞态,R:就绪态,S:挂起态,D:删除态
Priority任务优先级
Stack任务堆栈的“高水位线”,就是堆栈历史最小剩余值
Num任务编号,这个编号是唯一的;当多个任务使用同一个任务名的时候;可以通过编号来区分
void task1(void *pvParam)
{
    while (1)
    {
        printf("task1!\n");
        vTaskDelay(3000 / portTICK_PERIOD_MS);
    }
}

void task2(void *pvParam)
{
    while (1)
    {
        printf("task2!\n");
        vTaskDelay(3000 / portTICK_PERIOD_MS);
    }
}

void app_main(void)
{
    xTaskCreate(task1, "task1", 4096, NULL, 1, NULL);
    xTaskCreate(task2, "task2", 4096, NULL, 1, NULL);

    static char pcWriteBuffer[512] = {0};

    while(1)
    {
        vTaskList(pcWriteBuffer);

        printf("-----------------------------------------\n");
        printf("Name    State   Priority    Stack   Num\n");
        printf("%s\n",pcWriteBuffer);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

 3.2  查看任务剩余的堆栈空间 uxTaskGetStackHighWaterMark() 

函数原型:

UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask)

传 入 值:xTask 要查询的任务的任务句柄,若为NULL表示查询自身任务的高水位线

返 回 值:任务堆栈的高水位线值,即堆栈的历史剩余最小值。

注意是以字节为单位

void task1(void *pvParam)
{
    while (1)
    {
        printf("task1!\n");
        vTaskDelay(3000 / portTICK_PERIOD_MS);
    }
}

void app_main(void)
{
    TaskHandle_t pxTask1;

    xTaskCreate(task1, "task1", 4096, NULL, 1,&pxTask1);
    UBaseType_t iStack;

    while(1)
    {
        iStack = uxTaskGetStackHighWaterMark(pxTask1);
        printf("task1 iStack = %d\n",iStack);

        vTaskDelay(3000 / portTICK_PERIOD_MS);
    }
}

 上述代码中,task1有两行函数。运行效果如下:

如果我们将 task1中的 printf 注释掉

void task1(void *pvParam)
{
    while (1)
    {
        printf("task1!\n");
        vTaskDelay(3000 / portTICK_PERIOD_MS);
    }
}

效果如下:

与之对比,可得出printf占用了大概300多字节的堆栈。


http://www.kler.cn/a/157620.html

相关文章:

  • PDF书籍《手写调用链监控APM系统-Java版》第7章 插件与链路的结合:Tomcat插件实现
  • 从虚拟到现实:AI与AR/VR技术如何改变体验经济?
  • Mysql 查询性能调优总结
  • 计算机毕业设计Python+卷积神经网络租房推荐系统 租房大屏可视化 租房爬虫 hadoop spark 58同城租房爬虫 房源推荐系统
  • 【Select 语法全解密】.NET开源ORM框架 SqlSugar 系列
  • 重温设计模式-外观模式和适配器模式的异同
  • 【每日一题】从二叉搜索树到更大和树
  • 仅 CSS 阅读进度条
  • Spring Boot 之 ModelFactory
  • 【23-24 秋学期】NNDL 作业12 优化算法2D可视化
  • 【蓝桥杯软件赛 零基础备赛20周】第5周——高精度大数运算与队列
  • 基于Python的PyGame的俄罗斯方块游戏设计与实现
  • HostHunter虚拟主机发现
  • 12、pytest上下文友好的输出
  • 【重点】【滑动窗口】76.最小覆盖子串
  • YoloV5改进策略:Swift Parameter-free Attention,无参注意力机制,超分模型的完美迁移
  • VSCode Vue 开发环境配置
  • clip-path,css裁剪函数
  • C语言碎片知识
  • PTA 7-231 买文具
  • 陀螺仪LSM6DSV16X与AI集成(2)----姿态解算
  • 数据结构-栈和队列
  • 一键式紧急报警柱系统
  • 力扣labuladong一刷day27天数组去重
  • 4-Docker命令之docker run
  • 剑指 Offer(第2版)面试题 16:数值的整数次方