模擬優先級翻轉實驗是在 FreeRTOS 中創建了三個任務與一個二值信號量, 任務分別是高優先級任務,中優先級任務,低優先級任務, 用於模擬產生優先級翻轉。 低優先級任務在獲取信號量的時候,被中優先級打斷,中優先級的任務執行時間較長,因為低優先級還未釋放信號量,那么高優先級任務就無法取得信號量繼續運行,此時就發生了優先級翻轉。
創建工程RTOS_BinarySem,
配置HCLK,使用內部晶振,頻率為180MHZ(根據板子設置)

將SYS中時基源(Timebase Source)改為除SysTick之外的任意定時器即可,如:

配置FreeRTOS,使用CMSIS_V1,先定義一個二值信號量。

定義3個任務,

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 LowPriority_Tas 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 binarySem!\n"); //獲取二值信號量 xSemaphore,沒獲取到則一直等待 if(osSemaphoreWait(myBinarySem01Handle, osWaitForever) == osOK) { printf("LowPriority_Task Runing\n\n"); } for (i=0; i<2000000; i++) { //模擬低優先級任務占用信號量 osThreadYield();//發起任務調度 } printf("LowPriority_Task Releasing semaphore!\r\n"); osSemaphoreRelease( myBinarySem01Handle );//給出二值信號量 osDelay(500); } /* USER CODE END 5 */ }
/* USER CODE BEGIN Header_StartMidPriorityTask */ /** * @brief Function implementing the MidPriority_Tas 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 binarySem!\n"); //獲取二值信號量 xSemaphore,沒獲取到則一直等待 if(osSemaphoreWait(myBinarySem01Handle, osWaitForever) == osOK) { printf("HighPriority_Task Runing\n\n"); } printf("HighPriority_Task Releasing semaphore!\r\n"); osSemaphoreRelease( myBinarySem01Handle );//給出二值信號量 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任務獲取二值信號量,因為此時二值信號量被占用,所以會獲取失敗,進入阻塞態,執行MidPriority_Task,直到LowPriority_Task任務釋放二值信號量執行完畢。因此就出現了一個奇怪的現象,優先級最高的HighPriority_Task要等到LowPriority_Task執行完畢后才能執行,而此時優先級較低的MidPriority_Task和LowPriority_Task在正常執行,也就是程序設置的優先級被反轉了。
