FreeRTOS中的事件组



一、什么是事件组

之前在FreeRTOS中学了队列和信号量,利用队列和信号量来传达信息,但是我们仔细思考一下,
1、如果单单只依靠队列或者信号量是不是只能唤醒一个任务?但是我需要同时唤醒达到条件的所有任务呢?
2、如果使用队列或者信号量是不是在使用之后就需要释放消息?但是我们希望使用之后还要唤醒其他事件呢?

所以这个时候我们就引入了事件组这个概念,那么什么是事件组呢?

  • 事件组可以看成一个整数,他的每一位bit可以看成一个事件,bit1表示事件发生了,bit0表示事件没有发生。
  • 一个或多个任务都可以去写这些位,也可以去读这些位。
  • 可以等待其中的某一位,也可以等待所有位
如果configUSE_16_BIT_TICK是1,那么就表示整数是16位,低8位是表示事件
如果configUSE_32_BIT_TICK是0,那么就表示整数是32位,低24位是表示事件

1、事件组函数

事件组的创建

 EventGroupHandle_t xEventGroupCreateStatic( EventGroupHandle_t * pxEventGroupBuffer );

在这里插入图片描述可以看到xEventGroupCreate(void)事件组创建函数,非NULL即为创建成功

设置事件

 EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );

其中参数是指哪个事件组?哪些位?
在这里插入图片描述

等待事件

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:等待那些位?
  • xClearOnExit:函数提出前是否需要清楚事件,如果是pdTRUE那就会清楚uxBitsToWaitFor指定的位,如果是pdFALSE就不会清除。
  • xTicksToWait:你希望阻塞的时间,可以设置为0,这里我们设置为成功才返回。

二、事件组的使用

1、 事件组之等待事件

任务函数

void Task1Function(void * param)
{
	volatile int i = 0;
	while (1)
	{
		for (i = 0; i < 100000; i++)
			sum++;
		xQueueSend(xQueueCalcHandle, &sum, 0);
		/* 设置事件0 */
		xEventGroupSetBits(xEventGroupCalc, (1<<0));
	}
}

void Task2Function(void * param)
{
	volatile int i = 0;
	while (1)
	{
		for (i = 0; i < 100000; i++)
			dec--;
		xQueueSend(xQueueCalcHandle, &dec, 0);
		/* 设置事件1 */
		xEventGroupSetBits(xEventGroupCalc, (1<<1));
	}
}
void Task3Function(void * param)
{
	int val1, val2;
	while (1)
	{
		/*等待事件  */
		xEventGroupWaitBits(xEventGroupCalc, (1<<0)|(1<<1), pdTRUE, pdTRUE, portMAX_DELAY);
	
		xQueueReceive(xQueueCalcHandle, &val1, 0);
		xQueueReceive(xQueueCalcHandle, &val2, 0);
		
		printf("val1 = %d, val2 = %d\r\n", val1, val2);
	}
}

主函数

xEventGroupCalc = xEventGroupCreate();
xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
xTaskCreate(Task3Function, "Task3", 100, NULL, 1, NULL);

将程序跑起来,我们可以观察到现象
在这里插入图片描述

2、事件组之同步点

我们举一个生活例子,做一道菜,是不是需要洗菜,煮饭,炒菜等等一系列步骤,只有等全部做完之后我们才能吃到香喷喷的白米饭。事件组之同步点就是这一概念

我们需要引入xEventGroupSync() 函数

EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
                             const EventBits_t uxBitsToSet,
                             const EventBits_t uxBitsToWaitFor,
                             TickType_t xTicksToWait )
  • xEventGroup:哪一个事件组
  • uxBitsToSet:需要设置哪些位
  • uxBitsToWaitFor:等待哪些位
  • xTicksToWait:需要等待的时间

在此直接引用官方提供的源程序进行分析

/* bit0: 洗菜
 * bit1: 生火
 * bit2: 炒菜
 */
#define TABLE    (1<<0)
#define BUYING   (1<<1)
#define COOKING  (1<<2)
#define ALL      (TABLE | BUYING | COOKING)
static void vCookingTask( void *pvParameters )
{
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );		
	int i = 0;
	
	/* 无限循环 */
	for( ;; )
	{
		/* 做自己的事 */
		printf("%s is cooking %d time....\r\n", (char *)pvParameters, i);
		
		/* 表示我做好了, 还要等别人都做好 */
		xEventGroupSync(xEventGroup, COOKING, ALL, portMAX_DELAY);
	
		/* 别人也做好了, 开饭 */
		printf("%s is eating %d time....\r\n", (char *)pvParameters, i++);
		vTaskDelay(xTicksToWait);
	}
}

static void vBuyingTask( void *pvParameters )
{
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );		
	int i = 0;
	
	/* 无限循环 */
	for( ;; )
	{
		/* 做自己的事 */
		printf("%s is buying %d time....\r\n", (char *)pvParameters, i);
		
		/* 表示我做好了, 还要等别人都做好 */
		xEventGroupSync(xEventGroup, BUYING, ALL, portMAX_DELAY);
	
		/* 别人也做好了, 开饭 */
		printf("%s is eating %d time....\r\n", (char *)pvParameters, i++);
		vTaskDelay(xTicksToWait);
	}
}

static void vTableTask( void *pvParameters )
{
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );		
	int i = 0;
	
	/* 无限循环 */
	for( ;; )
	{
		/* 做自己的事 */
		printf("%s is do the table %d time....\r\n", (char *)pvParameters, i);
		
		/* 表示我做好了, 还要等别人都做好 */
		xEventGroupSync(xEventGroup, TABLE, ALL, portMAX_DELAY);
	
		/* 别人也做好了, 开饭 */
		printf("%s is eating %d time....\r\n", (char *)pvParameters, i++);
		vTaskDelay(xTicksToWait);
	}
}

在这里插入图片描述
可以看到在任务中,分别写入自己的位,并且等待所有的位然后再执行任务。程序运行起来的结果和所说无差别。

总结

本文讲述了FreeRTOS中的事件组,以及事件组基本的使用。通过这两天的学习感觉FreeRTOS就是在调用别人写好的API函数,但是里面内核是如何实现的我一无所知,等将这门课过一遍之后再回过头来仔细研究一下实现的原理和过程。

  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值