任務建立函數的本質就是建立新任務并初始化,最後将它放入任務就緒清單
vTaskCreate()動态建立任務函數
/*vTaskCreate()動态建立任務函數
參數1:任務入口
參數2:任務名稱
參數3:任務棧大小:機關為字
參數4:任務形參
參數5:任務優先級
參數6:任務句柄
*/
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
{
TCB_t *pxNewTCB; //定義任務控制塊指針
BaseType_t xReturn; //定義任務句柄用于指向任務的TCB
StackType_t *pxStack;//定義堆棧指針
//為堆棧申請記憶體
pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) );
if( pxStack != NULL )
{
//給任務控制塊申請記憶體
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
if( pxNewTCB != NULL )
{
//若任務控制塊記憶體申請成功,任務控制塊的任務棧起始位址等于堆棧指針
pxNewTCB->pxStack = pxStack;
}
else
{
vPortFree( pxStack );
}
}
else
{
pxNewTCB = NULL;
}
}
if( pxNewTCB != NULL )
{
//如果任務控制塊建立成功,初始化任務
prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );
//将任務控制塊添加到就緒清單中
prvAddNewTaskToReadyList( pxNewTCB );
xReturn = pdPASS;
}
else
{
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
}
return xReturn;
}
prvInitialiseNewTask()初始化新任務函數
/*
prvInitialiseNewTask()
參數1:任務入口
參數2:任務名稱
參數3:任務棧大小
參數4:任務形參
參數5:任務優先級
參數6:任務句柄
參數7:任務控制塊指針
參數8:擷取棧頂位址
*/
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask,
TCB_t *pxNewTCB,
const MemoryRegion_t * const xRegions
{
StackType_t *pxTopOfStack; //定義棧頂指針
UBaseType_t x;
//初始化堆棧為0xa5,用于堆棧溢出檢測
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
//擷取棧頂位址,由于堆棧向下增長,即由高位址向低位址增長,則棧頂位址為棧起始位址加任務棧長度-1
pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
//棧頂指針向下做8位元組對齊,即找到棧頂大小%8=0的位置為棧頂位址
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
//将任務名儲存在TCB中
for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
{
pxNewTCB->pcTaskName[ x ] = pcName[ x ];
if( pcName[ x ] == 0x00 )
{
break;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
//若輸入任務優先級大于最大優先級,則強制設為32—1
if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
{
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
//将任務優先級存儲到TCB中
pxNewTCB->uxPriority = uxPriority;
//初始化TCB的狀态清單和事件清單:設定兩個節點所在的連結清單為空,表示該節點沒有插入到連結清單
vListInitialiseItem( &( pxNewTCB->xStateListItem ) );
vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
//将任務塊狀态清單項,也就是任務節點挂載到pxNewTCB
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );
//初始化節點排序輔助值,為最大優先級-輸入優先級
listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority );
//将任務塊事件清單項挂載到pxNewTCB
listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB );
//初始化任務堆棧
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
//讓任務句柄指向任務控制塊
if( ( void * ) pxCreatedTask != NULL )
{
*pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
pxPortInitialiseStack()堆棧初始化函數
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{
pxTopOfStack--; //堆棧指針減一,指針初始指在棧頂
*pxTopOfStack = portINITIAL_XPSR; 棧頂下面存入portINITIAL_XPSR的值,為0x01000000
pxTopOfStack--;
*pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* r15(程式計數器PC)寄存器儲存任務入口位址*/
pxTopOfStack--;
*pxTopOfStack = ( StackType_t ) prvTaskExitError; /* r14(連結寄存器LR)寄存器儲存任務的傳回位址,若傳回則跳轉無限循環*/
pxTopOfStack -= 5; /* R12, R3, R2 and R1預設初始化為0. */
*pxTopOfStack = ( StackType_t ) pvParameters; /* R0儲存任務形參 */
pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
return pxTopOfStack; //傳回堆棧指針,最後指向r4
}
prvAddNewTaskToReadyList()添加新任務到就緒清單
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
{
taskENTER_CRITICAL();
{
uxCurrentNumberOfTasks++; //目前任務數加一
//pxCurrentTCB是全局變量表示目前任務,若為空則表示目前沒有任務,可能是建立第一個任務
if( pxCurrentTCB == NULL )
{
pxCurrentTCB = pxNewTCB;
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
{
若目前任務為一,則表示這是第一個任務,初始化就緒清單
prvInitialiseTaskLists();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
//若任務排程器沒有運作
if( xSchedulerRunning == pdFALSE )
{
//判斷目前任務優先級與新任務優先級大小,若新任務大,則目前任務為新任務
if( pxCurrentTCB->uxPriority <= pxNewTCB->uxPriority )
{
pxCurrentTCB = pxNewTCB;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
uxTaskNumber++; //全局變量,初始為0,記錄任務數
pxNewTCB->uxTCBNumber = uxTaskNumber; TCB的任務标号等于任務數字
traceTASK_CREATE( pxNewTCB ); //無函數實作
prvAddTaskToReadyList( pxNewTCB );//将新任務添加到就緒清單中
portSETUP_TCB( pxNewTCB ); //無函數實作
}
taskEXIT_CRITICAL();
if( xSchedulerRunning != pdFALSE )
{
/* 如果任務排程器已經運作了,且新建立的任務優先級比目前運作任務的優先級高,産生任務切換*/
if( pxCurrentTCB->uxPriority < pxNewTCB->uxPriority )
{
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
prvInitialiseTaskLists()初始化就緒清單
static void prvInitialiseTaskLists( void )
{
UBaseType_t uxPriority;
//優先級從0開始周遊至最大優先級,逐個初始化就緒清單
for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
{
vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );
}
//初始化兩個延時任務清單
vListInitialise( &xDelayedTaskList1 );
vListInitialise( &xDelayedTaskList2 );
//初始化就緒态任務暫存清單
vListInitialise( &xPendingReadyList );
//将延時任務清單1賦給目前工作延時清單
pxDelayedTaskList = &xDelayedTaskList1;
//将延時任務清單2賦給溢對外連結表
pxOverflowDelayedTaskList = &xDelayedTaskList2;
}
prvAddTaskToReadyList()添加任務至就緒清單
/*1.根據任務優先級将uxTopReadyPriority相應的位至1
2.根據優先級将任務末尾插入就緒清單pxReadyTasksLists[]相應的位置*/
#define prvAddTaskToReadyList( pxTCB ) \
traceMOVED_TASK_TO_READY_STATE( pxTCB ); \
taskRECORD_READY_PRIORITY( ( pxTCB )->uxPriority ); \
vListInsertEnd( &( pxReadyTasksLists[ ( pxTCB )->uxPriority ] ), &( ( pxTCB )->xStateListItem ) ); \
tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )