FreeRTOS(6)---FreeRTOS 任务应用函数

文章由 FreeRTOS 系列博客整理而来,仅为学习记录,如有不妥,请告知。

FreeRTOS 任务应用函数

任务应用函数是一组辅助类函数,一般用于调试信息输出、获取任务句柄、获取任务状态、操作任务标签值等等。

获取任务系统状态

函数描述

UBaseType_t uxTaskGetSystemState(
			TaskStatus_t * constpxTaskStatusArray,
			const UBaseType_tuxArraySize,
			unsigned long * constpulTotalRunTime );

该函数向 TaskStatus_t 结构体填充相关信息,系统中每一个任务的信息都可以填充到 TaskStatus_t 结构体数组中,数组大小由 uxArraySize 指定。结构体 TaskStatus_t 定义如下:

typedef struct xTASK_STATUS
{
   /* 任务句柄*/
   TaskHandle_t xHandle;
 
   /* 指针,指向任务名*/
   const signed char *pcTaskName;
 
   /*任务ID,是一个独一无二的数字*/
   UBaseType_t xTaskNumber;
 
   /*填充结构体时,任务当前的状态(运行、就绪、挂起等等)*/
   eTaskState eCurrentState;
 
   /*填充结构体时,任务运行(或继承)的优先级。*/
   UBaseType_t uxCurrentPriority;
 
   /* 当任务因继承而改变优先级时,该变量保存任务最初的优先级。仅当configUSE_MUTEXES定义为1有效。*/
   UBaseType_t uxBasePriority;
 
   /* 分配给任务的总运行时间。仅当宏configGENERATE_RUN_TIME_STATS为1时有效。*/
   unsigned long ulRunTimeCounter;
 
   /* 从任务创建起,堆栈剩余的最小数量,这个值越接近0,堆栈溢出的可能越大。 */
   unsigned short usStackHighWaterMark;
}TaskStatus_t;

注意,这个函数仅用来调试用,调用此函数会挂起所有任务,直到函数最后才恢复挂起的任务,因此任务可能被挂起很长时间。在文件 FreeRTOSConfig.h 中,宏 configUSE_TRACE_FACILITY 必须设置为 1,此函数才有效。.

参数描述

  • pxTaskStatusArray:指向 TaskStatus_t 类型的结构体数组。这个数组至少要包含 1 个元素。RTOS控制的任务数量可以使用API函数 uxTaskGetNumberOfTasks()获取。
  • uxArraySize:参数 pxTaskStatusArray 指向的数组大小,也就是该数组的索引数目。
  • pulTotalRunTime:如果在文件 FreeRTOSConfig.h 中设置宏 configGENERATE_RUN_TIME_STATS 为 1,则该函数将总运行时间写入*pulTotalRunTime中。pulTotalRunTime 可以设置为 NULL,表示忽略总运行时间。

返回值

被填充的 TaskStatus_t 结构体数量。这个值应该等于通过调用 API 函数 uxTaskGetNumberOfTasks() 返回的值,但如果传递给 uxArraySize 参数的值太小,则返回0。

用法举例

