ESP32 FreeRTOS-调试任务实用工具(4)

提示:好记性不如烂笔头。本博客作为学习笔记,有错误的地方希望指正

ESP32-FreeRTOS序列:

ESP32 FreeRTOS-任务的创建与删除 (1)
ESP32 FreeRTOS-任务输入参数(2)
ESP32 FreeRTOS-任务优先级(3)
ESP32 FreeRTOS-调试任务实用工具(4)

前言:

  参考资料:FreeRTOS API参考
  对于多任务的调试,FreeRTOS也给出了许多的API,方便我们在调试的时候查看任务各方面的资源。

一、获取系统状态uxTaskGetSystemState()

API原型:

UBaseType_t uxTaskGetSystemState(
                       TaskStatus_t * const pxTaskStatusArray,
                       const UBaseType_t uxArraySize,
                       unsigned long * const pulTotalRunTime );

  configUSE_TRACE_FACILITY必须在FreeRTOSConfig.h中定义为1,uxTaskGetSystemState()才可用。
  uxTaskGetSystemState()为系统中的每个任务填充一个 TaskStatus_t 结构。TaskStatus_t结构包含了任务句柄、任务名称、任务优先级、任务状态和任务所消耗的总运行时间等成员。
  参见vTaskGetInfo(),该版本为单个任务,而不是每个任务填充TaskStatus_t结构。
  注意:该函数仅用于调试,因为它的使用会导致调度器在很长一段时间内保持暂停。
参数:

  • pxTaskStatusArray: 一个指向TaskStatus_t结构阵列的指针。该数组必须包含每个在RTOS控制下的任务的至少一个TaskStatus_t结构。在RTOS控制下的任务数量可以通过uxTaskGetNumberOfTasks()API函数来确定。
  • uxArraySize: 由pxTaskStatusArray参数指向的数组的大小。该大小被指定为数组中的索引数(数组中包含的TaskStatus_t结构数),而不是数组中的字节数。
  • pulTotalRunTime: 如果在FreeRTOSConfig.h中configGENERATE_RUN_TIME_STATS被设置为1,那么*pulTotalRunTime被uxTaskGetSystemState()设置为目标启动后的总运行时间(由运行时间统计时钟定义)。 pulTotalRunTime可以被设置为NULL,省略总运行时间值。
    返回:
      由uxTaskGetSystemState()填充的TaskStatus_t结构的数量。这应该等于uxTaskGetNumberOfTasks()API函数返回的数量,但如果uxArraySize参数中传递的值太小,则为零。
    使用范例:
    TaskStatus_t的定义:
typedef struct xTASK_STATUS
{
   /* The handle of the task to which the rest of the information in the
   structure relates. */
   TaskHandle_t xHandle;

   /* A pointer to the task's name.  This value will be invalid if the task was
   deleted since the structure was populated! */
   const signed char *pcTaskName;

   /* A number unique to the task. */
   UBaseType_t xTaskNumber;

   /* The state in which the task existed when the structure was populated. */
   eTaskState eCurrentState;

   /* The priority at which the task was running (may be inherited) when the
   structure was populated. */
   UBaseType_t uxCurrentPriority;

   /* The priority to which the task will return if the task's current priority
   has been inherited to avoid unbounded priority inversion when obtaining a
   mutex.  Only valid if configUSE_MUTEXES is defined as 1 in
   FreeRTOSConfig.h. */
   UBaseType_t uxBasePriority;

   /* The total run time allocated to the task so far, as defined by the run
   time stats clock.  Only valid when configGENERATE_RUN_TIME_STATS is
   defined as 1 in FreeRTOSConfig.h. */
   unsigned long ulRunTimeCounter;

   /* Points to the lowest address of the task's stack area. */
   StackType_t *pxStackBase;

   /* The minimum amount of stack space that has remained for the task since
   the task was created.  The closer this value is to zero the closer the task
   has come to overflowing its stack. */
   configSTACK_DEPTH_TYPE usStackHighWaterMark;
} TaskStatus_t;
/* This example demonstrates how a human readable table of run time stats
information is generated from raw data provided by uxTaskGetSystemState().
The human readable table is written to pcWriteBuffer.  (see the vTaskList()
API function which actually does just this). */
void vTaskGetRunTimeStats( signed char *pcWriteBuffer )
{
TaskStatus_t *pxTaskStatusArray;
volatile UBaseType_t uxArraySize, x;
unsigned long ulTotalRunTime, ulStatsAsPercentage;

   /* Make sure the write buffer does not contain a string. */
   *pcWriteBuffer = 0x00;

   /* Take a snapshot of the number of tasks in case it changes while this
   function is executing. */
   uxArraySize = uxTaskGetNumberOfTasks();

   /* Allocate a TaskStatus_t structure for each task.  An array could be
   allocated statically at compile time. */
   pxTaskStatusArray = pvPortMalloc( uxArraySize * sizeof( TaskStatus_t ) );

   if( pxTaskStatusArray != NULL )
   {
      /* Generate raw status information about each task. */
      uxArraySize = uxTaskGetSystemState( pxTaskStatusArray,
                                 uxArraySize,
                                 &ulTotalRunTime );

      /* For percentage calculations. */
      ulTotalRunTime /= 100UL;

      /* Avoid divide by zero errors. */
      if( ulTotalRunTime > 0 )
      {
         /* For each populated position in the pxTaskStatusArray array,
         format the raw data as human readable ASCII data. */
         for( x = 0; x < uxArraySize; x++ )
         {
            /* What percentage of the total run time has the task used?
            This will always be rounded down to the nearest integer.
            ulTotalRunTimeDiv100 has already been divided by 100. */
            ulStatsAsPercentage =
                  pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalRunTime;

            if( ulStatsAsPercentage > 0UL )
            {
               sprintf( pcWriteBuffer, "%stt%lutt%lu%%rn",
                                 pxTaskStatusArray[ x ].pcTaskName,
                                 pxTaskStatusArray[ x ].ulRunTimeCounter,
                                 ulStatsAsPercentage );
            }
            else
            {
               /* If the percentage is zero here then the task has
               consumed less than 1% of the total run time. */
               sprintf( pcWriteBuffer, "%stt%lutt<1%%rn",
                                 pxTaskStatusArray[ x ].pcTaskName,
                                 pxTaskStatusArray[ x ].ulRunTimeCounter );
            }

            pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );
         }
      }

      /* The array is no longer needed, free the memory it consumes. */
      vPortFree( pxTaskStatusArray );
   }
}

  需要使用该API需要打开sdkconfig打开USE_TRACE_FACILITY和GENERATE_RUN_TIME_STATS的配置。
在这里插入图片描述
在这里插入图片描述

二、获取任务信息vTaskGetInfo()

API原型:

void vTaskGetInfo( TaskHandle_t xTask,
                   TaskStatus_t *pxTaskStatus,
                   BaseType_t xGetFreeStackSpace,
                   eTaskState eState );

  configUSE_TRACE_FACILITY必须在FreeRTOSConfig.h中定义为1,vTaskGetInfo()才可用。
  uxTaskGetSystemState()为系统中的每个任务填充一个TaskStatus_t结构,而vTaskGetInfo()只为单个任务填充一个TaskStatus_t结构。TaskStatus_t结构包含了任务句柄、任务名称、任务优先级、任务状态和任务所消耗的总运行时间等成员。
  注意:该函数仅用于调试,因为它的使用会导致调度器长时间悬浮。
参数:

  • xTask: 被查询的任务的句柄。将xTask设置为NULL将返回调用任务的信息。
  • pxTaskStatus: 由pxTaskStatus指向的TaskStatus_t结构将被填入由xTask参数中传递的句柄引用的任务信息。
  • xGetFreeStackSpace: TaskStatus_t结构包含一个成员,报告被查询任务的堆栈高水位。堆栈高水位线是曾经存在的最小的堆栈空间,所以数字越接近于零,任务就越接近于溢出其堆栈。计算堆栈高水位线需要相对较长的时间,并可能使系统暂时没有反应–所以提供xGetFreeStackSpace参数,允许跳过高水位线检查。只有当xGetFreeStackSpace没有被设置为pdFALSE时,高水位标记值才会被写入TaskStatus_t结构。
  • eState: TaskStatus_t 结构包含一个成员,用于报告被查询任务的状态。获取任务状态并不像简单的赋值那么快–所以提供eState参数是为了允许从TaskStatus_t结构中省略状态信息。要获得状态信息,就把eState设置为eInvalid–否则eState中传递的值将被报告为TaskStatus_t结构中的任务状态。
    TaskStatus_t的定义:
typedef struct xTASK_STATUS
{
   /* The handle of the task to which the rest of the information in the
   structure relates. */
   TaskHandle_t xHandle;

   /* A pointer to the task's name.  This value will be invalid if the task was
   deleted since the structure was populated! */
   const signed char *pcTaskName;

   /* A number unique to the task. */
   UBaseType_t xTaskNumber;

   /* The state in which the task existed when the structure was populated. */
   eTaskState eCurrentState;

   /* The priority at which the task was running (may be inherited) when the
   structure was populated. */
   UBaseType_t uxCurrentPriority;

   /* The priority to which the task will return if the task's current priority
   has been inherited to avoid unbounded priority inversion when obtaining a
   mutex.  Only valid if configUSE_MUTEXES is defined as 1 in
   FreeRTOSConfig.h. */
   UBaseType_t uxBasePriority;

   /* The total run time allocated to the task so far, as defined by the run
   time stats clock.  Only valid when configGENERATE_RUN_TIME_STATS is
   defined as 1 in FreeRTOSConfig.h. */
   unsigned long ulRunTimeCounter;

   /* Points to the lowest address of the task's stack area. */
   StackType_t *pxStackBase;

   /* The minimum amount of stack space that has remained for the task since
   the task was created.  The closer this value is to zero the closer the task
   has come to overflowing its stack. */
   configSTACK_DEPTH_TYPE usStackHighWaterMark;
} TaskStatus_t;

使用示例:

void vAFunction( void )
{
TaskHandle_t xHandle;
TaskStatus_t xTaskDetails;

    /* Obtain the handle of a task from its name. */
    xHandle = xTaskGetHandle( "Task_Name" );

    /* Check the handle is not NULL. */
    configASSERT( xHandle );

    /* Use the handle to obtain further information about the task. */
    vTaskGetInfo( /* The handle of the task being queried. */
                  xHandle,
                  /* The TaskStatus_t structure to complete with information
                  on xTask. */
                  &xTaskDetails,
                  /* Include the stack high water mark value in the
                  TaskStatus_t structure. */
                  pdTRUE,
                  /* Include the task state in the TaskStatus_t structure. */
                  eInvalid );
}

  需要使用该API需要打开sdkconfig打开USE_TRACE_FACILITY的配置。
在这里插入图片描述

三、获取应用任务标签xTaskGetApplicationTaskTag() xTaskGetApplicationTaskTagFromISR()

API原型:

TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask );
TaskHookFunction_t xTaskGetApplicationTaskTagFromISR( TaskHandle_t xTask );

  configUSE_APPLICATION_TASK_TAG必须被定义为1,这些功能才可用。更多信息请参见RTOS配置文档。
  xTaskGetApplicationTaskTagFromISR()是xTaskGetApplicationTaskTag()的一个版本,可以从中断服务程序(ISR)中调用。
  返回与一个任务相关的 "标签 "值。标签值的含义和用途由应用程序编写者定义。RTOS内核本身通常不会访问标签值。
  这个函数只为高级用户准备。
参数:
  xTask 被查询的任务的句柄。一个任务可以通过使用NULL作为参数值来查询自己的标签值。
返回:
  被查询的任务的 "标签 "值。
使用示例:

/* In this example, an integer is set as the task tag value. */
void vATask( void *pvParameters )
{
    /* Assign a tag value of 1 to the currently executing task.
    The (void *) cast is used to prevent compiler warnings. */
    vTaskSetApplicationTaskTag( NULL, ( void * ) 1 );

    for( ;; )
    {
        /* Rest of task code goes here. */
    }
}

void vAFunction( void )
{
TaskHandle_t xHandle;
int iReturnedTaskHandle;

   /* Create a task from the vATask() function, storing the handle to the
   created task in the xTask variable. */

   /* Create the task. */
   if( xTaskCreate(
             vATask,         /* Pointer to the function that implements
                                the task. */
             "Demo task",    /* Text name given to the task. */
             STACK_SIZE,     /* The size of the stack that should be created
                                for the task.  This is defined in words, not
                                bytes. */
             NULL,           /* The task does not use the
                              parameter. */
             TASK_PRIORITY,  /* The priority to assign to the newly created
                                task. */
             &xHandle        /* The handle to the task being created will be
                                placed in xHandle. */
             ) == pdPASS )
   {
       /* The task was created successfully.  Delay for a short period to allow
       the task to run. */
       vTaskDelay( 100 );

       /* What tag value is assigned to the task?  The returned tag value is
       stored in an integer, so cast to an integer to prevent compiler
       warnings. */
       iReturnedTaskHandle = ( int ) xTaskGetApplicationTaskTag( xHandle );
   }
}

四、获取任务当前句柄xTaskGetCurrentTaskHandle()

API原型:

TaskHandle_t xTaskGetCurrentTaskHandle( void );

  INCLUDE_xTaskGetCurrentTaskHandle必须被设置为1才能使用这个函数。
返回:
  当前运行(调用)的任务的句柄。

五、获取任务状态eTaskGetState()

API原型:

eTaskState eTaskGetState( TaskHandle_t xTask );

  作为一个枚举类型返回任务在执行eTaskGetState()时存在的状态。INCLUDE_eTaskGetState必须在FreeRTOSConfig.h中被设置为1,以便eTaskGetState()可用。参见vTaskGetInfo()。
参数:

  • xTask: 主题任务(被查询的任务)的句柄。

返回:
  下表列出了eTaskGetState()对xTask参数所引用的任务可能存在的每种状态的返回值。

