使用freeRTOS時(shí),創(chuàng)建的每一個(gè)任務(wù)都需要分配任務(wù)的堆??臻g,這些堆??臻g一般都是使用者根據(jù)任務(wù)的情況大致分配的。使用者往往不能直接知道分配的任務(wù)堆棧空間是否足夠任務(wù)運(yùn)行使用,有時(shí)候可能會(huì)不夠,在運(yùn)行過程中就出現(xiàn)了堆棧溢出,導(dǎo)致程序出現(xiàn)各種各樣的奇怪問題,出現(xiàn)問題之后可能一時(shí)半會(huì)還難以找出來。
這種情況如果能有一種檢測(cè)手段能夠知道任務(wù)在運(yùn)行過程中堆棧的使用情況或者剩余情況,那就可以很好的把握任務(wù)堆棧的情況,也可以在一開始就避免堆棧溢出這樣的問題發(fā)生,將來項(xiàng)目產(chǎn)品上線了也避免了這樣的風(fēng)險(xiǎn)存在!
值得開心的是,freeRTOS真的有提供這樣的檢測(cè)堆棧剩余量的功能。下面介紹怎么使用freeRTOS的任務(wù)堆棧的剩余量的方法。
1、允許堆棧檢測(cè) API 的使用
freeRTOS中堆棧使用剩余量的檢測(cè)使用的是 uxTaskGetStackHighWaterMark ,使用這個(gè)函數(shù)需要先將一個(gè)宏定義為 1 才能使用堆棧檢測(cè)功能。
打開 FreeRTOSConfig.h 文件,找到宏
INCLUDE_uxTaskGetStackHighWaterMark 并將其值定為 1,如下:
#define INCLUDE_uxTaskGetStackHighWaterMark 1
這個(gè)宏定義為 1 之后再文件 task.c 中就可以看到函數(shù) uxTaskGetStackHighWaterMark 生效了,說明這個(gè)函數(shù)已經(jīng)是可以使用的狀態(tài)了。
2、uxTaskGetStackHighWaterMark 函數(shù)的說明
freeRTOS 中任務(wù)堆棧的檢測(cè)函數(shù)的函數(shù)原型如下:
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
{
TCB_t * pxTCB;
uint8_t * pucEndOfStack;
UBaseType_t uxReturn;
pxTCB = prvGetTCBFromHandle( xTask );
#if portSTACK_GROWTH < 0
{
pucEndOfStack = ( uint8_t * ) pxTCB->pxStack;
}
#else
{
pucEndOfStack = ( uint8_t * ) pxTCB->pxEndOfStack;
}
#endif
uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace( pucEndOfStack );
return uxReturn;
}
函數(shù)描述:
函數(shù)參數(shù):
xTask:需要檢查的堆棧情況的任務(wù)句柄。這個(gè)句柄在創(chuàng)建任務(wù)時(shí)就可以知道的。
注意:將 xTask 設(shè)置為 NULL 的話檢測(cè)的就是調(diào)用這個(gè)函數(shù)的任務(wù)堆棧情況。
函數(shù)返回值:
自創(chuàng)建 xTask 這個(gè)任務(wù)以來,已存在的最小可用堆??臻g量(以字為單位)。即返回的值是以字為單位的堆棧剩余量(例如,在 32 位機(jī)器上,返回值 1 表示任務(wù)堆棧中未使用的堆棧還剩余 4 個(gè)字節(jié))。如果返回值為零,則該任務(wù)可能堆棧已經(jīng)溢出。如果返回值接近零,則任務(wù)接近堆棧溢出。
特別注意:
freeRTOS中還有一個(gè) uxTaskGetStackHighWaterMark2() ,這個(gè)是 uxTaskGetStackHighWaterMark() 的另外一個(gè)版本,它返回一個(gè)用戶可定義的類型,主要用在一些 8 位架構(gòu)上數(shù)據(jù)類型寬度有限制的MCU中。
3、堆棧剩余量檢測(cè)的使用方法
3.1、任務(wù)自己檢測(cè)自己的堆棧情況
如果 UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) 的參數(shù) xTask 設(shè)置為NULL,則哪個(gè)任務(wù)調(diào)用這個(gè)函數(shù)檢測(cè)的就是哪個(gè)任務(wù)的堆棧情況,如下:
void vTask1( void * pvParameters )
{
UBaseType_t uxHighWaterMark;
// 檢測(cè)任務(wù)使用前的堆棧情況
uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
for( ;; )
{
... // 其他代碼
...
...
vTaskDelay( 1000 );
// 檢測(cè)任務(wù)運(yùn)行之后的堆棧剩余情況
uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
}
}
3.2、使用任務(wù)單獨(dú)檢測(cè)任務(wù)的堆棧情況
可以使用一個(gè)任務(wù)單獨(dú)進(jìn)行項(xiàng)目中的任務(wù)堆棧的情況進(jìn)行檢測(cè),如下:
void TaskStackDetect_Task1( void * pvParameters )
{
UBaseType_t uxHighWaterMark;
for( ;; )
{
uxHighWaterMark = uxTaskGetStackHighWaterMark( 任務(wù)句柄1 );
print(uxHighWaterMark);
uxHighWaterMark = uxTaskGetStackHighWaterMark( 任務(wù)句柄2 );
print(uxHighWaterMark);
uxHighWaterMark = uxTaskGetStackHighWaterMark( 任務(wù)句柄3 );
print(uxHighWaterMark);
......
uxHighWaterMark = uxTaskGetStackHighWaterMark( 任務(wù)句柄n );
print(uxHighWaterMark);
vTaskDelay( 1000 );
}
}
3.3、使用軟件定時(shí)器檢測(cè)任務(wù)堆棧的情況
檢測(cè)堆棧的剩余情況也可以使用freeRTOS中提供的軟件定時(shí)器服務(wù),創(chuàng)建一個(gè)軟件定時(shí)器,然后在軟件定時(shí)器的回調(diào)函數(shù)里面定時(shí)進(jìn)行檢測(cè)即可,原理和使用一個(gè)任務(wù)檢測(cè)是一樣的。如下:
void TaskStackDetect_Callback(TimerHandle_t pxTimer)
{
UBaseType_t uxHighWaterMark;
uxHighWaterMark = uxTaskGetStackHighWaterMark( 任務(wù)句柄1 );
print(uxHighWaterMark);
uxHighWaterMark = uxTaskGetStackHighWaterMark( 任務(wù)句柄2 );
print(uxHighWaterMark);
uxHighWaterMark = uxTaskGetStackHighWaterMark( 任務(wù)句柄3 );
print(uxHighWaterMark);
......
uxHighWaterMark = uxTaskGetStackHighWaterMark( 任務(wù)句柄n );
print(uxHighWaterMark);
}
-
堆棧
+關(guān)注
關(guān)注
0文章
182瀏覽量
20000 -
FreeRTOS
+關(guān)注
關(guān)注
12文章
485瀏覽量
63497 -
空間
+關(guān)注
關(guān)注
2文章
50瀏覽量
13788
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論