FreeRTOS学习七(事件标志组)

        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);
    }
}

结果:

结果分析:

  1. 等待事件组
  2. Bit1置位
  3. 事件组BIT1被检测到。当前事件组为0
  4. 等待事件组
  5. Bit2置位
  6. 事件组BIT2被检测到。当前事件组为0
  7. Bit0置位
  8. 事件组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));
        }

}

结果:

结果分析:

  1. 等待事件组
  2. BIT1被置位
  3. 事件组被检测到,此时事件组值为0x02.
  4. 检测是到BIT1
  5. 清零事件组值
  6. 重新等待

        从结果可以看,如果等待事件组的函数被设置为不清除,那就需要用户手动调用函数去清除事件组。

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值