状态返回值
ReadyeRead(就绪)
RunningeRunning (the calling task is querying its own priority)(运行)
BlockedeBlocked(堵塞)
SuspendedeSuspended(挂起)
DeletedeDeleted (the tasks TCB is waiting to be cleaned up(删除)

  关于任务的状态准备在下一篇中介绍。

六、获取任务名字pcTaskGetName()

API原型:

char * pcTaskGetName( TaskHandle_t xTaskToQuery );

  从一个任务的句柄中查找该任务的名称。
参数:
  xTaskToQuery 被查询的任务的句柄。xTaskToQuery可以被设置为NULL来查询调用任务的名称。
返回:
  一个指向主题任务名称的指针,它是一个标准的以NULL结尾的C语言字符串。

七、获取任务句柄xTaskGetHandle()

API原型:

TaskHandle_t xTaskGetHandle( const char *pcNameToQuery );

  从任务的名称中查找任务的句柄。
  注意:这个函数需要较长的时间来完成,对每个任务只应调用一次。一旦获得一个任务的句柄,就可以将其保存在本地以便再次使用。
  INCLUDE_xTaskGetHandle必须在FreeRTOSConfig.h中设置为1,才能使用xTaskGetHandle()。
参数:

  • pcNameToQuery: 将被返回句柄的任务的文本名称(作为标准的C语言NULL结束的字符串)。
    参见xTaskCreate()和xTaskCreateStatic()API函数的pcName参数,以了解关于设置任务文本名称的信息。

返回:
  如果可以找到一个具有pcNameToQuery中传递的名称的任务,那么将返回该任务的句柄,否则将返回NULL。

八、获取任务滴答计数xTaskGetTickCount()

API原型:

volatile TickType_t xTaskGetTickCount( void );

  这个函数不能从ISR中调用。请使用xTaskGetTickCountFromISR()代替。
返回:
  自vTaskStartScheduler被调用后的刻度计数。

九、中断中获取任务滴答计数xTaskGetTickCountFromISR()

API原型:

volatile TickType_t xTaskGetTickCountFromISR( void );

  xTaskGetTickCount()的一个版本,可以从ISR中调用。
返回:
  自vTaskStartScheduler被调用后的刻度计数。

十、获取任务调度状态xTaskGetSchedulerState()

API原型:

BaseType_t xTaskGetSchedulerState( void );

返回:
  以下常量之一(在task.h中定义):taskSCHEDULER_NOT_STARTED, taskSCHEDULER_RUNNING, taskSCHEDULER_SUSPENDED。
  INCLUDE_xTaskGetSchedulerState或configUSE_TIMERS必须在FreeRTOSConfig.h中设置为1才能使用此函数。

十一、获取总任务数量uxTaskGetNumberOfTasks()

API原型:

UBaseType_t uxTaskGetNumberOfTasks( void );

返回:
  实时操作系统内核目前正在管理的任务数量。这包括所有准备好的、阻塞的和暂停的任务。一个已经被删除但尚未被空闲任务释放的任务也将被包括在这个计数中。

十二、任务列表vTaskList()

API原型:

void vTaskList( char *pcWriteBuffer );

  configUSE_TRACE_FACILITY 和 configUSE_STATS_FORMATTING_FUNCTIONS 必须在 FreeRTOSConfig.h 中定义为 1 才能使用此函数。更多信息请参见配置部分。
  注意:这个函数将在其持续时间内禁用中断。它不打算用于正常的应用程序的运行,而是作为一个调试辅助工具。
  vTaskList()调用uxTaskGetSystemState(),然后将uxTaskGetSystemState()生成的原始数据格式化为人类可读的(ASCII)表格,显示每个任务的状态,包括任务的堆栈高水位线(高水位线数字越小,任务越接近堆栈溢出)。点击这里可以看到生成的输出示例。
  在ASCII表中,以下字母用来表示任务的状态。

  • ‘B’–阻塞的
  • ’R’- 准备就绪
  • ‘D’- 已删除(等待清理)。
  • ‘S’ - 暂停,或没有超时的阻塞

  vTaskList()是一个只为方便而提供的实用函数。它不被认为是内核的一部分。参见vTaskGetRunTimeStats(),该函数可以生成一个类似的运行时任务利用信息表。

参数:

  • pcWriteBuffer: 一个缓冲区,上述的细节将以ASCII形式写入其中。这个缓冲区被假定为足够大,以包含生成的报告。每个任务大约有40个字节应该足够了。

  其中状态打印格式如下

  • Name:任务的名称,例如 IDLE、Task1 等。
  • State:任务的当前状态,例如 R 表示就绪,B 表示阻塞。
  • Prio:任务的优先级,数值越小优先级越高。
  • HWM:任务堆栈的高水位线,表示堆栈的最大使用量。
  • Number:任务的编号,通常是任务的句柄值。
Name      State Prio HWM Number
IDLE      R     0    128 0x20000000
Task1     B     1    256 0x20000100
Task2     S     2    512 0x20000200
Task3     D     3    128 0x20000300

十三、任务开始跟踪vTaskStartTrace()

API原型:

void vTaskStartTrace( char * pcBuffer, unsigned long ulBufferSize );

  该功能与传统的跟踪工具有关--在FreeRTOS V7.1.0中被移除--用户可能会发现较新的Trace Hook Macros更容易使用,也更强大。
  启动一个RTOS内核活动跟踪。追踪记录了哪个任务在什么时候运行的身份。
  追踪文件是以二进制格式存储的。一个单独的DOS工具叫做convtrce.exe,用来将其转换为一个以制表符分隔的文本文件,可以在电子表格中查看和绘制。
参数:

  • pcBuffer: 将被写入跟踪的缓冲区。
  • ulBufferSize: pcBuffer的大小,字节数。追踪将持续到缓冲区满了,或者调用ulTaskEndTrace()。

十四、 任务结束追踪ulTaskEndTrace()

API原型:

unsigned long ulTaskEndTrace( void );

  [该功能与传统的跟踪工具有关--在FreeRTOS V7.1.0中被删除--用户可能会发现较新的Trace Hook Macros使用起来更方便、更强大。]
  停止一个RTOS内核活动跟踪。参见vTaskStartTrace()。
返回:
  已经写入跟踪缓冲区的字节数。

十五、获取任务运行时间统计信息vTaskGetRunTimeStats()

API原型:

void vTaskGetRunTimeStats( char *pcWriteBuffer );

  关于该功能的完整描述,请参见运行时间统计页面。
  configGENERATE_RUN_TIME_STATS、configUSE_STATS_FORMATTING_FUNCTIONS 和 configSUPPORT_DYNAMIC_ALLOCATION 都必须定义为 1 才能使用这个功能。然后,应用程序还必须提供portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()和portGET_RUN_TIME_COUNTER_VALUE的定义,以配置一个外设定时器/计数器,并分别返回定时器的当前计数值。计数器的频率应该至少是滴答计数的10倍。
  注意:这个函数将在其持续时间内禁用中断。它不打算用于正常的应用程序运行时,而是作为一种调试辅助工具。
  vTaskGetRunTimeStats()调用uxTaskGetSystemState(),然后将uxTaskGetSystemState()生成的原始数据格式化为人类可读的(ASCII)表格,显示每个任务在运行状态下花费的时间(每个任务消耗了多少CPU时间)。该数据以绝对值和百分比值的形式提供。绝对值的分辨率取决于应用程序提供的运行时间统计时钟的频率。
  vTaskGetRunTimeStats()是一个实用的函数,只为方便而提供。它不被认为是内核的一部分。参见vTaskList(),它是一个生成每个任务的状态信息的实用函数。
参数:

  • pcWriteBuffer: 一个缓冲区,执行时间将以ASCII形式写入其中。这个缓冲区被假定为足够大,以包含生成的报告。每个任务大约40个字节应该足够了。

返回:NULL

  其中状态打印格式如下

  • 任务名 (Name):任务的名称。
  • 运行时间百分比 (%):任务的运行时间占总运行时间的百分比。
  • 绝对运行时间 (Absolute Time):任务的绝对运行时间(可选,取决于配置)。
Name            Time (%)    Absolute Time
IDLE            50.00       5000
Task1           30.00       3000
Task2           20.00       2000

十六、获取任务空闲运行时间计数器vTaskGetIdleRunTimeCounter()

API原型:

TickType_t xTaskGetIdleRunTimeCounter( void );

  返回空闲任务的运行时间计数器。这个函数可以用来确定空闲任务获得多少CPU时间。关于运行时间统计功能的完整描述,请参见运行时间统计页面。
  configGENERATE_RUN_TIME_STATS和INCLUDE_xTaskGetIdleTaskHandle必须都定义为1,这个函数才可用。然后,应用程序还必须提供portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()和portGET_RUN_TIME_COUNTER_VALUE的定义,以便分别配置外设的定时器/计数器和返回定时器的当前计数值。建议使定时器的频率至少是滴答计数的10倍。

十七、综合示例

示例代码:

/**
 * @file 4_Task_Utilities.c
 * @author WSP
 * @brief  调试任务实用工具
 * @version 0.1
 * @date 2022-10-08
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#include "System_Include.h"

const static char * TAG = "Task_Parameter";
//  APP_task 任务的一些变量
TaskHandle_t APP_task_Utilities_handle = NULL;

// 根据宏定义来修改测试代码中不同部分
#define User_xTaskGetIdleRunTimeCounter    1

/**
 * @brief APP_task
 * @param arg 任务传入的参数
 * @return NULL
 */
void APP_task_Utilities(void * arg)
{
    while (1){
        vTaskDelay(1000/portTICK_PERIOD_MS);
        ESP_LOGI(TAG,"APP_task_Utilities");
    }
}
/**
 * @brief   创建函数初始化
 * @param   NULL
 * @return  NULL
 */
void Task_Utilities_Init(void)
{
    // 创建任务二
    xTaskCreate(APP_task_Utilities,             // 创建任务
                "Task_Utilities",           // 创建任务名
                2048,                           // 任务堆栈
                NULL,                           // 任务参数
                3 ,                             // 任务优先级
                &APP_task_Utilities_handle);    // 任务句柄
    vTaskDelay(5000/portTICK_PERIOD_MS);        // 延时等待

    while (1){
        #if User_uxTaskGetSystemState
            char *  pcWriteBuffer  = (char *)malloc (512);
            TaskStatus_t *pxTaskStatusArray ;                   // 与uxTaskGetSystemState()函数一起使用,返回每个任务的状态。
            volatile UBaseType_t uxArraySize, x;                // volatile确保本条指令不会被编译器的优化而忽略
            uint32_t ulTotalRunTime, ulStatsAsPercentage;       // 定义时间变量、百分比
            uxArraySize = uxTaskGetNumberOfTasks();             // 获取任务数量
            /* 为每个任务分配一个TaskStatus_t结构。 一个数组可以在编译时静态地分配。*/
            pxTaskStatusArray = pvPortMalloc(uxArraySize * sizeof( TaskStatus_t ));
            printf("------------------------ begin output task info----------------------------\n\r");
            if(pxTaskStatusArray != NULL){
                uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize,&ulTotalRunTime);
                printf("\tuxArraySize:%d   RunTime:%u\n\r",uxArraySize,ulTotalRunTime);
                printf("\tfunction name:  ArraySize:          RunTime\n\r");
                if(ulTotalRunTime != 0){
                    for (x = 0; x < uxArraySize; x++){
                        /* 该任务使用了总运行时间的多少百分比?这将总是向下四舍五入到最接近的整数。ulTotalRunTimeDiv100已经被除以100了。*/
                        ulStatsAsPercentage = pxTaskStatusArray[x].ulRunTimeCounter / ulTotalRunTime;
                        if(ulStatsAsPercentage > 0){
                            printf("\t%s\t\t%d\t\t%u\n\r",
                                                    pxTaskStatusArray[x].pcTaskName,            //任务名
                                                    pxTaskStatusArray[x].ulRunTimeCounter,      //任务运行时间
                                                    ulStatsAsPercentage);                       //任务占用率
                        }
                        else{
                            /* 如果这里的百分比为零,那么该任务所消耗的时间不到总运行时间的1%。消耗的时间不到总运行时间的1%。*/
                            printf("\t%s\t\t%u\t\t\n\r",
                                                    pxTaskStatusArray[ x ].pcTaskName,          //任务名
                                                    pxTaskStatusArray[ x ].ulRunTimeCounter);   //任务运行时间
                        }
                    }
                }
            }
            free(pcWriteBuffer);
            vPortFree( pxTaskStatusArray );
            printf("------------------------ end output task info----------------------------\n\r\n\r");
        #elif   User_vTaskGetInfo   
            TaskHandle_t xHandle;
            TaskStatus_t xTaskDetails;
            xHandle = xTaskGetHandle("Task_Utilities");
            vTaskGetInfo(xHandle,&xTaskDetails,pdTRUE,eInvalid); //APP_task_Utilities_handle
            printf("pcTaskName:%s xTaskNumber:%d eCurrentState:%d uxCurrentPriority:%d uxBasePriority:%d usStackHighWaterMark:%d\n\r",  
                                                xTaskDetails.pcTaskName,
                                                xTaskDetails.xTaskNumber,
                                                xTaskDetails.eCurrentState,
                                                xTaskDetails.uxCurrentPriority,
                                                xTaskDetails.uxBasePriority,
                                                xTaskDetails.usStackHighWaterMark);
        #elif User_eTaskGetState
            // Typedef enum
            // {
            //     eRunning = 0,/* 一个任务正在查询自己的状态,所以必须正在运行。*/
            //     eReady,      /* 被查询的任务处于已读或待定的准备列表中。*/
            //     eBlocked,    /* 被查询的任务处于阻塞状态。*/
            //     eSuspended,  /* 被查询的任务处于暂停状态,或者处于无限期超时的阻塞状态。*/
            //     eDeleted,    /* 被查询的任务已被删除,但其TCB尚未被释放。*/
            //     eInvalid     /* 用作 "无效状态 "值。*/
            // } eTaskState;
            printf("Get Task State:%d\n\r",eTaskGetState(APP_task_Utilities_handle));   //获取任务状态
        #elif User_pcTaskGetName
            printf("Get Task Name:%s\n\r",pcTaskGetName(APP_task_Utilities_handle));    //获取任务名称
        #elif User_xTaskGetHandle
            TaskHandle_t Task_Utilities_Handle = xTaskGetHandle("Task_Utilities");      //获取任务句柄
            // 验证获取的句柄是否正确
            printf("Get Task Name:%s\n\r",pcTaskGetName(Task_Utilities_Handle));
        #elif User_xTaskGetTickCount
            printf("Get Task TickCount:%d\n\r",xTaskGetTickCount());                    //获取任务滴答计数
        #elif User_xTaskGetSchedulerState
             printf("Get Task Scheduler State:%d\n\r",xTaskGetSchedulerState());        //获取调度状态
        #elif User_uxTaskGetNumberOfTasks
            printf("Task Get Number Of Tasks:%d\n\r",uxTaskGetNumberOfTasks());
        #elif User_vTaskList
            printf("------------------------ begain vTaskList info----------------------------\n\r");
            char * vTaskList_Buffer = (char *)malloc(512);
            vTaskList(vTaskList_Buffer);
            printf(vTaskList_Buffer);
            free(vTaskList_Buffer);
            printf("------------------------ end vTaskList info----------------------------\n\r\n\r");
        #elif User_vTaskGetRunTimeStats
            printf("------------------------ begain vTaskGetRunTimeStats info----------------------------\n\r");
            char * vTaskList_Buffer = (char *)malloc(512);
            vTaskGetRunTimeStats(vTaskList_Buffer);         //获取任务运行时间统计信息
            printf(vTaskList_Buffer);
            free(vTaskList_Buffer);
            printf("------------------------ end vTaskGetRunTimeStats info----------------------------\n\r\n\r");
        #elif User_xTaskGetIdleRunTimeCounter
            printf("xTaskGetIdleRunTimeCounter:%u\n\r",xTaskGetIdleRunTimeCounter()); 
        #endif  
        // StartTask_Key(NULL);
        vTaskDelay(1000/portTICK_PERIOD_MS);
    }   
}

