(定時器用于計時和觸發事件,任務則由調度器進行調度和執行:每當時鐘節拍到達時,系統會觸發一個稱為 tick 中斷的事件。當 tick 中斷發生時,操作系統會在中斷服務例程中執行一定的處理,其中包括更新任務的運行時間、檢查任務的狀態和優先級等。然后,調度器會在中斷返回后根據任務的優先級和調度策略,從就緒列表中選擇下一個要執行的任務。FreeRTOS 不直接提供像 OSEK 調度表(Schedule Table)那樣的概念和功能。OSEK 調度表是一種基于時間的調度機制,按照預定義的時間順序在到期點執行不同的任務,在調度表中,是可以做到在每個EP到期點執行各種優先級任務,只要在下個EP到期點抵達之前執行完就可以)
RTOS的任務觸發底層邏輯
從整體來看,首先FreeRTOS的任務執行是基于全搶占調度的,也就是說任務按照就緒列表中優先級高低執行的,如果一個任務優先級很高,沒有其他同級別任務,并且任務也沒有阻塞,掛起或延時,那這個高優先級任務就會一直執行,其他的任務就會完全失效。所以如果設計一個合理的系統,就必須合理安排他的優先級,時間片以及判斷高中底優先級任務的執行時間,在合理的時間里,釋放CPU的資源,讓低優先級任務進入執行。比如高優先級任務執行后,在這個任務的結尾用vTaskDelay 來暫時釋放 CPU 資源。之后中等優先級會搶占資源執行任務,之后在這個任務的結尾用vTaskDelay 來暫時釋放 CPU 資源。低優先級任務搶占執行。vTaskDelay的時間要設計的合理,否則任務就進入空閑任務或低優先級任務沒有執行完就被高優先級任務搶占。
如何觸發各個優先級任務以及RTOS調度任務邏輯
在 FreeRTOS 中 vTaskStartScheduler 用于啟動 FreeRTOS 調度器,并且執行第一個任務,在 main 函數中 xTaskCreate 創建任務,并將創建的任務添加到雙向鏈表中,在雙向鏈表中,當一個高優先級任務執行完釋放了CPU的資源后,就切換到鏈表中的下一個任務。
(猜想:從RTOS的雙向鏈表可以猜測OSEK的調度表機制,也就是為什么調度表可以周期往復的執行,以及調度表為什么每到一個EP到期點就可以執行下一個任務。當最后一個任務執行完,返回到第一個任務,這就是OSEK中任務會依次周期觸發邏輯)
在 main 函數中 xTaskCreate 創建任務,并分配任務的優先級。創建的任務放在就緒任務列表中,就緒任務列表根據任務的優先級進行排序(其實就是雙向鏈表套了個任務優先級排序插入的邏輯以及數據結構增加了些要判斷的內容)。
FreeRTOS的任務調度是基于優先級和時間片輪轉的機制:
- 基于優先級的任務調度:創建的任務根據優先級的高低插入到就緒列表中,之后調度器根據任務的優先級來執行任務。如果遇到相同優先級任務,調度器就采用先到先服務(First-Come, First-Served)的策略,即按照任務在就緒列表中的順序進行選擇。
- 基于時間片輪轉的任務調度:為了解決在遇到相同優先級多個任務的情況,采用時間片輪轉調度通過每個任務輪流地享有相同的 CPU 時間(享有 CPU 的時間叫時間片), 解決具有相同優先級的多個任務之間的公平性問題。每個任務會按照設定的時間片長度輪流地享有相同的 CPU 時間。確保每個任務都能獲得一定的執行時間,而不會長時間獨占處理器資源。
FreeRTOS的任務調度順序是基于就緒列表的高低優先級,那高優先級任務執行完要如何切到低優先級任務里,或者說豈不是系統基本主要都在執行高優先級任務,低優先級任務只有在特殊情況下才會被觸發:
任務在系統中的狀態:
首先高優先級任務確實要更頻繁的去執行,所以在一個實時系統中,主要的幾個任務要被配置成很高的優先級,基本處于一直run的狀態。與此同時,時間片輪轉調度就派上了用場,同級別的高優先級太多,就要用到時間片來劃分執行時間。要注意時間片輪轉調度的任務切換,時間片用完的情況下會從就緒列表中獲取優先級最高的任務去執行。
其次,高優先級任務想切換到低優先級任務,那么高優先級任務一定是由run的狀態,切到了掛起Suspend或者阻塞Block狀態。或者主動切換任務taskYIELD或者用延時函數 vTaskDelay 來暫時釋放 CPU 資源,vTaskDelay 可以使較低優先級的任務有機會得到執行。但請注意,使用延時函數可能導致較高優先級任務的執行時間不確定,因為它們會暫時停止執行。vTaskDelay函數可以使低優先級任務在執行一段時間后暫時讓出CPU,等待指定的延遲時間后再次被調度執行。但是,一旦高優先級任務變為可運行狀態并具備運行條件,它可以隨時搶占低優先級任務,并開始執行。
RTOS的任務觸發場景描述和分析
場景描述:智能車控制系統
- 高優先級任務:
- 緊急安全任務:例如緊急制動、避障等任務。這些任務需要立即執行以確保車輛和乘客的安全。
- 實時任務:例如車輪控制、電機控制等任務,需要及時響應和執行,確保車輛的平穩運行和精確控制。
- 中優先級任務:
- 傳感器讀取任務:例如讀取距離傳感器、攝像頭等任務。這些任務提供車輛周圍環境的信息,需要及時獲取,但相對于實時控制任務來說,可以略有延遲。
- 數據處理任務:例如圖像處理、數據濾波等任務。這些任務對傳感器數據進行處理和分析,為決策任務提供支持。
- 低優先級任務:
- 決策任務:例如路徑規劃、目標識別等任務。這些任務基于傳感器數據和環境信息做出決策,但相對于實時控制任務來說,可以有一定的延遲。
- 用戶界面任務:例如與用戶的交互界面、顯示信息等任務。這些任務對于整個系統的實時響應性要求相對較低。
系統分析:
- 高優先級任務:
- 當智能車系統啟動時,實時控制任務會立即開始執行,控制車輛的轉向和速度。緊急制動任務則處于阻塞狀態,等待緊急情況的觸發。
- 這些任務應具有最高的執行優先級,能夠立即搶占其他任務執行。
- 電機控制任務通常具有較高的優先級,因為它直接影響到物理設備(電機)的動作。該任務負責監測和控制電機的狀態,確保電機按照預期速度或位置進行運轉。該任務需要及時響應,并且通常需要以較高的采樣率進行控制,以保證電機的穩定性和精確性。
- 中優先級任務:
- 傳感器讀取任務和數據處理任務以較低的頻率定時執行。在 FreeRTOS 中,任務切換的頻率非常高,通常以微秒級或毫秒級為單位。這意味著任務的執行時間很短,任務切換速度很快。當高優先級任務(如電機控制任務)一直運行時,RTOS 調度器會以非常短的時間間隔切換到中優先級任務(如攝像頭數據采集和數據處理任務),并執行它們的代碼。然后,調度器會再次迅速切換回高優先級任務,恢復電機控制任務的執行。
- camera數據采集放到這里也可以放在低優先級,如果系統對相機采集的圖像數據有較高的實時性要求,例如需要快速檢測和響應變化的場景或對象,那么將相機圖像采集任務設置為中優先級可能更合適。相機圖像采集任務如果需要大量的計算資源來處理和分析圖像數據,例如進行目標檢測、圖像識別等算法。如果系統的計算資源有限,將相機圖像采集任務設置為低優先級可以確保其他任務(如電機控制和決策任務)能夠獲得足夠的計算資源和響應時間。如果決策任務依賴于相機圖像采集任務的輸出數據進行分析和決策,那么將相機圖像采集任務設置為中優先級可能更合適。
- 在智能車控制中PID算法應該算在這個層面。根據電機的反饋信號進行實時的控制決策。PID算法根據設定的目標值和當前反饋值計算出控制輸出,以調整電機的速度或位置。該任務與電機控制任務密切相關,因此通常被劃分為中優先級任務。PID算法的執行周期通常較快,但相對于電機控制任務可能有一定的延遲。
- 低優先級任務:
- 決策任務可能涉及識別和避免障礙物的策略。該任務可能需要使用傳感器數據來檢測障礙物,并根據障礙物的位置、大小和運動狀態等信息,決定如何安全地避開障礙物。
- 決策任務通常需要對相機采集的數據進行處理和分析,這可能涉及復雜的計算和算法。如果將決策任務設置為高優先級,它將占用大量的計算資源和時間片,可能導致電機控制任務得不到足夠的執行時間,影響系統的實時性。因此,將決策任務放到低優先級可以確保電機控制任務得到及時的執行,保證了系統對電機的實時控制。
- 決策任務的執行可能是基于一系列的檢測和分析結果,可能需要多次采樣和處理。如果決策任務設置為高優先級并立即反饋給電機,可能會導致頻繁的控制信號變化,從而造成系統的震蕩和不穩定。將決策任務放到低優先級,可以允許一定的延遲和平滑控制信號的變化,提高系統的穩定性和抗干擾能力。
閉環分析:
- 高優先級任務,車輛電機的主動控制。
- 中優先級任務,camera的數據采集和PID算法電機控制。
- 低優先級任務,對于camera采集的數據進行數據處理和分析,之后將分析結果反饋給高優先級任務電機控制。
滴答定時器如何觸發任務的執行和任務的切換
OS基于滴答定時器通過中斷觸發任務的執行:
在啟動調度器的過程中,會配置 SysTick 定時器的加載值 (Load Value) 和使能定時器,在 vPortSetupTimerInterrupt 中將這些配置定義到硬件中。(FreeRTOS中沒有專門的軟件定時器用于設置時間片并觸發任務)
當 SysTick 定時器的計數器減為零時,會觸發 SysTick 中斷。SysTick 定時器的計數器會從加載值遞減,當減到零時會觸發中斷。
中斷的觸發是通過硬件來執行的,根據不同的芯片配置啟動文件,在啟動文件中,定義好中斷向量表,根據上面的配置,就會定時觸發定時器中斷,
當 SysTick 中斷觸發時,處理器會跳轉到預定義的 SysTick_Handler 函數執行相應的處理,進入到 xTaskIncrementTick 函數,它是在任務調度器中的關鍵函數之一,負責管理系統時間和任務調度。
xTaskIncrementTick 函數的作用:
- 增加系統時基計數:xTaskIncrementTick() 函數會遞增 FreeRTOS 內核的系統時基計數器。在內核中存在一個系統時基計數器(System Tick Counter)和一個滴答定時器(Tick Timer)。滴答時間是滴答定時器的觸發間隔,通常以固定的時間間隔產生中斷。當滴答定時器的計數達到滴答時間時,會觸發一個中斷。每當滴答定時器中斷發生時,在中斷處理函數中會遞增系統時基計數器的值。遞增的步長通常是1,表示一個滴答時間間隔。
- 執行任務調度:增加系統時基計數器后,函數會檢查是否有更高優先級的任務需要被調度。如果有,它會選擇一個優先級最高的任務來執行,并且切換到該任務的上下文環境。
- 處理延時和阻塞操作:函數會檢查所有正在延時或阻塞的任務,并根據任務的延時時間或等待條件來決定是否需要喚醒這些任務。
通過滴答時鐘觸發滴答中斷,對調度器的進一步思考
調度器并不是一個函數執行很多功能,而是很多函數,很多功能組成的調度器。調度器的核心函數有 vTaskStartScheduler() 啟動調度器。vTaskEndScheduler() 終止調度器。vTaskSuspend() 掛起任務。vTaskResume() 恢復任務。vTaskDelay() 延遲任務。vTaskDelete() 刪除任務。taskYIELD()任務切換。xTaskCreate() 創建任務等等。
對任務的切換和任務執行的思考
對于高優先級任務,那種需要一直執行的,需要在TASK里加入while(1)循環執行。所以在設計的智能車的電機控制任務中要加入while(1)循環執行,除非等到了某些事件觸發了掛起或阻塞任務或 vTaskDelay 才交出CPU的控制權給低優先級,vTaskDelay 之后高優先級任務重回控制權,循環在while里。
對于任務的切換,當高優先級任務在while(1)的循環中時,在while的循環內部加入一個 vTaskDelay,暫時釋放CPU,所謂的釋放CPU確實就是先將調度器掛起,將高優先級任務放到延時列表中,之后在恢復調度器的執行。在調度器恢復執行后,再從就緒列表中找到下一個優先級的任務去執行,調用的? portYIELD 去切換任務。
vTaskDelay輸入的參數是需要延時的系統節拍數,它使用的是 FreeRTOS 內部的時鐘節拍來進行延時,不直接使用系統時鐘頻率 SystemCoreClock。假如我想延時500ms,就直接輸入vTaskDelay(500);
xTaskIncrementTick 在被觸發的時候,會判斷vTaskDelay定義的延時節拍,如果時間到了后,會將在延時列表中的任務進行喚醒。延時列表是按照延時時間排列,第一個任務就是最先需要被喚醒的任務。之后高優先級任務重回掌控權。
基于上面的智能車控制系統的閉環分析,高優先級任務,車輛電機的主動控制。中優先級任務,camera的數據采集和PID算法電機控制。低優先級任務,對于camera采集的數據進行數據處理和分析。我要如何分配這個系統中這三個任務的執行時間。對于車輛電機的主動控制是最高的優先級,在整個系統的運行中,我可以每次執行電機控制后用vTaskDelay釋放一會時間,切換到中優先級任務camera的數據采集和PID算法電機控制,預估這兩個中優先級任務要執行多久,之后用vTaskDelay釋放一會時間,切換到低優先級任務對于camera采集的數據進行數據處理和分析。中優先級任務vTaskDelay的時間是低優先級任務判斷的時間,高優先級任務vTaskDelay的時間是中優先級和低優先級任務的時間。
時間片輪轉調度機制對系統的影響
FreeRTOS 中的時間片輪轉調度機制主要用于解決相同優先級任務之間的公平調度,確保每個任務輪流地享有相同的 CPU 時間。在函數 taskSELECT_HIGHEST_PRIORITY_TASK 中執行 listGET_OWNER_OF_NEXT_ENTRY 時間片輪轉調度任務的功能。
時間片的大小是由 configTICK_RATE_HZ 的值來控制,如果將 configTICK_RATE_HZ 設置為 1000,表示每秒鐘有 1000 個時鐘節拍,則默認情況下時間片的大小就是 1 毫秒,所以時間輪轉調度是每個時間片切一個任務,也就是說每毫秒執行一個任務,如果有3個相同優先級的任務在3毫秒內將會挨個執行一遍,但是每個時間片基本都不會執行完任務,每個時間片過后,先將任務掛起,將寄存器或數據保存到堆棧上,之后切到下一個任務,等到又拿到時間片后,恢復堆棧上的寄存器和數據,繼續執行上一次沒執行完的內容。比如任務在while(1)循環里。
時間片輪轉調度機制其實最好的應用法是對于某些任務,需要等待某個事件,或者需要等待什么資源的時候,為了不白白空等,就先去執行其他的任務,等到其他任務執行完了,我這個任務也等到了想要的資源。比如camera的數據采集和數據處理與分析,完全可以在同一個優先級,也就是數據該采集采集,等camera數據采集完了我就執行數據分析,之后camera依舊在不同的時間片進行數據采集,采集完的數據在不同的時間片進行分析。兩不耽誤。