FreeRTOS的事件标志组

描述

之前介绍了使用信号量来完成同步,但是使用信号量来同步的话,任务只能与单个的事件或任务进行同步。有时候某个任务可能会需要与多个事件或任务进行同步,此时信号量就无能为力了。FreeRTOS 提供了一个可选的解决方法,那就是事件标志组。

事件标志位可以理解为一个Bit位,多个事件位就组成了事件标志组,FreeRTOS可选8个事件标志位或者24个事件标志位,具体是由configUSE_16_BIT_TICKS来确定,它为1的时候是8个标准位,为0时是24个标志位!

创建标志组

EventGroupHandle_t xEventGroupCreate( void );

返回值:

创建失败返回NULL,创建成功返回句柄

置位API函数

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
                                 const EventBits_t uxBitsToSet );

参数:

xEventGroup:需要操作的事件标志组的句柄

uxBitsToSet:写入数值,例如0x09就表示置位第0位和第三位

读取事件组的位

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

参数:

xEventGroup:事件标志组的句柄

uxBitsToWaitFor:需要等待的标志位

xClearOnExit:是否需要清除标志位

xWaitForAllBits:是否等待所有设定标志位

xTicksToWait:最大等待时间

注意:更多API函数,请参考官方相关

附上简单使用应用

#include "stm32f10x.h"
#include 
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"


#define START_TASK_PRIO 1      //任务优先级
#define START_STK_SIZE 128      //任务堆栈大小
TaskHandle_t StartTask_Handler;   //任务句柄
void start_task(void *pvParameters);//任务函数


#define LED0_TASK_PRIO 2       //任务优先级
#define LED0_STK_SIZE 50       //任务堆栈大小
TaskHandle_t LED0Task_Handler;     //任务句柄
void led0_task(void *p_arg);     //任务函数


EventGroupHandle_t Event_Handle = NULL;//事件标志组的句柄


void LED_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;        //定义结构体变量

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);  //开启时钟

  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;            //选择你要设置的IO口
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;      //设置推挽输出模式
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;     //设置传输速率
  GPIO_Init(GPIOC,&GPIO_InitStructure);                //初始化GPIO

  GPIO_SetBits(GPIOC,GPIO_Pin_0);             //将LED端口拉高,熄灭LED
}


int main( void ) 
{
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4
  LED_Init(); //初始化 LED
  //创建任务标志组
  Event_Handle = xEventGroupCreate();
  //置位标志位
  xEventGroupSetBits( ( EventGroupHandle_t) Event_Handle,
            ( EventBits_t )       0x08       );

  //创建开始任务
  xTaskCreate(
    (TaskFunction_t )start_task,     //任务函数
    (const char* )"start_task",     //任务名称
    (uint16_t )START_STK_SIZE,       //任务堆栈大小
    (void* )NULL,             //传递给任务函数的参数
    (UBaseType_t )START_TASK_PRIO,     //任务优先级
    (TaskHandle_t* )&StartTask_Handler  //任务句柄 
  );
  vTaskStartScheduler();  //开启调度
}
//开始任务函数
void start_task(void *pvParameters)
{
  taskENTER_CRITICAL();   //进入临界区
  //创建 LED0 任务
  xTaskCreate(
    (TaskFunction_t )led0_task, 
    (const char* )"led0_task", 
    (uint16_t )LED0_STK_SIZE, 
    (void* )NULL,
    (UBaseType_t )LED0_TASK_PRIO,
    (TaskHandle_t* )&LED0Task_Handler
  );
  vTaskDelete(StartTask_Handler); //删除开始任务
  taskEXIT_CRITICAL();   //退出临界区
}


//LED0 任务函数
void led0_task(void *pvParameters)
{
  while(1)
  {
    xEventGroupWaitBits( ( EventGroupHandle_t ) Event_Handle,  //句柄
               ( EventBits_t        ) 0x08,      //需要等待的位
               ( BaseType_t         ) pdTRUE ,    //需要清零
               ( BaseType_t         ) pdTRUE,      //等待所有设定标志位
               ( TickType_t         ) portMAX_DELAY );//死等待

    if(GPIO_ReadInputDataBit( GPIOC, GPIO_Pin_0))
    {
      GPIO_ResetBits( GPIOC, GPIO_Pin_0);
    }
    else
    {
      GPIO_SetBits( GPIOC, GPIO_Pin_0);
    }
    //置位标志位
    xEventGroupSetBits( ( EventGroupHandle_t) Event_Handle,
              ( EventBits_t )       0x08         );

    vTaskDelay(400);
  }
}

注意:如果LED0任务中的置位函数,那么LED0函数只会运行一次,因为标志位已经清除了,需要再次置位标志位才会继续运行!

--END--

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分