基于STM32F407的FreeRTOS学习笔记(8)

发布者:TranquilBreeze最新更新时间:2024-04-02 来源: elecfans关键字:STM32F407  FreeRTOS  优先级反转 手机看文章 扫描二维码
随时随地手机看文章

前面几期我们介绍过队列、二进制信号量以及计数信号量。但是在使用二进制信号量的时候会有一种优先级反转问题的出现,简而言之就是低优先级任务因为无法及时释放信号量而导致等待信号量发生的高优先级任务迟迟无法进行。

众所周知,FreeRTOS的各任务的运行顺序是由任务的优先级决定的,优先级高的任务比优先级低的任务先执行。

假设我们有三个任务:任务H,任务M,任务L,分别代表高优先级,中优先级以及低优先级。 任务H和任务M同时被挂起,正在等待某一个事件的发生 , 同时任务H和任务L使用同样的全局资源 (意味着当任务L正在占用全局资源时任务H的执行需要等待任务L执行完释放信号量)

图片

  1. 当任务L运行时占用了全局资源。

  2. 任务H的事件被触发后由于其高优先级任务H获得CPU的使用权

  3. 当任务H需要使用全局资源时,由于任务L还没有使用完全局资源,因此任务H被挂起等待任务L的信号量释放即使用函数xSemaphoreTake(SemaphoreHandler,portMAX_DELAY);等待信号量

  4. 此时任务L恢复工作

  5. 任务M的事件触发,此时任务L在等待任务M的结束,而然后任务H此时也在等待着任务M的任务结束。因此这段时间的任务M优先级高于任务H,这种现象就是优先级反转。

  6. 等任务M执行完,任务L继续执行直到释放信号量,任务H得以继续运行。

因此使用信号量就会导致优先级反转的出现,打破原有的任务运行顺序,这在RTOS系统中应当是尽量避免的。

问题解决

为了解决二进制信号量可能带来的优先级反转现象,FreeRTOS中有一种特殊的二进制信号量——互斥信号量也就是互斥锁

图片

官方的开发者文档中介绍了互斥锁的存在,互斥锁实际上是一个包含了优先级继承机制的二进制信号量。任务在使用资源时则相当于手持一块令牌,其他没有这块令牌的任务无法就使用资源这就是所谓的互斥。当任务结束使用资源时,也就会返回所对应的令牌。

当两个任务使用相同的信号量时,为了避免前面介绍的优先级反转现象, 于是优先级高的任务会把持有令牌的低优先级任务的优先级提升到和自己一样的情况 ,这样子就可以导致中间出现的中优先级任务抢占CPU资源,使得优先级出现反转。

图片

相当于如图,将之后执行的低优先级任务的有限制强制抬高到与自己同一等级,颇有一种富家少爷为了吃葡萄而包下葡萄园的故事感。

这样子的做法可以有效地防止优先级反转现象的出现,也可以使已经出现的优先级反转得到更快的结束。

注意,互斥锁一定一定一定不能在中断中使用,因为中断无法使用延时函数来阻塞事件。

使用互斥锁

在FreeRTOS中有两种方法创建互斥锁,分别是动态创建和静态创建,我们主要介绍一下动态创建互斥锁。

图片

API文档中关于互斥锁的内容很多,主要是介绍互斥锁以及说明使用互斥锁使用的一些细节。

信号量的释放和获取则和二进制信号量一样,参考二进制信号量文章。

我们来测试一下互斥锁。

测试代码

我们需要三个不同优先级的任务,用来测试优先级反转的情况。

我们分别定义高优先级任务,中优先级任务以及低优先级任务。

图片

启动相关宏定义。先测试二进制信号量


void High_Task(void * pvParameters);//高优先级任务

void Mid_Task(void * pvParameters);//中优先级任务

void Low_Task(void * pvParameters);//低优先级任务

void Scan(void * pvParameters);

#define START_TASK_PRIO 1

TaskHandle_t High_Handler;

TaskHandle_t Start_LED_Handler;

TaskHandle_t Mid_Handler;

TaskHandle_t Low_Handler;

TaskHandle_t Scan_Handler;

xSemaphoreHandle TaskSemaphoer_Handler;

void Start_LED(void * pvParameters)