/*本例演示如是使用uxTaskGetSystemState()函数来获取运行时间信息,并将其转化为程序员更易识别的字符格式,这些转化后的字符保存到pcWriteBuffer中。*/
void vTaskGetRunTimeStats(signed char *pcWriteBuffer )
{
   TaskStatus_t*pxTaskStatusArray;
   volatileUBaseType_t uxArraySize, x;
   unsignedlong ulTotalRunTime, ulStatsAsPercentage;
 
   /* 防御性代码,确保字符串有合理的结束*/
  *pcWriteBuffer = 0x00;
 
   /* 获取任务总数目*/
  uxArraySize = uxTaskGetNumberOfTasks ();
 
   /*为每个任务的TaskStatus_t结构体分配内存,也可以静态的分配一个足够大的数组 */
  pxTaskStatusArray = pvPortMalloc( uxArraySize * sizeof( TaskStatus_t ));
 
   if(pxTaskStatusArray != NULL )
   {
      /*获取每个任务的状态信息 */
     uxArraySize = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize,&ulTotalRunTime );
 
      /* 百分比计算 */
     ulTotalRunTime /= 100UL;
 
      /* 避免除零错误 */
      if(ulTotalRunTime > 0 )
      {
         /* 将获得的每一个任务状态信息部分的转化为程序员容易识别的字符串格式*/
        for( x = 0; x < uxArraySize; x++ )
         {
           /* 计算任务运行时间与总运行时间的百分比。*/
           ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter /ulTotalRunTime;
 
           if( ulStatsAsPercentage > 0UL )
           {
              sprintf( pcWriteBuffer, "%s\t\t%lu\t\t%lu%%\r\n",
                                pxTaskStatusArray[ x ].pcTaskName,
                                pxTaskStatusArray[ x ].ulRunTimeCounter,
                                ulStatsAsPercentage );
           }
           else
           {
              /* 任务运行时间不足总运行时间的1%*/
              sprintf( pcWriteBuffer, "%s\t\t%lu\t\t<1%%\r\n",
                                pxTaskStatusArray[ x ].pcTaskName,
                                 pxTaskStatusArray[x ].ulRunTimeCounter );
           }
 
           pcWriteBuffer += strlen( ( char * ) pcWriteBuffer );
         }
      }
 
      /* 释放之前申请的内存*/
     vPortFree( pxTaskStatusArray );
   }
}

获取当前任务句柄

函数描述

TaskHandle_t xTaskGetCurrentTaskHandle(void );

在文件 FreeRTOSConfig.h 中,宏 INCLUDE_xTaskGetCurrentTaskHandle 必须设置为 1,此函数才有效。

返回值

返回当前任务(调用该函数的任务)的句柄。

获取空闲任务句柄

函数描述

TaskHandle_t xTaskGetIdleTaskHandle(void );

在文件 FreeRTOSConfig.h 中,宏 INCLUDE_xTaskGetIdleTaskHandle 必须设置为1,此函数才有效。

返回值

返回空闲任务句柄。空闲任务在 RTOS 调度器启动时自动创建。

获取任务堆栈最大使用深度

函数描述

UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );

任务的堆栈空间会随着任务执行以及中断处理而增长或缩小。该函数可以返回任务启动后的最小剩余堆栈空间。换句话说,可以间接估算出一个任务最多需要多少堆栈空间。在文件 FreeRTOSConfig.h 中,宏 INCLUDE_uxTaskGetStackHighWaterMark 必须设置成1,此函数才有效。

参数描述

  • xTask:任务句柄。NULL 表示查看当前任务的堆栈使用情况。

返回值

返回最小剩余堆栈空间,以字为单位。比如一个 32 为架构处理器,返回值为 1 表示有 4 字节堆栈空间没有使用过。如果返回值为 0,则任务很可能已经发生了堆栈溢出。

用法举例

void vTask1( void * pvParameters )
 {
     UBaseType_tuxHighWaterMark;

     /* 入口处检测一次 */
     uxHighWaterMark =uxTaskGetStackHighWaterMark( NULL );

     for( ;; )
     {
         /* 正常调用函数 */
         vTaskDelay( 1000 );

         /* 测量堆栈使用情况 */
         uxHighWaterMark =uxTaskGetStackHighWaterMark( NULL );
     }
}

获取任务状态

函数描述

eTaskState eTaskGetState( TaskHandle_txTask );

返回一个枚举类型的任务状态值。在文件 FreeRTOSConfig.h 中,宏 INCLUDE_eTaskGetState 必须设置为 1,此函数才有效。

参数描述

  • xTask:任务句柄

返回值

下表列出返回值和对应的任务状态。

状态返回值
就绪eReady
运行eRunning
阻塞eBlocked
挂起eSuspended
删除eDeleted

获取任务描述内容

函数描述

char * pcTaskGetTaskName( TaskHandle_txTaskToQuery );

获取任务的描述内容,在文件 FreeRTOSConfig.h 中,宏 INCLUDE_pcTaskGetTaskName 必须设置成 1,此函数才有效。

