在 FreeRTOS 操作系統中為了降低優先級翻轉問題利用了優先級繼承算法。優先級繼承算法是指,暫時提高某個占有某種資源的低優先級任務的優先級,使之與在所有等待該資源的任務中優先級最高那個任務的優先級相等,而當這個低優先級任務執行完畢釋放該資源時,優先級重新回到初始設定值。因此,繼承優先級的任務避免了系統資源被任何中間優先級的任務搶占。互斥量與二值信號量最大的不同是:互斥量具有優先級繼承機制,而信號量沒有。也就是說,某個臨界資源受到一個互斥量保護,如果這個資源正在被一個低優先級任務使用,那么此時的互斥量是閉鎖狀態,也代表了沒有任務能申請到這個互斥量,如果此時一個高優先級任務想要對這個資源進行訪問,去申請這個互斥量,那么高優先級任務會因為申請不到互斥量而進入阻塞態,那么系統會將現在持有該互斥量的任務的優先級臨時提升到與高優先級任務的優先級相同,這個優先級提升的過程叫做優先級繼承。這個優先級繼承機制確保高優先級任務進入阻塞狀態的時間盡可能短,以及將已經出現的“優先級翻轉”危害降低到最小。_ _ _ _ _ _ _ _以上內容摘自《野火FreeRTOS 內核實現與應用開發實戰指南》
互斥量實驗是基於優先級翻轉實驗進行修改的,目的是為了測試互斥量的優先級繼承機制是否有效。
創建工程RTOS_Mutex,
配置HCLK,使用內部晶振,頻率為180MHZ(根據板子設置)
將SYS中時基源(Timebase Source)改為除SysTick之外的任意定時器即可,如:
配置FreeRTOS,使用CMSIS_V1,先定義一個互斥信號量:
定義三個任務:
Ctrl + S生成代碼
修改代碼,
1,在main.h中添加
/* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "stdio.h" /* USER CODE END Includes */
2,在mian.c中添加
/* USER CODE BEGIN PFP */ int _write(int file , char *ptr,int len) { int i = 0; for(i = 0;i<len;i++) ITM_SendChar((*ptr++)); return len; } /* USER CODE END PFP */ ... ... ... /* USER CODE BEGIN 2 */ printf("starting...\n"); /* USER CODE END 2 */
3,在main.c中修改3個任務入口函數的內容
/* USER CODE BEGIN Header_StartLowPriorityTask */ /** * @brief Function implementing the LowPriorityTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartLowPriorityTask */ void StartLowPriorityTask(void const * argument) { /* USER CODE BEGIN 5 */ static uint32_t i; /* Infinite loop */ for(;;) { printf("LowPriority_Task gets mutex!\n"); //獲取二值信號量 xSemaphore,沒獲取到則一直等待 if(osMutexWait(myMutex01Handle, osWaitForever) == osOK) { printf("LowPriority_Task Runing\n\n"); } for (i=0; i<2000000; i++) { //模擬低優先級任務占用信號量 osThreadYield();//發起任務調度 } printf("LowPriority_Task Releasing mutex!\r\n"); osMutexRelease( myMutex01Handle );//給出二值信號量 osDelay(500); } /* USER CODE END 5 */ }
/* USER CODE BEGIN Header_StartMidPriorityTask */ /** * @brief Function implementing the MidPriorityTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartMidPriorityTask */ void StartMidPriorityTask(void const * argument) { /* USER CODE BEGIN StartMidPriorityTask */ /* Infinite loop */ for(;;) { printf("MidPriority_Task Runing\n"); osDelay(500); } /* USER CODE END StartMidPriorityTask */ }
/* USER CODE BEGIN Header_StartHighPriority_Task */ /** * @brief Function implementing the HighPriority_Ta thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartHighPriority_Task */ void StartHighPriority_Task(void const * argument) { /* USER CODE BEGIN StartHighPriority_Task */ /* Infinite loop */ for(;;) { printf("HighPriority_Task gets mutex!\n"); //獲取二值信號量 xSemaphore,沒獲取到則一直等待 if(osMutexWait(myMutex01Handle, osWaitForever) == osOK) { printf("HighPriority_Task Runing\n\n"); } printf("HighPriority_Task Releasing mutex!\r\n"); osMutexRelease( myMutex01Handle );//給出二值信號量 osDelay(500); } /* USER CODE END StartHighPriority_Task */ }
修改完畢后點擊 小錘子 構建工程,然后點擊Debug,按如下步驟配置ITM調試
全速運行之前一定要先點擊SWV ITM data Console 頁面中的紅色圓圈
現象:
分析:
3個任務,LowPriority_Task,的優先級為 osPriorityLow ,任務先獲取互斥量,獲取成功后先不釋放,進行任務調度2000000次,然后釋放二值信號量。
MidPriority_Task的優先級為 osPriorityNormal ,任務每個500ms輸出提示信息MidPriority_Task Runing。
HighPriority_Task的優先級為 osPriorityHigh,任務先獲取互斥量,獲取成功后輸出提示信息,然后立即釋放互斥量。
程序先執行優先級最高的HighPriority_Task的,然后執行優先級第二高的MidPriority_Task,最后執行優先級最低的LowPriority_Task 。在LowPriority_Task中,任務先獲取互斥量,獲取成功后先不釋放,進行任務調度,調度到優先級最高的HighPriority_Task,HighPriority_Task任務獲取互斥量,因為此時互斥量被占用,所以會獲取失敗,進入阻塞態。由於互斥量的優先級繼承機制,此時的LowPriority_Task的優先級被暫時提高到與HighPriority_Task一樣,所以即使進行任務調度也不會執行MidPriority_Task,直到LowPriority_Task釋放信號量(此時,由於優先級繼承機制,LowPriority_Task恢復到原來的優先級),程序立即執行HighPriority_Task,當HighPriority_Task執行完畢后,按照優先級執行MidPriority_Task,最后再執行LowPriority_Task。如此循環...