FreeRTOS——創建任務

FreeRTOS的設計小巧且簡易,整個核心代碼只有3到4個C文件,爲了讓代碼容易閱讀、移植和維護,大部分的代碼都是以C語言編寫,只有一些函數(多數是架構特定排班副程序)採用彙編語言編寫。

FreeRTOS提供許多方法以實現多線程(threads)、多作業(task)、互斥鎖(mutex)、信號量(semaphore)和軟件計時器(software timer),有個爲低耗電應用程序提供的無嘀嗒(tick-less)模式,線程的優先權管理也有支持。

FreeRTOS所有的工作都是在任務中完成的,所以我們來看看任務是怎麼創建的;

創建任務API函數

創建任務使用xTaskCreate函數

portBASE_TYPE xTaskCreate(  pdTASK_CODE pvTaskCode,
                            const signed portCHAR * const pcName,
                            unsigned portSHORT usStackDepth,
							void *pvParameters,
							unsigned portBASE_TYPE uxPriority,
							xTaskHandle *pxCreatedTask );
參數名 描述
pvTaskCode 任務只是永不退出的C 函數,實現常通常是一個死循環。參數pvTaskCode 只一個指向任務的實現函數的指針(效果上僅僅是函數名)。
pcName 具有描述性的任務名。這個參數不會被FreeRTOS 使用。其只是單純地用於輔助調試。識別一個具有可讀性的名字總是比通過句柄來識別容易得多。應用程序可以通過定義常量config_MAX_TASK_NAME_LEN 來定義任務名的最大長度——包括’\0’結束符。如果傳入的字符串長度超過了這個最大值,字符串將會自動被截斷。
usStackDepth 當任務創建時,內核會分爲每個任務分配屬於任務自己的唯一狀態。usStackDepth 值用於告訴內核爲它分配多大的棧空間。這個值指定的是棧空間可以保存多少個字(word),而不是多少個字節(byte)。比如說,如果是32 位寬的棧空間,傳入的usStackDepth值爲100,則將會分配400 字節的棧空間(100 * 4bytes)。棧深度乘以棧寬度的結果千萬不能超過一個size_t 類型變量所能表達的最大值。應用程序通過定義常量configMINIMAL_STACK_SIZE 來決定空閒任務任用的棧空間大小。
pvParameters 任務函數接受一個指向void 的指針(void*)。pvParameters 的值即是傳遞到任務中的值。這篇文檔中的一些範例程序將會示範這個參數可以如何使用。
uxPriority 指定任務執行的優先級。優先級的取值範圍可以從最低優先級0 到最高優先級(configMAX_PRIORITIES – 1)。configMAX_PRIORITIES 是一個由用戶定義的常量。優先級號並沒有上限(除了受限於採用的數據類型和系統的有效內存空間),但最好使用實際需要的最小數值以避免內存浪費。如果uxPriority 的值超過了(configMAX_PRIORITIES – 1),將會導致實際賦給任務的優先級被自動封頂到最大合法值。
pxCreatedTask pxCreatedTask 用於傳出任務的句柄。這個句柄將在API 調用中對該創建出來的任務進行引用,比如改變任務優先級,或者刪除任務。如果應用程序中不會用到這個任務的句柄,則pxCreatedTask 可以被設爲NULL。
返回值
1. pdTRUE

表明任務創建成功。

2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY

由於內存堆空間不足,FreeRTOS 無法分配足夠的空間來保存任務
結構數據和任務棧,因此無法創建任務。

例子

1.創建任務1

void Task1( void *pvParameters )
{
	const char *pcTaskName = "Task1 output ........";
	volatile unsigned long ul;
	/* 和該任務處於一個死循環中。 */
	while(1)
	{
		/* 輸出變量名,此處可以用自己方式驗證 */
		vPrintString( pcTaskName );
		/* 延遲,以產生一個週期 */
		for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
		{
		/* 這個空循環是最原始的延遲實現方式。 */
		}
	}
}

1.創建任務2

void Task2( void *pvParameters )
{
	const char *pcTaskName = "Task2 output ........";
	volatile unsigned long ul;
	/* 和該任務處於一個死循環中。 */
	while(1)
	{
		/* 輸出變量名,此處可以用自己方式驗證 */
		vPrintString( pcTaskName );
		/* 延遲,以產生一個週期 */
		for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
		{
		/* 這個空循環是最原始的延遲實現方式。 */
		}
	}
}

3、main()函數只是簡單地創建這兩個任務,然後啓動調度器

int main( void )
{
/* 創建第一個任務。需要說明的是一個實用的應用程序中應當檢測函數xTaskCreate()的返回值,以確保任
務創建成功。 */
	xTaskCreate( Task1, /* 指向任務函數的指針 */
				"Task 1", /* 任務的文本名字,只會在調試中用到 */
				1000, /* 棧深度 – 大多數小型微控制器會使用的值會比此值小得多 */
				NULL, /* 沒有任務參數 */
				1, /* 此任務運行在優先級1上. */
				NULL ); /* 不會用到任務句柄 */
	/* Create the other task in exactly the same way and at the same priority. */
	xTaskCreate( Task2, "Task 2", 1000, NULL, 1, NULL );
	/* 啓動調度器,任務開始執行 */
	vTaskStartScheduler();
	/* 如果一切正常,main()函數不應該會執行到這裏。但如果執行到這裏,很可能是內存堆空間不足導致空閒
	任務無法創建。第五章有講述更多關於內存管理方面的信息 */
	while(1);
}

這樣兩個簡單的任務就創建完成了

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