1. 程式人生 > >FreeRTOS 學習筆記 4 —— API 使用指南

FreeRTOS 學習筆記 4 —— API 使用指南

轉自:http://xilinx.eetrend.com/article/7845
FreeRTOS

繁星電子開發團隊製作
作為一個輕量級的作業系統,FreeRTOS 提供的功能包括:任務管理、時間管理、訊號量、訊息佇列、記憶體管理、記錄功能等,可基本滿足較小系統的需要。FreeRTOS 核心支援優先順序排程演算法,每個任務可根據重要程度的不同被賦予一定的優先順序,CPU 總是讓處於就緒態的、優先順序最高的任務先執行。FreeRT0S 核心同時支援輪換排程演算法,系統允許不同的任務使用相同的優先順序,在沒有更高優先順序任務就緒的情況下,同一優先順序的任務共享CPU 的使用時間。

FreeRTOS 的核心可根據使用者需要設定為可剝奪型核心或不可剝奪型核心。當FreeRTOS 被設定為可剝奪型核心時,處於就緒態的高優先順序任務能剝奪低優先順序任務的CPU 使用權,這樣可保證系統滿足實時性的要求;當FreeRTOS 被設定為不可剝奪型核心時,處於就緒態的高優先順序任
務只有等當前執行任務主動釋放CPU 的使用權後才能獲得執行,這樣可提高CPU 的執行效率FreeRTOS 對系統任務的數量沒有限制。

一 變數型別定義
#define portCHAR char
#define portFLOAT float
#define portDOUBLE double
#define portLONG long
#define portSHORT short
#define portSTACK_TYPE unsigned portLONG
#define portBASE_TYPE long
Generated by Foxit PDF Creator © Foxit Software
http://www.foxitsoftware.com For evaluation only.

二 任務函式


 任務建立
標頭檔案:task.h
portBASE_TYPE xTaskCreate (
pdTASK_CODE pvTaskCode, 指向任務的實現函式的指標。效果上僅僅是函式名
const portCHAR * const pcNane, 具有描述性的任務名。FreeRTOS 不會使用它。
unsigned portSHORT usStackDepth, 指定任務堆疊的大小
void *pvParameters, 指標用於作為一個引數傳向建立的任務
unsigned portBASE_TYPE uxPriority, 任務執行時的優先順序
xTaskHandle *pvCreatedTask 用於傳遞任務的控制代碼,可以引用從而對任務進行其他操作。
)

說明:
1. 這裡的任務是指一個永遠不會退出的C 函式,通常是一個死迴圈。
2. pcNane 其只是單純地用於輔助除錯。應用程式可以通過定義常量
config_MAX_TASK_NAME_LEN 來定義任務名的最大長度——包括’\0’結束符。如果傳入的
字串長度超過了這個最大值,字串將會自動被截斷
3. usStackDepth 這個值指定的是棧空間可以儲存多少個字(word),而不是多少個位元組(byte)。棧空間
大小為usStackDepth*4(bytes)。
4. uxPriority 優先順序的取值範圍可以從最低優先順序0 到最高優先順序(configMAX_PRIORITIES–1)。

返回:
1. pdPASS 表明任務建立成功,準備執行。
2. errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 由於記憶體堆空間不足,FreeRTOS 無法分配
足夠的空間來儲存任務結構資料和任務棧,因此無法建立任務。

 任務刪除
標頭檔案:task.h
void vTaskDelete (
xTaskHandle pxTask 處理要刪除的任務。傳遞NULL 將刪除自己
)

說明:
1. FreeRTOSConfig.h 中的INCLUDE_vTaskDelete=1,這個函式才能用。從RTOS 實時核心管理
中移除任務。要刪除的任務將從就緒,封鎖,掛起,事件列表中移除。
2. 任務被刪除後就不復存在,也不會再進入執行態
3. 空閒任務負責釋放核心分配給已刪除任務的記憶體。

使用提示:只有核心為任務分配的記憶體空間才會在任務被刪除後由空閒任務自動回收。任務自己佔用的記憶體或資源需要由應用程式自己顯式地釋放
Generated by Foxit PDF Creator © Foxit Software
http://www.foxitsoftware.com For evaluation only.

 任務延時
標頭檔案:task.h
void vTaskDelay (
portTickType xTicksToDelay 時間數量,呼叫任務應該鎖住的時間片週期
)

說明:
1. FreeRTOSConfig.h 中的INCLUDE_vTaskDelay=1,這個函式才能用。
2. 延時任務為已知時間片,任務被鎖住剩餘的實際時間由時間片速率決定。portTICK_RATE_MS 常量
以時間片速率來計算實際時間
3. vTaskDelay()指定一個任務希望的時間段,這個時間之後任務解鎖。
4. vTaskDelay()不提供一個控制週期性任務頻率的好方法,和其他任務和中斷一樣,在呼叫vTaskDelay()

後將影響頻率
提示:vTaskDelayUntil() ,這個交替的API 函式設計了執行固定的頻率。它是指定的一個絕對時間(而不是
一個相對時間)後,呼叫任務解鎖。--------可以實現週期性任務執行。

 任務延遲到指定時間
標頭檔案:task.h
void vTaskDelayUntil (
portTickType *pxPreviousWakeTime, 指定一個變數來掌握任務最後開啟的時間, 第一次使用時必須使用當前時間來初始化, 在vTaskDelayUntil 中,這個變數是自動修改的
portTickType xTimeIncrement 迴圈週期時間
)

說明:
1. FreeRTOSConfig.h 中的INCLUDE_vTaskDelayUntil=1,這個函式才能用。
2. 延時一個任務到指定時間,這個和vTaskDelay() 不同, vTaskDelay 是延時一個相對時間,而
vTaskDelayUntil 是延時一個絕對時間
3. 常量 portTICK_RATE_MS 用來計算時間片頻率的實時時間- 按照一個時間片週期
4. 任務將在一定時間開啟(*pxPreviousWakeTime + xTimeIncrement)。使用相同的xTimeIncrement 引數值來呼叫vTaskDelayUntil()將使任務按固定的週期執行。

注意:vTaskDelayUntil() 如果指定的甦醒時間使用完,將立即返回。因此,一個使用vTaskDelayUntil() 來週期性的執行的任務,如果執行週期因為任何原因(例如任務是臨時為懸掛狀態)暫停而導致任務錯過一個或多個執行週期,那麼需要重新計算甦醒時間。通過檢查像pxPreviousWakeTime 可變的引數來組織當前時間片計數。然而在大多數使用中並不是必須的。

使用提示:如果一個任務想按固定的頻率執行,如讓一個LED 燈,按1KHz 頻率執行,如果只有一個任務那麼呼叫vTaskDelay 或vTaskDelayUntil 都能完成,但是如果有多個任務,vTaskDelay 就不行了,因為優先順序或其它問題,它不知道什麼時候再能執行,因此其不是週期執行,也就談不上固定頻率了,這時就要用vTaskDelayUntil 這個函數了

 獲得任務優先順序
