信号量来同步的话任务只能与单个的事件或任务进行同步。有时候某个任务可能会需要与多个事件或任务进行同步,此时信号量就无能为力了。FreeRTOS为此提供了一个可选的解决方法,那就是事件标志组。
一、事件标志组简介
1、事件位(事件标志)
事件位用来表明某个事件是否发生,事件位通常用作事件标志,比如下面的几个例子:
- 当收到一条消息并且把这条消息处理掉以后就可以将某个位(标志)置1,当队列中没有消息需要处理的时候就可以将这个位(标志)置0。
- 当把队列中的消息通过网络发送输出以后就可以将某个位(标志)置1,当没有数据需要从网络发送出去的话就将这个位(标志)置0。
- 现在需要向网络中发送一个心跳信息,将某个位(标志)置1。现在不需要向网络中发送心跳信息,这个位(标志)置0。
2、事件组
一个事件组就是一组的事件位,事件组中的事件位通过位编号来访问,同样,以上面列出的三个例子为例:
- 事件标志组的bit0表示队列中的消息是否处理掉。
- 事件标志组的bit1表示是否有消息需要从网络中发送出去。
- 事件标志组的bit2表示现在是否需要向网络发送心跳信息。
3、事件标志组和事件位的数据类型
事件标志组的数据类型为EventGroupHandle_t,当configUSE_16_BIT_TICKS为1的时候事件标志组可以存储8个事件位,当configUSE_16_BIT_TICKS为0的时候事件标志组存储24个事件位。事件标志组中的所有事件位都存储在一个无符号的EventBits_t类型的变量中,EventBits_t在event_groups.h中有如下定义:
#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
#define portTICK_TYPE_IS_ATOMIC 1
#endif
可以看出当configUSE_16_BIT_TICKS为0的时候TickType_t是个32位的数据类型,因此EventBits_t也是个32位的数据类型。EventBits_t类型的变量可以存储24个事件位,另外的那高8位有其他用。事件位0存放在这个变量的bit0上,变量的bit1就是事件位1,以此类推。
对于STM32来说一个事件标志组最多可以存储24个事件位。![FreeRTOS事件标志组_第1张图片](http://img.e-com-net.com/image/info8/ac68b6121df1482991664122462cfde6.png)
二、事件标志组相关API函数详解
1、创建事件标志组
FreeRTOS提供了两个用于创建事件标志组的函数,如下表所示:
函数 |
描述 |
xEventGroupCreate() |
使用动态方法创建事件标志组。 |
xEventGroupCreateStatic() |
使用静态方法创建事件标志组 |
- ①、函数xEventGroupCreate()
此函数用于创建一个事件标志组,所需要的内存通过动态内存管理方法分配。由于内部处理的原因,事件标志组可用的bit数取决于configUSE_16_BIT_TICKS,当
configUSE_16_BIT_TICKS1为1的时候事件标志组有8个可用的位(bit0~ bit7),当configUSE_16_BIT_TICKS为0的时候事件标志组有24个可用的位(bit0~bit23)。EventBits_t类型的变量用来存储事件标志组中的各个事件位,函数原型如下:
EventGroupHandle_txEventGroupCreate(void)
参数 |
描述 |
返回值 |
NULL:事件标志组创建失败。其他值:创建成功的事件标志组句柄。 |
- ②、函数xEventGroupCreateStatic()
此函数用于创建一个事件标志组定时器,所需要的内存需要用户自行分配,此函数原型如下:
EventGroupHandle_txEventGroupCreateStatic(
StaticEventGroup_t*pxEventGroupBuffer)
参数 |
描述 |
pxEventGroupBuffer |
参数指向一个StaticEventGroup_t类型的变量,用来保存事件标志组结构体。 |
返回值 |
NULL:事件标志组创建失败。其他值:创建成功的事件标志组句柄。 |
2、设置事件位
FreeRTOS提供了4个函数用来设置事件标志组中事件位(标志),事件位(标志)的设置包括清零和置1两种操作,这4个函数如下表所示:
函数 |
描述 |
XEventGroupClearBits() |
将指定的事件位清零,用在任务中。 |
xEventGroupClearBitsFromISR() |
将指定的事件位清零,用在中断服务函数中 |
xEventGroupSetBits() |
将指定的事件位置1,用在任务中。 |
xEventGroupSetBitsFromISR() |
将指定的事件位置1,用在中断服务函数中。 |
- ①、函数xEventGroupClearBits()
将事件标志组中的指定事件位清零,此函数只能用在任务中,不能用在中断服务函数中!中断服务函数有其他的API函数。函数原型如下:
EventBits_txEventGroupClearBits(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear);
参数 |
描述 |
xEventGroup |
要操作的事件标志组的句柄。 |
uxBitsToClear |
要清零的事件位,比如要清除bit3的话就设置为0X08。可以同时清除多个bit,如设置为0X09的话就是同时清除bit3和bit0。 |
返回值 |
任何值:将指定事件位清零之前的事件组值。 |
- ②、函数xEventGroupClearBitsFromISR()
此函数为函数xEventGroupClearBits0的中断级版本,也是将指定的事件位(标志)清零。此函数用在中断服务函数中,此函数原型如下:
BaseType_t xEventGroupClearBitsFromISR(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear);
参数 |
描述 |
xEventGroup |
要操作的事件标志组的句柄。 |
uxBitsToClear |
要清零的事件位,比如要清除bit3的话就设置为0X08。可以同时清除多个bit,如设置为0X09的话就是同时清除bit3和bit0。 |
返回值 |
pdPASS:事件位清零成功。pdFALSE:事件位清零失败。 |
- ③、函数xEventGroupSetBits()
设置指定的事件位为1,此函数只能用在任务中,不能用于中断服务函数,此函数原型如下:
EventBits_t xEventGroupSetBits(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet);
参数 |
描述 |
xEventGroup |
要操作的事件标志组的句柄。 |
uxBitsToSet |
指定要置1的事件位,比如要将bit3值1的话就设置为0X08。可以同时将多个bit置1,如设置为0X09的话就是同时将bit3和bit0置1。 |
返回值 |
在将指定事件 置1后的事件组值。 |
- ④、函数xEventGroupSetBitsFromISR()
此函数也用于将指定的事件位置1,此函数是xEventGroupSetBits()的中断版本,用在中断服务函数中,函数原型如下:
BaseType_t xEventGroupSetBitsFromlSR(
EventGroupHandle_t xEventGroup
const EventBits_t uxBitsToSet,
BaseType_t* pxHigherPriorityTaskWoken);
参数 |
描述 |
XEventGroup |
要操作的事件标志组的句柄。 |
uxBitsToSet |
指定要置1的事件位,比如要将bit3值1的话就设置为0X08。可以同时将多个bit置1,如设置为0X09的话就是同时将bit3和bit0置1。 |
pxHigherPriorityTaskWoken |
标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。 |
返回值 |
pdPASS:事件位置1成功。pdFALSE:事件位置1失败。 |
3、获取事件标志组值
我们可以通过FreeRTOS提供的API函数来查询事件标准组值,FreeRTOS一共提供了两个这样的API函数,如下表所示:
函数 |
描述 |
xEventGroupGetBits() |
获取当前事件标志组的值(各个事件位的值),用在任务中。 |
xEventGroupGetBitsFromISR() |
获取当前事件标志组的值,用在中断服务函数中。 |
- ①、函数xEventGroupGetBits()
此函数用于获取当前事件标志组的值,也就是各个事件位的值。此函数用在任务中,不能用在中断服务函数中。此函数是个宏,真正执行的是函数xEventGroupClearBits(),函数原型如下:
EventBits_t xEventGroupGetBits(EventGroupHandle_t xEventGroup)
参数 |
描述 |
xEventGroup |
要获取的事件标志组的句柄 |
返回值 |
当前事件标志组的值 |
4、等待指定的事件位
某个任务可能需要与多个事件进行同步,那么这个任务就需要等待并判断多个事件位(标志),使用函数xEventGroupWaitBits()可以完成这个功能。调用函数以后如果任务要等待的事件位还没有准备好(置1或清零)的话任务就会进入阻塞态,直到阻塞时间到达或者所等待的事件
位准备好。函数原型如下:
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
const TickType_t xTicksToWait )
参数 |
描述 |
xEventGroup |
指定要等待的事件标志组。 |
uxBitsToWaitFor |
指定要等待的事件位,比如要等待bit0和(或)bit2的时候此参数就是0X05,如果要等待bit0和(或)bit1和(或)bit2的时候此参数就是0X07,以此类推 |
XClearOnExit |
此参数要是为pdTRUE的话,那么在退出此函数之前由参数uxBitsToWaitFor所设置的这些事件位就会清零。如果设置pdFALSE的话这些事件位就不会改变。 |
xWaitForAllBits |
此参数如果设置为pdTRUE的话,当uxBitsToWaitFor所设置的这些事件位都置1,或者指定的阻塞时间到的时候函数xEventGroupWaitBits()才会返回。当此函数为pdFALSE的话,只要uxBitsToWaitFor所设置的这些事件位其中的任意一个置1,或者指定的阻塞时间到的话函数xEventGroupWaitBits()就会返回。 |
xTicksToWait |
设置阻塞时间,单位为节拍数。 |
返回值 |
返回当所等待的事件位置1以后的事件标志组的值,或者阻塞时间到。根据这个值我们就知道哪些事件位置1了。如果函数因为阻塞时间到而返回的话这个返回值就不代表任何含义。 |
FreeRTOS事件标志组就介绍到这里啦!!!欢迎大家收看!!!