




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、USING THE FREERTOSREAL TIME KERNELA Practical GuideRichard BarryFREERTOS 實(shí)時內(nèi)核實(shí)用指南1FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.這篇文章的英文原版我是在上得到的。其實(shí)我并沒有決定是否要在系統(tǒng)中使用FreeRTOS,雖然要的也僅僅是一個實(shí)時內(nèi)核,當(dāng)然更重要的是。之所以翻譯這篇文章倒不是因?yàn)镕reeRTOS有多
2、么優(yōu)秀,完全是因?yàn)檫@篇文章還不算太長。而且FreeRTOS.net仿佛致力于這個內(nèi)核在國內(nèi)的推廣,也做了不少中文化的工作。所以我是打算利用工作之余,邊看邊譯,到讀完這篇文檔,也就有個中文版了。如果FreeRTOS.net不棄的話,我倒是情愿放到這個上與大家共享。另外,我本人很懶,沒有翻譯附錄,而且譯完正文后也沒有做過任何檢查。所以如果有任何問題,請不要罵我。Zou Changjun2FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is
3、 strictly prohibited.第一章任務(wù)管理3FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.1.1 概覽附錄中提供了使用 FreeRTOS 源代碼的實(shí)用信息小型多任務(wù)系統(tǒng)簡介不同的多任務(wù)系統(tǒng)有不同的側(cè)重點(diǎn)。以工作站和桌面電腦為例:· 早期的處理器非常昂貴,所以那時的多任務(wù)用于實(shí)現(xiàn)在單處理器上支持多用戶。這類系統(tǒng)中的調(diào)度算法側(cè)重于讓每個用戶”公平共享”處理器時間。
4、183; 隨著處理器功能越來越強(qiáng)大,價格卻更偏宜,所以每個用戶都可以獨(dú)占一個或多個處理器。這類系統(tǒng)的調(diào)度算法則設(shè)計(jì)為讓用戶可以同時運(yùn)行多個應(yīng)用程序,而計(jì)算機(jī)也顯得反應(yīng)遲鈍。例如某個用戶可能同時運(yùn)行了一個字處理程序,一個電子表格,一個郵件客戶端和一個 WEB 瀏覽器,并且期望每個應(yīng)用程序任何時候都能對輸入有足夠快的響應(yīng)時間。桌面電腦的輸入處理可以歸類為”軟實(shí)時”。為了保證用戶的最佳體驗(yàn),計(jì)算機(jī)對每個輸入的響應(yīng)應(yīng)當(dāng)限定在一個恰當(dāng)?shù)臅r間范圍但是如果響應(yīng)時間超出了限定范圍,并讓人覺得這臺電腦無法使用。比如說,鍵盤操作必須在鍵按下后的某個時間內(nèi)作出明顯的提示。但如果按鍵提示超出了這個時間,會使得這個系統(tǒng)
5、看起來響應(yīng)太慢,而不致于說這臺電腦不能使用。僅僅從單處理器運(yùn)行多線程這一點(diǎn)來說,實(shí)時系統(tǒng)中的多任務(wù)與桌面電腦的多任務(wù)從概念上來講是相似的。但實(shí)時系統(tǒng)的側(cè)重點(diǎn)卻不同于桌面電腦特別是當(dāng)系統(tǒng)期望提供”硬實(shí)時”行為的時候。硬實(shí)時功能必須在給定的時間限制之內(nèi)完成如果無法做到即意味著整個系統(tǒng)的絕對失敗。汽車的安全氣囊觸發(fā)機(jī)制就是一個硬實(shí)時功能的例子。安全氣囊在撞擊發(fā)生后給定時間限制內(nèi)必須彈出。如果響應(yīng)時間超出了這個時間限制,會使得駕駛員受到,而這原本是可以避免的。大多數(shù)系統(tǒng)不僅能滿足硬實(shí)時要求,也能滿足軟實(shí)時要求。4FreeRTOSDesigned For Microcontrollers;©
6、2009 Richard Barry. Distribution or publication in any form is strictly prohibited.術(shù)語說明在 FreeRTOS 中,每個執(zhí)行線程都被稱為”任務(wù)”。在社區(qū)中,對此并沒有一個公允的術(shù)語,但我更喜歡用”任務(wù)”而不是”線程”,因?yàn)閺囊郧暗慕?jīng)驗(yàn)來看,線程具有的特定含義。本章的目的是讓讀者充分了解:····在應(yīng)用程序中,F(xiàn)reeRTOS 如何為各任務(wù)分配處理時間。在任意給定時刻,F(xiàn)reeRTOS 如何選擇任務(wù)投入運(yùn)行。任務(wù)優(yōu)先級如何影響系統(tǒng)行為。任務(wù)存在哪些狀態(tài)。此外,還期望能夠讓讀
7、者解:·······如何實(shí)現(xiàn)一個任務(wù)。如何創(chuàng)建一個或多個任務(wù)的實(shí)例。如何使用任務(wù)參數(shù)。如何改變一個已創(chuàng)建任務(wù)的優(yōu)先級。如何刪除任務(wù)。如何實(shí)現(xiàn)周期性處理??臻e任務(wù)何時運(yùn)行,可以用來干什么。本章所介紹的概念是理解如何使用 FreeRTOS 的基礎(chǔ),也是理解基于 FreeRTOS的應(yīng)用程序行為方式的基礎(chǔ)因此,本章也是這本書中最為詳盡的一章。5FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in
8、any form is strictly prohibited.1.2 任務(wù)函數(shù)任務(wù)是由 C 語言函數(shù)實(shí)現(xiàn)的。唯一特別的只是任務(wù)的函數(shù)原型,其必須返回 void,而且?guī)в幸粋€ void 指針參數(shù)。其函數(shù)原型參見程序1。void ATaskFunction( void *pvParameters );程序1 任務(wù)函數(shù)原型每個任務(wù)都是在自己權(quán)限范圍內(nèi)的一個小程序。其具有程序,通常會運(yùn)行在一2 所示。個死循環(huán)中,也。一個典型的任務(wù)結(jié)構(gòu)如程序FreeRTOS 任務(wù)不允許以任何方式從實(shí)現(xiàn)函數(shù)中返回它們絕不能有一條”return”語句,也不能執(zhí)行到函數(shù)末尾。如果一個任務(wù)不再需要,可以顯式地將其刪2 展現(xiàn)。
9、除。這也在程序一個任務(wù)函數(shù)可以用來創(chuàng)建若干個任務(wù)創(chuàng)建出的任務(wù)均是的執(zhí)行實(shí)例,擁有屬于自己的??臻g,以及屬于自己的自動變量(棧變量),即任務(wù)函數(shù)本身定義的變量。void ATaskFunction( void *pvParameters )/* 可以像普通函數(shù)一樣定義變量。用這個函數(shù)創(chuàng)建的每個任務(wù)實(shí)例都有一個屬于自己的iVarialbleExample變量。但如果iVariableExample被定義為static,這一點(diǎn)則不成立 這種情況下只存在一個變量,所有的任務(wù)實(shí)例將會共享這個變量。 */int iVariableExample = 0;/* 任務(wù)通常實(shí)現(xiàn)在一個死循環(huán)中。 */for( ;
10、 )/* 完成任務(wù)功能的代碼將放在這里。 */* 如果任務(wù)的具體實(shí)現(xiàn)會跳出上面的死循環(huán),則此任務(wù)必須在函數(shù)運(yùn)行完之前刪除。傳入NULL參數(shù)表示刪除的是當(dāng)前任務(wù) */vTaskDelete( NULL );程序2 典型的任務(wù)函數(shù)結(jié)構(gòu)6FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.1.3 頂層任務(wù)狀態(tài)應(yīng)用程序可以包含多個任務(wù)。如果運(yùn)行應(yīng)用程序的微控制器只有一個核(core),那么在任意給定時
11、間,實(shí)際上只會有一個任務(wù)被執(zhí)行。這就意味著一個任務(wù)可以有一個或兩個狀態(tài),即運(yùn)行狀態(tài)和非運(yùn)行狀態(tài)。我們先考慮這種最簡單的模型但請牢記這其實(shí)是過于簡單,我們稍后將會看到非運(yùn)行狀態(tài)實(shí)際上又可劃分為若干個子狀態(tài)。當(dāng)某個任務(wù)處于運(yùn)行態(tài)時,處理器就正在執(zhí)行它的代碼。當(dāng)一個任務(wù)處于非運(yùn)行態(tài)時,該任務(wù)進(jìn)行休眠,它的所有狀態(tài)都被妥善保存,以便在下一次調(diào)試器決定讓它進(jìn)入運(yùn)行態(tài)時可以恢復(fù)執(zhí)行。當(dāng)任務(wù)恢復(fù)執(zhí)行時,其將精確地從離開運(yùn)行態(tài)時正準(zhǔn)備執(zhí)行的那一條指令開始執(zhí)行。圖 1 頂層任務(wù)狀態(tài)及狀態(tài)轉(zhuǎn)移任務(wù)從非運(yùn)行態(tài)轉(zhuǎn)移到運(yùn)行態(tài)被稱為” 切換入或切入(switched in)” 或” 交換入(swapped in)”。相反
12、,任務(wù)從運(yùn)行態(tài)轉(zhuǎn)移到非運(yùn)行態(tài)被稱為”切換出或切出(switched out)”或”交換出(swapped out)”。FreeRTOS 的調(diào)度器是能讓任務(wù)切入切出的唯一實(shí)體。7FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.1.4 創(chuàng)建任務(wù)xTaskCreate() API 函數(shù)創(chuàng)建任務(wù)使用 FreeRTOS 的 API 函數(shù) xTaskCreate()。這可能是所有 API 函數(shù)中最復(fù)雜
13、的函數(shù),但不幸的是這也是我們第一個遇到的 API 函數(shù)。但我們必須首先掌控任務(wù), 因?yàn)樗鼈兪嵌嗳蝿?wù)系統(tǒng)中最基本的組件。本書中的所有示例程序都會用到 xTaskCreate(),所以會有大量的例子可以參考。附錄 5:描述用到的數(shù)據(jù)類型和命名約定。portBASE_TYPExTaskCreate( pdTASK_CODE pvTaskCode,const signed portCHAR * const pcName, unsigned portSHORT usStackDepth,void *pvParameters,unsigned portBASE_TYPE uxPriority, xTask
14、Handle *pxCreatedTask );程序3 xTaskCreate() API 函數(shù)原型表 1xTaskCreate()參數(shù)與返回值pvTaskCode任務(wù)只是永不的 C 函數(shù),實(shí)現(xiàn)常通常是一個死循環(huán)。參數(shù)pvTaskCode 只一個指向任務(wù)的實(shí)現(xiàn)函數(shù)的指針(效果上僅僅是函數(shù)名)。pcName具有描述性的任務(wù)名。這個參數(shù)被 FreeRTOS 使用。其只是單純地用于輔助調(diào)試。識別一個具有可讀性的名字總是比通過句柄來識別容易得多。應(yīng)用程序可以通過定義常量 config_MAX_TASK_NAME_LEN 來定義任務(wù)名的最大長度包括0結(jié)束符。如果傳入的字符串長度超過了這個最大值,字符串將
15、會自動被截?cái)唷?FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.參數(shù)名描述usStackDepth當(dāng)任務(wù)創(chuàng)建時,內(nèi)核會分為每個任務(wù)分配屬于任務(wù)自己的唯一狀態(tài)。usStackDepth 值用于告訴內(nèi)核為它分配多大的??臻g。這個值指定的是棧空間可以保存多少個字(word),而不是多少個字節(jié)(byte)。比如說,如果是 32 位寬的??臻g,傳入的 usStackDepth 值為 100,則將會分
16、配 400 字節(jié)的??臻g(100 * 4bytes)。棧深度乘以棧寬度的結(jié)果千萬不能超過一個 size_t 類型變量所能表達(dá)的最大值。應(yīng)用程序通過定義常量 configMINIMAL_STACK_SIZE 來決定空閑任務(wù)任用的??臻g大小。在 FreeRTOS 為微控制器架構(gòu)提供的Demo 應(yīng)用程序中,賦予此常量的值是對所有任務(wù)的最小建議值。如果你的任務(wù)會使用大量??臻g,那么你應(yīng)當(dāng)賦予一個更大的值。沒有任何簡單的方法可以決定一個任務(wù)到底需要多大的??臻g。計(jì)算出來雖然是可能的,但大多數(shù)用戶會先簡單地賦予一個自認(rèn)為合理的值,然后利用 FreeRTOS 提供的特性來確證分配的空間既不欠缺也不浪費(fèi)。第六
17、章包括了一些信息,可以知道如何去任務(wù)使用了多少??臻g。pvParameters任務(wù)函數(shù)接受一個指向 void 的指針(void*)。pvParameters 的值即是傳遞到任務(wù)中的值。這篇文檔中的一些范例程序?qū)痉哆@個參數(shù)可以如何使用。uxPriority指定任務(wù)執(zhí)行的優(yōu)先級。優(yōu)先級的取值范圍可以從最低優(yōu)先級 0 到最高優(yōu)先級(configMAX_PRIORITIES 1)。configMAX_PRIORITIES 是一個由用戶定義的常量。優(yōu)先級號并沒有上限(除了受限于采用的數(shù)據(jù)類型和系統(tǒng)的有效內(nèi)存空間),但最好使用實(shí)際需要的最小數(shù)值以避免內(nèi)存浪費(fèi)。如果 uxPriority 的值超過了(c
18、onfigMAX_PRIORITIES 1),將會導(dǎo)致實(shí)際賦給任務(wù)的優(yōu)先級被自動封頂?shù)阶畲蠛戏ㄖ怠?FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.pxCreatedTaskpxCreatedTask 用于傳出任務(wù)的句柄。這個句柄將在 API 調(diào)用中對該創(chuàng)建出來的任務(wù)進(jìn)行,比如改變?nèi)蝿?wù)優(yōu)先級,或者刪除任務(wù)。如果應(yīng)用程序中用到這個任務(wù)的句柄,則 pxCreatedTask 可以被設(shè)為 NUL
19、L。返回值有兩個可能的返回值:1. pdTRUE表明任務(wù)創(chuàng)建成功。2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY由于內(nèi)存堆空間不足,F(xiàn)reeRTOS 無法分配足夠的空間來保存任務(wù)結(jié)構(gòu)數(shù)據(jù)和任務(wù)棧,因此無法創(chuàng)建任務(wù)。第五章將提供有關(guān)內(nèi)存管理方面的信息。例 1. 創(chuàng)建任務(wù)附錄 1:包含一些關(guān)于示例程序生成工具的信息。本例演示了創(chuàng)建并啟動兩個任務(wù)的必要步驟。這兩個任務(wù)只是周期性地打印輸出字符串,采用原始的空循環(huán)方式來產(chǎn)生周期延遲。兩者在創(chuàng)建時指定了相同的優(yōu)先級,并且在實(shí)現(xiàn)上除輸出的字符串外完全一樣程序4 和程序5 是這兩個任務(wù)對應(yīng)的實(shí)現(xiàn)代碼。10FreeRTOSDe
20、signed For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.void vTask1( void *pvParameters )const char *pkName = "Task 1 is runningrn"volatile unsigned long ul;/* 和大多數(shù)任務(wù)一樣,該任務(wù)處于一個死循環(huán)中。 */for( ; )/* Print out the name of this task.
21、*/vPrintString( pkName );/* 延遲,以產(chǎn)生一個周期 */for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul+ )/* 這個空循環(huán)是最原始的延遲實(shí)現(xiàn)方式。在循環(huán)中不做任何事情。后面的示例程序?qū)⒉捎胐elay/sleep函數(shù)代替這個原始空循環(huán)。 */程序4 例1中的第一個任務(wù)實(shí)現(xiàn)代碼void vTask2( void *pvParameters )const char *pkName = "Task 2 is runningrn"volatile unsigned long ul;/* 和大多數(shù)任務(wù)一樣,該任務(wù)處
22、于一個死循環(huán)中。 */for( ; )/* Print out the name of this task. */vPrintString( pkName );/* 延遲,以產(chǎn)生一個周期 */for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul+ )/* 這個空循環(huán)是最原始的延遲實(shí)現(xiàn)方式。在循環(huán)中不做任何事情。后面的示例程序?qū)⒉捎胐elay/sleep函數(shù)代替這個原始空循環(huán)。 */程序5 例 1 中的第二個任務(wù)實(shí)現(xiàn)代碼main()函數(shù)只是簡單地創(chuàng)建這兩個任務(wù),然后啟動調(diào)度器具體實(shí)現(xiàn)代碼參見程序程單 6。11FreeRTOSDesigned For Micr
23、ocontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly main( void )/* 創(chuàng)建第一個任務(wù)。需要說明的是一個實(shí)用的應(yīng)用程序中應(yīng)當(dāng)檢測函數(shù)xTaskCreate()的返回值,以確保任務(wù)創(chuàng)建成功。 */xTaskCreate( vTask1,"Task 1",1000, NULL, 1,NULL );/* 指向任務(wù)函數(shù)的指針 */* 任務(wù)的文本名字,只會在調(diào)試中用到 */* 棧深度 大多數(shù)小型微控制器會使用的值會
24、比此值小得多 */* 沒有任務(wù)參數(shù) */* 此任務(wù)運(yùn)行在優(yōu)先級1上. */*用到任務(wù)句柄 */* Create the other task in exactly the same way and at the same priority. */xTaskCreate( vTask2, "Task 2", 1000, NULL, 1, NULL );/* 啟動調(diào)度器,任務(wù)開始執(zhí)行 */vTaskStartScheduler();/* 如果一切正常,main()函數(shù)不應(yīng)該會執(zhí)行到這里。但如果執(zhí)行到這里,很可能是內(nèi)存堆空間不足導(dǎo)致空閑任務(wù)無法創(chuàng)建。第五章有講述關(guān)于內(nèi)存管理方面的
25、信息 */for( ; );程序6 啟動例 1 中的任務(wù)本例的運(yùn)行輸出如圖 2 所示圖 2 例 1 的運(yùn)行輸出圖 2 中看到兩個任務(wù)在同時運(yùn)行,但實(shí)際上這兩個任務(wù)運(yùn)行在同一個處理器上,所以不可能會同時運(yùn)行。事實(shí)上這兩個任務(wù)都迅速地進(jìn)入與運(yùn)行態(tài)。由于這兩個任務(wù)運(yùn)行在同一個處理器上,所以會平等共享處理器時間。真實(shí)的執(zhí)行流程所圖 3 所示。12FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.圖
26、3 中底部的箭頭表示從 t1 起始的運(yùn)行時刻。彩色的線段表示在每個時間點(diǎn)上正在運(yùn)行的任務(wù)比如 t1 與 t2 之間運(yùn)行的是任務(wù) 1。在任何時刻只可能有一個任務(wù)處于運(yùn)行態(tài)。所以一個任務(wù)進(jìn)入運(yùn)行態(tài)后(切入),另一個任務(wù)就會進(jìn)入非運(yùn)行態(tài)(切出)。圖 3例 1 的實(shí)際執(zhí)行流程例 1 中,main()函數(shù)在啟動調(diào)度器之前先完成兩個任務(wù)的創(chuàng)建。當(dāng)然也可以從一個任務(wù)中創(chuàng)建另一個任務(wù)。我們可以先在 main()中創(chuàng)建任務(wù) 1,然后在任務(wù) 1 中創(chuàng)建任務(wù)2。如果我們需要這樣做,則任務(wù) 1 代碼就應(yīng)當(dāng)修改成程序7 所示的樣子。這樣,在調(diào)度器啟動之前,任務(wù) 2 還沒有被創(chuàng)建,但是整個程序運(yùn)行的輸出結(jié)果還是相同的。1
27、3FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.void vTask1( void *pvParameters )const char *pkName = "Task 1 is runningrn"volatile unsigned long ul;/* 如果已經(jīng)執(zhí)行到本任務(wù)的代碼,表明調(diào)度器已經(jīng)啟動。在進(jìn)入死循環(huán)之前創(chuàng)建另一個任務(wù)。 */xTaskCreate( v
28、Task2, "Task 2", 1000, NULL, 1, NULL );for( ; )/* Print out the name of this task. */vPrintString( pkName );/* Delay for a period. */for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul+ )/* This loop is just a very crude delay implementation. nothing to do in here. Later examples will replace th
29、is loop with a proper delay/sleep function. */There iscrude程序7 在一個任務(wù)中創(chuàng)建另一個任務(wù) 在調(diào)度器啟動之后例 2. 使用任務(wù)參數(shù)例 1 中創(chuàng)建的兩個任務(wù)幾乎完全相同,唯一的區(qū)別就是打印輸出的字符串。這種重復(fù)性可以通過創(chuàng)建同一個任務(wù)代碼的兩個實(shí)例來去除。這時任務(wù)參數(shù)就可以用來傳遞各自打印輸出的字符串。程序8 包含了例 2 中用到的唯一一個任務(wù)函數(shù)代碼(vTaskFunction)。這一個任務(wù)函數(shù)代替了例 1 中的兩個任務(wù)函數(shù)(vTask1 與 vTask2)。這個函數(shù)的任務(wù)參數(shù)被強(qiáng)制轉(zhuǎn)化為 char*以得到任務(wù)需要打印輸出的字符串。
30、14FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.void vTaskFunction( void *pvParameters )char *pkName;volatile unsigned long ul;/* 需要打印輸出的字符串從參數(shù)傳入。強(qiáng)制轉(zhuǎn)換為字符指針。 */pkName = ( char * ) pvParameters;/* As per most tasks, this
31、 task is implemented in an infinite loop. */for( ; )/* Print out the name of this task. */vPrintString( pkName );/* Delay for a period. */for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul+ )/* This loop is just a very crude delay implementation. There is nothing to do in here. Later exercises will repla
32、ce this crude loop with a proper delay/sleep function. */程序8 例 2 中用于創(chuàng)建兩個任務(wù)實(shí)例的任務(wù)函數(shù)盡管現(xiàn)在只有一個任務(wù)實(shí)現(xiàn)代碼(vTaskFunction),但是可以創(chuàng)建多個任務(wù)實(shí)例。每個任務(wù)實(shí)例都可以在 FreeRTOS 調(diào)度器的控制下獨(dú)運(yùn)行。傳遞給 API 函數(shù) xTaskCreate()的參數(shù) pvPrameters 用于傳入字符串文本。如程序9 所示。15FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publ
33、ication in any form is strictly prohibited./* 定義將要通過任務(wù)參數(shù)傳遞的字符串。定義為const,且不是在??臻g上,以保證任務(wù)執(zhí)行時也有效。 */static const char *pcTextForTask1 = “Task static const char *pcTextForTask2 = “Task int main( void )12is runningrn”;is runningtn”;/* Create one of the two tasks.xTaskCreate( vTaskFunction,"Task 1&quo
34、t;,1000,*/* 指向任務(wù)函數(shù)的指針. */* 任務(wù)名. */* 棧深度. */* 通過任務(wù)參數(shù)傳入需要打印輸出的文本. */* 此任務(wù)運(yùn)行在優(yōu)先級1上. */(void*)pcTextForTask1, 1,NULL );/*用到此任務(wù)的句柄. */* 同樣的方法創(chuàng)建另一個任務(wù)。至此,由相同的任務(wù)代碼(vTaskFunction)創(chuàng)建了多個任務(wù),僅僅是傳入的參數(shù)不同。同一個任務(wù)創(chuàng)建了兩個實(shí)例。 */xTaskCreate( vTaskFunction, "Task 2", 1000, (void*)pcTextForTask2, 1, NULL );/* Start
35、 the scheduler so our tasks start executing. */vTaskStartScheduler();/* If all is well then main() will never reach here as the scheduler willnow be running the tasks. If main() does reach here then it islikely thatthere was insufficient heap memory available for the idle CHAPTER 5 provides more inf
36、ormation on memory management.for( ; );task*/tobecreated.程序9 例 2 中的 main()函數(shù)實(shí)現(xiàn)代碼例 2 的運(yùn)行輸出結(jié)果與例 1 完全一樣,參見圖 2。16FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.1.5 任務(wù)優(yōu)先級xTaskCreate() API 函數(shù)的參數(shù) uxPriority 為創(chuàng)建的任務(wù)賦予了一個初始優(yōu)先級。這個
37、侁先級可以在調(diào)度器啟動后調(diào)用 vTaskPrioritySet() API 函數(shù)進(jìn)行修改。應(yīng) 用 程 序 在 文 件 FreeRTOSConfig.h中 設(shè) 定 的 編 譯 時 配 置 常 量configMAX_PRIORITIES 的值,即是最多可具有的優(yōu)先級數(shù)目。FreeRTOS 本身并沒有限定這個常量的最大值,但這個值越大,則內(nèi)核花銷的內(nèi)存空間就越多。所以總是建議將此常量設(shè)為能夠用到的最小值。對于如何為任務(wù)指定優(yōu)先級,F(xiàn)reeRTOS 并沒有強(qiáng)加任何限制。任意數(shù)量的任務(wù)可以共享同一個優(yōu)先級以保證最大設(shè)計(jì)彈性。當(dāng)然,如果需要的話,你也可以為每個任務(wù)指定唯一的優(yōu)先級(就如同某些調(diào)度算法的要求
38、一樣),但這不是強(qiáng)制要求的。低優(yōu)先級號表示任務(wù)的優(yōu)先級低,優(yōu)先級號 0 表示最低優(yōu)先級。有效的優(yōu)先級號范圍從 0 到(configMAX_PRIORITES 1)。調(diào)度器保證總是在所有可運(yùn)行的任務(wù)中選擇具有最高優(yōu)先級的任務(wù),并使其進(jìn)入運(yùn)行態(tài)。如果被選中的優(yōu)先級上具有不止一個任務(wù),調(diào)度器會讓這些任務(wù)輪流執(zhí)行。這種行為方式在之前的例子中可以明顯看出來。兩個測試任務(wù)被創(chuàng)建在同一個優(yōu)先級上,并且一直是可運(yùn)行的。所以每個任務(wù)都執(zhí)行一個”時間片”,任務(wù)在時間片起始時刻進(jìn)入運(yùn)行態(tài),在時間片結(jié)束時刻又運(yùn)行態(tài)。圖 3 中 t1 與 t2 之間的時段就等于一個時間片。要能夠選擇下一個運(yùn)行的任務(wù),調(diào)度器需要在每個時
39、間片的結(jié)束時刻運(yùn)行自己本身。一個稱為心跳(tick,有些地方被稱為時鐘滴答,本文中一律稱為時鐘心跳)中斷的周期性中斷用于此目的。時間片的長度通過心跳中斷的頻率進(jìn)行設(shè)定,心跳中斷頻率由FreeRTOSConfig.h 中的編譯時配置常量 configTICK_RATE_HZ 進(jìn)行配置。比如說, 如果 configTICK_RATE_HZ 設(shè)為 100(HZ),則時間片長度為 10ms。可以將圖 3 進(jìn)行擴(kuò)展,將調(diào)度器本身的執(zhí)行時間在整個執(zhí)行流程中體現(xiàn)出來。請參見圖 4。需要說明的是,F(xiàn)reeRTOS API 函數(shù)調(diào)用中指定的時間總是以心跳中斷為(通常的提法為心跳”ticks”)。常量 portT
40、ICK_RATE_MS 用于將以心跳為的時間值轉(zhuǎn)化為以毫秒為的時間值。有效精度依賴于系統(tǒng)心跳頻率。心跳計(jì)數(shù)(tick count)值表示的是從調(diào)度器啟動開始,心跳中斷的總數(shù),并假定心跳17FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.計(jì)數(shù)器溢出。用戶程序在指定延遲周期時不必考慮心跳計(jì)數(shù)溢出問題,因?yàn)闀r間連貫性在內(nèi)核中進(jìn)行管理。圖 4對執(zhí)行流程進(jìn)行擴(kuò)展以顯示心跳中斷的執(zhí)行圖 4 中紅色的線
41、段表時內(nèi)核本身在運(yùn)行。黑色箭頭表示任務(wù)到中斷,中斷再到另一個任務(wù)的執(zhí)行順序。例 3. 優(yōu)先級實(shí)驗(yàn)調(diào)度器總是在可運(yùn)行的任務(wù)中,選擇具有最高優(yōu)級級的任務(wù),并使其進(jìn)入運(yùn)行態(tài)。到目前為止的示例程序中,兩個任務(wù)都創(chuàng)建在相同的優(yōu)先級上。所以這兩個任務(wù)輪番進(jìn)入和運(yùn)行態(tài)。本例將改變例 2 其中一個任務(wù)的優(yōu)先級,看一下倒底會發(fā)生什么。現(xiàn)在第一個任務(wù)創(chuàng)建在優(yōu)先級 1 上,而另一個任務(wù)創(chuàng)建在優(yōu)先級 2 上。創(chuàng)建這兩個任務(wù)的10。這兩個任務(wù)的實(shí)現(xiàn)函數(shù)沒有任何改動,還是通過空循環(huán)產(chǎn)生延代碼參見程序遲來周期性打印輸出字符串。18FreeRTOSDesigned For Microcontrollers;© 20
42、09 Richard Barry. Distribution or publication in any form is strictly prohibited./* 定義將要通過任務(wù)參數(shù)傳遞的字符串。定義為const,且不是在棧空間上,以保證任務(wù)執(zhí)行時也有效。 */static const char *pcTextForTask1 = “Taskstatic const char *pcTextForTask2 = “Task12is runningrn”;is runningtn”;int main( void )/* 第一個任務(wù)創(chuàng)建在優(yōu)先級1上。優(yōu)先級是倒數(shù)第二個參數(shù)。 */xTaskC
43、reate( vTaskFunction, "Task 1", 1000, (void*)pcTextForTask1,1,NULL);/* 第二個任務(wù)創(chuàng)建在優(yōu)先級2上。 */xTaskCreate( vTaskFunction, "Task 2", 1000, (void*)pcTextForTask2,2,NULL);/* Start the scheduler so the tasks start executing. */vTaskStartScheduler();return 0;程序10 兩個任務(wù)創(chuàng)建在不同的優(yōu)先級上圖 5 是例 3 的運(yùn)行結(jié)
44、果。圖 5兩個測試任務(wù)運(yùn)行在不同的優(yōu)先級上調(diào)度器總是選擇具有最高優(yōu)先級的可運(yùn)行任務(wù)來執(zhí)行。任務(wù) 2 的優(yōu)先級比任務(wù)1高,并且總是可運(yùn)行,因此任務(wù) 2 是唯一一個一直處于運(yùn)行態(tài)的任務(wù)。而任務(wù) 1 不可能進(jìn)入運(yùn)行態(tài),所以不可能輸出字符串。這種情況我們稱為任務(wù) 1 的執(zhí)行時間被任務(wù) 2” (starved)”了。任務(wù) 2 之所以總是可運(yùn)行,是因?yàn)槠滢D(zhuǎn),要么往終端打印字符串。FreeRTOS等待任何事情它要么在空循環(huán)里打19Designed For Microcontrollers;© 2009 Richard Barry. Distribution or publication in an
45、y form is strictly prohibited.圖 6 展現(xiàn)了例 3 的執(zhí)行流程。圖 6當(dāng)一個任務(wù)優(yōu)先比另一個高時的執(zhí)行流程20FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.1.6 擴(kuò)充“非運(yùn)行態(tài)”到目前為止所有用到的示例中,創(chuàng)建的每個任務(wù)都只顧不停地處理自己的事情而沒有其它任何事情需要等待由于它們不需要等待所以總是能夠進(jìn)入運(yùn)行態(tài)。這種”不停處理”類型的任務(wù)限制了其有用性,因
46、為它們只可能被創(chuàng)建在最低優(yōu)先級上。如何它們運(yùn)行在其它任何優(yōu)先級上,那么比它們優(yōu)先級更低的任務(wù)將永遠(yuǎn)沒有執(zhí)行的機(jī)會。為了使我們的任務(wù)切實(shí)有用,我們需要通過某種方式來進(jìn)行驅(qū)動。一個驅(qū)動任務(wù)只會在發(fā)生后觸發(fā)工作(處理),而在沒有發(fā)生時是不能進(jìn)入運(yùn)行態(tài)的。調(diào)度器總是選擇所有能夠進(jìn)入運(yùn)行態(tài)的任務(wù)中具有最高優(yōu)先級的任務(wù)。一個高優(yōu)先級但不能夠運(yùn)行的任務(wù)意味著被調(diào)度器選中,而代之以另一個優(yōu)先級雖然更低但能夠運(yùn)行的任務(wù)。因此,采用驅(qū)動任務(wù)的意義就在于任務(wù)可以被創(chuàng)建在許多不同的優(yōu)先級上,并且最高優(yōu)先級任務(wù)把所有的低優(yōu)先級任務(wù)。阻塞狀態(tài)如果一個任務(wù)正在等待某個,則稱這個任務(wù)處于”阻塞態(tài)(blocked)”。阻塞態(tài)是
47、非運(yùn)行態(tài)的一個子狀態(tài)。任務(wù)可以進(jìn)入阻塞態(tài)以等待以下兩種不同類型的:1. 定時(時間相關(guān))這類可以是延期或是絕對時間到點(diǎn)。比如說某個任務(wù)可以進(jìn)入阻塞態(tài)以延遲 10ms。2. 同步源于其它任務(wù)或中斷的。比如說,某個任務(wù)可以進(jìn)入阻塞態(tài)以等待隊(duì)列中有數(shù)據(jù)到來。同步囊括了所有板級范圍內(nèi)的類型。FreeRTOS 的隊(duì)列,二值信號量,計(jì)數(shù)信號量,互斥信號量(recursive semaphore,遞歸信號量,本文一律稱為互斥信號量,因?yàn)槠渲饕糜趯?shí)現(xiàn)互斥)和互斥量都可以用來實(shí)現(xiàn)同步。第二章和第三章涵蓋了有關(guān)這些的詳細(xì)內(nèi)容。任務(wù)可以在進(jìn)入阻塞態(tài)以等待同步時指定一個等待超時時間,這樣可以有效地實(shí)現(xiàn)阻塞狀態(tài)下同時
48、等待兩種類型的。比如說,某個任務(wù)可以等待隊(duì)列中有數(shù)據(jù)到來,但最多只等 10ms。如果 10ms 內(nèi)有數(shù)據(jù)到來,或是 10ms 過去了還沒有數(shù)據(jù)到來,這兩種情況下該任務(wù)都將阻塞態(tài)。21FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.掛起狀態(tài)“掛起(suspended)”也是非運(yùn)行狀態(tài)的子狀態(tài)。處于掛起狀態(tài)的任務(wù)對調(diào)度器而言是不可見的。讓一個任務(wù)進(jìn)入掛起狀態(tài)的唯一辦法就是調(diào)用 vTaskSus
49、pend() API 函數(shù);而把一個掛起狀態(tài)的任務(wù)喚 醒的唯一途徑就是調(diào)用 vTaskResume() 或vTaskResumeFromISR() API 函數(shù)。大多數(shù)應(yīng)用程序中都用到掛起狀態(tài)。就緒狀態(tài)如果任務(wù)處于非運(yùn)行狀態(tài),但既沒有阻塞也沒有掛起,則這個任務(wù)處于就緒(ready,準(zhǔn)備或就緒)狀態(tài)。處于就緒態(tài)的任務(wù)能夠被運(yùn)行,但只是”準(zhǔn)備(ready)”運(yùn)行,而當(dāng)前尚未運(yùn)行。完整的狀態(tài)轉(zhuǎn)移圖圖 7 對之前那個過于簡單的狀態(tài)圖進(jìn)行了擴(kuò)充,包含了本節(jié)描述的非運(yùn)行狀態(tài)的子狀態(tài)。目前為止所有用到的示例程序中創(chuàng)建的任務(wù)都還沒有用到阻塞狀態(tài)和掛起狀態(tài),僅僅是在就緒狀態(tài)和運(yùn)行狀態(tài)之間轉(zhuǎn)移圖 7 中以粗線進(jìn)行
50、醒目提示。圖 7 完整的任務(wù)狀態(tài)機(jī)22FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.例 4. 利用阻塞態(tài)實(shí)現(xiàn)延遲之前的示例中所有創(chuàng)建的任務(wù)都是”周期性”的它們延遲一個周期時間,打印輸出字符串,再一次延遲,如此周而復(fù)始。而產(chǎn)生延遲的方法也相當(dāng)原始地使用了空循環(huán)不停地并遞增一個循環(huán)計(jì)數(shù)直至計(jì)到某個指定值。例 3 明確的指出了這種方法的缺點(diǎn)。一直保持在運(yùn)行態(tài)中執(zhí)行空循環(huán),可能將其它任務(wù)。其實(shí)以
51、任何方式的都不僅僅只是低效,還有各種其它方面的缺點(diǎn)。在過程中,任務(wù)實(shí)際上并沒有做任何有意義的事情,但它依然會耗盡所有處理時間,對處理器周期造成浪費(fèi)。例 4 通過調(diào)用 vTaskDelay() API 函數(shù)來代替空循環(huán),對這種”不良行為”進(jìn)行糾正。vTaskDelay()的函數(shù)原型見程序11,而新的任務(wù)實(shí)現(xiàn)見程序12。void vTaskDelay( portTickType xTicksToDelay );程序11 vTaskDelay() API 函數(shù)原型表 2vTaskDelay()參數(shù)xTicksToDelay延遲多少個心跳周期。調(diào)用該延遲函數(shù)的任務(wù)將進(jìn)入阻塞態(tài),經(jīng)延遲指定的心跳周期數(shù)后
52、,再轉(zhuǎn)移到就緒態(tài)。舉個例子,當(dāng)某個任務(wù)調(diào)用 vTaskDelay( 100 )時,心跳計(jì)數(shù)值為 10,000 ,則該任務(wù)將保持在阻塞態(tài),直到心跳計(jì)數(shù)計(jì)到10,100。常數(shù) portTICK_RATE_MS 可以用來將以毫秒為的時間值轉(zhuǎn)換為以心跳周期為的時間值。23FreeRTOSDesigned For Microcontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.參數(shù)名描述void vTaskFunction( void *pvParamet
53、ers )char *pkName;/* The string to print out is passed in via the parameter. Cast this to a character pointer. */pkName = ( char * ) pvParameters;/* As per most tasks, this task is implemented in an infinite loop. */for( ; )/* Print out the name of this task. */vPrintString( pkName );/* 延遲一個循環(huán)周期。調(diào)用v
54、TaskDelay()以讓任務(wù)在延遲期間保持在阻塞態(tài)。延遲時間以心跳周期為,常量portTICK_RATE_MS可以用來在毫秒和心跳周期之間相換轉(zhuǎn)換。本例設(shè)定250毫秒的循環(huán)周期。 */vTaskDelay( 250 / portTICK_RATE_MS );程序12 調(diào)用 vTaskDelay()來代替空循環(huán)實(shí)現(xiàn)延遲盡管兩個任務(wù)實(shí)例還是創(chuàng)建在不同的優(yōu)先級上,但現(xiàn)在兩個任務(wù)都可以得到執(zhí)行。例 4 的運(yùn)行輸出結(jié)果參見圖 8。圖 9 所示的執(zhí)行流程可以解釋為什么此時不同優(yōu)先級的兩個任務(wù)竟然都可以得到執(zhí)行。圖中為了簡便,忽略了內(nèi)核自身的執(zhí)行時間。24FreeRTOSDesigned For Micr
55、ocontrollers;© 2009 Richard Barry. Distribution or publication in any form is strictly prohibited.空閑任務(wù)是在調(diào)度器啟動時自動創(chuàng)建的,以保證至少有一個任務(wù)可運(yùn)行(至少有一個任務(wù)處于就緒態(tài))。本章第 7 節(jié)會對空閑任務(wù)進(jìn)行更詳細(xì)的描述。圖 9 用 vTaskDelay()代替空循環(huán)后的執(zhí)行流程本例是只改變了兩個任務(wù)的實(shí)現(xiàn)方式,并沒有改變其功能。對比圖 9 與圖 4 可以清晰地看到本例以更有效的方式實(shí)現(xiàn)了任務(wù)的功能。圖 4 展現(xiàn)的是當(dāng)任務(wù)采用空循環(huán)進(jìn)行延遲時的執(zhí)行流程結(jié)果就是任務(wù)總是可運(yùn)行并占用了大量的周期。從圖 9 中的執(zhí)行流程中可以看到,任務(wù)在整個延遲周期內(nèi)都處于阻塞態(tài),只在完成實(shí)際工作的時候才占用處理器時間(本例中任務(wù)的實(shí)際工作只是簡單地打印輸出一條信息)。在圖 9 所示的情形中,任務(wù)離開阻塞態(tài)后,僅僅執(zhí)行了一個心跳周期的一個片段, 然后又再次進(jìn)入阻塞態(tài)。所以大多數(shù)時間都沒有一個應(yīng)用任務(wù)可運(yùn)行(即沒
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 城管洪災(zāi)搶險方案(3篇)
- 內(nèi)部審計(jì)面試題及答案
- 現(xiàn)代車輛收售方案
- 甲狀腺手術(shù)并發(fā)癥
- 場監(jiān)督管理局建設(shè)項(xiàng)目施工許可合同示范文本
- 期權(quán)產(chǎn)品面試題及答案
- 綏化中考試題及答案
- 北方小區(qū)綠化改造方案
- 銷售內(nèi)勤考試題及答案
- 票務(wù)崗位面試題及答案
- 2025至2030中國電壓暫降治理行業(yè)產(chǎn)業(yè)運(yùn)行態(tài)勢及投資規(guī)劃深度研究報(bào)告
- 遼寧省2024年7月普通高中學(xué)業(yè)水平合格性考試化學(xué)試卷(含答案)
- 煤炭造價知識培訓(xùn)
- 2025屆遼寧省大連市高新區(qū)英語七年級第二學(xué)期期末學(xué)業(yè)質(zhì)量監(jiān)測模擬試題含答案
- 腫瘤全程康復(fù)管理制度
- 2025至2030中國護(hù)眼燈行業(yè)發(fā)展趨勢預(yù)判及市場前景預(yù)測報(bào)告
- 2025年人教版小學(xué)一年級下冊數(shù)學(xué)期末易錯題測試試題(含答案和解析)
- 一書一簽收發(fā)管理制度
- 對患者的健康教育制度
- 2025年酒店管理專業(yè)基礎(chǔ)知識考試試題及答案
- 三級醫(yī)院評審標(biāo)準(zhǔn)感染防控部分解讀(25VS22版)
評論
0/150
提交評論