参数描述

  • xTaskToQuery:任务的句柄。NULL 表示获取当前任务的描述内容指针。

返回值

一个指针,指向任务描述字符串。

获取系统节拍次数

函数描述

volatile TickType_t xTaskGetTickCount(void );      

这个函数不能在 ISR 中调用。在 ISR 中用 xTaskGetTickCountFromISR(),原型为 volatileTickType_t xTaskGetTickCountFromISR(void)

返回值

返回从 vTaskStartScheduler 函数调用后的系统时钟节拍次数。

获取调度器状态

函数描述

BaseType_t xTaskGetSchedulerState( void);      

获取调度器当前状态。在文件 FreeRTOSConfig.h 中,宏 INCLUDE_xTaskGetSchedulerStateconfigUSE_TIMERS 必须定义为 1,此函数才有效。

返回值

返回值是以下常量之一(定义在 task.h):taskSCHEDULER_NOT_STARTED(未启动)、taskSCHEDULER_RUNNING(正常运行)、taskSCHEDULER_SUSPENDED(挂起)。

获取任务总数

函数描述

UBaseType_t uxTaskGetNumberOfTasks(void );      

获取 RTOS 内核当前管理的任务总数。包含所有就绪、阻塞和挂起状态的任务。对于一个删除的任务,如果它的堆栈空间还没有被空闲任务释放掉,则这个被删除的任务也含在计数值中。

返回值

返回 RTOS 内核当前管理的任务总数。

获取所有任务详情

函数描述

void vTaskList( char *pcWriteBuffer );      

将每个任务的状态、堆栈使用情况等以字符的形式保存到参数 pcWriteBuffer 指向的区域。vTaskList() 函数调用 usTaskGetSystemState() 函数,然后将得到的信息格式化为程序员易读的字符形式。输出的内容例子如下图所示,图中 State 一栏中,B 表示阻塞、R 表示就绪、D 表示删除(等待清除内存)、S 表示挂起或阻塞。

sss
注意,调用这个函数会挂起所有任务,这一过程可能持续较长时间,因此本函数仅在调试时使用。在文件 FreeRTOSConfig.h 中,宏 configUSE_TRACE_FACILITYconfigUSE_STATS_FORMATTING_FUNCTIONS 必须定义为 1,此函数才有效。

参数描述

  • pcWriteBuffer:任务的信息会写入这个缓冲区,为 ASCII 表单形式。这个缓冲区要足够大,以容纳生成的报告,每个任务大约需要 40 个字节。

获取任务运行时间

函数描述

void vTaskGetRunTimeStats( char*pcWriteBuffer );     

这个函数用于统计每个任务的运行时间。要使用这个函数必须满足一些条件,那就是必须有一个用于时间统计的定时器或计数器,这个定时器或计数器的精度要至少大于 10 倍的系统节拍周期。这个定时器或计数器的配置以及获取定时时间是由两个宏定义实现的,这两个宏一般在文件 FreeRTOSConfig.h 中定义。配置定时器或计数器的宏为 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(),获取定时时间的宏为 portGET_RUN_TIME_COUNTER_VALUE。实现了这两个宏定义后,还必须在文件 FreeRTOSConfig.h 中将宏 configGENERATE_RUN_TIME_STATSconfigUSE_STATS_FORMATTING_FUNCTIONS 设置为 1,此 API 函数才有效。

这个 API 函数调用 usTaskGetSystemState() 函数获取每个任务的状态信息,并把其中的运行时间格式化为程序员易读的字符形式,并将这些信息保存到参数 pcWriteBuffer 指向的区域。

注意,调用这个函数会挂起所有任务,这一过程可能持续较长时间,因此本函数仅在调试时使用。

参数描述

  • pcWriteBuffer:任务的运行时间信息会写入这个缓冲区,为 ASCII 表单形式。这个缓冲区要足够大,以容纳生成的报告,每个任务大约需要 40 个字节。

用法举例

以 lpc17xx 系列为控制为例,我们使用定时器 0 来作为统计基准时钟。

使能函数宏

在文件 FreeRTOSConfig.h 中,设置宏 configGENERATE_RUN_TIME_STATSconfigUSE_STATS_FORMATTING_FUNCTIONS 为 1,

定时初始化定时器代码
void vConfigureTimerForRunTimeStats( void )
{
    /* 使能定时器0的外设电源,配置外设时钟 */
    PCONP |= 0x02UL;
    PCLKSEL0 = (PCLKSEL0& (~(0x3<<2))) | (0x01 << 2);
 
    /* 复位定时器 0 */
    T0TCR = 0x02;
 
    /* 作为计数器 */
    T0CTCR = 0x00;
 
    /* 预分频,设置合适的分辨率即可 */
    T0PR =  ( configCPU_CLOCK_HZ / 10000UL ) - 1UL;
 
    /* 启动计数器 */
    T0TCR = 0x01;
}
定义配置定时器和获取定时时间宏

在文件 FreeRTOSConfig.h 中,定义下列代码:

extern void vConfigureTimerForRunTimeStats( void );
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats()
#defineportGET_RUN_TIME_COUNTER_VALUE() T0TC

设置任务标签值

函数描述

voidvTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_tpxTagValue );      

可以给每个任务分配一个标签值。这个值一般用于应用程序,RTOS 内核不会使用。在文件 FreeRTOSConfig.h 中,宏 configUSE_APPLICATION_TASK_TAG 必须设置为1,此函数才有效。

参数描述

  • xTask:任务句柄。NULL表示当前任务。
  • pxTagValue:要分配给任务的标签值。这是一个 TaskHookFunction_t 类型的函数指针,但也可以给任务标签分配任意的值。

注:TaskHookFunction_t 原型定义:typedef BaseType_t (*TaskHookFunction_t)(void * )

用法举例

/* 在这个例子中,给任务设置一个整形标签值。例子中使用了RTOS跟踪钩子宏。*/
void vATask( void *pvParameters )
{
  /* 为自己的标签分配一个整形值 */
 vTaskSetApplicationTaskTag( NULL, ( void * ) 1 );
 
  for( ;; )
  {
    /* 任务主体代码 */
  }
}
/*****************************************************************************/
 
/*在这个任务中,给任务设置一个函数标签值。首先定义一个回调函数,这个函数必须声明为TaskHookFunction_t类型。 */
static BaseType_t prvExampleTaskHook( void * pvParameter )
{
  /* 这里为用户定义代码 –可能是记录数据、更新任务状态值等。*/
 
  return 0;
}
 
/* 将回调函数设置为任务的标签值。 */
void vAnotherTask( void *pvParameters )
{
  /* 注册回调函数*/
 vTaskSetApplicationTaskTag( NULL, prvExampleTaskHook );
 
  for( ;; )
  {
     /* 任务主体代码 */
  }
}
 
/* 每当任务切换时,会调用xTaskCallApplicationTaskHook 函数(见14.)。 */
#define traceTASK_SWITCHED_OUT() xTaskCallApplicationTaskHook(pxCurrentTCB,0 )

获取任务标签值

函数描述

TaskHookFunction_txTaskGetApplicationTaskTag( TaskHandle_t xTask );      

返回分配给任务的标签值。程序员定义标签值,RTOS 内核通常不会访问标签值。

函数仅对高级用户使用。在文件 FreeRTOSConfig.h 中,宏 configUSE_APPLICATION_TASK_TAG 必须设置为 1,此函数才有效。

参数描述

  • xTask:任务句柄。NULL 表示当前任务。

返回值

返回指定任务的标签值。

执行任务的应用钩子函数

函数描述

BaseType_txTaskCallApplicationTaskHook( TaskHandle_txTask, void*pvParameter );      

可以为每个任务分配一个标签值,当这个值是一个 TaskHookFunction_t 类型函数指针时,相当于应用程序向任务注册了一个回调函数,而 API 函数 xTaskCallApplicationTaskHook 用来调用这个回调函数。

一般这个函数配合 RTOS 跟踪钩子宏使用,见12.设置任务标签值一节的用法举例。

参数描述

  • xTask:任务句柄。NULL 表示当前任务。
  • pvParameter:作为参数传递给应用钩子函数

