第18章 FreeRTOS 事件标志组


目录

18.1 事件标志组

18.1.1 为什么要 使用事件标志

18.1.2 F reeRTOS 任务 间 事件标志组的实现 

18.1.3 F reeRTOS 中断 方式事件标志 组 的实现

18.2 事件标志组 API 函数

18.2.1 函数 xEventGroupCreate

18.2.2 函数 xEventGroupCreateStatic

18.2.3 函 数 vEventGroupDelete

18.2.4 函 数 xEventGroupSetBits

18.2.5 函数 xEventGroupSetBitsFromISR

18.2.6 函数 xEventGroupWaitBits

18.2.7 函数 xEventGroupClearBits

18.2.8 函数 xEventGroupClearBitsFromISR

18.2.9 函数 xEventGroupGetBits

18.2.10 函数 xEventGroupGetBitsFromISR

18.2.11 函数 xEventGroupSync



前面的章节我们已经讲解了任务管理和时间管理,从本章节开始讲解任务间的通信和同步机制。首先讲解任务间的通信和同步机制之一,事件标志组。

18.1 事件标志组

18.1.1 为什么要 使用事件标志

事件标志组是实现多任务同步的有效机制之一。也许有不理解的初学者会问采用事件标志组多麻烦,搞个全局变量不是更简单?其实不然,在裸机编程时,使用全局变量的确比较方便,但是在加上RTOS后就是另一种情况了。使用全局变量相比事件标志组主要有如下三个问题:

  1.  使用事件标志组可以让RTOS内核有效地管理任务,而全局变量是无法做到的,任务的超时等机制需要用户自己去实现。
  2.  使用了全局变量就要防止多任务的访问冲突,而使用事件标志组则处理好了这个问题,用户无需担心。
  3.  使用事件标志组可以有效地解决中断服务程序和任务之间的同步问题。

18.1.2 F reeRTOS 任务 间 事件标志组的实现 

任务间事件标志组的实现是指各个任务之间使用事件标志组实现任务的通信或者同步机制。 下面我们来说说FreeRTOS中事件标志的实现,根据用户在FreeRTOSConfig.h文件中的配置:

  •  #define configUSE_16_BIT_TICKS 1 配置宏定义configUSE_16_BIT_TICKS为1时,每创建一个事件标志组,用户可以使用的事件标志是8个。
  •  #define configUSE_16_BIT_TICKS 0

配置宏定义configUSE_16_BIT_TICKS为0时,每创建一个事件标志组,用户可以使用的事件标志是24个。 上面说的8个和24个事件标志应该怎么理解呢?其实就是定义了一个16位变量,仅使用了低8bit或者定义了一个32位变量,仅使用了低24bit。每一个bit用0和1两种状态来代表事件标志。反映到FreeRTOS上就是将事件标志存储到了EventBits_t类型的变量中,这个变量又是怎么回事呢?定义如下:

/*
* The type that holds event bits always matches TickType_t therefore the
* number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to
* 32 bits if set to 0.
* defgroup EventBits_t EventBits_t
* ingroup EventGroup
typedef TickType_t EventBits_t;

进一步跟踪TickType_t的数据类型,定义如下:

#if( configUSE_16_BIT_TICKS == 1 )
    typedef uint16_t TickType_t;
    #define portMAX_DELAY ( TickType_t ) 0xffff
#else
    typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
    /* 32 bit tick type on a 32 bit architecture, so reads of the tick count do
    not need to be guarded with a critical section. */
    #define portTICK_TYPE_IS_ATOMIC 1
#endif

由上面定义可以看出,TickType_t数据类型可以是16位数或者32位数,这样就跟上面刚刚说的configUSE_16_BIT_TICKS 宏定义呼应上了。教程配套的例子都是配置宏定义configUSE_16_BIT_TICKS 为0,即用户每创建一个事件标志组,有24个标志可以设置。如下图所示,这里仅使用bit0,bit1和bit2。

注意:后面的讲解中,默认全是创建一个事件标志,支持24个事件标志设置。 下面我们通过如下的框图来说明一下FreeRTOS事件标志的实现,让大家有一个形象的认识。

运行条件:

  •  创建2个任务:Task1和Task2

运行过程描述如下:

  •  任务Task1运行过程中调用函数xEventGroupWaitBits,等待事件标志位被设置,任务Task1由运行态进入到阻塞态。
  •  任务Task2设置Task1等待的事件标志,任务Task1由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。

上面就是一个简单的FreeRTOS任务间事件标志通信过程。

18.1.3 F reeRTOS 中断 方式事件标志 组 的实现

FreeRTOS中断方式事件标志组的实现是指中断函数和FreeRTOS任务之间使用事件标志。下面我们通过如下的框图来说明一下FreeRTOS事件标志的实现,让大家有一个形象的认识。

运行条件:  创建一个任务和一个串口接收中断

运行过程描述如下:

  1.  任务Task1运行过程中调用函数xEventGroupWaitBits,等待事件标志位被设置,任务Task1由运行态进入到阻塞态。
  2.  Task1阻塞的情况下,串口接收到数据进入到了串口中断服务程序,在串口中断服务程序中设置Task1等待的事件标志,任务Task1由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。

上面就是一个简单的FreeRTOS中断方式事件标志通信过程。实际应用中,中断方式的消息机制要注意以下四个问题:

  1.  中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。
  2.  实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效地保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行。
  3.  中断服务程序中一定要调用专用于中断的事件标志设置函数,即以FromISR结尾的函数。
  4.  在操作系统中实现中断服务程序与裸机编程的区别。

 如果FreeRTOS工程的中断函数中没有调用FreeRTOS的事件标志组API函数,与裸机编程是一样的。

 如果FreeRTOS工程的中断函数中调用了FreeRTOS的事件标志组的API函数,退出的时候要检测是否有高优先级任务就绪,如果有就绪的,需要在退出中断后进行任务切换,这点跟裸机编程稍有区别,详见18.4小节实验例程说明(中断方式):

 另外强烈推荐用户将Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407,F429的NVIC优先级分组设置为4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便。

 用户要在FreeRTOS多任务开启前就设置好优先级分组,一旦设置好切记不可再修改。

18.2 事件标志组 API 函数

使用如下11个函数可以实现FreeRTOS的事件标志组:

  •  xEventGroupCreate()
  •  xEventGroupCreateStatic()
  •  vEventGroupDelete()
  •  xEventGroupWaitBits()
  •  xEventGroupSetBits()
  •  xEventGroupSetBitsFromISR()
  •  xEventGroupClearBits()
  •  xEventGroupClearBitsFromISR()
  •  xEventGroupGetBits()
  •  xEventGroupGetBitsFromISR()
  •  xEventGroupSync()

 

18.2.1 函数 xEventGroupCreate

EventGroupHandle_t xEventGroupCreate(void);

创建一个新的RTOS 事件组,并返回一个句柄,通过它可以引用新创建的事件组。

要使此RTOS API函数可用:

  1. 必须在FreeRTOSConfig.h 中将configSUPPORT_DYNAMIC_ALLOCATION设置为1,或者未定义(在这种情况下,它将默认为1)。
  2. RTOS源文件FreeRTOS / source / event_groups.c必须包含在构建中。

每个事件组都需要[非常]少量的RAM,用于保留事件组的状态。如果使用xEventGroupCreate()创建事件组,则将从FreeRTOS堆中自动分配所需的RAM 。如果使用xEventGroupCreateStatic()创建事件组,则RAM由应用程序编写器提供,它需要一个附加参数,但允许在编译时静态分配RAM。有关更多信息,请参见静态与动态分配页面。

事件组存储在EventBits_t类型的变量中。如果将configUSE_16_BIT_TICKS设置为1,则在事件组内实现的位数(或标志)为8;如果将configUSE_16_BIT_TICKS设置为0,则为24。对configUSE_16_BIT_TICKS的依赖性是由于在内部实现中用于线程本地存储的数据类型RTOS任务。

