????????RTOS中可以通过信号量来完成同步,但是信号量只能与单个的事件或任务进行同步。有时某个任务可能会需要与多个事件或任务进行同步,此时信号量就无法满足要求了。事件标志组就排上了用场。
事件位(事件标志)
????????事件位用来表明某个事件是否发生,事件位通常用于事件标志。比如有个事件需要处理,则将某个标志位置1。没有事件要处理,则置0.
事件组
????????一个事件组就是一组的事件位,事件组中的事件位通过位编号来访问。比如事件标志组的Bit0表示任务0需要处理,bit1表示任务1需要处理,bit2表示任务2需要处理。
????????事件标志组的事件标志位类型为EventBits。
typedef TickType_t EventBits_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
????????可以看到EventBits的类型是TickType,而TickType的类型根据configUSE_16_BIT_TICKS标志来,该标志位1时,TickType类型为uint16_t 。该标志位0时,TickType类型为uint32_t。EventBits的变量可以存储24个事件位,另外高8位有其他用。事件位0存放在变量的bit0上,变量的Bit1就是事件位1,以此类推。
1.xEventGroupCreate()创建事件标志组(动态内存)
此函数用于创建一个事件标志组,所需要的内存通过动态内存管理方法分配。
函数原型:
EventGroupHandle_t xEventGroupCreate( void )
参数:无
返回值:
NULL:创建失败
其他值:创建成功的事件标志组句柄
实例:
EventGroupHandle_t xCreatedEventGroup;
xCreatedEventGroup = xEventGroupCreate();
2.xEventGroupCreateStatic() 创建事件标志组(静态内存)
函数原型:
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )
参数:
pxEventGroupBuffer :参数指向一个StaticEventGroup_t类型的变量,用来保存事件标志组结构体
返回值:
NULL:失败
其他值:成功的时间标志组句柄
实例:
StaticEventGroup_t xEventGroupBuffer;xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
3.xEventGroupSetBits()将指定事件位置1
函数原型:
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION;
参数:
xEventGroup:要操作的事件标志组
uxBitsToSet :指定要置1的事件位,比如要将Bit3置1的话,就设置为0x08。可以同时将多个bit置1.
返回值:
任何值:在将指定事件置1后的事件组值
实例:
EventBits_t uxBits;
uxBits = xEventGroupSetBits(
xEventGroup, // The event group being updated.
BIT_0 | BIT_4 );// The bits being set.
4.xEventGroupSetBitsFromISR()中断中将指定事件位置1
函数原型:
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
参数:
xEventGroup:要操作的事件标志组
uxBitsToSet :指定要置1的事件位,比如要将Bit3置1的话,就设置为0x08。可以同时将多个bit置1.
pxHigherPriorityTaskWoken:标记退出此函数后是否进行任务切换。当设置为pdTRUE时,退出中断服务函数之前一定会进行一次任务切换。
返回值:
pdPASS:成功
pdFALSE:失败
实例:
xHigherPriorityTaskWoken = pdFALSE;
xResult = xEventGroupSetBitsFromISR(
xEventGroup, // The event group being updated.
BIT_0 | BIT_4 // The bits being set.
&xHigherPriorityTaskWoken );
5.xEventGroupClearBits()清除指定事件位
函数原型:
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
参数:
xEventGroup:要操作的时间标志组的句柄
uxBitsToClear :要清零的事件位。可以同时清除多个Bit
返回值:
任何值:将指定事件位清零之前的事件组值
实例:
EventBits_t uxBits;
uxBits = xEventGroupClearBits(
xEventGroup, // The event group being updated.
BIT_0 | BIT_4 );// The bits being cleared.
6.xEventGroupClearBitsFromISR()中断中清除指定事件位
函数原型:
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
参数:
xEventGroup:要操作的时间标志组的句柄
uxBitsToClear :要清零的事件位。可以同时清除多个Bit
返回值:
pdPASS:成功
pdFAIL:失败
实例:
xResult = xEventGroupClearBitsFromISR(
xEventGroup, // The event group being updated.
BIT_0 | BIT_4 ); // The bits being set.
7.xEventGroupGetBits()获取当前事件标志组值
函数原型:
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
参数:
xEventGroup :要获取的事件标志组的句柄
返回值:
当前标志组的值
实例:
EventBits_t xResult
xResult = xEventGroupGetBits(xEventGroup)
8.xEventGroupGetBitsFromISR()中断中获取当前事件标志组值
函数原型:
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) PRIVILEGED_FUNCTION;
参数:
xEventGroup :要获取的事件标志组的句柄
返回值:
当前标志组的值
实例:
EventBits_t xResult
xResult = xEventGroupGetBitsFromISR(xEventGroup)
9.xEventGroupWaitBits()等待时间标志位
????????某个任务可能需要与多个事件进行同步,那么这个任务就需要等待并判断多个事件位(标志)。调用该函数后如果任务要等待的事件位还没有准备好(置1或清零)的话,任务就会进入阻塞状态,直到阻塞时间到达或者所等待的时间位准备好。
函数原型:
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
参数:
xEventGroup:指定要等待的事件标志组
uxBitsToWaitFor:指定要等待的事件位。比如要等待bit0和(或)bit1,此参数为0x03
xClearOnExit:在退出此函数之前由参数uxBitsToWaitFor所设置的这些事件位是否清零。pdTRUE清零。pdFALSE不清零。
xWaitForAllBits:此参数为pdTRUE时,当uxBitsToWaitFor所设置的这些事件位都置1,或者指定的阻塞时间到的时候,才会返回。当为pdFALSE,只要uxBitsToWaitFor所设置的这些事件位其中的任意一个置1,或者指定的阻塞时间到,才返回。
xTicksToWait:设置阻塞时间
返回值:
????????返回当所等待的事件位置1以后的时间标志组的值,或阻塞时间到。根据这个值就知道哪些时间位置1了。如果函数因为阻塞时间到而返回的话,该返回值不代表任何含义。
实例:
EventBits_t uxBits;
uxBits = xEventGroupWaitBits(
xEventGroup, // The event group being tested.
BIT_0 | BIT_4, // The bits within the event group to wait for.
pdTRUE, // BIT_0 and 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 ) )
{
// bit0和bit4都被检测到
}
else if( ( uxBits & BIT_0 ) != 0 )
{
// bit0被检测到
}
else if( ( uxBits & BIT_4 ) != 0 )
{
// bit4被检测到
}
else
{
// 超时
}
代码验证:
????????创建3个任务,任务1创建一个1秒的周期定时器,在定时器回调中设置标志位bit0。任务2以1.5秒周期置标志位Bit1。任务3以1秒周期置标志位Bit2。任务1中等待标志位。等待到之后自动清除标志位。
任务1
#define BIT_0 ( 1 << 0 )
#define BIT_1 ( 1 << 1 )
#define BIT_2 ( 1 << 2 )
#define BIT_3 ( 1 << 3 )
EventGroupHandle_t xCreatedEventGroup;
void vTimerCallback( TimerHandle_t pxTimer )
{
configASSERT( pxTimer );
static uint32_t time_cnt = 0;
time_cnt++;
int32_t lArrayIndex = 0;
lArrayIndex = ( int32_t ) pvTimerGetTimerID( pxTimer );
LOG_I(common,"[DEBUG]:timer name:%stimer id:%d",pcTimerGetName(pxTimer),lArrayIndex);
if(lArrayIndex = timer_id)
{
LOG_I(common,"[DEBUG]:time cnt:%d",time_cnt);
LOG_I(common,"[TIMER]:BIT0 set");
xEventGroupSetBits(xCreatedEventGroup,BIT_0);
}
}
static void vTestTask1_H(void *pvParameters)
{
xCreatedEventGroup = xEventGroupCreate(); //创建事件组
xTimer_test = xTimerCreate("Test timer", /* Just a text name, not used by the kernel. */
(1000 / portTICK_PERIOD_MS), /* The timer period in ticks. */
pdTRUE, /* The timers will auto-reload themselves when they expire. */
(void *)timer_id, /* Assign each timer a unique id equal to its array index. */
vTimerCallback /* Each timer calls the same callback when it expires. */
);
if(xTimer_test == NULL)
{
LOG_I(common,"[TASK1]:Timer create fail"); //失败
}
else
{
LOG_I(common,"[TASK1]:Timer create sucess"); //成功
if( xTimerStart( xTimer_test, 0 ) != pdPASS )
{
LOG_I(common,"[TASK1]:Timer start fail"); //失败
}
}
EventBits_t uxBits;
while(1)
{
LOG_I(common,"[TASK1]:wait event group");
uxBits = xEventGroupWaitBits(
xCreatedEventGroup, // The event group being tested.
BIT_0 | BIT_1 | BIT_2 | BIT_3, // The bits within the event group to wait for.
pdTRUE, // BIT_0 and BIT_4 should be cleared before returning.
pdFALSE, // Don't wait for both bits, either bit will do.
portMAX_DELAY ); // Wait a maximum of 100ms for either bit to be set.
LOG_I(common,"[DEBUG]:event group,rst:%d",xEventGroupGetBits(xCreatedEventGroup));
if(uxBits & BIT_0)
{
LOG_I(common,"[DEBUG]:event group BIT0 get");
}
if(uxBits & BIT_1)
{
LOG_I(common,"[DEBUG]:event group BIT1 get");
}
if(uxBits & BIT_2)
{
LOG_I(common,"[DEBUG]:event group BIT2 get");
}
if(uxBits & BIT_3)
{
LOG_I(common,"[DEBUG]:event group BIT3 get");
}
}
任务2
static void vTestTask2_M(void *pvParameters)
{
while(1)
{
LOG_I(common,"[TASK2]:BIT1 set");
xEventGroupSetBits(xCreatedEventGroup,BIT_1);
vTaskDelay(1500);
}
}
任务3
static void vTestTask3_L(void *pvParameters)
{
while(1)
{
LOG_I(common,"[TASK3]:BIT2 set");
xEventGroupSetBits(xCreatedEventGroup,BIT_2);
vTaskDelay(500);
}
}
结果:
结果分析:
- 等待事件组
- Bit1置位
- 事件组BIT1被检测到。当前事件组为0
- 等待事件组
- Bit2置位
- 事件组BIT2被检测到。当前事件组为0
- Bit0置位
- 事件组BIT0检测到。当前事件组为0
????????从结果可以看到,因为等待事件组的函数设置了返回后清除标志位,所以每次在检测到事件组之后获取事件组,结果都是0.
将等待事件组参数设置为不清除,然后手动清除。
LOG_I(common,"[TASK1]:wait event group");
uxBits = xEventGroupWaitBits(
xCreatedEventGroup, // The event group being tested
BIT_0 | BIT_1 | BIT_2 | BIT_3, // The bits within the event group to wait for.
pdFALSE, // BIT_0 and BIT_4 should be cleared before returning.
pdFALSE, // Don't wait for both bits, either bit will do
portMAX_DELAY ); // Wait a maximum of 100ms for either bit to be set.
LOG_I(common,"[DEBUG]:event group,rst:%d",xEventGroupGetBits(xCreatedEventGroup));
if(uxBits & BIT_0)
{
LOG_I(common,"[DEBUG]:event group BIT0 get");
xEventGroupClearBits(xCreatedEventGroup,BIT_0);
LOG_I(common,"[DEBUG]:event group BIT0 clean,rst:%d",xEventGroupGetBits(xCreatedEventGroup));
}
if(uxBits & BIT_1)
{
LOG_I(common,"[DEBUG]:event group BIT1 get");
xEventGroupClearBits(xCreatedEventGroup,BIT_1);
LOG_I(common,"[DEBUG]:event group BIT1 clean,rst:%d",xEventGroupGetBits(xCreatedEventGroup));
}
if(uxBits & BIT_2)
{
LOG_I(common,"[DEBUG]:event group BIT2 get");
xEventGroupClearBits(xCreatedEventGroup,BIT_2);
LOG_I(common,"[DEBUG]:event group BIT2 clean,rst:%d",xEventGroupGetBits(xCreatedEventGroup));
}
if(uxBits & BIT_3)
{
LOG_I(common,"[DEBUG]:event group BIT3 get");
xEventGroupClearBits(xCreatedEventGroup,BIT_3);
LOG_I(common,"[DEBUG]:event group BIT3 clean,rst:%d",xEventGroupGetBits(xCreatedEventGroup));
}
}
结果:
结果分析:
- 等待事件组
- BIT1被置位
- 事件组被检测到,此时事件组值为0x02.
- 检测是到BIT1
- 清零事件组值
- 重新等待
????????从结果可以看,如果等待事件组的函数被设置为不清除,那就需要用户手动调用函数去清除事件组。
?
?
|