设置线程本地存储指针

函数描述

void vTaskSetThreadLocalStoragePointer(TaskHandle_t xTaskToSet, BaseType_t xIndex, void*pvValue )      

此函数仅用于高级用户。

线程本地存储允许应用程序在任务的控制块中存储一些值,每个任务都有自己独立的储存空间。

比如,许多库函数都包含一个叫做errno的全局变量。某些库函数使用errno返回库函数错误信息,应用程序检查这个全局变量来确定发生了那些错误。在单线程程序中,将errno定义成全局变量是可以的,但是在多线程应用中,每个线程(任务)必须具有自己独有的errno值,否则,一个任务可能会读取到另一个任务的errno值。

FreeRTOS 提供了一个灵活的机制,使得应用程序可以使用线程本地存储指针来读写线程本地存储。在文件 FreeRTOSConfig.h 中,宏 configNUM_THREAD_LOCAL_STORAGE_POINTERS 指定每个任务线程本地存储指针数组的大小。API 函数 vTaskSetThreadLocalStoragePointer() 用于向指针数组中写入值,API 函数 pvTaskGetThreadLocalStoragePointer() 用于从指针数组中读取值。

参数描述

  • xTaskToSet:任务句柄。NULL 表示当前任务。
  • xIndex:写入到线程本地存储数组的索引号,线程本笃存储数组的大小由宏 configNUM_THREAD_LOCAL_STORAGE_POINTERS 设定,该宏在文件 FreeRTOSConfig.h 中。
  • pvValue:写入到指定索引地址的数据值

用法举例

参见16.获取线程本地存储指针一节。

读取线程本地存储指针

函数描述

void*pvTaskGetThreadLocalStoragePointer( TaskHandle_txTaskToQuery, BaseType_txIndex );      

此函数仅用于高级用户。从线程本地存储指针数组中读取值。更详细描述见15.设置线程本地存储指针一节。

参数描写

  • xTaskToQuery:任务句柄。NULL表示当前任务。
  • xIndex:写入到线程本地存储数组的索引号,线程本笃存储数组的大小由宏 configNUM_THREAD_LOCAL_STORAGE_POINTERS 设定,该宏在文件 FreeRTOSConfig.h 中。

返回值

返回一个指针,这个指针存储在线程本地存储指针数组中,数组索引由参数 xIndex 指定。

用法举例

存储一个整形数
uint32_tulVariable;
 
/* 向当前任务的线程本地存储数组下标为1的位置写入一个指向32位常量值的指针。*/
vTaskSetThreadLocalStoragePointer(NULL, 1, ( void * ) 0x12345678 );
 
/*向当前任务的线程本地存储数组下标为0的位置写入一个指向32整形值的指针*/
ulVariable= ERROR_CODE;
vTaskSetThreadLocalStoragePointer(NULL, 0, ( void * ) ulVariable );
 
/*从当前任务的线程本地存储数组下标为5的位置读取出一个指针并赋值给32位整形变量。*/
ulVariable= ( uint32_t ) pvTaskGetThreadLocalStoragePointer( NULL, 5 );
存储结构体
typedefstruct
{
    uint32_t ulValue1;
    uint32_t ulValue2;
}xExampleStruct;
 
xExampleStruct*pxStruct;
 
/*为结构体分配内存*/
pxStruct= pvPortMalloc( sizeof( xExampleStruct ) );
 
/*为结构体成员赋值*/
pxStruct->ulValue1= 0;
pxStruct->ulValue2= 1;
 
/*向当前任务的线程本地存储数组下标为0的位置写入一个指向结构体变量的指针*/
vTaskSetThreadLocalStoragePointer(NULL, 0, ( void * ) pxStruct );
 
/*从当前任务的线程本地存储数组下标为0的位置读取出一个结构体指针*/
pxStruct= ( xExampleStruct * ) pvTaskGetThreadLocalStoragePointer( NULL, 0 );

设置超时状态

函数描述

void vTaskSetTimeOutState( TimeOut_t *const pxTimeOut );      