<think>嗯,用户想了解ESP32在大型项目中的应用,涉及FreeRTOS、多任务框架、事件驱动模型、低功耗、嵌入式AI和边缘计算。首先,我需要确认用户的需求是什么。他们可能是开发者,希望在实际项目中使用ESP32,所以需要具体案例和学习资源。 用户可能已经对ESP32有基础了解,现在想深入大型项目的实施。他们提到的技术点都是ESP32的核心功能,比如FreeRTOS是ESP-IDF的基础,多任务和事件驱动是常见的设计模式,低功耗和AI边缘计算则是当前的热门方向。 需要推荐实际项目案例,这可能包括工业、物联网、智能家居等领域。例如,智能农业系统可能用到传感器网络和低功耗,而智能家居中枢可能涉及边缘计算和AI。然后要找到这些项目的详细资料或开源代码,比如GitHub上的仓库或者厂商提供的案例。 书籍方面,需要涵盖ESP32的高级应用,特别是结合FreeRTOS和AI。O'Reilly的书通常比较实用,还有国内出版社的书籍可能更适合中文用户。在线资源如乐鑫的官方文档、博客和论坛也是关键,尤其是应用笔记和白皮书。 还要考虑用户可能需要的学习路径,比如先掌握FreeRTOS,再学习事件驱动和低功耗设计,最后集成AI模型。边缘计算部分可能需要网络通信和数据处理的知识,比如MQTT、LoRaWAN等协议。 用户可能没有明确说出的是,他们可能在寻找如何将这些技术整合到实际项目中的指导,或者遇到性能优化、多任务协调的问题。因此,推荐的资料不仅要涵盖理论,还要有实践案例和代码示例。 需要验证推荐的资源是否最新,因为ESP32和AI框架更新很快。比如TensorFlow Lite Micro的版本是否支持ESP32的最新芯片。还要考虑中文资源的可用性,比如是否有翻译的书籍或国内开发者的教程。 总结来说,回答需要结构清晰,分点列出项目案例和资源,涵盖书籍、在线文档、开源项目等,并强调实际应用中的技术整合和最佳实践。确保信息准确,链接有效,帮助用户进一步学习和实施项目。</think>以下是针对ESP32在大型项目中应用的综合指南,涵盖FreeRTOS、多任务框架、事件驱动模型、低功耗、嵌入式AI及边缘计算的技术要点和学习资源: --- ### 一、**典型大型项目案例** 1. **工业物联网监测系统** - **技术栈**:FreeRTOS任务协调 + LoRaWAN低功耗通信 + TensorFlow Lite Micro异常检测 - **案例特点**:通过ESP32网关聚合传感器数据,实现电机振动频谱分析的边缘AI推理,云端仅接收报警信息 - **参考项目**:乐鑫《ESP-IoT-Solution》仓库中的Predictive Maintenance示例 2. **城市级智能照明网络** - **技术栈**:Mesh网络事件驱动 + 光感/PIR传感器协同 + 动态功耗管理 - **实现亮点**:2000+节点组网,支持OTA灰度升级与光照策略动态加载 - **行业应用**:飞利浦Hue城市版(基于ESP32定制方案) 3. **农业自动化集群** - **技术组合**:Modbus多主机协议栈 + CNN图像识别(病虫害检测) + 太阳能供电优化 - **开源参考**:AgOpenGPS项目中的ESP32边缘控制器模块 4. **医疗级可穿戴设备** - **关键技术**:FreeRTOS Tickless模式 + 心电信号实时处理 + BLE5.0低功耗传输 - **商业案例**:Withings血压监测手环的ESP32-H2方案 --- ### 二、**核心开发资料** #### 1. **官方权威文档** - **《ESP-IDF编程指南》**(中文版) 深度讲解FreeRTOS移植细节、事件循环机制(esp_event)、低功耗模式(Light-sleep/Deep-sleep) - **《ESP32硬件设计指南》** 含射频电路设计/电源管理章节,适合大型系统PCB布局参考 #### 2. **进阶技术书籍** - **《ESP32-C3物联网工程开发实战》**(机械工业出版社) 第7章详解多任务优先级反转问题解决方案,第11章提供边缘计算数据压缩算法实现 - **《Hands-On Embedded Programming with FreeRTOS》**(Packt) 通过物流AGV控制案例,演示任务看门狗、内存池管理等高级技巧 - **《TinyML:基于ESP32的机器学习实战》**(O'Reilly中文版) 包含语音唤醒词训练、视觉异常检测等工业级案例,配套Jupyter Notebook教程 #### 3. **在线资源** - **GitHub精选仓库**: - [espressif/esp-iot-solution](https://github.com/espressif/esp-iot-solution)(官方工业级解决方案) - [edgeimpulse/example-esp32](https://github.com/edgeimpulse/example-esp32)(端到端ML项目模板) - **在线课程**: - Udemy《Advanced ESP32》(含Zigbee3.0组网实验) - 极客时间《ESP32开发实战》(中文,含智能停车场实战项目) --- ### 三、**关键技术实现要点** #### 1. **FreeRTOS优化技巧** - 使用`uxTaskGetStackHighWaterMark()`监控任务栈深度 - 通过`xTaskCreateStatic()`实现静态内存分配 - 多核任务分配策略(ESP32双核特性应用) #### 2. **事件驱动开发模式** - 结合`esp_event_loop`与MQTT异步通信 - 使用`FreeRTOS队列+信号量`实现跨任务事件传递 - 案例:智能家居中语音/APP/传感器多事件源处理 #### 3. **低功耗设计** - 动态时钟调整API:`esp_pm_configure()` - 外设功耗管理:`esp_sleep_enable_timer_wakeup()` - 实测数据:Deep-sleep模式下电流<10μA #### 4. **嵌入式AI实践** - 模型优化工具:NNOM框架(专为MCU设计) - 典型应用: - 音频场景分类(Librosa特征提取+TensorFlow Lite) - 视觉缺陷检测(量化后的MobileNetV2模型) #### 5. **边缘计算架构** - 本地决策引擎设计: ```c void edge_computing_task(void *pvParam) { while(1) { sensor_data_t data = xQueueReceive(sensor_queue); if(anomaly_detection(data)) { xEventGroupSetBits(event_group, CLOUD_ALERT_BIT); } else { store_local_cache(data); } } } ``` - 数据协议选择:MessagePack vs JSON性能对比 --- ### 四、**开发工具链** 1. **调试工具**: - OpenOCD+JTAG实时追踪任务状态 - ESP-Insights(官方远程诊断平台) 2. **性能分析**: - IDF的`heap_trace`内存分析工具 - Wireshark抓取Wi-Fi/BLE数据包 3. **AI工作流**: Edge Impulse Studio → 模型量化 → ESP-Deploy插件一键部署 --- ### 五、**延伸学习建议** 1. **参加官方认证**:乐鑫ESP-IoT开发者认证(含边缘AI专项) 2. **参考论文**:IEEE《Low-Power Computer Vision on ESP32》 3. **实践路线**: 传感器数据采集 → FreeRTOS任务设计 → 功耗优化 → 集成ML模型 → 构建边缘服务 通过以上资源和技术路线的系统学习,可掌握构建基于ESP32的大型复杂系统的核心能力。建议从官方例程入手,逐步扩展到实际工业项目开发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值