目錄
一、基礎介紹
1.1 調度策略
1.1.1 調度方式
1.1.2 調度器
1.2 任務以及優先級
1.2.1 任務與協程
1.2.2 任務狀態
1.2.3 任務優先級
1.2.4 任務優先級分配方案
1.3 任務間通信 - 信號量
1.3.1 信號量
1.3.2 任務間計數信號量的實現
1.3.3 中斷方式計數信號量的實現
1.3.4 計數信號量API函數
1.4 任務間通信 - 消息隊列
1.4.1 消息隊列
1.4.2 任務間消息隊列的實現
1.4.3 中斷方式消息隊列的實現
1.4.4 消息隊列常用API
1.5 任務間通信 - 互斥信號量
1.5.1 互斥信號量概念
1.5.2 優先級翻轉
1.5.3 互斥信號量的實現
1.5.4 常用互斥鎖API
一、基礎介紹
1.1 調度策略
1.1.1 調度方式
搶占式調度、時間片調度、合作式調度;
其中以搶占式、時間片為主,少見合作式;
(1).搶占式調度:任務有優先級,程序被高優先級先搶占,或者遇到阻塞式API函數;
(2).時間片調度:每個任務優先級相同,任務運行固定的時間片;
1.1.2 調度器
調度器會使用相關的調度算法,來決定當前應該做哪個任務;
調度器的共同特性:
(1).可以區分就緒態、掛起態任務;
(2).可以激活就緒態任務,讓它變成正在運行的運行態任務;
(3).不同調度器之間最大區別是如何分配就緒態任務間的完成時間;
操作系統核心是調度器和任務的切換;
1.搶占式調度器:
需要實現搶占式調度器,可以先在FreeRTOS配置文件FreeRTOSConfig.h中禁止使用時間片調度,這時候每個任務都需要配置不同優先級;
優先級值越大,優先等級越高;
比如,現在有任務Task1,Task2,Task3,他們的優先級分別是1,2,3;
此時會先運行Task3,直到它遇到系統阻塞式的API函數(比如延遲、標志位等),這時候Task3被掛起,到了Task2運行,以此類推;
2.時間片調度器:
這個可以理解為,在同優先級的情況下。把時間拆分成時間片,比如現在有Task1,Task2,Task3,那么時間片先都為5個系統時鐘,Task1運行5個系統時鐘然后到Task2,Task2也運行5個,到Task3。不管你干完了沒有,你的時間片用完了,就該到下一個任務運行。并且在這過程中,發生了阻塞,那么這個時間片過完了,也到下一個任務,并不會因為阻塞而等待;
1.2 任務以及優先級
1.2.1 任務與協程
!目前FreeRTOS 的協程功能在較新的版本中已被標記為 “過時”(deprecated),官方推薦使用輕量級任務(Lightweight Tasks)?或軟件定時器替代。
協程與標準任務的區別:
- 調度方式:任務是搶占式的(優先級決定執行權),協程是協作式的(需主動讓出 CPU)。
- 資源占用:協程棧開銷小,適合內存緊張的系統;任務需要獨立棧空間,內存消耗更大。
- 實時性:任務適合強實時需求,協程適合對響應時間要求不高的場景。
適用場景:
- 周期性執行但實時性要求不高的任務(如狀態監測、日志打印)。
- 內存受限的小型嵌入式系統。
- 簡化復雜狀態機的實現(避免使用大量全局變量保存狀態)。
1.2.2 任務狀態
運行:正在執行,正在占用處理器;
就緒:任務準備執行,但是因為目前有更高優先級的任務在執行。這個不同于阻塞和掛起;
阻塞:任務在等待某個觸發條件,一般進入阻塞態有個超時周期,超時后解除阻塞;
掛起:任務被強制暫停,不會參與調度,且無法被任何事件(包括超時)喚醒。
1.2.3 任務優先級
FreeRTOS最高優先級是通過 FreeRTOSConfig.h文件中的 configMAX_PRIORITIES進行配置的,實際可以用的優先級范圍是 [0,configMax_PRIORITIES-1];
比如configMAX_PRIORITIES=5,那么優先級可以填 0,1,2,3,4;
優先級0表示的是空閑任務,一般建議configMAX_PRIORITIES<32;
1.2.4 任務優先級分配方案
IRQ任務:通過中斷服務程序進行觸發的任務,這種任務優先級最高;
高優先級后臺任務:如按鍵檢測、觸摸檢測、USB消息處理、串口消息處理;
低優先級:比如LED數碼管顯示,不需要實時性很強的任務;
這里記得把IRQ任務、高優先級任務設置成阻塞式,這樣才能釋放CPU使用權,讓低優先級任務有機會執行;
1.3 任務間通信 - 信號量
1.3.1 信號量
信號量最初是為了共享資源建立一個標志,該標志表示占用情況;
像是停車場剩余車位,比如剛開始初始值設置為50個空閑位置。有車進來就-1,假如減到0了,也就是沒車位了,那么需要停車場內有車出去,新來的車才能停進來,要不就等著;
功能:(1).任務之間? 或者? 中斷函數與任務之間? 的同步;
(2).多個共享資源的管理;
1.3.2 任務間計數信號量的實現
任務間信號量,是指各個任務間使用信號量實現任務同步 或者 資源共享功能;
?其實很好理解,有點像我們平時寫代碼時的標志位;
目前有兩個任務 Task1、Task2,計數信號量可用資源為1;
任務Task1運行時,用xSemaphoreTake獲取信號量資源,假如資源沒被占用,那么Task1直接獲取資源,或者Task2占用了信號量,那么Task1轉到阻塞態,等待資源可用。Task1在獲取資源,并且使用后,通過xSemaphoreGive釋放資源;
在運行Task2時,也是按上面的邏輯;
1.3.3 中斷方式計數信號量的實現
FreeRTOS中斷方式信號量的實現,是指中斷函數 與 FreeRTOS任務之間使用信號量;
目前假設有一個任務Task1,和一個串口接受中斷;
信號量初始值為0,串口中斷調用xSemaphoreGiveFromISR 釋放信號量,Task1調用xSemaphoreTake獲取信號量資源;
運行流程:
(1).Task1 調用xSemaphoreTake獲取信號量,但是初始值是0,沒資源可以用,進入阻塞態;
(2).串口接受中斷接受到新數據,在中斷服務函數中調用xSemaphoreGiveFromISR釋放信號量資源,信號量數值+1,Task1從阻塞態到就緒態,獲取信號量后,信號量計數值-1,變成0;
(3).再次循環時,Task1調用xSemaphoreTake沒資源可用,再進入阻塞,再等串口接受新數據;
注意事項:
(1).中斷函數執行時間要短,防止其他低于中斷優先級的異常沒及時響應;
(2).不要在中斷中實現消息處理,應該在中斷服務函數中發送消息通知,然后在任務中進行消息處理。并且要注意這個任務優先級,使退出中斷服務函數后,任務可以及時執行;
(3).中斷服務程序中一定要調用專用于中斷的信號量設置函數,即以FromISR結尾的函數;
1.3.4 計數信號量API函數
單片機 - FreeRTOS 常用的API(未完)-CSDN博客
1.4 任務間通信 - 消息隊列
1.4.1 消息隊列
- 指通過RTOS內核提供的服務,任務或者中斷子程序可用把一個消息(FreeRTOS中傳遞的是實際數據)放入到隊列,同時任務或者中斷子程序 可用從中獲取;
?- 支持 FIFO 和 LIFO 的數據存取方式;
1.4.2 任務間消息隊列的實現
假設消息隊列可以放10個消息;
創建了Task1 和 Task2 兩個任務,Task1放數據,Task2取數據;
采用FIFO方式;
假如Task1放數據的速度,比Task2取數據的速度快,消息會放滿,FreeRTOS的消息存放函數xQueueSend支持超時等待;
同樣的,取的速度大于存的速度,消息獲取函數xQueueReceive支持超時等待;
1.4.3 中斷方式消息隊列的實現
假設消息隊列可以放10個消息;
創建任務Task1,和串口接收中斷;
采用FIFO;
串口中斷接受到消息后進行中斷,往隊列里放數據。Task1從隊列里取數據,
(1).串口中斷放數據速度 超過 Task1取數據的速度,則會造成存放過滿,但是中斷服務程序的消息隊列發送函數 xQueueSendFromISR 不支持超時設置,所以發送前要用 xQueueIsQueueFullFromISR 檢測消息隊列是否滿了;
(2).假如是取數據的速度? 超過? 放數據的速度。這時候消息隊列是空的,Task1沒東西取,而且Task1 獲取消息的函數是 xQueueReceive ,這個函數可以設置超時等待,沒消息Task1就等著,直到隊列中有消息,或者是超過我們設定的時間;
1.4.4 消息隊列常用API
單片機 - FreeRTOS 常用的API(ing)-CSDN博客
1.5 任務間通信 - 互斥信號量
1.5.1 互斥信號量概念
主要作用是對資源實現互斥訪問,類似二值信號。互斥信號與二值信號的區別是 互斥信號可以防止優先級翻轉;
1.5.2 優先級翻轉
假設目前有3個任務 Task1,Task2,Task3,優先級分別是3,2,1,Task1優先級最高;
任務Task1 和 Task3互斥訪問串口打印 printf,采用二值信號實現互斥訪問;
Task3通過二值信號調用printf,被Task1搶占了,開始做Task1;
運行過程:
(1).Task1在運行時需要printf,這時候Task3正在用printf,就會把Task1掛起,等Task3釋放printf;
(2).調度器的作用下,Task3運行過程中,Task2就緒,把Task3給搶了。優先級翻轉出現在這;
(3).Task3因為被Task2搶了任務,所以沒法及時釋放printf,這時候變成得等待Task2干完之后,才能釋放printf,然后才到Task1;
?
1.5.3 互斥信號量的實現
首先,我們引入互斥信號量這一步,是為了解決1.5.2 中的優先級翻轉問題;
?互斥信號量的實現是這樣的:
比如Task1和Task2的優先級分別是1和3,首先先是Task1在執行,這時候Task2也需要占用這個資源。那么會先把Task1的優先級抬到3,也就是和Task2的優先級一樣,這時候就算有一個優先級是2的任務,也無法搶占Task1;然后是Task2被掛起,Task1釋放資源,Task2等待資源,這里Task1釋放完資源,又會回到1的優先級;
?
1.5.4 常用互斥鎖API
單片機 - FreeRTOS 常用的API(ing)-CSDN博客