一: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函數
三:任務函數spa
(1)任務建立操作系統
頭文件: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 沒法分配
足夠的空間來保存任務結構數據和任務棧,所以沒法建立任務。指針
(2)任務刪除調試
頭文件:task.h
void vTaskDelete (
xTaskHandle pxTask 處理要刪除的任務。傳遞NULL 將刪除本身
)
說明:
1. FreeRTOSConfig.h 中的INCLUDE_vTaskDelete=1,這個函數才能用。從RTOS 實時內核管理
中移除任務。要刪除的任務將從就緒,封鎖,掛起,事件列表中移除。
2. 任務被刪除後就不復存在,也不會再進入運行態
3. 空閒任務負責釋放內核分配給已刪除任務的內存。
使用提示:只有內核爲任務分配的內存空間纔會在任務被刪除後由空閒任務自動回收。任務本身佔用的內存或資源須要由應用程序本身顯式地釋放
(3)任務延時
頭文件:task.h
void vTaskDelay (
portTickType xTicksToDelay 時間數量,調用任務應該鎖住的時間片週期
)
說明:
1. FreeRTOSConfig.h 中的INCLUDE_vTaskDelay=1,這個函數才能用。
2. 延時任務爲已知時間片,任務被鎖住剩餘的實際時間由時間片速率決定。portTICK_RATE_MS 常量
以時間片速率來計算實際時間
3. vTaskDelay()指定一個任務但願的時間段,這個時間以後任務解鎖。
4. vTaskDelay()不提供一個控制週期性任務頻率的好方法,和其餘任務和中斷同樣,在調用vTaskDelay()
後將影響頻率
提示:vTaskDelayUntil() ,這個交替的API 函數設計了執行固定的頻率。它是指定的一個絕對時間(而不是
一個相對時間)後,調用任務解鎖。--------能夠實現週期性任務執行。
(4)任務延遲到指定時間
頭文件: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 這個函數了
(5)得到任務優先級
頭文件:task.h
unsigned portBASE_TYPE uxTaskPriorityGet (
xTaskHandle pxTask 須要處理的任務. 當傳遞NULL 時,將返回調用該任務的優先級
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskPriorityGet=1,這個函數才能用
返回:pxTask 的優先級
(6) 設置任務優先級
頭文件:task.h
void vTaskPrioritySet (
xTaskHandle pxTask , 須要設置優先級的任務。當傳遞NULL,將設置調用任務的優先級
unsigned portBASE_TYPE uxNewPriority 任務須要設置的優先級
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskPrioritySet 爲1,才能使用此函數.若是設置的優先級高於
當前執行任務的優先級,則上下文切換將在此函數返回前發生
(7)掛起任務
頭文件:task.h
void vTaskSuspend (
xTaskHandle pxTaskToSuspend 處理須要掛起的任務。傳遞NULL 將掛起調用此函數的任務
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskSuspend 爲1,才能使用此函數。當掛起一個任務時,無論優先級是多少,不須要佔用任何微控制器處理器時間。調用vTaskSuspend 不會累積——即:在同一任務中調用vTaskSuspend 兩次,但只須要調用一次vTaskResume()就能使掛起的任務就緒
(8)喚醒掛起的任務
頭文件:task.h
void vTaskResume (
xTaskHandle pxTaskToResume 就緒任務的句柄
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskSuspend 爲1,才能使用此函數。必須是調用 vTaskSuspend
() 後掛起的任務,纔有可能經過調用 vTaskResume ()重新運行
(9)從中斷喚醒掛起的任務
頭文件:task.h
portBase_TYPE vTaskResumeFromISR (
xTaskHandle pxTaskToResum 就緒任務的句柄
)
說明:FreeRTOSConfig.h 中的INCLUDE_vTaskSuspendhe 和INCLUDE_xTaskResumeFromISR 都爲1,才能使用此函數。vTaskResumeFromISR()不該該用於任務和中斷同步,由於可能會在中斷髮生期間,任務已經掛起——這樣致使錯過中斷。使用信號量最爲同步機制將避免這種偶然性。
返回:pdTRUE: 若是喚醒了任務將引發上下文切換。pdFALSE:用於ISR 肯定是否上下文切換
(10)爲任務分配標籤值
頭文件:task.h
void vTaskSetApplicationTaskTag (
xTaskHandle xTask , 將分配給標籤值的任務。傳遞NULL 將分配標籤給調用的任務。
pdTASK_HOOK_CODE pxTagValue 分配給任務的標籤值 類型爲 pdTASK_HOOK_CODE 容許一
個函數指針賦值給標籤,所以實際上任何值均可以分配
)
說明:FreeRTOSConfig.h 中的onfigUSE_APPLICATION_TASK_TAG 爲1,這個函數才能可用。這個值僅
在應用程序中使用,內核自己不使用它。
xTaskCallApplicationTaskHook
四:內核函數
(1)啓動實時內核處理
頭文件:task.h
void vTaskStartScheduler ( void );
說明:當 vTaskStartScheduler() 被調用時,空閒任務自動建立。若是 vTaskStartScheduler() 成功調用,這個函數不返回,直到執行任務調用vTaskEndScheduler()。若是可供給空閒任務的RAM 不足,那麼函數調用失敗,並當即返回。
(2)中止實時內核運行
頭文件:task.h
void vTaskEndScheduler ( void );
說明:全部建立的任務將自動刪除,而且多任務(優先級或合做式)將中止。當vTaskStartScheduler()調用時,執行將再次開始,像vTaskStartScheduler()僅僅返回。
注意:vPortEndScheduler ()致使全部由內核分配的資源釋放——可是不會釋放由應用程序的任務分配的資源。
(3) 掛起全部活動的實時內核,同時容許中斷(包括內核滴答)
頭文件:task.h
void vTaskSuspendAll ( void );
說明:任務在調用vTaskSuspendAll ()後,這個任務將繼續執行,不會有任何被切換的危險,直到調用xTaskResumeAll ()函數重啓內核。
注意:API 中有可能影響影響上下文切換的函數(例如,vTaskDelayUntil(), xQueueSend()等等),必定不能在調度器掛起時被調用。
五:聯合函數
一個聯合程序能夠如下面的狀態中的一種存在:
運行:當一個聯合程序正在執行時它就是處於運行狀態,它就佔用了處理器。
就緒:就緒狀態的聯合程序是那些能夠執行(沒有被阻塞)可是尚未被執行的程序。一個聯合程序可能處於就緒狀態是由於另一個相同或高優先級的聯合程序正處於運行狀態,或一個任務處於運行狀態——這隻會在系統同時使用了任務和聯合程序時發生。
阻塞:若是一個聯合程序正處於暫時等待或等待外部事件,它就是處於阻塞狀態。例如,聯合程序調用 crDELAY()它就會被阻塞(放入到阻塞狀態)直到達到延時時間 - 一個臨時事件。被阻塞的聯合程序不會被調度。
有效的聯合程序狀態轉換
(1)聯合程序屬性:
每一個聯合程序被分配一個從 0 到 ( configMAX_CO_ROUTINE_PRIORITIES - 1 ) 的優先級。
configMAX_CO_ROUTINE_PRIORITIES 在 FreeRTOSConfig.h 中定義並在基本系統中設置。
configMAX_CO_ROUTINE_PRIORITIES 的數值越大 FreeRTOS 消耗的 RAM 越多。
低優先級聯合程序使用小數值。
聯合程序優先級只針對其餘聯合程序,任務的優先級老是高於聯合程序
(2)建立一個新的聯合程序而且將其增長到聯合程序的就緒列表中
頭文件:croutine.h
portBASE_TYPE xCoRoutineCreate (
crCOROUTINE_CODE pxCoRoutineCode, 聯合程序函數的指針
unsigned portBASE_TYPE uxPriority, 優先級
unsigned portBASE_TYPE uxIndex 當不一樣的聯合程序使用同一個函數來運行時用於相互識別
);
返回:若是聯合程序成功建立並增長到就緒列表中則返回pdPASS,不然返回ProjDefs.h 中定義的錯誤代碼
(3)把一個聯合程序延時一個特定的時間
頭文件:croutine.h
void crDELAY (
xCoRoutineHandle xHandle, 要延時的聯合程序的句柄
portTickType xTicksToDelay 聯合程序要延時的時間片數
)
(4) 聯合程序向其餘聯合程序發送數據
頭文件:croutine.h
crQUEUE_SEND (
xCoRoutineHandle xHandle, 調用的聯合程序的句柄
xQueueHandle pxQueue, 數據將被髮送到的隊列的句柄
void *pvItemToQueue, 將被髮送到隊列的數據的指針
portTickType xTicksToWait, 若是此刻隊列沒有可用空間,此值爲聯合程序用於阻塞等待隊列空間可用的時間片數。
portBASE_TYPE *pxResult 一個指向pxResult 變量的指針,若是數據成功發送到隊列就會被設置爲
pdPASS,不然設置爲 ProjDefs.h 中定義的錯誤碼。
)
(5)聯合程序接受其餘聯合程序發送的數據
頭文件:croutine.h
void crQUEUE_RECEIVE(
xCoRoutineHandle xHandle,
xQueueHandle pxQueue,
void *pvBuffer,
portTickType xTicksToWait,
portBASE_TYPE *pxResult
)
說明:同上
(6) 中斷處理程序向聯合程序發送數據
頭文件:croutine.h
portBASE_TYPE crQUEUE_SEND_FROM_ISR(
xQueueHandle pxQueue, 將發送到的隊列的句柄
void *pvItemToQueue, 將被髮送到隊列的條目的指針
portBASE_TYPE xCoRoutinePreviouslyWoken
)
(7) 聯合程序向中斷處理程序發送數據
頭文件:croutine.h
portBASE_TYPE crQUEUE_SEND_FROM_ISR(
xQueueHandle pxQueue,
void *pvBuffer,
portBASE_TYPE * pxCoRoutineWoken
)
(8)運行一個聯合程序
頭文件:croutine.h
void vCoRoutineSchedule ( void );
說明:vCoRoutineSchedule() 與性具備最高優先級的就緒聯合程序。此聯合程序將運行,直到其阻塞,讓出系統或被任務搶佔。聯合程序是合做式運行的,因此一個聯合程序不會被另外一個聯合程序搶佔,可是能夠被任務搶佔。
若是一個應用程序同時包含任務與聯合程序,則vCoRoutineSchedule 應該在空閒任務中調用(在一個空閒任務鉤子中)
六:隊列管理
隊列是內部通訊的主要形式。它能夠用於在任務和任務之間以及任務和中斷之間發送消息。在大多數狀況下使用線程安全 FIFO(先進先出)緩存,新數據放在隊列的最後,雖然數據也能夠放在前面。
隊列能夠包含固定大小的 '項目' - 每一個項目的大小和隊列能夠保存項目的最大數量在建立隊列時就已經定義了。
項目以複製而不是引用的方式放入隊列,所以最好使放入隊列項目的大小成爲最小。以複製的方式放入隊列可使你的系統設計極大的簡化,由於兩個任務不會同時訪問數據。隊列幫助你管理全部的互斥問題。
若是你但願在隊列中使用大的項目,可能最好用插入隊列指針 - 可是這樣作必須注意要確保你的系統明肯定義任務和/或中斷是數據的"因此者"。
隊列 API 函數能夠指定阻塞的時間。阻塞時間表明任務進入阻塞狀態或者等待隊列中數據時(當任務讀取隊列可是隊列是空的時候)的最大'節拍'數,或者等待隊列空間變爲可使用(當任務須要寫數據到隊列,可是隊列已滿時)。當一個以上任務在同一個隊列中被阻塞時,高優先級的任務先解除阻塞。
(1)建立一個新的隊列
頭文件:queue. H
xQueueHandle xQueueCreate (
unsigned portBASE_TYPE uxQueueLength, 隊列中包含最大項目數量
unsigned portBASE_TYPE uxItemSize 隊列中每一個項目所需的字節數
);
說明:建立一個新的隊列。爲新的隊列分配所需的存儲內存,並返回一個隊列處理。
注意:項目經過複製而不是引用排隊,所以,所需的字節數,將複製給每一個項目。隊列中每一個項目必須分配一樣大小。
返回:若是隊列成功建立,則返回一個新建隊列的處理。若是不能建立隊列,將返回0。
(2)傳遞一個項目到隊列
頭文件:queue. H
portBASE_TYPE xQueueSend (
xQueueHandle xQueue, 將項目傳進的隊列
const void * pvItemToQueue, 項目的指針【源數據】
portTickType xTicksToWait 等待的最大時間量【時間使用滴答週期】
);
說明:傳遞一個項目到隊列。這個項目經過複製而不是經過引用排隊。這個函數不能從中斷服務程序調用。
注意:當隊列滿時,確定傳遞不成功,則等待xTicksToWait 個滴答週期後再傳遞,但若是xTicksToWait 設置爲0,調用將當即返回。
返回:pdTRUE:項目成功傳遞。不然爲:errQUEUE_FULL.
(3) 傳遞項目到一個隊列中的後面
頭文件:queue. H
portBASE_TYPE xQueueSendToBack (
xQueueHandle xQueue, 將項目傳進的隊列
const void * pvItemToQueue, 項目的指針【源數據】
portTickType xTicksToWait 等待的最大時間量
);
說明:這個與xQueueSend 是同樣的,參照xQueueSend 的用法
(4)從隊列接收一個項目
頭文件:queue. H
portBASE_TYPE xQueueReceive (
xQueueHandle xQueue, 發送項目的隊列句柄
void *pvBuffer, 指向緩衝區的指針,將接收的項目被複制進去
portTickType xTicksToWait 任務中斷並等待隊列中可用空間的最大時間
);
說明:這個項目經過複製接收,所以緩衝器必須提供足夠大的空間。這個函數必定不能在中斷服務程序中使用當隊列空時,確定複製傳遞不成功,則等待xTicksToWait 個滴答週期後再複製,但若是xTicksToWait 設置爲0,調用將當即返回。
返回:若是項目成功被隊列接收爲pdTRUE ,不然爲 pdFALSE。
(5) 從中斷傳遞一個項目到隊列的後面
頭文件:queue. H
portBASE_TYPE xQueueSendFromISR (
xQueueHandle pxQueue, 將項目傳進的隊列
const void *pvItemToQueue, 項目的指針【源數據】
portBASE_TYPE *pxHigherPriorityTaskWoken 因空間數據問題被掛起的任務是否解鎖
);
說明: 若是傳進隊列而致使因空間數據問題被掛起的任務解鎖,而且解鎖的任務的優先級高於當前運行任務,xQueueSendFromISR 將設置 *pxHigherPriorityTaskWoken 到 pdTRUE。當pxHigherPriorityTaskWoken被設置爲pdTRUE 時,則在中斷退出以前將請求任務切換。
返回:pdTRUE:數據成功傳遞進隊列。不然爲:errQUEUE_FULL。
(6)從中斷傳遞項目到一個隊列中的後面
頭文件:queue. H
portBASE_TYPE xQueueSendToBackFromISR (
xQueueHandle pxQueue,
const void *pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken
);
說明:參照xQueueSendFromISR
(7) 從中斷傳遞一個項到隊列的前面
頭文件:queue. H
portBASE_TYPE xQueueSendToFrontFromISR (
xQueueHandle pxQueue,
const void *pvItemToQueue,
portBASE_TYPE *pxHigherPriorityTaskWoken
);
說明:參照xQueueSendFromISR
(8) 中斷時從隊列接收一個項目
頭文件:queue. H
portBASE_TYPE xQueueReceiveFromISR (
xQueueHandle pxQueue, 發送項目的隊列句柄
void *pvBuffer, 指向緩衝區的指針,將接收的項目被複制進去
portBASE_TYPE *pxTaskWoken 任務將鎖住,等待隊列中的可用空間
);
說明: 若是xQueueReceiveFromISR 引發一個任務解鎖,*pxTaskWoken 將設置爲pdTRUE,不然*pxTaskWoken保留不變
返回:pdTRUE :若是項目成功從隊列接收。不然爲: pdFALSE
(9) 爲隊列命名,並加入隊列到登記管理中
頭文件:queue.h
void vQueueAddToRegistry (
xQueueHandle xQueue, 將要添加登記的隊列句柄
signed portCHAR *pcQueueName, 爲指定的隊列命名。 僅僅是文本串,方便調試。
);
說明:隊列登記有兩個特色, 均與內核的相關調試有關:
容許文本式名字,使隊列在調試GUI 中方便定義。
包含調試器須要的信息,如:定位每一個已經登記的隊列和信號量。
隊列的登記沒有目的,除非使用內核相關的調試。
configQUEUE_REGISTRY_SIZE 定義了隊列和信號量的最大數目.僅當使用內核相關的調試時須要顯示已經登記的信號量和隊列。
(10) 從登記管理中移除隊列
頭文件:queue.h
void vQueueUnregisterQueue (
xQueueHandle xQueue, 從登記管理處中移出的隊列句柄
);
說明:隊列登記有兩個特色, 均與內核的相關調試有關:
容許文本式名字,使隊列在調試GUI 中方便定義。
包含調試器須要的信息,如:定位每一個已經登記的隊列和信號量。
隊列的登記沒有目的,除非使用內核相關的調試。
configQUEUE_REGISTRY_SIZE 定義了隊列和信號量的最大數目.僅當使用內核相關的調試時須要顯示已經登記的信號量和隊列。
七:信號量
(1) 使用已存在的隊列結構來建立計數型信號量
頭文件:semphr. H
xSemaphoreHandle xSemaphoreCreateCounting (
unsigned portBASE_TYPE uxMaxCount, 能夠達到的最大計數值。
unsigned portBASE_TYPE uxInitialCount 信號量建立時分配的初始值
)
說明:兩種典型應用
事件計數
在這種應用的情形下,事件處理程序會在每次事件發生時發送信號量(增長信號量計數值),而任務處理程序會在每次處理事件時請求信號量(減小信號量計數值)。所以計數值爲事件發生與事件處理二者間的差值,在這種狀況下計數值初始化爲0 是合適的。
資源管理
在這種應用情形下,計數值指示出可用的資源數量。任務必須首先「請求」信號量來得到資源的控制權--減小信號量計數值。當計數值降爲0 時表示沒有空閒資源。任務使用完資源後「返還」信號量--增長信號量計數值。在這種狀況下計數值初始化爲與最大的計數值相一致是合適的,這指示出全部的空閒資源。
返回:已建立的信號量句柄,爲xSemaphoreHandle 類型,若是信號量沒法建立則爲NULL。
(2)使用已存在的隊列結構來建立互斥鎖信號量的宏
頭文件:semphr. H
xSemaphoreHandle xSemaphoreCreateMutex ( void )
說明: 經過此宏建立的互斥鎖可使用xSemaphoreTake() 與 xSemaphoreGive() 宏來訪問。不能使用
xSemaphoreTakeRecursive()與 xSemaphoreGiveRecursive()宏
二元信號量與互斥鎖十分相像,不過二者間有細微的差異:互斥鎖包含一個優先級繼承機制,而信號量沒有。這種差異使得二元信號量更適合於實現同步(任務之間或任務與中斷之間),互斥鎖更適合於實現簡單的互斥。
當有另一個具備更高優先級的任務試圖獲取同一個互斥鎖時,已經得到互斥鎖的任務的優先級會被提高。已經得到互斥鎖的任務將繼承試圖獲取同一互斥鎖的任務的優先級。這意味着互斥鎖必須老是要返還的,不然高優先級的任務將永遠也不能獲取互斥鎖,而低優先級的任務將不會放棄優先級的繼承。
二元信號量並不須要在獲得後當即釋放,所以任務同步能夠經過一個任務/中斷持續釋放信號量而另一個持續得到信號量來實現。
互斥鎖與二元信號量均賦值爲xSemaphoreHandle 類型,而且能夠在任何此類型參數的API 函數中使用。
返回: 已建立的信號量句柄,須要爲xSemaphoreHandle 類型。
(3)使用已存在的隊列結構來建立遞歸互斥鎖的宏
頭文件:semphr. H
xSemaphoreHandle xSemaphoreCreateRecursiveMutex ( void )
說明:經過此宏建立的互斥鎖可使用xSemaphoreTakeRecursive()與 xSemaphoreGiveRecursive()宏 來訪問。
不能使用xSemaphoreTake()與 xSemaphoreGive()宏
一個遞歸的互斥鎖能夠重複地被其全部者「獲取」。在其全部者爲每次的成功「獲取」請求調用xSemaphoreGiveRecursive()前,此互斥鎖不會再次可用。例如,若是一個任務成功「獲取」同一個互斥鎖5 次,則在其「釋放」互斥鎖剛好爲5 次後,其餘任務纔可使用此互斥鎖。
這種類型的信號量使用一個優先級繼承機制,所以已取得信號量的任務「必須老是」在再也不須要信號量時馬上「釋放」。
互斥類型的信號量不能在中斷服務程序中使用。
能夠參考vSemaphoreCreateBinary()來得到一個二選一運行的實現方式,能夠在中斷服務程序中實現純粹的同步(一個任務或中斷老是「釋放」信號量,而另外一個老是「獲取」信號量)。
返回: 已建立的信號量句柄,須要爲xSemaphoreHandle 類型。
(4) 獲取信號量的宏 頭文件:semphr. H
xSemaphoreTake (
xSemaphoreHandle xSemaphore, 將被得到的信號量句柄,此信號量必須已經被建立
portTickType xBlockTime 等待信號量可用的時鐘滴答次數
)
說明:當信號量不可用時,則等待xBlockTime 個時鐘滴答,再看是否可用,當是爲0 時若是不可用,則當即退出,所以爲0 時能夠達到對信號量輪詢的做用。
返回:若是成功獲取信號量則返回pdTRUE,若是xBlockTime 超時而信號量還未可用則返回pdFALSE。
(5)遞歸得到互斥鎖信號量的宏
頭文件:semphr. H
xSemaphoreTakeRecursive (
xSemaphoreHandle xMutex, 將被得到的互斥鎖句柄
portTickType xBlockTime 等待信號量可用的時鐘滴答次數
)
說明:FreeRTOSConfig.h 中的configUSE_RECURSIVE_MUTEXES 必須設置爲1 纔可使用此宏。一個遞歸型的互斥鎖能夠被其全部者重複地「獲取」, 在其全部者爲每次成功的「獲取」請求調用xSemaphoreGiveRecursive()前,此互斥鎖不會再次可用。
返回:若是成功獲取信號量則返回pdTRUE,若是xBlockTime 超時而信號量還未可用則返回pdFALSE。
(6)釋放信號量的宏
頭文件:semphr. H
xSemaphoreGive (
xSemaphoreHandle xSemaphore 即將釋放的信號量的句柄,在信號量建立是返回
)
返回:若是信號量成功釋放返回pdTRUE,若是發生錯誤則返回pdFALSE。信號量使用的是隊列,所以若是隊列沒有位置用於發送消息就會發生一個錯誤——說明開始時沒有正確獲取信號量。
(7)用於遞歸釋放,或‘返還’,互斥鎖信號量的宏
頭文件:semphr. H
xSemaphoreGiveRecursive (
xSemaphoreHandle xMutex 將被釋放或‘返還’的互斥鎖的句柄
)
返回:若是信號量成功釋放則爲pdTRUE
(8)從中斷釋放一個信號量的宏
頭文件:semphr. H
xSemaphoreGiveFromISR (
xSemaphoreHandle xSemaphore, 將被釋放的信號量的句柄
portBASE_TYPE *pxHigherPriorityTaskWoken 因空間數據問題被掛起的任務是否解鎖
)
返回:若是信號量成功釋放則返回pdTRUE,不然返回errQUEUE_FULL