第21章節 FreeRTOS計數信號量
注意 :該文章摘錄自:
新浪博客:http://blog.sina.com.cn/s/blog_98ee3a930102wgpe.html
本章節介紹了講解了FreeRTOS任務間的同步和資源共享機制,計數信號量。FreeRTOS中計數信號量的源碼實現是基於消息隊列實現。
本章教程配套的例子含Cortex-M3內核的STM32F103和Cortex-M4內核的STM32F407以及F429
21.1 信號量
21.2 計數信號量API函數
21.3 實驗例程說明(任務間通信)
21.4 實驗例程說明(中斷方式通信)
21.5 總結
21.1 信號量
21.1.1 信號量的概念及其作用
信號量(Semaphores)是20世紀60年代中期的Edgser Dijkstra發明的。使用信號量的最初目的是給共享資源建立一個標誌,該標誌表示該共享資源被佔用情況。這樣,當一個任務在訪問共享資源之前,就可以先對這個標誌進行查詢,從而在瞭解資源被佔用的情況之後,在決定自己的行爲。
實際的應用中,信號量的作用又該如何體現呢?比如有個30人的電腦機房,我們就可以創建信號量的初始值是30,表示30個可用資源,不理解的初學者表示信號量還可以有初始值?是的,信號量說白了就是共享資源的數量。另外我們要求一個同學使用一臺電腦,這樣每個同學使用一臺電腦,那麼信號量的數值就減一,直到30臺電腦都被佔用,此時的信號量的數值就是0。如果此時還有幾個同學沒有電腦使用,那麼這幾個同學就等待,直到同學離開。有一個同學離開,那麼信號量的數值就加1,有兩個就加2,依此類推。剛纔沒有電腦用的同學就有電腦可以用了,有幾個同學用,信號量就減幾,直到再次沒有電腦可以用,這麼一個過程就是使用信號量來管理共享資源的過程。
平時使用信號量主要實現以下兩個功能:
-
兩個任務之間或者中斷函數跟任務之間的同步功能,這個和前面章節講解的事件標誌組是類似的。其實就是共享資源爲1的時候。
-
多個共享資源的管理,就像上面舉的機房上機的例子。
針對這兩個功能,FreeRTOS分別提供了二值信號量和計數信號量,其中二值信號量可以理解成計數信號量的一種特殊形式,即初始化爲僅一個資源可用,只不過FreeRTOS對這種都提供了API,而像RTX,uCOS-II,III是僅提供了一個信號量功能,設置不同的初始值就可以分別實現二值信號量和計數信號量。當然,FreeRTOS使用計數信號量也能夠實現同樣的效果。
實際上信號量還有很多其它用法,而且極具挑戰性,可以大大的開拓大家的視野,有興趣的同學可以閱讀以下《The Little Boob Of Semaphores》,作者是Allen B.Downy。
21.1.2 FreeRTOS任務間計數信號量的實現
任務間信號量的實現是指各個任務之間使用信號量實現任務同步或者資源共享功能。下面我們通過如下框圖來說明以下FreeRTOS計數信號量的實現,讓大家有一個形象的認識。
運行條件:
- 創建2個任務Task1和Task2。
- 創建計數信號量可用資源爲1。
運行過程描述如下:
- 任務Task1運行過程中調用函數xSemaphoreTake獲取信號量資源,如果信號量沒有被任務Task2佔用,Task1將直接獲取資源。如果信號量被Task2佔用,任務Task1將由運行態轉到阻塞狀態,等待資源可用。一旦獲取了資源並且使用完畢後會通過函數xSemaphoreGive釋放掉資源。
- 任務Task2運行過程中調用了函數xSemaphoreTake獲取信號量資源,如果信號量沒有被任務Task1佔用,Task2將直接獲取資源。如果信號量被Task1佔用,任務Task2由運行態轉到阻塞狀態,等待資源可用。一旦獲取了資源並使用完畢後會通過函數xSemaphoreGive釋放掉資源。
上面是一個簡單的FreeRTOS任務間計數信號量的使用過程。
21.1.3 FreeRTOS中斷方式計數信號量的實現
FreeRTOS中斷方式的信號量的實現是指中斷函數和FreeRTOS任務之間使用信號量。信號量的中斷方式主要是用於實現任務同步,與前面章節講解事件標誌組中斷方式是一樣的。
下面我們通過如下的框圖說明一下FreeRTOS中斷方式信號量的實現,讓大家有一個形象的認識。
運行條件:
- 創建一個任務Task1和一個串口接受中斷。
- 信號量的初始值爲0,串口中斷調用函數xSemaphoreGiveFromISR釋放信號量,任務Task1調用函數xSemaphoreTake獲取信號量資源。
運行過程描述如下:
-
任務Task1運行過程中調用函數xSemaphoreTake,由於信號量的初始值是0,沒有信號量資源可用,Task1由運行狀態到阻塞狀態。
-
Task1阻塞的情況下,串口接收到數據進入到了串口中斷服務程序,在串口中斷服務程序中調用函數xSemaphoreGiveFromISR釋放信號量資源,信號量數值加1,此時信號量計數值爲1,任務Task1由阻塞狀態進入就緒狀態,在調度器的作用下由就緒狀態又進入運行態,任務Task1獲得信號量後,信號量數值減1,此時信號量計數又變成了0。
-
再次循環執行任務,任務Task1調用函數xSemaphoreTake由於沒有資源可用再次進入到阻塞態,等待串口釋放信號量資源,如此往復循環。
上面就是一個簡單的FreeRTOS中斷方式同步過程。實際應用中,中斷方式的消息機制要注意以下四個問題:
-
中斷函數的執行時間越短越好,防止其他低於這個中斷優先級的異常得不到及時響應。
-
實際應用中,建議不要在中斷實現消息處理,用戶可以在中斷服務程序裏發送消息通知任務,在任務中實現消息處理,這樣可以有效地保證中斷服務程序的實時響應。同時此任務也需要設置爲高優先級,以便中斷函數後任務可以得到及時執行。
-
中斷服務程序中一定要調用專用於中斷的信號量設置函數,即以FromISR結尾的函數。
-
在操作系統中實現中斷服務程序與裸機編程的區別:
- 如果FreeRTOS工程的中斷函數中沒有調用FreeRTOS的信號量API函數,與裸機編程是一樣的。
- 如果FreeRTOS工程的中斷函數中調用了FreeRTOS的API函數,退出的時候要檢測是否有高級優先級任務就緒,如果有就緒的,需要在退出中斷後進行任務切換,這點與裸機編程稍有區別,詳見21.4小結實驗例程說明(中斷方式):
- 例外強烈推薦用戶將Cortex-M3內核的STM32F103和Cortex—M4內核的STM32F407,F429的NVIC優先級分組設置爲4,即:NVIC_PriorityGroupCofig(NVIC_PriorityGroup_4);這樣中斷優先級管理將非常方便。
- 用戶要在FreeRTOS多任務開啓錢就設置好優先級分組,一旦設置好切記不可再修改。
21.2計數信號量API函數
使用如下的18個函數可以實現FreeRTOS的信號量(含計數信號量,二值信號量與互斥信號):
xSemaphoreCreateBinary()
xSemaphoreCreateBinaryStatic()
vSemaphoreCreateBinary()
xSemaphoreCreateCounting()
xSemaphoreCreateCountingStatic()
xSemaphoreCreateMutex()
xSemaphoreCreateMutexStatic
xSem'CreateRecursiveMutex()
xSem'CreateRecursiveMutexStatic()
vSemaphoreDelete()
xSemaphoreGetMutexHolder()
uxSemaphoreGetCount()
xSemaphoreTake()
xSemaphoreTakeFromISR()
xSemaphoreTakeRecursive()
xSemaphoreGive()
xSemaphoreGiveRecursive()
xSemaphoreGiveRecursive()
關於這18個函數的講解及其使用方法可以看FreeRTOS在線版手冊: