- 任務應用函數是一組輔助類函數,一般用於調試信息輸出、獲取任務句柄、獲取任務狀態、操作任務標籤值等等。
獲取任務系統狀態
函數描述
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:任務句柄
返回值
下表列出返回值和對應的任務狀態。
獲取任務描述內容
函數描述
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_xTaskGetSchedulerState或configUSE_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表示掛起或阻塞。
- 注意,調用這個函數會掛起所有任務,這一過程可能持續較長時間,因此本函數僅在調試時使用。在文件FreeRTOSConfig.h中,宏configUSE_TRACE_FACILITY和configUSE_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_STATS和configUSE_STATS_FORMATTING_FUNCTIONS設置爲1,此API函數纔有效。
- 這個API函數調用usTaskGetSystemState()函數獲取每個任務的狀態信息,並把其中的運行時間格式化爲程序員易讀的字符形式,並將這些信息保存到參數pcWriteBuffer指向的區域。
- 注意,調用這個函數會掛起所有任務,這一過程可能持續較長時間,因此本函數僅在調試時使用。
參數描述
pcWriteBuffer:任務的運行時間信息會寫入這個緩衝區,爲ASCII表單形式。這個緩衝區要足夠大,以容納生成的報告,每個任務大約需要40個字節。
用法舉例
以lpc17xx系列爲控制爲例,我們使用定時器0來作爲統計基準時鐘。
使能函數宏
在文件FreeRTOSConfig.h中,設置宏configGENERATE_RUN_TIME_STATS和configUSE_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, askHookFunction_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:寫入到指定索引地址的數據值
用法舉例
參見獲取線程本地存儲指針一節。
讀取線程本地存儲指針
函數描述
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()函數會設置結構體的成員。
用法舉例
參見超時檢測。
超時檢測
函數描述
BaseType_t xTaskCheckForTimeOut(TimeOut_t * const pxTimeOut, TickType_t* const pxTicksToWait );
- 此函數僅用於高級用戶,通常與API函數vTaskSetTimeOutState共同使用。
- 詳細描述見設置超時狀態。
參數描述
- 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;
}