此函数仅用于高级用户,通常与 API 函数 xTaskCheckForTimeOut() 共同使用。

任务因为等待某事件而进入阻塞状态,通常情况下任务会设置一个等待超时周期。如果在等待事件超时,任务会退出阻塞状态。想象一个这样的应用,某任务等待一个事件而进入阻塞状态,但是事件迟迟不发生,超时后任务退出阻塞状态继续执行任务。假如任务等待的事件仍然没有发生,则任务又会阻塞在该事件下。只要任务等待的事件一直不发生,这个任务进入阻塞然后超时退出阻塞,再进入阻塞的循环就会一直存在。是不是可以设定一个总超时时间,只要总阻塞时间大于这个总超时时间,则可以结束这个任务或进行相应记录,freeRTOS 提供了两个 API 函数来完成这个功能,这就是 vTaskSetTimeOutState()xTaskCheckForTimeOut()

vTaskSetTimeOutState() 函数用于设置初始条件,之后调用 xTaskCheckForTimeOut() 函数检查任务总阻塞时间是否超过总超时时间,如果没有超过,则调整剩余的超时时间计数器。

参数描述

  • pxTimeOut:指向一个结构体的指针,该结构体用来保存确定超时是否发生的必要信息。vTaskSetTimeOutState() 函数会设置结构体的成员。

用法举例

参见18.超时检测。

超时检测

函数描述

BaseType_t xTaskCheckForTimeOut(TimeOut_t * const pxTimeOut, TickType_t* const pxTicksToWait );     

此函数仅用于高级用户,通常与 API 函数 vTaskSetTimeOutState 共同使用。
详细描述见17.设置超时状态。

参数描述

  • pxTimeOut:指向一个结构体的指针。该结构体保存确定超时是否发生的必要信息。使用 API 函数 vTaskSetTimeOutState 初始化该结构体。
    pxTicksToWait:TickType_t 指针,指向的变量保存总超时时间。

返回值

  • pdTRUE:总超时发生 pdFALSE:总超时未发生

用法举例

/* 函数用于从RX缓冲区中接收uxWantedBytes字节数据,RX缓冲区由UART中断填充。如果RX缓冲区没有足够的数据,则任务进入阻塞状态,直到RX缓冲区有足够数据或者发生超时。如果超时后仍然没有足够的数据,则任务会再次进入阻塞状态,xTaskCheckForTimeOut()函数用于重新计算总超时时间以确保总阻塞状态时间不超过MAX_TIME_TO_WAIT。如果总阻塞状态时间大于了总超时时间,则不管RX缓冲区是否有充足数据,都将这些数据读出来。
 */
size_txUART_Receive( uint8_t *pucBuffer, size_t uxWantedBytes )
{
    size_t uxReceived = 0;
    TickType_t xTicksToWait = MAX_TIME_TO_WAIT;
    TimeOut_t xTimeOut;
 
   /* 初始化结构体变量xTimeOut。*/
   vTaskSetTimeOutState( &xTimeOut );
 
   /* 无限循环,直到缓冲区包含足够的数据或者阻塞超时发生。*/
   while( UART_bytes_in_rx_buffer(pxUARTInstance ) < uxWantedBytes )
   {
      /* RX缓冲区没有足够多的数据,表示任务已经进入过一次阻塞状态。调用API函数xTaskCheckForTimeOut检查总阻塞时间是否超过总超时时间,如果没有,则调整剩余的总超时时间。*/
      if( xTaskCheckForTimeOut( &xTimeOut,&xTicksToWait ) != pdFALSE )
      {
         /* 如果总阻塞时间大于总超时时间,则退出这个循环 */
         break;
      }
 
      /* 在等待了xTicksToWait个系统节拍周期后,向接收中断发出通知,需要更多数据。
*/
      ulTaskNotifyTake( pdTRUE, xTicksToWait );
   }
 
    /*从RX缓冲区读取uxWantedBytes个字节并放到pucBuffer缓冲区。*/
    uxReceived = UART_read_from_receive_buffer(pxUARTInstance,  pucBuffer,  uxWantedBytes );
 
    return uxReceived;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值