FreeRTOS——事件标志组

一、事件标志组

        前面所介绍的队列、信号量,只能实现与单个任务进行同步。而有时候某个任务可能需要与多个事件或任务进行同步,此时,事件标志组的作用就凸显出来

1.1 事件标志组简介

事件标志位:用一个位,来表示事件是否发生

事件标志组:一组事件标志位的集合, 可以简单的理解事件标志组,就是一个(16/32)整数

事件标志组是一种实现任务/中断间通信的机制,主要用于实现多任务间的同步

根据configUSE_16_BIT_TICKS 的宏定义不同,每个事件标志组的位数也就不同

        虽然使用了 32 位无符号的数据类型变量来存储事件标志, 但其中的8用作存储事件标志组的控制信息,低24位用作存储事件标志 ,所以说一个事件组最多可以存储 24 个事件标志

        可以发现,事件标志组与外设的状态寄存器SR非常类似,每一位都代表一个事件是否发生(高8位除外) 

1.2 事件标志组与队列、信号量的区别

此外:设置事件不会阻塞等待事件标志支持阻塞 

 

二、事件组结构体

typedef struct EventGroupDef_t
{
    EventBits_t uxEventBits;
    List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */

    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxEventGroupNumber;
    #endif

    /* 如果事件组是静态分配,则设置为pdTURE,以确保不尝试释放内存 */
    #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
        uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
    #endif
} EventGroup_t;
成员说明
uxEventBits

EventBits_t类型的变量,其中,

高八位:事件标志组的控制信息

剩余位:存储事件标志(1:发生;2:未发生)

xTasksWaitingForBits链表,等待事件标志位的任务的链表

三、相关API

函数

描述

xEventGroupCreate()

使用动态方式创建事件标志组

xEventGroupCreateStatic()

使用静态方式创建事件标志组

xEventGroupClearBits()

清零事件标志位

xEventGroupClearBitsFromISR()

在中断中清零事件标志位

xEventGroupSetBits()

设置事件标志位

xEventGroupSetBitsFromISR()

在中断中设置事件标志位

xEventGroupWaitBits()

等待事件标志位

xEventGroupSync()

设置事件标志位,并等待事件标志位

2.1 动态创建事件组

使用条件:configSUPPORT_DYNAMIC_ALLOCATION必须在 FreeRTOSConfig.h 中设置为 1,或保留未定义状态(此时默认为 1)

EventGroupHandle_t    xEventGroupCreate ( void ) ; 

返回值

描述

NULL

事件标志组创建失败

句柄

事件标志组创建成功

2.1.1 函数详解


#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )

    EventGroupHandle_t xEventGroupCreate( void )
    {
        /* 创建一个事件标志组结构体指针:pxEventBits */
        EventGroup_t * pxEventBits;


        /* 申请结构体空间,并将首地址赋给指针变量:pxEventBits */
        pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); 


        /* 申请成功 */
        if( pxEventBits != NULL )
        {
            /* 将结构体中的时间标志组变量初始化为0*/
            pxEventBits->uxEventBits = 0;

            /* 初始化等待任务链表 */
            vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );

            #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
            {
               
                pxEventBits->ucStaticallyAllocated = pdFALSE;
            }
            #endif /* configSUPPORT_STATIC_ALLOCATION */

            traceEVENT_GROUP_CREATE( pxEventBits );
        }


        /* 申请失败 */
        else
        {

            traceEVENT_GROUP_CREATE_FAILED(); 
        }

        /* 返回结构体的地址 */
        return pxEventBits;
    }

 2.1.2 函数实现总结

(1)创建一个时间标志组的结构体指针变量

(2)申请内存空间

        成功:将事件标志组变量初始化为0,并初始化等待事件标志任务列表

        失败:定义但未实现的宏

(3)返回:事件标志组的结构体指针变量

2.2 清除事件标志位

EventBits_t  xEventGroupClearBits( EventGroupHandle_t 	xEventGroup,				                                  
                                   const EventBits_t 	uxBitsToClear ) 

形参

描述

xEventGroup

待操作的事件标志组句柄

uxBitsToSet

待清零的事件标志位

返回值

描述

整数

清零事件标志位之前事件组中事件标志位的值

注:要清零的事件标志位,可以是一位,也可以是多位

0x08: 清除bit3

0x09:清除bit3和bit0

 2.3 设置事件标志位

EventBits_t   xEventGroupSetBits(  EventGroupHandle_t 	xEventGroup,					  
                                   const EventBits_t 		uxBitsToSet    ) 

形参

描述

xEventGroup

待操作的事件标志组句柄

uxBitsToSet

待设置的事件标志位 

返回值

描述

整数

函数返回时,事件组中的事件标志位值

注:要设置的事件标志位,可以是一位,也可以是多位

0x08: 设置bit3

0x09:设置bit3和bit0

2.4 获取事件标志组值

 

2.5 等待事件标志位

等待事件标志组的某些位被设置,选择性的进入阻塞状态,中断中无法调用此函数

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

形参

描述

xEvenrGroup

等待的事件标志组句柄

uxBitsToWaitFor

等待的事件标志位,可以用逻辑或等待多个事件标志位

xClearOnExit

成功等待到事件标志位后,清除事件组中对应的事件标志位,

                pdTRUE  :清除uxBitsToWaitFor指定位;

                pdFALSE:不清除

xWaitForAllBits

等待 uxBitsToWaitFor 中的所有事件标志位(逻辑与)

pdTRUE:等待的位,全部为1     逻辑与

pdFALSE:等待的位,某个为1   逻辑或

xTicksToWait

等待的阻塞时间

返回值

描述

等待的事件标志位值

等待事件标志位成功,返回所等待到的事件标志位置1的事件标志组的值

其他值

等待事件标志位失败,返回事件组中的事件标志位

2.4.1 函数详解

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

    /**
      * uxReturn:返回值(32位时间标志组变量)
      * uxControlBits:记录控制位信息(高八位)
      * xWaitConditionMet:记录等待条件是否已满足
      * xAlreadyYielded:记录调度器的状态
    */
    EventGroup_t * pxEventBits = xEventGroup;
    EventBits_t uxReturn, uxControlBits = 0;
    BaseType_t xWaitConditionMet, xAlreadyYielded;
    BaseType_t xTimeoutOccurred = pdFALSE;


    /* 检查用户没有去尝试等待内核本身使用的位(高8位),并且至少请求了一个位(低24位)。*/
    configASSERT( xEventGroup );
    configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 );
    configASSERT( uxBitsToWaitFor != 0 );

    #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
    {
        configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
    }
    #endif


    /* 挂起调度器 */
    vTaskSuspendAll();
    {
        /* 取出结构体的32位变量,赋值给uxCurrentEventBits
        const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;

        /* 检查是否以满足等待条件 */
        xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );


         /* 等待条件已满足 */
        if( xWaitConditionMet != pdFALSE )
        {
            
            /* 将32变量赋给uxReturn,并将等待时间设置为0 */
            uxReturn = uxCurrentEventBits;
            xTicksToWait = ( TickType_t ) 0;

            /* 判断是否需要清除标志位 */
            if( xClearOnExit != pdFALSE )
            {
                pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }

        /* 等待条件不满足,并且未设置等待时间 */
        else if( xTicksToWait == ( TickType_t ) 0 )
        {
            /* 返回当前32位变量,并将超时标志置为:pdTURE */
            uxReturn = uxCurrentEventBits;
            xTimeoutOccurred = pdTRUE;
        }

        /* 等待条件不满足 */
        else
        {
        
            /* 需要清除标志位,将第25位置1 */
            if( xClearOnExit != pdFALSE )
            {
                uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }

            
            /* 需要等待所有标志位 or 至少一个标志位,将第26位置1 */
            if( xWaitForAllBits != pdFALSE )
            {
                uxControlBits |= eventWAIT_FOR_ALL_BITS;
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }


            
            /* 此函数的功能:
            ** (1)控制位 | 等待的事件标志位 的结果,赋给列表项的值(用于升序排列)
            ** (2)将任务添加到等待事件组的列表中
            ** (3)将任务添加到阻塞列表中,任务进入阻塞状态
            */
            vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );

            /* 返回值赋为0 */
            uxReturn = 0;

            traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
        }
    }


    /* 恢复调度器 */
    xAlreadyYielded = xTaskResumeAll();

    if( xTicksToWait != ( TickType_t ) 0 )
    {
        if( xAlreadyYielded == pdFALSE )
        {
            portYIELD_WITHIN_API();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* The task blocked to wait for its required bits to be set - at this
         * point either the required bits were set or the block time expired.  If
         * the required bits were set they will have been stored in the task's
         * event list item, and they should now be retrieved then cleared. */
        uxReturn = uxTaskResetEventItemValue();

        if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
        {
            taskENTER_CRITICAL();
            {
                /* The task timed out, just return the current event bit value. */
                uxReturn = pxEventBits->uxEventBits;

                /* It is possible that the event bits were updated between this
                 * task leaving the Blocked state and running again. */
                if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
                {
                    if( xClearOnExit != pdFALSE )
                    {
                        pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }

                xTimeoutOccurred = pdTRUE;
            }
            taskEXIT_CRITICAL();
        }
        else
        {
            /* The task unblocked because the bits were set. */
        }

        /* The task blocked so control bits may have been set. */
        uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
    }

    traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );

    /* Prevent compiler warnings when trace macros are not used. */
    ( void ) xTimeoutOccurred;

    return uxReturn;
}

2.6 同步函数

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

形参

描述

xEventGroup

等待事件标志所在事件组

uxBitsToSet

达到同步点后,要设置的事件标志

uxBitsToWaitFor

等待的事件标志

xTicksToWait

等待的阻塞时间,等待uxBitsToWaitFor参数值指定的 所有位设置完成的最长时间 

返回值

描述

等待的事件标志位值

等待事件标志位成功,返回等待到的事件标志位

其他值

等待事件标志位失败,返回事件组中的事件标志位

特点:通过设置某一位或多位(uxBitsToSet) ,等待标志位(uxBitsToWaitFor),即设置了uxBitsToSet,还需要等待uxBitsToWaitFor被设置才可以进行后续操作

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值