参数:

没有    

返回值:

如果创建了事件组,则返回事件组的句柄。如果FreeRTOS堆不足以 创建事件组,则返回NULL。

用法示例:

    /* Declare a variable to hold the created event group. */
    EventGroupHandle_t xCreatedEventGroup;

    /* Attempt to create the event group. */
    xCreatedEventGroup = xEventGroupCreate();

    /* Was the event group created successfully? */
    if( xCreatedEventGroup == NULL )
    {
        /* The event group was not created because there was insufficient
        FreeRTOS heap available. */
    }
    else
    {
        /* The event group was created. */
    }

 

 18.2.2 函数 xEventGroupCreateStatic


EventGroupHandle_t xEventGroupCreateStatic(
                              StaticEventGroup_t * pxEventGroupBuffer);

创建一个新的RTOS 事件组,并返回一个句柄,通过它可以引用新创建的事件组。 必须在FreeRTOSConfig.h 中将configSUPPORT_STATIC_ALLOCATION设置为1,并且必须将RTOS源文件FreeRTOS / source / event_groups.c包含在构建中,以便xEventGroupCreateStatic()函数可用。

每个事件组都需要[非常]少量的RAM,用于保留事件组的状态。如果使用xEventGroupCreate()创建事件组,则将 从FreeRTOS堆中自动分配所需的RAM 。如果使用xEventGroupCreateStatic()创建事件组,则RAM由应用程序编写器提供,它需要一个附加参数,但允许在编译时静态分配RAM。有关更多信息,请参见静态与动态分配页面。

事件组存储在EventBits_t类型的变量中。如果将configUSE_16_BIT_TICKS设置为1,则在事件组内实现的位数(或标志)为8;如果将configUSE_16_BIT_TICKS设置为0,则为24。对configUSE_16_BIT_TICKS的依赖性是由于在内部实现中用于线程本地存储的数据类型RTOS任务。

参数:

pxEventGroupBuffer   必须指向StaticEventGroup_t类型的变量,事件组数据结构将存储在该变量中。

返回值:

如果事件组创建成功,则返回事件组的句柄。如果pxEventGroupBuffer为NULL,则返回NULL。

用法示例: 

     /* Declare a variable to hold the handle of the created event group. */
    EventGroupHandle_t xEventGroupHandle;

    /* Declare a variable to hold the data associated with the created
    event group. */
    StaticEventGroup_t xCreatedEventGroup;

    /* Attempt to create the event group. */
    xEventGroupHandle = xEventGroupCreateStatic( &xCreatedEventGroup );

    /* pxEventGroupBuffer was not null so expect the event group to have
    been created? */
    configASSERT( xEventGroupHandle );

 

18.2.3 函 数 vEventGroupDelete


void vEventGroupDelete(EventGroupHandle_t xEventGroup);

删除以前使用xEventGroupCreate()调用创建的事件组。

在要删除的事件组上被阻止的任务将被取消阻止,并报告事件组值为0。

RTOS源文件FreeRTOS / source / event_groups.c必须包含在构建中,以便vEventGroupDelete()函数可用。

不能从中断中调用此函数。

参数:

xEventGroup   事件组被删除。

返回值:

没有。

 

18.2.4 函 数 xEventGroupSetBits

函数原型: EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet ); 
函数描述: 函数xEventGroupSetBits用于设置指定的事件标志位为1。

 第1个参数是事件标志组句柄。

 第2个参数表示24个可设置的事件标志位,EventBits_t是定义的32位变量(详解18.1.2小节说明),低24位用于事件标志设置。变量uxBitsToSet的低24位的某个位设置为1,那么被设置的事件标志组的相应位就设置为1。变量uxBitsToSet设置为0的位对事件标志相应位没有影响。比如设置变量uxBitsToSet = 0x0003就表示将事件标志的位0和位1设置为1,其余位没有变化。

 返回当前的事件标志组数值。