{

  taskENTER_CRITICAL();                            



  TaskSemaphoer_Handler = xSemaphoreCreateBinary();//创建二进制信号量

  if(TaskSemaphoer_Handler!=NULL)

  {

    printf('Semaphore Create Successfullyrn');

  }



  xTaskCreate((TaskFunction_t        )High_Task,//任务函数

              (char *                )'v',//任务名称

              (configSTACK_DEPTH_TYPE) 128,//堆栈空间128Byte

              (void*                 ) NULL,//无返回

              (UBaseType_t          ) 2,//优先级2

              (TaskHandle_t *        )&High_Handler);//任务函数句柄



   xTaskCreate((TaskFunction_t        )Mid_Task,//任务函数

              (char *                )'Mid_Task',//任务名称

              (configSTACK_DEPTH_TYPE) 128,//堆栈空间128Byte

              (void*                 ) NULL,//无返回

              (UBaseType_t          ) 1,//优先级1

              (TaskHandle_t *        )&Mid_Handler);//任务函数句柄



     xTaskCreate((TaskFunction_t        )Low_Task,//任务函数

              (char *                )'Low_Task',//任务名称

              (configSTACK_DEPTH_TYPE) 128,//堆栈空间128Byte

              (void*                 ) NULL,//无返回

              (UBaseType_t          ) 0,//优先级0

              (TaskHandle_t *        )&Low_Handler);//任务函数句柄



  vTaskSuspend(Mid_Handler);//挂起中优先级任务

  vTaskSuspend(High_Handler);//挂起高优先级任务    



  taskEXIT_CRITICAL();

  vTaskDelete(NULL);

}



void FreeRTOS_Init()

{

  xTaskCreate((TaskFunction_t        )Start_LED,

              (char *                )'starttask',

              (configSTACK_DEPTH_TYPE) 128,

              (void*                 ) NULL,

              (UBaseType_t          )START_TASK_PRIO,

              (TaskHandle_t *        )&Start_LED_Handler);

  vTaskStartScheduler();

}

接着我们按照会出现优先级反转的情况编写测试代码。


首先挂起高优先级和中优先级任务。


低优先级任务持续打印运行信息,当运行到5次时,恢复高优先级任务持续打印信息,高优先级任务打印三次后等待低优先级任务发送信号量。


当低优先级任务再执行5次后高恢复中优先级任务,再次执行5次后发送信号量示意高优先级任务继续运行。


中优先级任务执行3次后挂起自身。


复制

void Low_Task(void * pvParameters)//参数为 void * pvParameters

{

  int Low_number = 0;

  while(1)

  {

    printf('Low_Task Runing 1111rn');

    Low_number++;

    if(Low_number == 5)

    {

      vTaskResume(High_Handler);//恢复高优先级

    }

    if(Low_number == 10)

    {

      vTaskResume(Mid_Handler);//恢复中优先级任务

    }

    if(Low_number == 15)

    {

      xSemaphoreGive(TaskSemaphoer_Handler);//释放信号量

    }

  }

}



void Mid_Task(void * pvParameters)//参数为 void * pvParameters

{

  int Mid_number = 0;

  while(1)

  {

    printf('Mid_Task Runing 2222rn');

    Mid_number++;

    if(Mid_number == 3)

    {

      vTaskSuspend(NULL);//挂起自身

    }

  }

}



void High_Task(void * pvParameters)

{

  int High_number = 0;

  while(1)

  {

    printf('High_Task Runing 3333rn');

    High_number++;

    if(High_number==3)

    {

      xSemaphoreTake(TaskSemaphoer_Handler,portMAX_DELAY);//等待低优先级任务释放信号量

    }

  }

}


图片

图片

可以看见和预想的一样,高优先级的任务被中优先级任务所挤兑。

之后我们把代码中的二进制信号量换成互斥锁。

图片

图片

可以看到,中优先级的任务根本没有办法实现优先级反转跳到高优先级去。

因此善于使用互斥锁,避免优先级反转现象的出现有利于FreeRTOS系统任务调度顺序的正确性,防止出现意外错误。


关键字:STM32F407  FreeRTOS  优先级反转 引用地址:基于STM32F407的FreeRTOS学习笔记(8)

上一篇:基于STM32F407的FreeRTOS学习笔记(12)
下一篇:STM32Cube CubeMX生成点灯工程

推荐阅读最新更新时间:2026-03-19 20:58

