FreeRTOS篇章之事件位和事件组

写在前面:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。

 

目录

一、事件位(或标志)与事件组

二、事件组和事件位数据类型

三、使用事件组必须克服的问题

四、事件组的 RTOS API函数

五、实例代码


 

一、事件位(或标志)与事件组

事件位:用于指示事件是否发生;事件位通常称为事件标志。

事件组:是一组事件位;事件组中的各个事件位由位号引用(即每一 bit代表某个事件)

 

二、事件组和事件位数据类型

事件组由 EventGroupHandle_t类型的变量引用

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

configUSE_16_BIT_TICKS的具体的描述可以看 FreeRTOS篇章之 FreeRTOSConfig.h分析

事件组中的所有事件位都存储在 EventBits_t类型的单个无符号变量中。事件位 0存储在位位置 0,事件位1存储在位位置 1,依此类推

下图显示了一个 24位事件组,该组使用三个位来保存已描述的三个示例事件。在图像中,仅事件位 2被设置

FreeRTOS篇章之事件位和事件组_第1张图片

 

三、使用事件组必须克服的问题

实施事件组时,RTOS必须克服的两个主要挑战是:

1、避免在用户的应用程序中创建竞争条件:

在以下情况下,事件组的实现将会在应用程序中创建竞争条件:

  • 目前尚不清楚谁负责清除单个位(或标志)。
  • 尚不清楚何时清除一点。
  • 尚不清楚在任务退出测试该位值的 API函数时是否设置了位或清除了位(这可能是因为另一个任务或中断已更改了位的状态)。

FreeRTOS事件组的实现通过智能的建立来确保设置、测试和清除位的原子性,从而消除了竞争条件的可能性。线程本地存储和谨慎使用 API函数返回值使这成为可能

2、避免不确定性:

事件组的概念隐含了不确定性行为,因为它不知道事件组上有多少个任务被阻止,因此,当设置了事件位时,也不知道需要测试多少条件或解除多少任务阻塞。

FreeRTOS质量标准不允许不确定的行为在中断禁用或者中断服务中发生。为确保在设置事件位时不会违反这些严格的质量标准,需要以下两点:

  • RTOS调度器的锁定机制用于确保从 RTOS任务设置事件位时,中断保持启用状态。
  • 中央延迟中断机制用于在试图从中断服务例程设置事件位时,将设置位的动作延迟到任务。

 

四、事件组的 RTOS API函数

事件组的 API函数允许任务或者其他事项来设置事件组中的一个或多个事件位,清除事件组中的 一个或多个事件位,并暂挂(进入“阻止”状态,因此任务不会占用任何处理时间)以等待一个或多个事件位在事件组中被置位

事件组还可用于同步任务,创建通常称为任务 “会合” 的任务。任务同步点是应用程序代码中的一个位置,在这个位置上,任务将处于阻塞状态(不消耗任何 CPU时间)等待,直到参与同步的所有其他任务也到达它们的同步点

需要 #include "event_groups.h"

1、xEventGroupCreate() API函数

EventGroupHandle_t xEventGroupCreate( void );

返回参数(此返回值应当保存下来,以作为操作此队列的句柄):

  • NULL:表示事件组创建失败。原因是内存堆空间不足导致 FreeRTOS 无法为互斥量分配结构数据空间
  • 非 NULL:值表示事件组创建成功。返回值应当保存起来作为该事件组的句柄

2、xEventGroupWaitBits() API函数

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

传入参数:

  • xEventGroup:事件组的目标句柄。这个句柄即是调用 xEventGroupCreate()创建该事件组时的返回值
  • uxBitsToWaitFor:一个按位的值,表示在事件组中可设置的事件位(或标志)
  • xClearOnExit:如果设置为 pdTRUE,那么如果满足了等待条件(如果函数返回的原因不是超时),则在事件组中设置的 uxBitsToWaitFor中的任何位都将在 xEventGroupWaitBits()返回之前被清除;否则,如果设置为 pdFALSE,那么当调用 xEventGroupWaitBits()返回时,事件组中设置的位不会改变
  • xWaitForAllBits:如果设置为 pdTRUE,那么当 uxBitsToWaitFor中的所有位被设置或者指定的块时间过期时,xEventGroupWaitBits()将返回;否则,如果设置为 pdFALSE,那么当 uxBitsToWaitFor中设置的任何一个位或者指定的块时间过期时,xEventGroupWaitBits()将返回
  • xTicksToWait:阻塞超时时间

返回参数:

  • 事件组中事件位的设置情况。如果 xEventGroupWaitBits()因为超时而返回,则不会设置所有正在等待的事件位;在 xClearOnExit参数被设置为 pdTRUE的情况下,如果 xEventGroupWaitBits()是因为它正在等待的位被设置而返回,那么返回的值就是在任何位被自动清除之前的事件组值。

3、xEventGroupClearBits() API函数

EventBits_t   xEventGroupClearBits( EventGroupHandle_t    xEventGroup, const EventBits_t    uxBitsToClear );

传入参数:

  • xEventGroup:要清除其中位的事件组
  • uxBitsToClear :位值。表示在事件组中要清除的事件位(或标志)

返回参数:

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

4、xEventGroupClearBitsFromISR() API函数

BaseType_t   xEventGroupClearBitsFromISR( EventGroupHandle_t    xEventGroup, const EventBits_t    uxBitsToClear );

传入参数:

  • xEventGroup:要清除其中位的事件组
  • uxBitsToClear :位值。表示在事件组中要清除的事件位(或标志)

返回参数(有两个可能的返回值):

  • pdPASS:成功发送请求
  • pdFALSE:发送请求失败。计时器服务队列已满

5、xEventGroupSetBits() API函数

EventBits_t   xEventGroupSetBits( EventGroupHandle_t    xEventGroup, const EventBits_t    uxBitsToSet );

传入参数:

  • xEventGroup:要在其中位设置的事件组
  • uxBitsToSet :一个按位的值,表示要设置的事件位(或标志)

返回参数:

  • 事件组在调用 xEventGroupSetBits()时的值

注意:用户通过参数 uxBitsToSet设置的标志位并不一定会保留到此函数的返回值中,返回的值可能清除有以下两种情况:
  a. 调用此函数的过程中,其它高优先级的任务就绪了,并且也修改了事件标志,此函数返回的事件标志位会发生变化。
  b. 调用此函数的任务是一个低优先级任务,通过此函数设置了事件标志后,让一个等待此事件标志的高优先级任务就绪了,会立即切换到高优先级任务去执行,相应的事件标志位会被函数 xEventGroupWaitBits清除掉,等从高优先级任务返回到低优先级任务后,函数 xEventGroupSetBits的返回值已经被修改。

6、xEventGroupSetBitsFromISR() API函数

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

传入参数:

  • xEventGroup:要在其中位设置的事件组
  • uxBitsToSet :一个按位的值,表示要设置的事件位(或标志)
  • pxHigherPriorityTaskWoken:用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是 pdTRUE,说明有高优先级任务要执行,否则没有;必须将 xHigherPriorityTaskWoken初始化为 pdFALSE

返回参数(有两个可能的返回值):

  • pdPASS:成功发送请求
  • pdFALSE:发送请求失败。计时器服务队列已满

7、xEventGroupGetBits() API函数

EventBits_t   xEventGroupGetBits( EventGroupHandle_t    xEventGroup );

传入参数:

  • xEventGroup:需要查询的事件组

返回参数:

  • 调用 xEventGroupGetBits()时的事件组位

8、xEventGroupGetBitsFromISR() API函数

EventBits_t   xEventGroupGetBitsFromISR( EventGroupHandle_t    xEventGroup );

传入参数:

  • xEventGroup:需要查询的事件组

返回参数:

  • 调用 xEventGroupGetBitsFromISR()时的事件组位

9、xEventGroupDelete() API函数

void xEventGroupDelete( EventGroupHandle_t    xEventGroup );

传入参数:

  • xEventGroup:需要删除的事件组

10、xEventGroupCreateStatic() API函数

EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );

该函数是用于在静态的时候,利用该函数创建一个事件组,具体可以去看他的注释,这里就不说了

 

五、实例代码

相关的实例代码及文档,参看保存在官方文件路径 FreeRTOS/Demo/Common/Minimal下的 EventGroupsDemo.c文件

 

 

你可能感兴趣的:(FreeRTOS)