FreeRTOS 任務的創建 (4)

前言

  1. 本博文基於FreeRTOS V9.0.0和MDK環境;
  2. 本博文屬於野火學習筆記,如有不足之處還請多多指教;

任務的大三元素

先說幾個基本概念:
任務: 相當於裸機大循環系統中的每個獨立功能;例如LED和USART功能都可以作爲一個單獨的任務來說;
任務和邏輯的區別: 裸機是順序執行來完成總任務,而RTOS是通過任務的切換來完成;

①:任務函數 (獨立函數,無限循環)
任務函數是最終實現功能的地方;

 void task_entry (void *parg)
 {
	 /* 任務主體,無限循環且不能返回 */
	 for (;;) {
	 /* 任務主體代碼 */
	 }
 }

②:任務控制塊TCB
每一個任務都有一個TCB,在程序中,TCB是任務的身份證,TCB結構體內包含着任務的重要信息;

typedef struct tskTaskControlBlock
{
	volatile StackType_t    *pxTopOfStack;    /*棧頂*/
	ListItem_t               xStateListItem;   /*任務節點*/
	StackType_t 		    *pxStack;					/*任務棧起始地址*/
	char					pcTaskName[ configMAX_TASK_NAME_LEN ];   /*任務名稱,字符串形式*/
}tskTCB;

③任務棧(靜態棧/動態棧)
每個任務都有一個獨立的任務棧,用來臨時存儲截點信息,屬於軟件堆棧;

//靜態棧
#define TASK1_STACK_SIZE							128  
StackType_t Task1Stack[TASK1_STACK_SIZE];

//動態棧:暫無

任務的創建流程

在這裏插入圖片描述
代碼如下:

  	TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,   //任務函數名
																	const char * const pcName,   //配置任務名
																	const uint32_t ulStackDepth, //任務堆棧尺寸(32位爲單位)
																	void * const pvParameters,   //任務參數;
																	//UBaseType_t uxPriority,		 //任務優先級 (野火這裏對源程序有改動)
																	StackType_t * const puxStackBuffer, //任務堆棧緩衝區起始地址
																  TCB_t * const pxTaskBuffer   //任務控制塊起始地址;(野火在這裏對源程序有改動)
																 )
	{
		TCB_t *pxNewTCB;
		TaskHandle_t xReturn;  //建立一個任務句柄
		
		if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer ) )
		{
			pxNewTCB = ( TCB_t * )pxTaskBuffer;
			pxNewTCB->pxStack = ( StackType_t * )puxStackBuffer;
			
			//建立新的任務
			prvInitialiseNewTask( pxTaskCode,
							      pcName,
								  ulStackDepth,
								  pvParameters,
								  &xReturn,
								  pxNewTCB
								);
			
		}
		else
			xReturn = NULL;
		
		
		//返回任務句柄,如果任務創建成功,此時XReturn應該指向任務控制塊
		return xReturn;
		
	}

//新任務初始化函數
void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
													 const char * const pcName,
													 const uint32_t ulStackDepth,
													 void *const pvParameters,
													TaskHandle_t *const pxCreatedTask,
													TCB_t *pxNewTCB		
													)
{
	StackType_t *pxTopOfStack;
	UBaseType_t x;
	
	/**********初始化TCB*************/
	//獲取棧頂地址
	pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t )1 );
	//棧頂地址鄉下做8字節對齊
	pxTopOfStack = ( StackType_t * )( ( ( uint32_t )pxTopOfStack )&(~(( uint32_t )0x007)) );
	//將任務的名字存儲在TCB中
	for( x = ( UBaseType_t )0; x < ( UBaseType_t )configMAX_TASK_NAME_LEN; x++ )
	{
		pxNewTCB->pcTaskName[ x ] = pcName[x];
		
		if( pcName[x] == 0x00	)
			break;
		
	}
	//任務名字長度不能超過configMAX_TASK_NAMW_LEN
	pxNewTCB->pcTaskName[configMAX_TASK_NAME_LEN - 1] = '\0';
	
	/************初始化任務棧****************/
	pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack,
											        pxTaskCode,
													pvParameters);
	
	
	
	//讓任務句柄指向任務控制塊
	if( ( void *)pxCreatedTask != NULL)
	{
		*pxCreatedTask = ( TaskHandle_t )pxNewTCB;
	}
}

//定義任務棧初始初始化函數
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, //此時進來的棧頂指針已經是指向棧頂的8字節對齊指針;
																		TaskFunction_t pxCode,     //任務函數名
																		void *pvParameters				 //任務參數
																		)
{
	//異常發生時,自動加載到CPU寄存器的內容;
	pxTopOfStack--;
	*pxTopOfStack = portINITIAL_XPSR;
	pxTopOfStack--;
	*pxTopOfStack = ( ( StackType_t )pxCode )&portSTART_ADDRESS_MASK;
	pxTopOfStack--;
	*pxTopOfStack = ( StackType_t )prvTaskExitError;
	pxTopOfStack -= 5;
	*pxTopOfStack = ( StackType_t )pvParameters;
	
	//異常發生時,手動加載CPU寄存器的內容;
	pxTopOfStack -= 8;
	
	//返回棧頂指針,此時pxTopOfStack指向空閒棧;
	return pxTopOfStack;
	
	
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章