在 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。如此循环...
原文地址:https://www.cnblogs.com/tianxxl/p/12023562.html