基于STM32F407FreeRTOS学习笔记(6)
信号量(Semaphore)也被称为信号灯。有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量(来自百度百科) 简而言之,信号量就是在全局中表示共享资源状态的量。例如一个停车场,其中的车位就是共享资源。每当有车辆进进出出的时候,门口门卫总会统计出入车辆的数量,这就是信号量,我们可以通过信号量来获公共资源的信息(空余车位、已用车位) 而二进制信号量顾名思义只有0和1,例如电话亭的使用情况,当有人的时候其他人就无法使用电话
[单片机]
基于<font color='red'>STM32F407</font>的<font color='red'>FreeRTOS</font>学习笔记(6)
嵌入式实时系统中的优先级反转问题
1 问题的提出   目前,市场上占有率比较高的商业RTOS有VxWorks/PSOS、QNX、 LynxOS、VRTX,、Windows CE等。这些为数众多的RTOS绝大多数都是多任务实时微内核的结构,采用的是基于优先级的可抢占式调度策略。系统为每一个任务分配一个优先权,调度程序保证当前运行的进程是优先权最高的进程。但是,有时候会出现一种比较奇怪的现象:由于多进程共享资源,具有最高优先权的进程被低优先级进程阻塞,反而使具有中优先级的进程先于高优先级的进程执行,导致系统的崩溃。这就是所谓的优先级反转(Priority Inversion)。 2 优先级反转   RTOS普遍具有2个特点:实时性和多任务。实时是指系统的响
[单片机]
嵌入式实时系统中的<font color='red'>优先级</font><font color='red'>反转</font>问题
嵌入式实时系统中的优先级反转问题
摘要:嵌入式实时系统中由于多任务共享资源,通常会出现一些奇怪的现象。本文就什么是优先级反转及其产生原因进行分析,并提出2个行之有效的解决方案。 关键词:嵌入式实时系统 多任务 信号量 优先级反转 1 问题的提出   目前,市场上占有率比较高的商业RTOS有VxWorks/PSOS、QNX、 LynxOS、VRTX,、Windows CE等。这些为数众多的RTOS绝大多数都是多任务实时微内核的结构,采用的是基于优先级的可抢占式调度策略。系统为每一个任务分配一个优先权,调度程序保证当前运行的进程是优先权最高的进程。但是,有时候会出现一种比较奇怪的现象:由于多进程共享资源,具有最高优先权的进程被低优先级进程阻塞,反而使具有中优先级
[应用]
嵌入式实时系统中的优先级反转问题
摘要:嵌入式实时系统中由于多任务共享资源,通常会出现一些奇怪的现象。本文就什么是优先级反转及其产生原因进行分析,并提出2个行之有效的解决方案。 关键词:嵌入式实时系统 多任务 信号量 优先级反转 1 问题的提出   目前,市场上占有率比较高的商业RTOS有VxWorks/PSOS、QNX、 LynxOS、VRTX,、Windows CE等。这些为数众多的RTOS绝大多数都是多任务实时微内核的结构,采用的是基于优先级的可抢占式调度策略。系统为每一个任务分配一个优先权,调度程序保证当前运行的进程是优先权最高的进程。但是,有时候会出现一种比较奇怪的现象:由于多进程共享资源,具有最高优先权的进程被低优先级进程阻塞,反而使具有中优先级
[嵌入式]
[STM32F407系列学习]按键开关控制单个数码管加减计数
【思路分析】 首先我们将整个题目写出来 按键开关控制单个数码管加减计数。可以得出以下: 器材:stm32F407(含按键),共阴极数码管 功能:实现开关控制加减计数 这么一看,不难想出要实现整个功能,我们可以将它分为两部分:数显模块 和 计数器模块。 【方案设计】 2.1.1 电路图搭建 在硬件下载前,为验证程序正确性,我们可先用Proteus进行仿真实验。 下图仿真电路即为所需电路。 图1-1 【注:1.因Proteus器件库中并无stm32F407ZE,因而用图中F401系列代替,.hex文件的导入并不会出问题;2.关于数码管管脚与单片机连接的问题,注意一定是a-g分别对应PA0-PA6,(不用GPIOA用其它IO口
[单片机]
[<font color='red'>STM32F407</font>系列学习]按键开关控制单个数码管加减计数
STM32F407 ------ 使用定时器实现精确延时
测试环境:主频168M #include delay.h void delay_init() { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); TIM_TimeBaseStructure.TIM_Period = 83; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.
[单片机]
SPI 串行Flash闪存W25Q128FV 的使用(STM32F407)_硬件篇
1 性能概述  W25Q128BV的主要性能如下 通讯方式:为标准104MHz串行SPI方式,还可以双倍速204MHz和4倍速416MHz访问。 容 量:128Mbit,65536Page。 因为8 bit =1 byte , 256 byte=1Page 、16Page=1Secotr、16Secotr=1Block 所以W25Q128BV有:256 Block 4096 Secotr 65536 Page 16777216 byte W25Q128写入前必须先
[单片机]
SPI 串行Flash闪存W25Q128FV 的使用(<font color='red'>STM32F407</font>)_硬件篇
stm32F407(TJA1050)CAN通信成功
一,前言 最近我在公司玩单片机玩的不亦乐乎,好多开发板供我玩,总算MCU底层现在算告一段落。现在我又开始玩自己的开发板咯,之前stm32先移植了一个can,目的是测试买的TJA1050模块,以及自己买的canable设备。结果can不通,不过我用了公司开发板,验证了canable是正常的。TJA1050之前玩linux的时候也验证过是正常的。那么剩下的问题就是stm32我移植的can有问题。 二,瞬间解决问题 移植的can怎么会有问题呢?先猜测下复用引脚错误或者波特率选择的clock源不同导致波特率错误。果然看了code果然是这个原因。连示波器都不需要看了。 由于F429的主频为180M,而F407的主频为168M导致的原因。Ca
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved