概述
“任務”的特征
簡單來說,FreeRTOS實時系統(tǒng)能夠創(chuàng)建多個獨立的任務,任務之間互不干擾。任務創(chuàng)建之后并不是一起運行的,而是通過優(yōu)先級順序進行任務的調(diào)用,和調(diào)度也沒有依賴關系。所以不管什么時候程序只能執(zhí)行一個任務,只有當該任務執(zhí)行完成或者被打斷才能執(zhí)行下一個任務。具體應該執(zhí)行那個任務是由調(diào)度器來進行負責,因此RTOS可以重復的啟動和停止每個任務。這里RTOS調(diào)度器為了確保處理器在進行任務交換時的環(huán)境(寄存器、堆棧內(nèi)容)與交換之后的任務是完全相同。
因此,為了這一點的實現(xiàn),每個任務都應該有自己的堆??臻g。當任務進行切換,執(zhí)行環(huán)境則保存到該任務的堆棧中,所以,當一段時間后切換回該任務,它能夠精確地回復上次工作時的狀態(tài)。
任務總結(jié)
簡單
沒有使用限制
支持全部的搶占優(yōu)先級
完全優(yōu)先
X每個任務都有自己的堆棧,會導致RAM的使用空間增加
若是使用優(yōu)先級,應該考慮優(yōu)先級的問題
協(xié)程特征
在使用協(xié)程時,應該注意協(xié)程時為了非常小的設備實現(xiàn)的,現(xiàn)在已經(jīng)很少在實際中應用。
雖然這些代碼并沒有刪除,但是官方目前也沒有進一步開發(fā)的打算。因此,如果你使用了,應該注意一些。
協(xié)程其實和任務差不多,但是還是有一些區(qū)別的:
比如以下這幾點:
1.堆棧
協(xié)程是沒有堆棧分配的,是所有創(chuàng)建的協(xié)程共同使用一個堆??臻g,這相比于任務來說,減少了RAM的使用空間。
調(diào)度和優(yōu)先級
協(xié)程使用協(xié)同調(diào)度,但是可以包含在使用的搶占優(yōu)先級之中。
宏定義
協(xié)程例程實現(xiàn)是通過一組宏提供的。
條件限制
RAM使用量的減少是以在如何構(gòu)建協(xié)程方面的一些嚴格限制為代價的。
協(xié)程總結(jié)
在協(xié)程之間共享堆棧會大大降低RAM使用量。
協(xié)程操作使再入問題變得不那么嚴重。
跨架構(gòu)的可移植性很強。
完全優(yōu)先級相對于其他協(xié)程,但如果兩者混合,總是可以被任務搶占。
缺乏堆棧需要特別考慮。
API調(diào)用的位置限制。
協(xié)程操作只在協(xié)程之間進行。
1-任務
1.1 任務狀態(tài)
任務可以是以下幾種狀態(tài)中的一種:
1.1.1 運行
當任務實際執(zhí)行時,它被稱為處于正在運行狀態(tài)。它當前正在使用處理器。 如果運行RTOS的處理器只有一個內(nèi)核,那么 在任何給定時間只能是一個處于“正在運行”狀態(tài)的任務。
1.1.2 就緒(準備)
就緒任務是那些能夠執(zhí)行的任務(它們沒有處于阻塞或掛起狀態(tài)),但目前沒有執(zhí)行,因為一個相同或更高優(yōu)先級的不同任務已經(jīng)處于運行狀態(tài)。
1.1.3 阻塞
如果一個任務正在等待一個臨時事件或外部事件,則該任務被稱為處于阻塞狀態(tài)。例如,如果一個任務調(diào)用vTaskDelay(),它將阻塞(被置于阻塞狀態(tài)),直到延遲時間結(jié)束(一個臨時事件)。任務也可以阻塞來等待隊列、信號量、事件組、通知或信號量事件。處于阻塞狀態(tài)的任務通常有一個“超時”時間,過了這個時間任務就會超時并被取消阻塞,即使任務等待的事件還沒有發(fā)生。
處于“阻塞”狀態(tài)的任務不占用任何處理時間,并且不能被選澤進入“運行中”的狀態(tài)。
1.1.4 掛起
與“阻塞”狀態(tài)的任務一樣,處于“掛起”狀態(tài)的任務不能被選擇進入“正在運行”狀態(tài),但“掛起”狀態(tài)的任務沒有超時時間。相反,只有分別通過vTaskSuspend()和xTaskResume() 的API調(diào)用顯式地命令任務進入或退出Suspended狀態(tài)時,任務才會進入或退出Suspended狀態(tài)。
圖1是任務狀態(tài)轉(zhuǎn)換圖:
2- 任務優(yōu)先級
每個任務分配一個從0到(configMAX_PRIORITIES - 1)的優(yōu)先級,其中configMAX_PRIORITIES是在FreeRTOSConfig.h中定義的(后面的章節(jié)會說一下這個頭文件)。
如果正在使用的端口實現(xiàn)了端口優(yōu)化的任務選擇機制,該機制使用'計數(shù)前導零'類型的指令(用于單個指令中的任務選擇),并且configUSE_PORT_OPTIMISED_TASK_SELECTION在FreeRTOSConfig.h中設置為1,那么configMAX_PRIORITIES不能超過32。在其他情況下,configMAX_PRIORITIES可以在合理范圍內(nèi)取任何值(由于用到RAM空間,因此在使用時,盡可能的保持實際需要的空間大小需求)。
FreeRTOS優(yōu)先級設置是
數(shù)字越大優(yōu)先級越高
??杖蝿盏膬?yōu)先級是0(tskIDLE_PRIORITY)(注意:不同的系統(tǒng)優(yōu)先級不同,有的OS是數(shù)字越小優(yōu)先級越高,這點要注意一下)。
FreeRTOS調(diào)度器確保處于就緒或運行狀態(tài)的任務總是優(yōu)先于同樣處于就緒狀態(tài)的低優(yōu)先級任務,優(yōu)先獲得處理器(CPU)時間。換句話說,處于運行狀態(tài)的任務始終是運行優(yōu)先級最高的任務。
不管多少個任務都可以共享相同的優(yōu)先級。如果沒有定義configUSE_TIME_SLICING,或者configUSE_TIME_SLICING設置為1,那么具有相同優(yōu)先級的就緒狀態(tài)任務將使用時間切片輪詢調(diào)度方式共享可用的處理時間。
3-任務調(diào)度
3.1 RTOS調(diào)度(單核)
在默認情況下,F(xiàn)reeRTOS使用的是固定優(yōu)先級搶占方式,對相同優(yōu)先級的任務進行時間切換輪詢方式。
“固定優(yōu)先級”意味著調(diào)度器不會永久更改任務的優(yōu)先級,盡管它可能由于優(yōu)先級繼承而臨時提高任務的優(yōu)先級。
“搶占式”意味著調(diào)度程序總是運行最高優(yōu)先級RTOS任務,不管這個任務是什么時間可以運行。例如,如果中斷服務例程(ISR)更改了能夠運行的最高優(yōu)先級任務,調(diào)度器將停止當前運行的低優(yōu)先級任務并啟動高優(yōu)先級任務——即使這發(fā)生在一個時間片內(nèi)。在這種情況下,低優(yōu)先級任務被高優(yōu)先級任務“搶占”了。
“循環(huán)”是指具有相同優(yōu)先級的任務輪流進入運行狀態(tài)。
時間切片”意味著調(diào)度程序?qū)⒃诿總€tick中斷上在同等優(yōu)先級的任務之間切換——tick中斷之間的時間是一個時間切片(tick中斷是RTOS用來測量時間的周期性中斷)。
在使用搶占優(yōu)先級調(diào)度程序時,應當避免任務互斥。
始終運行最高優(yōu)先級任務的后果是,永遠不會進入阻塞或掛起狀態(tài)的高優(yōu)先級任務將永久阻斷所有低優(yōu)先級任務的任何執(zhí)行時間。這就是為什么最好創(chuàng)建事件驅(qū)動的任務的原因之一。例如,如果一個高優(yōu)先級的任務正在等待一個事件,那么它就不應該處于該事件的循環(huán)(輪詢)中,因為通過輪詢,它始終在運行,因此永遠不會處于阻塞或掛起狀態(tài)。相反,任務應該進入阻塞狀態(tài)來等待事件。可以使用眾多FreeRTOS任務間通信和同步之一將事件發(fā)送給任務。接收到事件后,優(yōu)先級更高的任務會自動從阻塞狀態(tài)中移除。當高優(yōu)先級任務處于阻塞狀態(tài)時,低優(yōu)先級任務將運行。
3.1.1配置RTOS調(diào)度策略
配置RTOS調(diào)度一般是在FreeRTOSConfig.h,當然你也可以在其他文件設置,但是這里不建議這么操作。
下面這些是更改默認時間調(diào)度的配置:
configUSE_PREEMPTION
如果configUSE_PREEMPTION為0,則搶占關閉,只有在運行狀態(tài)任務進入阻塞或掛起狀態(tài)、運行狀態(tài)任務調(diào)用或中斷服務例程(ISR)手動請求切換才會發(fā)生任務切換。
configUSE_TIME_SLICING
若configUSE_TIME_SLICING為0,則關閉時間切片,因此調(diào)度器不會在每個tick中斷中在同等優(yōu)先級的任務之間切換。
3.2 FreeRTOS AMP調(diào)度策略
使用FreeRTOS的非對稱多處理(AMP)是指多核設備的每個內(nèi)核運行自己獨立的FreeRTOS實例。這些內(nèi)核并不都需要具有相同的體系結(jié)構(gòu),但如果FreeRTOS實例需要彼此通信,則需要共享一些內(nèi)存。
每個內(nèi)核都運行自己的FreeRTOS實例,因此在任何給定的內(nèi)核上的調(diào)度算法與上面描述的單核系統(tǒng)完全相同。可以使用流或消息緩沖區(qū)作為核間通信原語,以便一個核上的任務可以進入Blocked狀態(tài),以等待來自另一個核的數(shù)據(jù)或事件發(fā)送。
3.3 FreeRTOS SMP調(diào)度策略
使用FreeRTOS的對稱多處理(SMP)是指FreeRTOS的一個實例跨多個處理器內(nèi)核調(diào)度RTOS任務。由于FreeRTOS只有一個實例在運行,所以一次只能使用FreeRTOS的一個端口**,因此每個內(nèi)核必須具有相同的處理器架構(gòu)并共享相同的內(nèi)存空間。**
FreeRTOS SMP調(diào)度策略使用與單核調(diào)度策略相同的算法,但與單核和AMP場景不同的是,SMP在任何給定時間會導致多個任務處于Running狀態(tài)(每個內(nèi)核有一個Running狀態(tài)任務)。這意味著,只有在沒有高優(yōu)先級任務可以運行時,才會運行低優(yōu)先級任務的假設不再成立。要理解其中的原因,就要考慮最初有一個高優(yōu)先級任務和兩個中等優(yōu)先級任務都處于Ready狀態(tài)時,SMP調(diào)度器將如何選擇在雙核微控制器上運行的任務。調(diào)度器需要選擇兩個任務,每個內(nèi)核對應一個任務。首先,高優(yōu)先級任務是能夠運行的最高優(yōu)先級任務,因此它將被選中用于第一個內(nèi)核。這樣就剩下兩個中等優(yōu)先級的任務作為能夠運行的最高優(yōu)先級的任務,因此會為第二個內(nèi)核選擇一個。結(jié)果是高優(yōu)先級和中等優(yōu)先級的任務同時運行。
3.3.1 配置SMP RTOS調(diào)度策略
下面的配置項有助于將為單核或AMP RTOS配置編寫的代碼移動到SMP RTOS配置,當這些代碼依賴于這樣一個假設:如果有一個高優(yōu)先級的任務能夠運行,那么低優(yōu)先級的任務將不會運行。
configRUN_MULTIPLE_PRIORITIES
在FreeRTOSConfig.h文件中,如果configRUN_MULTIPLE_PRIORITIES設置為0,那么調(diào)度器將支持同時運行具有相同優(yōu)先級的多個任務。這可能會修復假定一次只運行一個任務的代碼,但代價是失去SMP配置的一些好處。
configUSE_CORE_AFFINITY
在FreeRTOSConfig.h文件中 configUSE_CORE_AFFINITY被設置為1 ,那么可以使用vTaskCoreAffinitySet() API函數(shù)來定義一個哪些內(nèi)核任務可以運行,哪些內(nèi)核任務不運行,使用這種方法,可以防止兩個任務同時執(zhí)行,讓他們對各自的執(zhí)行順序進行判斷。
4-任務實現(xiàn)
4.1 任務執(zhí)行
一個任務應該有以下結(jié)構(gòu):
1void vATaskFunction( void *pvParameters )
2{
3for( ;; )
4{
5-- Task application code here. --
6}
7
8/* Tasks must not attempt to return from their implementing
9function or otherwise exit. In newer FreeRTOS port
10attempting to do so will result in an configASSERT() being
11called if it is defined. If it is necessary for a task to
12exit then have the task call vTaskDelete( NULL ) to ensure
13its exit is clean. */
14vTaskDelete( NULL );
15}
TaskFunction_t類型被定義為一個返回void并將void指針作為唯一形參的函數(shù)。實現(xiàn)一個任務的所有函數(shù)都應該是這種類型??梢允褂迷?a target="_blank">參數(shù)將任何類型的信息傳遞到任務中—這可以通過幾個標準的演示應用程序任務進行演示。(具體演示代碼請查看文件夾下的演示例程)
如下演示代碼:
1/* main_full() is called from main() if the #define in main.c is set to create
2the comprehensive demo, rather than simple blinky demo. */
3int main_full( void )
4{
5/* Setup the microcontroller hardware for the demo. */
6prvSetupHardware();
7
8/* Create the common demo application tasks, for example: */
9vStartInterruptQueueTasks();
10vStartMessageBufferAMPTasks()
11vCreatePollQTasks();
12Etc.
13
14/* Create any tasks defined within main.c itself, or otherwise specific to the
15demo being built. */
16xTaskCreate( vCheckTask, "check", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
17Etc.
18
19/* Start the RTOS scheduler, this function should not return as it causes the
20execution context to change from main() to one of the created tasks. */
21vTaskStartScheduler();
22
23/* Should never get here! */
24return 0;
25}
任務函數(shù)不應該返回,因此通常作為連續(xù)循環(huán)實現(xiàn)。通常最好創(chuàng)建事件驅(qū)動的任務,這樣就不會占用低優(yōu)先級任務的處理時間,如下結(jié)構(gòu):
1void vATaskFunction( void *pvParameters )
2{
3for( ;; )
4{
5/* Psudeo code showing a task waiting for an event
6with a block time. If the event occurs, process it.
7If the timeout expires before the event occurs, then
8the system may be in an error state, so handle the
9error. Here the pseudo code "WaitForEvent()" could
10replaced with xQueueReceive(), ulTaskNotifyTake(),
11xEventGroupWaitBits(), or any of the other FreeRTOS
12communication and synchronisation primitives. */
13if( WaitForEvent( EventObject, TimeOut ) == pdPASS )
14{
15-- Handle event here. --
16}
17else
18{
19-- Clear errors, or take actions here. --
20}
21}
22
23/* As per the first code listing above. */
24vTaskDelete( NULL );
25}
具體的請查看例程代碼嘗試下面的這幾個函數(shù):
通過調(diào)用xTaskCreate()或xTaskCreateStatic()創(chuàng)建任務,通過調(diào)用vTaskDelete()刪除任務。
4.2 任務宏的創(chuàng)建
任務函數(shù)可以使用portTASK_FUNCTION和portTASK_FUNCTION_PROTO宏來定義。提供這些宏是為了允許編譯器把特定的語法分別添加到函數(shù)定義和原型中。它們的使用不是必需的,除非你使用的端口的文檔中特別說明。
上面的原型可以寫成下面這樣:
1void vATaskFunction( void *pvParameters );
2Or,
3portTASK_FUNCTION_PROTO( vATaskFunction, pvParameters );
4Likewise the function above could equally be written as:
5portTASK_FUNCTION( vATaskFunction, pvParameters )
6{
7for( ;; )
8{
9-- Task application code here. --
10}
11}
當然具體的任務宏定義是需要根據(jù)你實現(xiàn)的功能函數(shù)進行任務宏定義的。
2-協(xié)程
2.1-協(xié)同狀態(tài)
協(xié)程僅適用于對RAM有限制的處理器,一般情況下32位MCU是不會使用的(在這里還是給大家說一下,基礎理論知識就全點)。
2.1.1 運行
當協(xié)程實際執(zhí)行時,我們稱其處于運行狀態(tài)。當前處理器正在工作。
2.1.2 就緒
就緒的協(xié)程是那些能夠執(zhí)行(它們沒有被阻塞)但目前沒有執(zhí)行的。協(xié)程可能處于Ready狀態(tài),一是 另一個具有同等或更高優(yōu)先級的協(xié)程已經(jīng)處于Running狀態(tài) ;二是任務處于Running狀態(tài)(只有當應用程序同時使用任務和協(xié)程時,才會出現(xiàn)這種情況)。
2.1.3 阻塞
如果一個協(xié)程當前正在等待一個臨時或外部事件,那么它就被稱為處于Blocked狀態(tài)。例如,如果一個協(xié)程調(diào)用crDELAY(),它將阻塞(被置于阻塞狀態(tài)),直到延遲周期超時,一個臨時事件。阻塞的協(xié)程無法用于調(diào)度。
下面是協(xié)程的通信圖:
2.2 協(xié)程的實現(xiàn)
協(xié)程的結(jié)構(gòu)如下:
1void vACoRoutineFunction( CoRoutineHandle_t xHandle,
2UBaseType_t uxIndex )
3{
4crSTART( xHandle );
5
6for( ;; )
7{
8-- Co-routine application code here. --
9}
10
11crEND();
12}
類型crCOROUTINE_CODE被定義為一個返回void并將CoRoutineHandle_t和索引作為參數(shù)的函數(shù)。實現(xiàn)協(xié)程的所有函數(shù)都應該是這種類型的(上面的這段代碼)。
協(xié)程的創(chuàng)建是通過xCoRoutineCreate()來進行的。
注意:
所有協(xié)程函數(shù)都必須以調(diào)用crSTART()開始。
所有協(xié)程函數(shù)都必須以對crEND()的調(diào)用結(jié)束。
協(xié)程函數(shù)不應該返回,因此通常作為連續(xù)循環(huán)實現(xiàn)。
可以從單個協(xié)程函數(shù)創(chuàng)建許多協(xié)程。
提供 uxIndex 參數(shù)是為了區(qū)分此類 協(xié)程。
2.3-協(xié)程優(yōu)先級
協(xié)程的優(yōu)先級從0到(configMAX_CO_ROUTINE_PRIORITIES - 1)。configMAX_CO_ROUTINE_PRIORITIES在FreeRTOSConfig.h中定義,可以在應用程序的基礎上設置。優(yōu)先級和任務一樣數(shù)字越大優(yōu)先級越高。
協(xié)程優(yōu)先級只與其他協(xié)程相關。如果在同一個應用程序中混合了任務和協(xié)程,那么任務的優(yōu)先級始終比協(xié)程的優(yōu)先級高。
2.4- 協(xié)程調(diào)度
協(xié)程是通過重復調(diào)用vCoRoutineSchedule() 來調(diào)度的。調(diào)用 vCoRoutineSchedule() 的最佳位置是從空閑任務鉤子。即使您的應用程序只使用協(xié)程,也會出現(xiàn)這種現(xiàn)象,因為空閑任務仍將在調(diào)度程序啟動時自動創(chuàng)建。
2.5- 協(xié)程和任務的混合
在空間任務中調(diào)度協(xié)程是允許任務和協(xié)程的混合的。這種方式只有當協(xié)程優(yōu)先級低于空閑任務的優(yōu)先級時,這種方式下才能執(zhí)行。
2.5.1-局限性和復雜性
和任務相比來說,協(xié)程的好處是降低了RAM的使用空間,但是這些也會帶來一定的限制。比如局限性以及復雜性。
2.5.2堆棧共享
當協(xié)程阻塞時,攜程的堆棧時不會被保存的,這樣即使在堆棧上有再多的變量,也會丟失。因此為了能夠解決這個問題,需要聲明一個在阻塞時保持調(diào)用的變量,作為靜態(tài)。例如:
1void vACoRoutineFunction( CoRoutineHandle_t xHandle,
2UBaseType_t uxIndex )
3{
4static char c = 'a';
5
6// Co-routines must start with a call to crSTART().
7crSTART( xHandle );
8
9for( ;; )
10{
11// If we set c to equal 'b' here ...
12c = 'b';
13
14// ... then make a blocking call ...
15crDELAY( xHandle, 10 );
16
17// ... c will only be guaranteed to still
18// equal 'b' here if it is declared static
19// (as it is here).
20}
21
22// Co-routines must end with a call to crEND().
23crEND();
24}
堆棧共用的另一種結(jié)果是,可能導致協(xié)程阻塞API函數(shù)的調(diào)用只能來自于協(xié)程函數(shù)本身,而不是協(xié)程函數(shù)調(diào)用的函數(shù)。
1例如:
2void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
3{
4// Co-routines must start with a call to crSTART().
5crSTART( xHandle );
6
7for( ;; )
8{
9// It is fine to make a blocking call here,
10crDELAY( xHandle, 10 );
11
12// but a blocking call cannot be made from within
13// vACalledFunction().
14vACalledFunction();
15}
16
17// Co-routines must end with a call to crEND().
18crEND();
19}
20
21void vACalledFunction( void )
22{
23// Cannot make a blocking call here!
24}
2.5.3 switch語句的應用
FreeRTOS文件中包含的默認協(xié)程實現(xiàn)不允許從switch語句中進行阻塞調(diào)用。
1void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
2{
3// Co-routines must start with a call to crSTART().
4crSTART( xHandle );
5
6for( ;; )
7{
8// It is fine to make a blocking call here,
9crDELAY( xHandle, 10 );
10
11switch( aVariable )
12{
13case 1 : // Cannot make a blocking call here!
14break;
15default: // Or here!
16}
17}
18
19// Co-routines must end with a call to crEND().
20crEND();
21}
2.6協(xié)程例子
2.6.1 創(chuàng)建LED協(xié)程
1void vFlashCoRoutine( CoRoutineHandle_t xHandle,
2UBaseType_t uxIndex )
3{
4// Co-routines must start with a call to crSTART().
5crSTART( xHandle );
6
7for( ;; )
8{
9// Delay for a fixed period.
10crDELAY( xHandle, 10 );
11
12// Flash an LED.
13vParTestToggleLED( 0 );
14}
15
16// Co-routines must end with a call to crEND().
17crEND();
18}
2.6.2 協(xié)程調(diào)度
協(xié)同例程是通過重復調(diào)用 vCoRoutineSchedule()來調(diào)度的。執(zhí)行此操作的最佳位置是從空閑任務中編寫空閑任務掛鉤。首先確保在FreeRTOSConfig.h 中將configUSE_IDLE_HOOK設置為 1。然后將空閑任務鉤子編寫為:
1void vApplicationIdleHook( void )
2{
3vCoRoutineSchedule( void );
4}
5或者,如果空閑任務不執(zhí)行任何其他函數(shù),從循環(huán)中調(diào)用vCoRoutineSchedule()會更有效:
6void vApplicationIdleHook( void )
7{
8for( ;; )
9{
10vCoRoutineSchedule( void );
11}
12}
2.6.3 創(chuàng)建協(xié)程并啟動RTOS調(diào)度
1#include "task.h"
2#include "croutine.h"
3
4#define PRIORITY_0 0
5
6void main( void )
7{
8// In this case the index is not used and is passed
9// in as 0.
10xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, 0 );
11
12// NOTE: Tasks can also be created here!
13
14// Start the RTOS scheduler.
15vTaskStartScheduler();
16}
2.6.4 擴展
現(xiàn)在假設我們要從同一個函數(shù)創(chuàng)建 8 個這樣的協(xié)程。每個協(xié)程將閃爍不同的 LED 以不同的速率顯示。index 參數(shù)可用于區(qū)分協(xié)程函數(shù)本身。
1#include "task.h"
2#include "croutine.h"
3
4#define PRIORITY_0 0
5#define NUM_COROUTINES 8
6
7void main( void )
8{
9int i;
10
11for( i = 0; i < NUM_COROUTINES; i++ )
12{
13// This time i is passed in as the index.
14xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, i );
15}
16
17// NOTE: Tasks can also be created here!
18
19// Start the RTOS scheduler.
20vTaskStartScheduler();
21}
22還擴展了協(xié)程功能,因此每個程序都使用不同的LED和閃光率。
23const int iFlashRates[ NUM_COROUTINES ] = { 10, 20, 30, 40, 50, 60, 70, 80 };
24const int iLEDToFlash[ NUM_COROUTINES ] = { 0, 1, 2, 3, 4, 5, 6, 7 }
25
26void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex )
27{
28// Co-routines must start with a call to crSTART().
29crSTART( xHandle );
30
31for( ;; )
32{
33// Delay for a fixed period. uxIndex is used to index into
34// the iFlashRates. As each co-routine was created with
35// a different index value each will delay for a different
36// period.
37crDELAY( xHandle, iFlashRate[ uxIndex ] );
38
39// Flash an LED. Again uxIndex is used as an array index,
40// this time to locate the LED that should be toggled.
41vParTestToggleLED( iLEDToFlash[ uxIndex ] );
42}
43
44// Co-routines must end with a call to crEND().
45crEND();
46}
-
RTOS
+關注
關注
21文章
809瀏覽量
119361 -
FreeRTOS
+關注
關注
12文章
483瀏覽量
61915 -
任務
+關注
關注
1文章
20瀏覽量
8525
發(fā)布評論請先 登錄
相關推薦
評論