標頭檔案:task.h
unsigned portBASE_TYPE uxTaskPriorityGet (
xTaskHandle pxTask 需要處理的任務. 當傳遞NULL 時,將返回呼叫該任務的優先順序
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskPriorityGet=1,這個函式才能用
返回:pxTask 的優先順序

 設定任務優先順序
標頭檔案:task.h
void vTaskPrioritySet (
xTaskHandle pxTask , 需要設定優先順序的任務。當傳遞NULL,將設定呼叫任務的優先順序
unsigned portBASE_TYPE uxNewPriority 任務需要設定的優先順序
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskPrioritySet 為1,才能使用此函式.如果設定的優先順序高於
當前執行任務的優先順序,則上下文切換將在此函式返回前發生

 掛起任務
標頭檔案:task.h
void vTaskSuspend (
xTaskHandle pxTaskToSuspend 處理需要掛起的任務。傳遞NULL 將掛起呼叫此函式的任務
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskSuspend 為1,才能使用此函式。當掛起一個任務時,不管優先順序是多少,不需要佔用任何微控制器處理器時間。呼叫vTaskSuspend 不會累積——即:在同一任務中呼叫vTaskSuspend 兩次,但只需要呼叫一次vTaskResume()就能使掛起的任務就緒

 喚醒掛起的任務
標頭檔案:task.h
void vTaskResume (
xTaskHandle pxTaskToResume 就緒任務的控制代碼
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskSuspend 為1,才能使用此函式。必須是呼叫 vTaskSuspend
() 後掛起的任務,才有可能通過呼叫 vTaskResume ()從新執行

 從中斷喚醒掛起的任務
標頭檔案:task.h
portBase_TYPE vTaskResumeFromISR (
xTaskHandle pxTaskToResum 就緒任務的控制代碼
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskSuspendhe 和INCLUDE_xTaskResumeFromISR 都為1,才能使用此函式。vTaskResumeFromISR()不應該用於任務和中斷同步,因為可能會在中斷髮生期間,任務已經掛起——這樣導致錯過中斷。使用訊號量最為同步機制將避免這種偶然性。
返回:pdTRUE: 如果喚醒了任務將引起上下文切換。pdFALSE:用於ISR 確定是否上下文切換

 為任務分配標籤值
標頭檔案:task.h
void vTaskSetApplicationTaskTag (
xTaskHandle xTask , 將分配給標籤值的任務。傳遞NULL 將分配標籤給呼叫的任務。
pdTASK_HOOK_CODE pxTagValue 分配給任務的標籤值 型別為 pdTASK_HOOK_CODE 允許一
個函式指標賦值給標籤,因此實際上任何值都可以分配
)
說明:FreeRTOSConfig.h 中的onfigUSE_APPLICATION_TASK_TAG 為1,這個函式才能可用。這個值僅
在應用程式中使用,核心本身不使用它。
 xTaskCallApplicationTaskHook

三:核心函式
 啟動實時核心處理
標頭檔案:task.h
void vTaskStartScheduler ( void );
說明:當 vTaskStartScheduler() 被呼叫時,空閒任務自動建立。如果 vTaskStartScheduler() 成功呼叫,這個函式不返回,直到執行任務呼叫vTaskEndScheduler()。如果可供給空閒任務的RAM 不足,那麼函式呼叫失敗,並立即返回。

 停止實時核心執行
標頭檔案:task.h
void vTaskEndScheduler ( void );
說明:所有建立的任務將自動刪除,並且多工(優先順序或合作式)將停止。當vTaskStartScheduler()呼叫時,執行將再次開始,像vTaskStartScheduler()僅僅返回。
注意:vPortEndScheduler ()導致所有由核心分配的資源釋放——但是不會釋放由應用程式的任務分配的資源。

 掛起所有活動的實時核心,同時允許中斷(包括核心滴答)
標頭檔案:task.h
void vTaskSuspendAll ( void );
說明:任務在呼叫vTaskSuspendAll ()後,這個任務將繼續執行,不會有任何被切換的危險,直到呼叫xTaskResumeAll ()函式重啟核心。
注意:API 中有可能影響影響上下文切換的函式(例如,vTaskDelayUntil(), xQueueSend()等等),一定不能在排程器掛起時被呼叫。

四:佇列管理
佇列是內部通訊的主要形式。它可以用於在任務和任務之間以及任務和中斷之間傳送訊息。在大多數情況下使用執行緒安全 FIFO(先進先出)快取,新資料放在佇列的最後,雖然資料也可以放在前面。

佇列可以包含固定大小的 '專案' - 每個專案的大小和佇列可以儲存專案的最大數量在建立佇列時就已經定義了。

專案以複製而不是引用的方式放入佇列,因此最好使放入佇列專案的大小成為最小。以複製的方式放入佇列可以使你的系統設計極大的簡化,因為兩個任務不會同時訪問資料。佇列幫助你管理所有的互斥問題。

如果你希望在佇列中使用大的專案,可能最好用插入佇列指標 - 但是這樣做必須注意要確保你的系統明確定義任務和/或中斷是資料的"所以者"。

佇列 API 函式可以指定阻塞的時間。阻塞時間代表任務進入阻塞狀態或者等待佇列中資料時(當任務讀取佇列但是佇列是空的時候)的最大'節拍'數,或者等待佇列空間變為可以使用(當任務需要寫資料到佇列,但是佇列已滿時)。當一個以上任務在同一個佇列中被阻塞時,高優先順序的任務先解除阻塞。

 建立一個新的佇列
標頭檔案:queue. H
xQueueHandle xQueueCreate (
unsigned portBASE_TYPE uxQueueLength, 佇列中包含最大專案數量
unsigned portBASE_TYPE uxItemSize 佇列中每個專案所需的位元組數
);
說明:建立一個新的佇列。為新的佇列分配所需的儲存記憶體,並返回一個佇列處理。
注意:專案通過複製而不是引用排隊,因此,所需的位元組數,將複製給每個專案。佇列中每個專案必須分配同樣大小。
返回:如果佇列成功建立,則返回一個新建佇列的處理。如果不能建立佇列,將返回0。

 傳遞一個專案到佇列
標頭檔案:queue. H
portBASE_TYPE xQueueSend (
xQueueHandle xQueue, 將專案傳進的佇列
const void * pvItemToQueue, 專案的指標【源資料】
portTickType xTicksToWait 等待的最大時間量【時間使用滴答週期】
);
說明:傳遞一個專案到佇列。這個專案通過複製而不是通過引用排隊。這個函式不能從中斷服務程式呼叫。
注意:當佇列滿時,肯定傳遞不成功,則等待xTicksToWait 個滴答週期後再傳遞,但如果xTicksToWait 設定為0,呼叫將立即返回。
返回:pdTRUE:專案成功傳遞。否則為:errQUEUE_FULL.

 傳遞專案到一個佇列中的後面
標頭檔案:queue. H
portBASE_TYPE xQueueSendToBack (
xQueueHandle xQueue, 將專案傳進的佇列
const void * pvItemToQueue, 專案的指標【源資料】
portTickType xTicksToWait 等待的最大時間量
);
說明:這個與xQueueSend 是一樣的,參照xQueueSend 的用法

 從佇列接收一個專案
標頭檔案:queue. H
portBASE_TYPE xQueueReceive (
xQueueHandle xQueue, 傳送專案的佇列控制代碼
void *pvBuffer, 指向緩衝區的指標,將接收的專案被複制進去
portTickType xTicksToWait 任務中斷並等待佇列中可用空間的最大時間
);
說明:這個專案通過複製接收,因此緩衝器必須提供足夠大的空間。這個函式一定不能在中斷服務程式中使用當佇列空時,肯定複製傳遞不成功,則等待xTicksToWait 個滴答週期後再複製,但如果xTicksToWait 設定為0,呼叫將立即返回。
返回:如果專案成功被佇列接收為pdTRUE ,否則為 pdFALSE。

 從中斷傳遞一個專案到佇列的後面
標頭檔案:queue. H
portBASE_TYPE xQueueSendFromISR (
xQueueHandle pxQueue, 將專案傳進的佇列
const void *pvItemToQueue, 專案的指標【源資料】
portBASE_TYPE *pxHigherPriorityTaskWoken 因空間資料問題被掛起的任務是否解鎖
);
說明: 如果傳進佇列而導致因空間資料問題被掛起的任務解鎖,並且解鎖的任務的優先順序高於當前執行任務,xQueueSendFromISR 將設定 *pxHigherPriorityTaskWoken 到 pdTRUE。當pxHigherPriorityTaskWoken被設定為pdTRUE 時,則在中斷退出之前將請求任務切換。
返回:pdTRUE:資料成功傳遞進佇列。否則為:errQUEUE_FULL。

 從中斷傳遞專案到一個佇列中的後面
標頭檔案:queue. H
portBASE_TYPE xQueueSendToBackFromISR (
xQueueHandle pxQueue,
const void *pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken
);
說明:參照xQueueSendFromISR

 從中斷傳遞一個項到佇列的前面
標頭檔案:queue. H
portBASE_TYPE xQueueSendToFrontFromISR (
xQueueHandle pxQueue,
const void *pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken
);
說明:參照xQueueSendFromISR

 中斷時從佇列接收一個專案
標頭檔案:queue. H
portBASE_TYPE xQueueReceiveFromISR (
xQueueHandle pxQueue, 傳送專案的佇列控制代碼
void *pvBuffer, 指向緩衝區的指標,將接收的專案被複制進去
portBASE_TYPE *pxTaskWoken 任務將鎖住,等待佇列中的可用空間
);
說明: 如果xQueueReceiveFromISR 引起一個任務解鎖,*pxTaskWoken 將設定為pdTRUE,否則*pxTaskWoken保留不變
返回:pdTRUE :如果專案成功從佇列接收。否則為: pdFALSE

 為佇列命名,並加入佇列到登記管理中
標頭檔案:queue.h
void vQueueAddToRegistry (
xQueueHandle xQueue, 將要新增登記的佇列控制代碼
signed portCHAR *pcQueueName, 為指定的佇列命名。 僅僅是文字串,方便除錯。
);
說明:佇列登記有兩個特點, 均與核心的相關除錯有關:
允許文字式名字,使佇列在除錯GUI 中方便定義。
包含偵錯程式需要的資訊,如:定位每個已經登記的佇列和訊號量。
佇列的登記沒有目的,除非使用核心相關的除錯。
configQUEUE_REGISTRY_SIZE 定義了佇列和訊號量的最大數目.僅當使用核心相關的除錯時需要顯示已經登記的訊號量和佇列。

 從登記管理中移除佇列
標頭檔案:queue.h
void vQueueUnregisterQueue (
xQueueHandle xQueue, 從登記管理處中移出的佇列控制代碼
);
說明:佇列登記有兩個特點, 均與核心的相關除錯有關:
允許文字式名字,使佇列在除錯GUI 中方便定義。
包含偵錯程式需要的資訊,如:定位每個已經登記的佇列和訊號量。
佇列的登記沒有目的,除非使用核心相關的除錯。
configQUEUE_REGISTRY_SIZE 定義了佇列和訊號量的最大數目.僅當使用核心相關的除錯時需要顯示已經登記的訊號量和佇列。

五:訊號量
 使用已存在的佇列結構來建立計數型訊號量
標頭檔案:semphr. H
xSemaphoreHandle xSemaphoreCreateCounting (
unsigned portBASE_TYPE uxMaxCount, 可以達到的最大計數值。
unsigned portBASE_TYPE uxInitialCount 訊號量建立時分配的初始值
)
說明:兩種典型應用
事件計數
在這種應用的情形下,事件處理程式會在每次事件發生時傳送訊號量(增加訊號量計數值),而任務處理程式會在每次處理事件時請求訊號量(減少訊號量計數值)。因此計數值為事件發生與事件處理兩者間的差值,在這種情況下計數值初始化為0 是合適的。

資源管理
在這種應用情形下,計數值指示出可用的資源數量。任務必須首先“請求”訊號量來獲得資源的控制權--減少訊號量計數值。當計數值降為0 時表示沒有空閒資源。任務使用完資源後“返還”訊號量--增加訊號量計數值。在這種情況下計數值初始化為與最大的計數值相一致是合適的,這指示出所有的空閒資源。

返回:已建立的訊號量控制代碼,為xSemaphoreHandle 型別,如果訊號量無法建立則為NULL。

 使用已存在的佇列結構來建立互斥鎖訊號量的巨集
標頭檔案:semphr. H
xSemaphoreHandle xSemaphoreCreateMutex ( void )

說明: 通過此巨集建立的互斥鎖可以使用xSemaphoreTake() 與 xSemaphoreGive() 巨集來訪問。不能使用
xSemaphoreTakeRecursive()與 xSemaphoreGiveRecursive()巨集

二元訊號量與互斥鎖十分相像,不過兩者間有細微的差別:互斥鎖包含一個優先順序繼承機制,而訊號量沒有。這種差別使得二元訊號量更適合於實現同步(任務之間或任務與中斷之間),互斥鎖更適合於實現簡單的互斥。

當有另外一個具有更高優先順序的任務試圖獲取同一個互斥鎖時,已經獲得互斥鎖的任務的優先順序會被提升。已經獲得互斥鎖的任務將繼承試圖獲取同一互斥鎖的任務的優先順序。這意味著互斥鎖必須總是要返還的,否則高優先順序的任務將永遠也不能獲取互斥鎖,而低優先順序的任務將不會放棄優先順序的繼承。

二元訊號量並不需要在得到後立即釋放,因此任務同步可以通過一個任務/中斷持續釋放訊號量而另外一個持續獲得訊號量來實現。

互斥鎖與二元訊號量均賦值為xSemaphoreHandle 型別,並且可以在任何此型別引數的API 函式中使用。

返回: 已建立的訊號量控制代碼,需要為xSemaphoreHandle 型別。

 使用已存在的佇列結構來建立遞迴互斥鎖的巨集
標頭檔案:semphr. H
xSemaphoreHandle xSemaphoreCreateRecursiveMutex ( void )

說明:通過此巨集建立的互斥鎖可以使用xSemaphoreTakeRecursive()與 xSemaphoreGiveRecursive()巨集 來訪問。

不能使用xSemaphoreTake()與 xSemaphoreGive()巨集

一個遞迴的互斥鎖可以重複地被其所有者“獲取”。在其所有者為每次的成功“獲取”請求呼叫xSemaphoreGiveRecursive()前,此互斥鎖不會再次可用。例如,如果一個任務成功“獲取”同一個互斥鎖5 次,則在其“釋放”互斥鎖恰好為5 次後,其他任務才可以使用此互斥鎖。

這種型別的訊號量使用一個優先順序繼承機制,因此已取得訊號量的任務“必須總是”在不再需要訊號量時立刻“釋放”。

互斥型別的訊號量不能在中斷服務程式中使用。

可以參考vSemaphoreCreateBinary()來獲得一個二選一執行的實現方式,可以在中斷服務程式中實現純粹的同步(一個任務或中斷總是“釋放”訊號量,而另一個總是“獲取”訊號量)。

返回: 已建立的訊號量控制代碼,需要為xSemaphoreHandle 型別。

 獲取訊號量的巨集 標頭檔案:semphr. H
xSemaphoreTake (
xSemaphoreHandle xSemaphore, 將被獲得的訊號量控制代碼,此訊號量必須已經被建立
portTickType xBlockTime 等待訊號量可用的時鐘滴答次數
)

說明:當訊號量不可用時,則等待xBlockTime 個時鐘滴答,再看是否可用,當是為0 時如果不可用,則立即退出,因此為0 時可以達到對訊號量輪詢的作用。

返回:如果成功獲取訊號量則返回pdTRUE,如果xBlockTime 超時而訊號量還未可用則返回pdFALSE。

 遞迴獲得互斥鎖訊號量的巨集
標頭檔案:semphr. H
xSemaphoreTakeRecursive (
xSemaphoreHandle xMutex, 將被獲得的互斥鎖控制代碼
portTickType xBlockTime 等待訊號量可用的時鐘滴答次數
)

說明:FreeRTOSConfig.h 中的configUSE_RECURSIVE_MUTEXES 必須設定為1 才可以使用此巨集。一個遞迴型的互斥鎖可以被其所有者重複地“獲取”, 在其所有者為每次成功的“獲取”請求呼叫xSemaphoreGiveRecursive()前,此互斥鎖不會再次可用。

返回:如果成功獲取訊號量則返回pdTRUE,如果xBlockTime 超時而訊號量還未可用則返回pdFALSE。

 釋放訊號量的巨集
標頭檔案:semphr. H
xSemaphoreGive (
xSemaphoreHandle xSemaphore 即將釋放的訊號量的控制代碼,在訊號量建立是返回
)

返回:如果訊號量成功釋放返回pdTRUE,如果發生錯誤則返回pdFALSE。訊號量使用的是佇列,因此如果佇列沒有位置用於傳送訊息就會發生一個錯誤——說明開始時沒有正確獲取訊號量。

 用於遞迴釋放,或‘返還’,互斥鎖訊號量的巨集
標頭檔案:semphr. H
xSemaphoreGiveRecursive (
xSemaphoreHandle xMutex 將被釋放或‘返還’的互斥鎖的控制代碼
)

返回:如果訊號量成功釋放則為pdTRUE

 從中斷釋放一個訊號量的巨集
標頭檔案:semphr. H
xSemaphoreGiveFromISR (
xSemaphoreHandle xSemaphore, 將被釋放的訊號量的控制代碼
portBASE_TYPE *pxHigherPriorityTaskWoken 因空間資料問題被掛起的任務是否解鎖
)

返回:如果訊號量成功釋放則返回pdTRUE,否則返回errQUEUE_FULL

六:聯合函式

一個聯合程式可以以下面的狀態中的一種存在:

執行:當一個聯合程式正在執行時它就是處於執行狀態,它就佔用了處理器。

就緒:就緒狀態的聯合程式是那些可以執行(沒有被阻塞)但是還沒有被執行的程式。一個聯合程式可能處於就緒狀態是因為另外一個相同或高優先順序的聯合程式正處於執行狀態,或一個任務處於執行狀態——這隻會在系統同時使用了任務和聯合程式時發生。

阻塞:如果一個聯合程式正處於暫時等待或等待外部事件,它就是處於阻塞狀態。例如,聯合程式呼叫 crDELAY()它就會被阻塞(放入到阻塞狀態)直到達到延時時間 - 一個臨時事件。被阻塞的聯合程式不會被排程。

有效的聯合程式狀態轉換

有效的聯合程式狀態轉換

聯合程式屬性:

每個聯合程式被分配一個從 0 到 ( configMAX_CO_ROUTINE_PRIORITIES - 1 ) 的優先順序。

configMAX_CO_ROUTINE_PRIORITIES 在 FreeRTOSConfig.h 中定義並在基本系統中設定。

configMAX_CO_ROUTINE_PRIORITIES 的數值越大 FreeRTOS 消耗的 RAM 越多。

低優先順序聯合程式使用小數值。

聯合程式優先順序只針對其他聯合程式,任務的優先順序總是高於聯合程式

 建立一個新的聯合程式並且將其增加到聯合程式的就緒列表中
標頭檔案:croutine.h
portBASE_TYPE xCoRoutineCreate (
crCOROUTINE_CODE pxCoRoutineCode, 聯合程式函式的指標
unsigned portBASE_TYPE uxPriority, 優先順序
unsigned portBASE_TYPE uxIndex 當不同的聯合程式使用同一個函式來執行時用於相互識別
);

返回:如果聯合程式成功建立並增加到就緒列表中則返回pdPASS,否則返回ProjDefs.h 中定義的錯誤程式碼

 把一個聯合程式延時一個特定的時間
標頭檔案:croutine.h
void crDELAY (
xCoRoutineHandle xHandle, 要延時的聯合程式的控制代碼
portTickType xTicksToDelay 聯合程式要延時的時間片數
)

 聯合程式向其他聯合程式傳送資料
標頭檔案:croutine.h
crQUEUE_SEND (
xCoRoutineHandle xHandle, 呼叫的聯合程式的控制代碼
xQueueHandle pxQueue, 資料將被髮送到的佇列的控制代碼
void *pvItemToQueue, 將被髮送到佇列的資料的指標
portTickType xTicksToWait, 如果此刻佇列沒有可用空間,此值為聯合程式用於阻塞等待佇列空間可用的時間片數。
portBASE_TYPE *pxResult 一個指向pxResult 變數的指標,如果資料成功傳送到佇列就會被設定為
pdPASS,否則設定為 ProjDefs.h 中定義的錯誤碼。

 聯合程式接受其他聯合程式傳送的資料
標頭檔案:croutine.h
void crQUEUE_RECEIVE(
xCoRoutineHandle xHandle,
xQueueHandle pxQueue,
void *pvBuffer,
portTickType xTicksToWait,
portBASE_TYPE *pxResult
)

說明:同上

 中斷處理程式向聯合程式傳送資料
標頭檔案:croutine.h
portBASE_TYPE crQUEUE_SEND_FROM_ISR(
xQueueHandle pxQueue, 將傳送到的佇列的控制代碼
void *pvItemToQueue, 將被髮送到佇列的條目的指標
portBASE_TYPE xCoRoutinePreviouslyWoken
)

 聯合程式向中斷處理程式傳送資料
標頭檔案:croutine.h
portBASE_TYPE crQUEUE_SEND_FROM_ISR(
xQueueHandle pxQueue,
void *pvBuffer,
portBASE_TYPE * pxCoRoutineWoken
)

 執行一個聯合程式
標頭檔案:croutine.h
void vCoRoutineSchedule ( void );

說明:vCoRoutineSchedule() 與性具有最高優先順序的就緒聯合程式。此聯合程式將執行,直到其阻塞,讓出系統或被任務搶佔。聯合程式是合作式執行的,所以一個聯合程式不會被另一個聯合程式搶佔,但是可以被任務搶佔。

如果一個應用程式同時包含任務與聯合程式,則vCoRoutineSchedule 應該在空閒任務中呼叫(在一個空閒任務鉤子中)