使用这个函数要注意以下问题:

1. 使用前一定要保证事件标志组已经通过函数xEventGroupCreate创建了。

2. 此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是 xEventGroupSetBitsFromISR

3. 用户通过参数uxBitsToSet设置的标志位并不一定会保留到此函数的返回值中,下面举两种情况:

a. 调用此函数的过程中,其它高优先级的任务就绪了,并且也修改了事件标志,此函数返回的事件标志位会发生变化。

b. 调用此函数的任务是一个低优先级任务,通过此函数设置了事件标志后,让一个等待此事件标志的高优先级任务就绪了,会立即切换到高优先级任务去执行,相应的事件标志位会被函数xEventGroupWaitBits清除掉,等从高优先级任务返回到低优先级任务后,函数xEventGroupSetBits的返回值已经被修改。 使用举例:

#define BIT_0	( 1 << 0 )
#define BIT_4	( 1 << 4 )

void aFunction( EventGroupHandle_t xEventGroup )
{
  EventBits_t uxBits;

  /* 在xEventGroup中设置位0和位4。*/
  uxBits = xEventGroupSetBits(
                              xEventGroup,    /* 正在更新的事件组。 */
                              BIT_0 | BIT_4 );/* 正在设置的位。 */

  if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
  {
      /* 当函数返回时,位0和位4都保持设置。 */
  }
  else if( ( uxBits & BIT_0 ) != 0 )
  {
      /* 当函数返回时,位0保持设置,但位4被清除。
         可能是由于等待位4的任务已从阻止状态中删除,位4被自动清除。 */
  }
  else if( ( uxBits & BIT_4 ) != 0 )
  {
      /* 当函数返回时,位4保持设置,但位0被清除。
         可能是位0被自动清除,因为等待位0的任务已从阻止状态中删除。 */
  }
  else
  {
      /* 第0位和第4位均未设置。可能是某个任务正在等待设置这两个位,
         当任务离开阻塞状态时,这些位被清除。 */
  }
}

 

18.2.5 函数 xEventGroupSetBitsFromISR

 

 BaseType_t xEventGroupSetBitsFromISR(
                          EventGroupHandle_t xEventGroup,
                          const EventBits_t uxBitsToSet,
                          BaseType_t * pxHigherPriorityTaskWoken);

在RTOS 事件组内设置位(标志)。可以从中断服务程序(ISR)调用的xEventGroupSetBits()版本。

在事件组中设置位将自动解除阻止等待这些位的任务。

在事件组中设置位不是确定性操作,因为可能有未知数量的任务正在等待设置一个或多个位。FreeRTOS不允许在中断或关键部分执行不确定的操作。因此,xEventGroupSetBitFromISR()向RTOS守护程序任务发送一条消息,以在守护程序任务的上下文中执行设置操作-在此任务中,使用调度程序锁代替关键节。

注意:如上段所述,来自ISR的设置位会将设置操作延迟到RTOS daemon任务(也称为计时器服务任务)。与其他任何RTOS任务一样,RTOS daemon 任务是根据其优先级安排的。因此,如果必须立即完成设置操作(在执行由应用程序创建的任务之前),则RTOS daemon 任务的优先级必须高于使用事件组的任何应用程序任务的优先级。RTOS daemon 任务的优先级由 FreeRTOSConfig.h中的configTIMER_TASK_PRIORITY定义设置 。

必须将FreeRTOSConfig.h中的INCLUDE_xEventGroupSetBitFromISR,configUSE_TIMERS和INCLUDE_xTimerPendFunctionCall都设置为1,才能使xEventGroupSetBitsFromISR()函数可用。

RTOS源文件FreeRTOS / source / event_groups.c必须包含在构建中,以便xEventGroupSetBitsFromISR()函数可用。

参数:

xEventGroup   将在其中设置位的事件组。必须事先通过调用xEventGroupCreate()创建事件组 。
uxBitsToSet   指示要设置的一个或多个位的按位值。例如,将uxBitsToSet设置为0x08仅设置第3位。将uxBitsToSet设置为0x09设置第3位和第0位。
pxHigherPriorityTaskWoken   如上所述,调用此函数将导致消息发送到RTOS daemon 任务。如果 daemon 任务的优先级高于当前正在运行的任务(中断被中断的任务)的优先级,则xEventGroupSetBitsFromISR()会将* pxHigherPriorityTaskWoken设置为pdTRUE,指示应在中断退出之前请求上下文切换。因此,必须将* pxHigherPriorityTaskWoken初始化为pdFALSE。请参见下面的示例代码。

返回值:

如果消息已发送到RTOS daemon 任务,则返回pdPASS,否则返回pdFAIL。如果计时器服务队列已满,则将返回pdFAIL 。

用法示例:

#define BIT_0    ( 1 << 0 )
#define BIT_4    ( 1 << 4 )

/*假定已通过调用 xEventGroupCreate() */
EventGroupHandle_t xEventGroup;

void anInterruptHandler( void )
{
  BaseType_t xHigherPriorityTaskWoken, xResult;

  /* xHigherPriorityTaskWoken必须初始化为pdFALSE. */
  xHigherPriorityTaskWoken = pdFALSE;

  /* Set bit 0 and bit 4 in xEventGroup. */
  xResult = xEventGroupSetBitsFromISR(
                              xEventGroup,   /* The event group being updated. */
                              BIT_0 | BIT_4, /* The bits being set. */
                              &xHigherPriorityTaskWoken );

  /* Was the message posted successfully? */
  if( xResult != pdFAIL )
  {
      /* 如果xHigherPriorityTaskWoken现在设置为pdTRUE,则应请求上下文切换。
         使用的宏是端口特定的,可以是portYIELD_FROM_ISR()或portendd_SWITCHING_ISR()
         -请参阅所用端口的文档页. */
      portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
  }
}

 

18.2.6 函数 xEventGroupWaitBits

EventBits_t xEventGroupWaitBits(
                       const EventGroupHandle_t xEventGroup,
                       const EventBits_t uxBitsToWaitFor,
                       const BaseType_t xClearOnExit,
                       const BaseType_t xWaitForAllBits,
                       TickType_t xTicksToWait);

读取RTOS 事件组中的位,可以选择进入Blocked状态(带有超时),以等待位或位组的置位。

不能从中断中调用此函数。

RTOS源文件FreeRTOS / source / event_groups.c必须包含在构建中,以便xEventGroupWaitBits()函数可用。

参数:

xEventGroup   在其中测试位的事件组。必须事先通过调用xEventGroupCreate()创建事件组 。
uxBitsToWaitFor   指示事件组内要测试的一个或多个位的按位值。例如,要等待位0和/或位2,请将uxBitsToWaitFor设置为0x05。要等待位0和/或位1和/或位2,请将uxBitsToWaitFor设置为0x07。等等。

uxBitsToWaitFor 不得设置为0。

xClearOnExit   如果xClearOnExit设置为pdTRUE,则如果xEventGroupWaitBits()由于超时以外的任何其他原因返回,则xEventGroupWaitBits()返回之前,将在事件组中清除作为uxBitsToWaitFor参数传递的值中设置的任何位。超时值由xTicksToWait参数设置。

如果xClearOnExit设置为pdFALSE,则当对xEventGroupWaitBits()的调用返回时,事件组中设置的位不会更改。

xWaitForAllBits   xWaitForAllBits用于创建逻辑AND测试(必须设置所有位)或逻辑OR测试(必须设置一个或多个位),如下所示:

如果将xWaitForAllBits设置为pdTRUE,则当在事件组中设置了作为uxBitsToWaitFor参数传递的值中设置的所有位或者指定的阻止时间到期时,xEventGroupWaitBits()将返回。

如果将xWaitForAllBits设置为pdFALSE,则在事件组中设置了作为uxBitsToWaitFor参数传递的值中设置的任何位或指定的阻止时间到期时,xEventGroupWaitBits()将返回。

xTicksToWait   等待设置uxBitsToWaitFor指定的位中的一个/全部(取决于xWaitForAllBits值)的最长时间(以“滴答”表示)。

返回值:

等待事件位被置位或块时间到期时事件组的值。如果更高优先级的任务或中断更改了调用任务离开阻塞状态与退出xEventGroupWaitBits()函数之间的事件位的值,则事件组中事件位的当前值将不同于返回值。

测试返回值以了解设置了哪些位。如果xEventGroupWaitBits()由于超时而返回,则不会设置所有等待的位。如果由于设置了xEventGroupWaitBits()而返回了等待的位,则返回值是事件组值,因为xClearOnExit参数设置为pdTRUE,因此在自动清除任何位之前。

用法示例:


#define BIT_0	( 1 << 0 )
#define BIT_4	( 1 << 4 )

void aFunction(EventGroupHandle_t xEventGroup)
{
    EventBits_t uxBits;
    const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;

    /* Wait a maximum of 100ms for either bit 0 or bit 4 to be set within
    the event group.  Clear the bits before exiting. */
    uxBits = xEventGroupWaitBits(
                 xEventGroup,   /* The event group being tested. */
                 BIT_0 | BIT_4, /* The bits within the event group to wait for. */
                 pdTRUE,        /* BIT_0 & BIT_4 should be cleared before returning. */
                 pdFALSE,       /* Don't wait for both bits, either bit will do. */
                 xTicksToWait); /* Wait a maximum of 100ms for either bit to be set. */

    if ((uxBits & (BIT_0 | BIT_4)) == (BIT_0 | BIT_4))
    {
        /* xEventGroupWaitBits() returned because both bits were set. */
    }
    else if ((uxBits & BIT_0) != 0)
    {
        /* xEventGroupWaitBits() returned because just BIT_0 was set. */
    }
    else if ((uxBits & BIT_4) != 0)
    {
        /* xEventGroupWaitBits() returned because just BIT_4 was set. */
    }
    else
    {
        /* xEventGroupWaitBits() returned because xTicksToWait ticks passed
        without either BIT_0 or BIT_4 becoming set. */
    }
}

 

18.2.7 函数 xEventGroupClearBits

EventBits_t xEventGroupClearBits(
                                 EventGroupHandle_t xEventGroup,
                                 const EventBits_t uxBitsToClear);

清除RTOS 事件组中的位(标志)。不能从中断中调用此函数。有关可从中断调用的版本,请参见xEventGroupClearBitsFromISR()。

RTOS源文件FreeRTOS / source / event_groups.c必须包含在构建中,以便xEventGroupClearBits()函数可用。

参数:

xEventGroup   要清除其中事件的事件组。必须事先通过调用xEventGroupCreate()创建事件组 。
uxBitsToClear   指示事件组中要清除的一个或多个位的按位值。例如,将uxBitsToClear设置为0x08仅清除位3。将uxBitsToClear设置为0x09以清除位3和位0。

返回值:

清除指定位之前 的事件组的值。

用法示例:

#define BIT_0	( 1 << 0 )
#define BIT_4	( 1 << 4 )

void aFunction( EventGroupHandle_t xEventGroup )
{
  EventBits_t uxBits;

  /* Clear bit 0 and bit 4 in xEventGroup. */
  uxBits = xEventGroupClearBits(
                                xEventGroup,  /* The event group being updated. */
                                BIT_0 | BIT_4 );/* The bits being cleared. */

  if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )
  {
      /* Both bit 0 and bit 4 were set before xEventGroupClearBits()
      was called.  Both will now be clear (not set). */
  }
  else if( ( uxBits & BIT_0 ) != 0 )
  {
      /* Bit 0 was set before xEventGroupClearBits() was called.  It will
      now be clear. */
  }
  else if( ( uxBits & BIT_4 ) != 0 )
  {
      /* Bit 4 was set before xEventGroupClearBits() was called.  It will
      now be clear. */
  }
  else
  {
      /* Neither bit 0 nor bit 4 were set in the first place. */
  }
}

 

18.2.8 函数 xEventGroupClearBitsFromISR

BaseType_t xEventGroupClearBitsFromISR(
                                EventGroupHandle_t xEventGroup,
                                const EventBits_t uxBitsToClear);

可以从中断中调用 的xEventGroupClearBits()版本。清除操作将推迟到RTOS守护程序任务,也称为计时器服务任务。守护程序任务的优先级由 FreeRTOSConfig.h中的 configTIMER_TASK_PRIORITY设置来设置。

RTOS源文件FreeRTOS / source / event_groups.c必须包含在构建中,以便xEventGroupClearBitsFromISR()函数可用。

参数:

xEventGroup   要清除其中事件的事件组。必须事先通过调用xEventGroupCreate()创建事件组 。
uxBitsToClear   指示事件组中要清除的一个或多个位的按位值。例如,将uxBitsToClear设置为0x08仅清除位3。将uxBitsToClear设置为0x09以清除位3和位0。

返回值:

pdPASS,如果操作已成功推迟到RTOS守护程序任务。否则为pdFALSE。仅当计时器命令队列已满时才返回pdFALSE 。

用法示例:

#define BIT_0	( 1 << 0 )
#define BIT_4	( 1 << 4 )

/* This code assumes the event group referenced by the
xEventGroup variable has already been created using a call to
xEventGroupCreate(). */
void anInterruptHandler( void )
{
  BaseType_t xSuccess;

  /* Clear bit 0 and bit 4 in xEventGroup. */
  xSuccess = xEventGroupClearBitsFromISR(
                                xEventGroup, /* The event group being updated. */
                                BIT_0 | BIT_4 );/* The bits being cleared. */

  if( xSuccess == pdPASS )
  {
      /* The command was sent to the daemon task. */
  }
  else
  {
      /* The clear bits command was not sent to the daemon task. */
  }
}

 

18.2.9 函数 xEventGroupGetBits

EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup);

返回RTOS 事件组中事件位(事件标志)的当前值。不能从中断使用此功能。有关 可以在中断中使用的版本,请参见xEventGroupGetBitsFromISR()。

RTOS源文件FreeRTOS / source / event_groups.c必须包含在构建中,以便xEventGroupGetBits()函数可用。

参数:

xEventGroup   正在查询的事件组。必须事先通过调用xEventGroupCreate()创建事件组 。

返回值:

调用xEventGroupGetBits()时,事件组中事件位的值。

 

18.2.10 函数 xEventGroupGetBitsFromISR

EventBits_t xEventGroupGetBitsFromISR(
                               EventGroupHandle_t xEventGroup);

可以从中断中调用 的xEventGroupGetBits()版本。

RTOS源文件FreeRTOS / source / event_groups.c必须包含在构建中,以便xEventGroupGetBitsFrom()函数可用。

参数:

xEventGroup   正在查询的事件组。必须事先通过调用xEventGroupCreate()创建事件组 。

返回值:

调用xEventGroupGetBitsFromISR()时,事件组中事件位的值。

 

18.2.11 函数 xEventGroupSync

EventBits_t xEventGroupSync(EventGroupHandle_t xEventGroup,
                              const EventBits_t uxBitsToSet,
                              const EventBits_t uxBitsToWaitFor,
                              TickType_t xTicksToWait);

以原子方式设置RTOS 事件组中的位(标志),然后等待在同一事件组中设置位的组合。此功能通常用于同步多个任务(通常称为任务集合点),其中每个任务必须等待其他任务到达同步点才能继续。

不能从中断使用此功能。

如果设置了uxBitsToWait参数指定的位,或者在该时间内设置了该功能,则该函数将在其块时间到期之前返回。在这种情况下,uxBitsToWait指定的所有位将在函数返回之前自动清除。

RTOS源文件FreeRTOS / source / event_groups.c必须包含在构建中,以便xEventGroupSync()函数可用。

参数:

xEventGroup   设置和测试位的事件组。必须事先通过调用xEventGroupCreate()创建事件组 。
uxBitsToSet   在确定(并可能等待)是否已设置uxBitsToWait参数指定的所有位之前,事件组中要设置的位。例如,将uxBitsToSet设置为0x04可将事件组中的位2设置为1。
uxBitsToWaitFor   指示事件组内要测试的一个或多个位的按位值。例如,将uxBitsToWaitFor设置为0x05以等待位0和位2。将uxBitsToWaitFor设置为0x07以等待位0和位1和位2等。
xTicksToWait   等待设置uxBitsToWaitFor参数值指定的所有位的最长时间(以“滴答”表示)。

返回值:

在等待位被置位或块时间到期时事件组的值。测试返回值以了解设置了哪些位。

如果xEventGroupSync()由于超时而返回,则不会设置所有等待的位。

如果由于设置了xEventGroupSync()而已等待的所有位而返回,则返回的值是事件组值,然后自动清除任何位。

用法示例:

/* Bits used by the three tasks. */
#define TASK_0_BIT        ( 1 << 0 )
#define TASK_1_BIT        ( 1 << 1 )
#define TASK_2_BIT        ( 1 << 2 )

#define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )

/* Use an event group to synchronise three tasks.  It is assumed this event
group has already been created elsewhere. */
EventGroupHandle_t xEventBits;

void vTask0( void *pvParameters )
{
  EventBits_t uxReturn;
  TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;

    for( ;; )
    {
        /* Perform task functionality here. */
        . . .

        /* Set bit 0 in the event group to note this task has reached the
        sync point.  The other two tasks will set the other two bits defined
        by ALL_SYNC_BITS.  All three tasks have reached the synchronisation
        point when all the ALL_SYNC_BITS are set.  Wait a maximum of 100ms
        for this to happen. */
        uxReturn = xEventGroupSync( xEventBits,
                                    TASK_0_BIT,
                                    ALL_SYNC_BITS,
                                    xTicksToWait );

        if( ( uxReturn & ALL_SYNC_BITS ) == ALL_SYNC_BITS )
        {
            /* All three tasks reached the synchronisation point before the call
            to xEventGroupSync() timed out. */
        }
    }
}

void vTask1( void *pvParameters )
{
    for( ;; )
    {
        /* Perform task functionality here. */
        . . .

        /* Set bit 1 in the event group to note this task has reached the
        synchronisation point.  The other two tasks will set the other two
        bits defined by ALL_SYNC_BITS.  All three tasks have reached the
        synchronisation point when all the ALL_SYNC_BITS are set.  Wait
        indefinitely for this to happen. */
        xEventGroupSync( xEventBits, TASK_1_BIT, ALL_SYNC_BITS, portMAX_DELAY );

        /* xEventGroupSync() was called with an indefinite block time, so
        this task will only reach here if the syncrhonisation was made by all
        three tasks, so there is no need to test the return value. */
    }
}

void vTask2( void *pvParameters )
{
    for( ;; )
    {
        /* Perform task functionality here. */
        . . .

        /* Set bit 2 in the event group to note this task has reached the
        synchronisation point.  The other two tasks will set the other two
        bits defined by ALL_SYNC_BITS.  All three tasks have reached the
        synchronisation point when all the ALL_SYNC_BITS are set.  Wait
        indefinitely for this to happen. */
        xEventGroupSync( xEventBits, TASK_2_BIT, ALL_SYNC_BITS, portMAX_DELAY );

        /* xEventGroupSync() was called with an indefinite block time, so
        this task will only reach here if the syncrhonisation was made by all
        three tasks, so there is no need to test the return value. */
    }
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章