FreeRTOS事件标志组

       事件标志组与信号量一样属于任务间同步的机制,但是信号量一般用于任务间的单事件同 步,对于任务间的多事件同步,仅使用信号量就显得力不从心了。FreeRTOS 提供的事件标志组 可以很好的处理多事件情况下的任务同步。
FreeRTOS 事件标志组简介
1. 事件标志 
       事件标志是一个用于指示事件是否发生的布尔值,一个事件标志只有 0 或 1 两种状态, FreeRTOS 将多个事件标志储存在一个变量类型为 EventBits_t 变量中,这个变量就是事件组。   
2. 事件组 
       事件组是一组事件标志的集合,一个事件组就包含了一个 EventBites_t 数据类型的变量, 变量类型 EventBits_t 的定义如下所示:

         从上面可以看出,EventBits_t 实际上是一个 16 位或 32 位无符号的数据类型。当 configUSE_16_BIT_TICKS 配置为 0 时,EventBits_t 是一个 32 位无符号的数据类型;当 configUSE_16_BIT_TICKS 配置为 1 时,EventBits_t 是一个 16 为无符号的数据类型。在本套教 程的所有配套例程中,都将配置项 configUSE_16_BIT_TICKS 配置为 0,因此本文就以 EventBits_t 为 32 位无符号数据类型为例进行讲解,对于另外一种情况,也是大同小异的。

         虽然说使用了 32 位无符号的数据类型变量来存储事件标志,但这并不意味着,一个 EventBits_t 数据类型的变量能够存储 32 个事件标志,FreeRTOS 将这个 EventBits_t 数据类型的 变量拆分成两部分,其中低 24 位[23:0](configUSE_16_BIT_TICKS 配置位 1 时,是低 8 位[7:0]) 用于存储事件标志,而高 8 位[31:24](configUSE_16_BIT_TICKS 配置位 1 时,依然是高 8 位 [15:8])用作存储事件标志组的一些控制信息,也就是说一个事件组最多可以存储 24 个事件标 志。EventBits_t 数据类型变量的位使用情况如下图所示:

       从上图中可以看到,变量中低 24 位中的每一位都是一个事件标志,当某一位被置一时,就 表示这一位对应的事件发生了。

FreeRTOS 事件标志组相关 API 函数

     FreeRTOS 提供了事件标志组的一些相关操作函数,如下表所示:

1. 创建事件标志组
        FreeRTOS 提供了两种创建事件标志组的方式,分别为动态方式创建事件标志组和静态方 式创建事件标志组,两者的区别在于静态方式创建事件标志组时,需要用户提供创建事件标志 组所需的内存空间,而使用动态方式创建事件标志组时,FreeRTOS 会自动从 FreeRTOS 管理的 堆中分配创建事件标志组所需的内存空间。
       动态方式创建事件标志组 API 函数的函数原型如下所示:
      函数 xEventGroupCreate()的形参描述,如下表所示:
2. 删除事件标志组
      FreeRTOS 提供了用于删除事件标志组的 API 函数,函数原型如下所示:
     函数 vEventGroupDelete()的形参描述,如下表所示:
3. 等待事件标志位
      等待事件标志位使用的是函数 xEventGroupWaitBits(),其函数原型如下所示:
      函数 xEventGroupWaitBits()的形参描述,如下表所示:
4. 设置事件标志位
         FreeRTOS 提供了两个用于设置事件标志位的 API 函数,这个两个函数分别用于在任务和 在中断中设置事件标志位。
        在任务中设置事件标志位 API 函数的函数原型如下所示:
        函数 xEventGroupSetBits()的形参描述,如下表所示:
5. 清零事件标志位
       FreeRTOS 提供了两个用于清零事件标志位的 API 函数,这个两个函数分别用于在任务和 在中断中清零事件标志位。
       在任务中清零事件标志位 API 函数的函数原型如下所示:
      函数 xEventGroupClearBits()的形参描述,如下表所示:
      函数 xEventGroupClearBits()的返回值,如下表所示:
6. 获取事件组中事件标志位的值
       FreeRTOS 提供了两个用于获取事件组中事件标志位值的 API 函数,这个两个函数分别用 于在任务和在中断中获取事件组中事件标志位的值。
      在任务中获取事件组中事件标志位值 API 函数的函数原型如下所示:
      函数 xEventGroupGetBits()的形参描述,如下表所示:
7. 函数 xEventGroupSync()
         此函数一般用于多任务同步,其中每个任务都必须等待其他任务达到同步点,然后才能继续执行。函数 xEventGroupSync()的函数原型如下所示:
        函数 xEventGroupSync()的形参描述,如下表所示:
FreeRTOS 事件标志组实验
       首先是事件标志组的定义:
#define EVENTBIT_0 (1<<0)
#define EVENTBIT_1 (1<<1)
#define EVENTBIT_2 (1<<2)
#define EVENTBIT_ALL (EVENTBIT_0|EVENTBIT_1|EVENTBIT_2)

       然后在start任务中进行事件标志组的创建:

EventGroupHandle_t EventGroupHandler;

void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();    
    
    EventGroupHandler = xEventGroupCreate();
    
    xTaskCreate((TaskFunction_t )counter_task,            
              (const char*    )"counter_task",          
              (uint16_t       )COUNTER_STK_SIZE,        
              (void*          )NULL,                  
              (UBaseType_t    )COUNTER_TASK_PRIO,       
              (TaskHandle_t*  )&CounterTask_Handler);

    xTaskCreate((TaskFunction_t )api_task,            
              (const char*    )"api_task",          
              (uint16_t       )API_STK_SIZE,        
              (void*          )NULL,                  
              (UBaseType_t    )API_TASK_PRIO,       
              (TaskHandle_t*  )&ApiTask_Handler);
    
    xTaskCreate((TaskFunction_t )led_green_task,            
              (const char*    )"led_green_task",          
              (uint16_t       )LED_GREEN_STK_SIZE,        
              (void*          )NULL,                  
              (UBaseType_t    )LED_GREEN_TASK_PRIO,       
              (TaskHandle_t*  )&LedGreenTask_Handler);

    xTaskCreate((TaskFunction_t )led_red_task,            
              (const char*    )"led_red_task",          
              (uint16_t       )LED_RED_STK_SIZE,        
              (void*          )NULL,                  
              (UBaseType_t    )LED_RED_TASK_PRIO,       
              (TaskHandle_t*  )&LedRedTask_Handler);     
    
    xTaskCreate((TaskFunction_t )ws2812b_task,            
              (const char*    )"ws2812b_task",          
              (uint16_t       )WS2812B_STK_SIZE,        
              (void*          )NULL,                  
              (UBaseType_t    )WS2812B_TASK_PRIO,       
              (TaskHandle_t*  )&Ws2812bTask_Handler);     
                                                
    vTaskDelete(StartTask_Handler);    
                            
    taskEXIT_CRITICAL();
}

然后在led闪烁以及在ws2812b任务中进行事件标志组的中事件置位:

void led_green_task(void *pvParameters)
{
    unsigned char led_green_on_flag = 0;
    
    while(1)
    {
        if(led_green_on_flag)
        {
             LED_GREEN_ON;    
       xEventGroupSetBits( (EventGroupHandle_t )EventGroupHandler, (EventBits_t )EVENTBIT_0);        
            
        }else
        {    
             LED_GREEN_OFF;     
        }
        
        led_green_on_flag = ~led_green_on_flag;
        vTaskDelay(500);
    }
}

void led_red_task(void *pvParameters)
{
    unsigned char led_red_on_flag = 0;
    
    while(1)
    {
        if(led_red_on_flag)
        {
             LED_RED_ON;
        }else
        {
             xEventGroupSetBits( (EventGroupHandle_t )EventGroupHandler, (EventBits_t )EVENTBIT_1);    
             LED_RED_OFF;
        }    
        
        led_red_on_flag = ~led_red_on_flag;
        
        vTaskDelay(2000);
    }
}

void ws2812b_task(void *pvParameters)
{
    unsigned char ws2812b_change_flag = 0;
    
    while(1)
    {
         if(ws2812b_change_flag)
         {
              ws2812b_write_rgb(0, 20, 0);
              xEventGroupSetBits( (EventGroupHandle_t )EventGroupHandler, (EventBits_t )EVENTBIT_2);    
             
         }else
         {
              ws2812b_write_rgb(0, 0, 0);
         }
         
         ws2812b_change_flag = ~ws2812b_change_flag;
         
         vTaskDelay(3000);
    }
}

最后在api任务以及counter任务中分别进行事件标志组的触发实验以及获取事件标志位实验:

void api_task(void *pvParameters)
{    
     while(1)
     {    
         xEventGroupWaitBits( (EventGroupHandle_t )EventGroupHandler,
                           (EventBits_t )EVENTBIT_ALL,
                           (BaseType_t )pdTRUE,
                           (BaseType_t )pdTRUE,
                               (TickType_t )portMAX_DELAY);
         
         taskENTER_CRITICAL();
         printf("\r\n三个事件全部触发!\r\n");
         taskEXIT_CRITICAL();    
         
         vTaskDelay(20);
     }
}


EventBits_t event_val_current = 0;
EventBits_t event_val_last = 0;
void counter_task(void *pvParameters)
{
    while(1)
    {
          
          event_val_current =  xEventGroupGetBits((EventGroupHandle_t)EventGroupHandler);
                 
          if(event_val_current != event_val_last)
            {
                  event_val_last = event_val_current;
                    taskENTER_CRITICAL();
                    printf("\r\n当前的事件标志数量为:º%d.\r\n", (unsigned char)event_val_current);
                    taskEXIT_CRITICAL();
            }


            vTaskDelay(10);
    }
}

下载验证:

补充:注释掉事件标志组触发逻辑:

NOTE:可以看到当前的事件标志都处于置位状态,0B 0000 0111 = 7

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

moon2shine

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值