FreeRTOS事件标志组
简介
事件的基本概念
事件是一种实现任务间通信的机制,主要用于实现任务间的同步,与信号量不同的是:事件通信只能传输事件是否发生,不能传递数据。而且事件可以实现一对多,多对多的同步。
一个任务可以等待多个事件的发送:可以是一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理,同样可以是多个任务同步多个事件
事件组的优点:多个事件的集合叫做事件组
通常编程时如果要定义一个标志位,最长用的类型是char类型,在STM32中,char类型要占用8位bit,可能我们用标志位只是用来1表示事件发生,0表示事件没有发生。使用8位比较浪费RAM空间,事件组可以很好的节省RAM空间。在FreeRTOS中事件组存储在一个EventBits_tl类型的变量中,这个变量还有一个宏来控制。
configUSE_16_BIT_TICKS 定义为 1 时变量uxEventBits为16位的,但是只能存储8个位来存储事件。
configUSE_16_BIT_TICKS 定义为 0 时变量uxEventBits为32位的,但是只能存储24个位来存储事件。
每一位代表一个事件,任务通过逻辑与或者逻辑或与一个或多个事件建立关联。
事件组特点
- 事件只与任务相关联,事件之间相互独立。
- 事件仅用于同步,不提供数据传输功能。
- 事件无排队性,多次设置一个事件(任务还没有读取走),等效于只设置一次
- 允许多个任务对同一事件进行读写操作
- 支持等待超时
事件应用场景
-
做标志位
用事件做标志位,用来标志某些情况是否发生。多个事件标志位可以组成事件组统一管理。
比如设备启动,有些需要进行一些列自检,当全部自检成功,设备才能启动正常,这时可以用事件作为自检成功或失败的标志位
事件运作机制
-
接收事件时,可以根据需要关注单个或多个事件类型,事件接收成功后可以选择是否清空事件标志位。
-
设置事件时,通过移位操作,对事件集合的对应事件位置1,可以同时写多个事件类型,设置事件成功后可能会出发任务调度。
-
清除事件时,根据传入参数事件句柄和待清除的事件类型,对事件对应为进行清0操作。
-
事件唤醒机制,当任务等待某个或者多个事件发生而进入阻塞态,当事件发生后任务进入就绪态,用户可以指定阻塞时间。
事件不与任务关联,事件之间相互独立,每一位表示一种事件类型,只有0或1两种情况。
事件函数接口讲解
事件控制块
/*------------------------------------------------------------------------------
如果宏 configUSE_16_BIT_TICKS 定义为 1,那么变量uxEventBits 就 是 16 位 的 ,
其 中 有 8 个 位 用来存储 事 件 组 , 如 果 宏configUSE_16_BIT_TICKS 定义为 0,
那么变量 uxEventBits 就是 32 位的,其中有 24 个位用来存储事件组
----------------------------------------------------------------------------------*/
EventGroupHandle_t Event_Handle =NULL;//定义事件组控制句柄
事件创建函数 xEventGroupCreate( )
/*-------------------------------------------------------------------------------
事件创建函数(动态),函数参数为空,返回值是一个EventGroupHandle_t类型的句柄
-----------------------------------------------------------------------------------*/
EventGroupHandle_t xEventGroupCreate( void );
//使用实例
static EventGroupHandle_t Event_Handle =NULL;//定义事件组句柄
Event_Handle = xEventGroupCreate();
if (NULL != Event_Handle)
printf("Event_Handle 事件创建成功!\r\n");
else
/* 创建失败,应为内存空间不足 */
事件删除函数 vEventGroupDelete( )
/*---------------------------------------------------------------------------------
事件删除函数,只有被创建成功的事件才能被删除,该函数不能用在中断里,当事件被删除后阻塞
在事件组上的任务或被解锁。
------------------------------------------------------------------------------------*/
使用实例:
static EventGroupHandle_t Event_Handle = NULL;
Event_Handle = xEventGroupCreate();
if(NULL!=Event_Handle)
{
printf("Event_Handle事件创建成功\r\n");
xEventGroupCreate(Event_Handle);//删除事件组
}
else
{
printf("Event_Handle事件创建失败\r\n");//空间不足,创建失败
}
事件组置位函数 xEventGroupSetBits()(任务)
/*---------------------------------------------------------------------------------
事件组置位函数,用于置位事件组中指定的位,当位被置为后,阻塞在该位上的任务将会被解锁。
该函数不能在中断中使用。
xEventGroup---事件句柄
xBitsToSet----指定事件中的事件标志位(设置为0X08只置位位3,设置为0X09则置位位3和位0)
返回值是事件组中的值
------------------------------------------------------------------------------------*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,const EventBits_t xBitsToSet );
#define KEY1_EVENT (0x01 << 0)//设置事件掩码的位 0
#define KEY2_EVENT (0x01 << 1)//设置事件掩码的位 1
if(key==1)//如果按键1按下
xEventGroupSetBits(Event_Handle,KEY1_EVENT);
if(key==2)//如果按键1按下
xEventGroupSetBits(Event_Handle,KEY2_EVENT);
事件组置位函数 xEventGroupSetBitsFromISR()(中断)
xEventGroupSetBitsFromISR()是 xEventGroupSetBits()的中断版本,用于置位事件组中
指定的位。置位事件组中的标志位是一个不确定的操作,因为阻塞在事件组的标志位上的
任务的个数是不确定的。FreeRTOS 是不允许不确定的操作在中断和临界段中发生的,所以
xEventGroupSetBitsFromISR()给 FreeRTOS 的守护任务发送一个消息,让置位事件组的操作
在守护任务里面完成,守护任务是基于调度锁而非临界段的机制来实现的。
等待事件函数 xEventGroupWaitBits( )
/*----------------------------------------------------------------------------------
等待事件函数
xEventGroup:事件句柄
uxBitsToWaitFor:一个按位或的值,指定需要等待事件组中的那些位置1
xClearOnExit:传入pdTURE时唤醒任务后,清除事件标志位;传入pdFALSE时,不清除事件标志位
xWaitForAllBits:传入pdTURE时-当指定位都置位后,才满足唤醒任务的条件。(逻辑与等待事件)
传入pdFALSE时-当指定位有一个置位后,即可满足唤醒任务的条件。(逻辑或等待事件)
xTicksToWait:超时等待时间。
返回值:返回事件中的哪些事件标志位被置位,返回值很可能并不是用户指定的事件位,需要对返回
值进行判断再处理。
-----------------------------------------------------------------------------------*/
EventBits_t xEventGroupWaitBits(const EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
清除事件组指定位函数 xEventGroupClearBits( )与 xEventGroupClearBitsFromISR( )
/*--------------------------------------------------------------------------------------
如果在获取事件的时候没有将对应的标志位清除,那么就需要用这个函数来进行显式清除,
EventGroupClearBits()函数不能在中断中使用,而是由具有中断保护功能的xEventGroupClearBitsFromISR()
来代替
xEventGroup:事件句柄
uxBitsToClear:指定事件组中的哪个位需要清除,如设置 uxBitsToSet 为0x08 则只清除位 3,如果设置
uxBitsToSet 为 0x09 则位 3 和位 0 都需要被清除。
返回值:事件在还没有清除指定位之前的值。
----------------------------------------------------------------------------------------*/
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );
BaseType_t xEventGroupClearBitsFromISR(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );