FreeRTOS事件标志组

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

0x01 事件标志组

事件标志组的数据类型为EventGroupHandle_t,当configUSE_16_BIT_TICKS为1的时候,事件标志组可以存储8个事件位,当configUSE_16_BIT_TICKS设置为0的时候,可以存储24个事件位。事件0存在在bit0上,EventGroupHandle_t变量的位1就是事件1。

0x02 创建事件标志组

FreeRTOS提供了两个用于创建事件标志组的函数

  • xEventGroupCreate():使用动态方法创建事件标志组
  • xEventGroupCreateStatic():使用静态方法创建事件标志组
EventGroupHandle_t xEventGroupCreate( void );
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer );

pxEventGroupBuffer :保存事件标志组结构体
xEventGroupCreate所需要的内存通过动态内存管理方法分配,当configUSE_16_BIT_TICKS为1的时候,事件标志组可以存储8个事件位(bit0-bit7),当configUSE_16_BIT_TICKS设置为0的时候,可以存储24个事件位(bit0-bit23)。

xEventGroupCreateStatic所需要的内存用户自己分配

0x03 设置事件位

FreeRTOS提供了4个函数用来设置事件标志组中事件位,事件位的设置包括清零和置1两种操作

  • xEventGroupClearBits():将指定的事件位清零,用在任务中

  • xEventGroupClearBitsFromISR():将指定的事件位清零,用在中断服务中

  • xEventGroupSetBits():将指定的事件位置1,用在任务中

  • xEventGroupSetBitsFromISR():将指定的事件位置1,用在中断中

EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
  • EventGroupHandle_t xEventGroup:要操作的时间标志组的句柄
  • EventBits_t uxBitsToClear:要清零的事件位,比如要清除bit3的话就设置0x08,可以同时清除多个位,如设置0x09,就同时清除bit3和bit0
	BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )

  • EventGroupHandle_t xEventGroup:要操作的时间标志组的句柄
  • EventBits_t uxBitsToClear:要清零的事件位,比如要清除bit3的话就设置0x08,可以同时清除多个位,如设置0x09,就同时清除bit3和bit0
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
  • EventGroupHandle_t xEventGroup:要操作的事件标志组的句柄
  • EventBits_t uxBitsToSet:指定要置1的事件位,比如要置bit3为1的话就设置0x08,可以同时设置多个位,如设置0x09,就同时置bit3和bit0为1
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken )
  • EventGroupHandle_t xEventGroup:要操作的事件标志组的句柄
  • EventBits_t uxBitsToSet:指定要置1的事件位,比如要置bit3为1的话就设置0x08,可以同时设置多个位,如设置0x09,就同时置bit3和bit0为1
  • BaseType_t *pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任务切换,传入pdTRUE在退出中断函数之前一定进行一次任务切换
0x04 获取事件标志组值

FreeRTOS提供了两个API函数用来查询事件标志组值。

  • xEventGroupGetBits():获取当前事件标志组的值(各个事件位的值),用在任务中
  • xEventGroupGetBitsFromISR():获取当前事件标志组的值,用在中断服务函数中
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup );
  • EventGroupHandle_t xEventGroup :要获取的事件标志组的句柄
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
  • EventGroupHandle_t xEventGroup :要获取的事件标志组的句柄
0x05 等待指定的事件位

某个任务可能需要与多个事件进行同步,那么这个任务就需要等待并判断多个事件位,FreeRTOS提供xEventGroupWaitBits()完成这个功能。如果任务要等待的事件位还没有准备好,任务就会进入阻塞态。

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
  • EventGroupHandle_t xEventGroup:指定要等待的时间标志组
  • EventBits_t uxBitsToWaitFor:指定要等待的事件位,比如要等待bit0和bit2的时间此参数就是0x05
  • const BaseType_t xClearOnExit:此参数为pdTRUE的话,那么在退出此函数之前由参数uxBitsToWaitFor指定的这些事件位就会清零,如果设置为pdFALSE的话,这些事件位就不会改变。
  • const BaseType_t xWaitForAllBits:此参数如果设置为pdTRUE的话,当uxBitsToWaitFor所设置的这些事件为都置1,或者指定的阻塞时间到的时候xEventGroupWaitBits函数才会返回,当设置为pdFALSE的话,只要uxBitsToWaitFor所设置的这些事件位其中的任意一个置1,或者指定的阻塞时间到的话,函数xEventGroupWaitBits就会返回
  • TickType_t xTicksToWait :设置阻塞时间,单位为节拍数

返回值:
返回当前所等待事件位置1以后的事件标志组的值,或者阻塞时间到,根据这个值,我们就知道哪些事件位置1了,如果函数因为阻塞时间到返回的话,那么这个返回值就不代表任何的含义。

实验

设计四个任务:
start_task:用来创建其他三个任务和事件标志组
eventsetbit_task:读取按键值,根据不同的按键值将事件标志组中相应的事件位置1,用来模拟事件的发生
eventgroup_task:同时等待事件标志组中的多个事件位,当这些事件位都置1的话就将其显示到LCD上,并且也通过串口打印出来

start_task代码:

void start_task(void *pvParameter)
{
	taskENTER_CRITICAL();
	EventGroup_Handler=xEventGroupCreate();
	xTaskCreate(eventsetbit_task,"eventsetbit_task",256,NULL,2,&EventSetBit_Handler);
	xTaskCreate(eventgroup_task,"eventgroup_task",256,NULL,4,&EventGp_Handler);
	xTaskCreate(eventquery_task,"eventquery_task",256,NULL,3,&EventQuery_Handler);
	
	vTaskDelete(StartTask_Handler);
	taskEXIT_CRITICAL();
}

创建三个任务和一个事件状态标志组

void eventsetbit_task(void *pvParameter)
{
	u8 key;
	while(1)
	{
		if(EventGroup_Handler!=NULL)
		{
			key = KEY_Scan(0);
			switch(key)
			{
				case KEY1_PRES:
					xEventGroupSetBits(EventGroup_Handler,2);
					break;
				case WKUP_PRES:
					xEventGroupSetBits(EventGroup_Handler,4);
					break;
			}
			
		}
		vTaskDelay(10);
		
	}
}

eventsetbit_task检查KEY1和KEY_UP有无按下,KEY1按下将bit1设置为1,KEY_UP按下将bit2设置为1

//中断服务函数
void EXTI3_IRQHandler(void)
{
	BaseType_t Result,xHigherPriorityTaskWoken;
	
	delay_xms(50);						//消抖
	if(KEY0==0)
	{
		Result=xEventGroupSetBitsFromISR(EventGroup_Handler,EVENTBIT_0,&xHigherPriorityTaskWoken);
		if(Result!=pdFAIL)
		{
			portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
		}
	}
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3);	//清除中断标志位
}

kEY0按下将bit0值1

eventgroup_task检查bit0、bit1、bit2是否都置为1了

void eventgroup_task(void *pvParameter)
{
	u8 num;
	EventBits_t EventValue;
	while(1)
	{
		if(EventGroup_Handler!=NULL)
		{
			EventValue=xEventGroupWaitBits(EventGroup_Handler,7,pdTRUE,pdTRUE,portMAX_DELAY);
			printf("事件标志组的值:%d\r\n",EventValue);
			LCD_ShowxNum(174,110,EventValue,1,16,0);
			num++;
			LED1 = !LED1;
			LCD_Fill(6,131,233,313,lcd_discolor[num%14]);
		}
		else
		{
			vTaskDelay(10);
		}
	}
	
}

查询当前的事件标志组的值,然后显示出来

void eventquery_task(void *pvParameter)
{
	u8 num=0;
	EventBits_t NewValue,LastValue;
	while(1)
	{
		if(EventGroup_Handler!=NULL)
		{
			NewValue=xEventGroupGetBits(EventGroup_Handler);
			if(NewValue!=LastValue)
			{
				LastValue = NewValue;
				printf("事件标志组的值: %d\r\n",NewValue);
				LCD_ShowxNum(174,110,NewValue,1,16,0);
			}
		}
		num++;
		if(num==0)
		{
			num=0;
			LED0 = !LED0;
		}
		vTaskDelay(50);
	}
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值