【FreeRtos事件标志组】

FreeRtos事件标志组


前言

本次分享的是FreeRtos中的事件标志组的使用,其本质也是一种同步机制实现的一种方法。


一、事件标志组介绍

事件位(事件标志)

事件位用来表明某个事件是否发生,事件位通常用作事件标志
譬如:
●当收到一条消息并且把这条消息处理掉以后就可以将某个位(标志)置 1,当队列中没有
消息需要处理的时候就可以将这个位(标志)置 0。
● 当把队列中的消息通过网络发送输出以后就可以将某个位(标志)置 1,当没有数据需要
从网络发送出去的话就将这个位(标志)置 0。
● 现在需要向网络中发送一个心跳信息,将某个位(标志)置 1。现在不需要向网络中发送
心跳信息,这个位(标志)置 0。

2、事件组 

一个事件组就是一组的事件位,事件组中的事件位通过位编号来访问,同样,以上面列出
的三个例子为例:
● 事件标志组的 bit0 表示队列中的消息是否处理掉。
● 事件标志组的 bit1 表示是否有消息需要从网络中发送出去。
● 事件标志组的 bit2 表示现在是否需要向网络发送心跳信息。

3、事件标志组和事件位的数据类型 

事件标志组的数据类型为 EventGroupHandle_t,当 configUSE_16_BIT_TICKS 为 1 的时候事件标志组可以存储 8 个事件位,当 configUSE_16_BIT_TICKS 为 0 的时候事件标志组存储 24个事件位。 事件标志组中的所有事件位都存储在一个无符号的 EventBits_t 类型的变量中,EventBits_t在 event_groups.h

#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 
 #define portTICK_TYPE_IS_ATOMIC 1 
#endif 

可以看出当 configUSE_16_BIT_TICKS 为 0 的时候 TickType_t 是个 32 位的数据类型,因
此 EventBits_t 也是个 32 位的数据类型。EventBits_t 类型的变量可以存储 24 个事件位,另外的那高 8 位有其他用。事件位 0 存放在这个变量的 bit0 上,变量的 bit1 就是事件位 1,以此类推。对于 STM32 来说一个事件标志组最多可以存储 24 个事件位。

二、事件标志组API函数

2.1 创建事件标志组

在这里插入图片描述

这里只介绍动态创建

函数 xEventGroupCreate() 

此函数用于创建一个事件标志组,所需要的内存通过动态内存管理方法分配。由于内部处
理 的 原 因 , 事 件 标 志 组 可 用 的 bit 数 取 决 于 configUSE_16_BIT_TICKS , 当
configUSE_16_BIT_TICKS1 为 1 的时候事件标志组有 8 个 可 用 的 位 (bit0~bit7) , 当
configUSE_16_BIT_TICKS 为 0 的时候事件标志组有 24 个可用的位(bit0~bit23)。EventBits_t 类型的变量用来存储事件标志组中的各个事件位

EventGroupHandle_t xEventGroupCreate( void ) 

参数:

返回值:
NULL: 事件标志组创建失败
其他值: 创建成功的事件标志组句柄

2.2 设置事件位

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

在这里插入图片描述

在这里插入图片描述

1、函数 xEventGroupClearBits()

将事件标志组中的指定事件位清零,此函数只能用在任务中,不能用在中断服务函数中!
中断服务函数有其他的 API 函数。

EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, 
const EventBits_t uxBitsToClear ); 

参数:
xEventGroup: 要操作的事件标志组的句柄。
uxBitsToClear: 要清零的事件位,比如要清除 bit3 的话就设置为 0X08。可以同时清除个bit,如设置为 0X09 的话就是同时清除 bit3 和 bit0。
返回值:
任何值: 将指定事件位清零之前的事件组值。

2、函数 xEventGroupClearBitsFromISR()

函数为函数 xEventGroupClearBits()的中断级版本,也是将指定的事件位(标志)清零。此函数用在中断服务函数中

BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, 
const EventBits_t uxBitsToSet ); 

参数:
xEventGroup: 要操作的事件标志组的句柄。
uxBitsToClear: 要清零的事件位,比如要清除 bit3 的话就设置为 0X08。可以同时清除多个bit,如设置为 0X09 的话就是同时清除 bit3 和 bit0。
返回值:
pdPASS: 事件位清零成功。
pdFALSE: 事件位清零失败。

3、函数 xEventGroupSetBits()

设置指定的事件位为 1,此函数只能用在任务中,不能用于中断服务函数

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, 
 const EventBits_t uxBitsToSet ); 

参数:
xEventGroup: 要操作的事件标志组的句柄。
uxBitsToClear: 指定要置 1 的事件位,比如要将 bit3 值 1 的话就设置为 0X08。可以同时将多个 bit 置 1,如设置为 0X09 的话就是同时将 bit3 和 bit0 置 1。
返回值:
任何值: 在将指定事件位置 1 后的事件组值。

4、函数 xEventGroupSetBitsFromISR()

此函数也用于将指定的事件位置 1,此函数是 xEventGroupSetBits()的中断版本,用在中断
服务函数中

BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, 
const EventBits_t uxBitsToSet, 
BaseType_t * pxHigherPriorityTaskWoken ); 

参数:
xEventGroup: 要操作的事件标志组的句柄。
uxBitsToClear: 指定要置 1 的事件位,比如要将 bit3 值 1 的话就设置为 0X08。可以同时将多个 bit 置 1,如设置为 0X09 的话就是同时将 bit3 和 bit0 置 1。
pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值:
pdPASS: 事件位置 1 成功。
pdFALSE: 事件位置 1 失败。

2.3 获取事件标志组值

在这里插入图片描述

1、函数 xEventGroupGetBits()

此函数用于获取当前事件标志组的值,也就是各个事件位的值。此函数用在任务中,不能
用在中断服务函数中。此函数是个宏,真正执行的是函数 xEventGroupClearBits()

EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup ) 

参数:
xEventGroup: 要获取的事件标志组的句柄。
返回值:
任何值:当前事件标志组的值

2、函数 xEventGroupGetBitsFromISR()

获取当前事件标志组的值,此函数是 xEventGroupGetBits()的中断版本

EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup ) 

参数:
xEventGroup: 要获取的事件标志组的句柄。
返回值:
任何值: 当前事件标志组的值。

2.4 等待指定的事件位

某个任务可能需要与多个事件进行同步,那么这个任务就需要等待并判断多个事件位(标志),使用函数 xEventGroupWaitBits()可以完成这个功能。调用函数以后如果任务要等待的事件位还没有准备好(置 1 或清零)的话任务就会进入阻塞态,直到阻塞时间到达或者所等待的事件位准备好。

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

参数:
xEventGroup: 指定要等待的事件标志组。
uxBitsToWaitFord: 指定要等待的事件位,比如要等待bit0和(或)bit2的时候此参数就是0X05,如果要等待 bit0 和(或)bit1 和(或)bit2 的时候此参数就是 0X07,以此类推。
xClearOnExit: 此参数要是为 pdTRUE 的话,那么在退出此函数之前由参数 uxBitsToWaitFor所设置的这些事件位就会清零。如果设置位 pdFALSE 的话这些事件位就不会改变。
xWaitForAllBits: 此参数如果设置为 pdTRUE 的话,当 uxBitsToWaitFor 所设置的这些事件位都置 1,或者指定的阻塞时间到的时候函数 xEventGroupWaitBits()才会
返回。当此函数为 pdFALSE 的话,只要 uxBitsToWaitFor 所设置的这些事件位其中的任意一个置 1 ,或者指定的阻塞时间到的话函数xEventGroupWaitBits()就会返回。
xTicksToWait: 设置阻塞时间,单位为节拍数。
返回值:
任何值: 返回当所等待的事件位置 1 以后的事件标志组的值,或者阻塞时间到。根
据这个值我们就知道哪些事件位置 1 了。如果函数因为阻塞时间到而返回

三、事件标志组实验

3.1 实验需求

通过按键将Bit1 Bit2置1后再输出打印信息

demo

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "semphr.h"
#include "string.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 EVENTSETBITS_TASK_PRIO		2
//任务堆栈大小	
#define EVENTSETBITS_STK_SIZE 		50  
//任务句柄
TaskHandle_t EVENTTSETBITSask_Handler;
//任务函数
void eventsetbits_task(void *pvParameters);

//事件组

#define EVENTGROUP_TASK_PRIO		3
//任务堆栈大小	
#define EVENTGROUP_STK_SIZE 		50  
//任务句柄
TaskHandle_t EVENTGROUPTask_Handler;
//任务函数
void eventgroup_task(void *pvParameters);

EventGroupHandle_t  EventGroupHandler;

#define EVENTBIT0  (1 << 0)
#define EVENTBIT1  (1 << 1)
#define EVENTBIT2  (1 << 2)
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	KEY_GPIO_INIT();          //按键初始化
	 
	//创建开始任务
    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();           //进入临界区
	
		EventGroupHandler = xEventGroupCreate();
		if(NULL == EventGroupHandler)
		{
			printf("EventGroupHandler Failed\r\n");
		}
		else
		{
			printf("EventGroupHandler success\r\n");
		}
    //事件置位
    xTaskCreate((TaskFunction_t )eventsetbits_task,     	
                (const char*    )"eventsetbits_task",   	
                (uint16_t       )EVENTSETBITS_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )EVENTSETBITS_TASK_PRIO,	
                (TaskHandle_t*  )&EVENTTSETBITSask_Handler);     

		//事件组
		xTaskCreate((TaskFunction_t )eventgroup_task,     
                (const char*    )"eventgroup_task",   
                (uint16_t       )EVENTGROUP_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )EVENTGROUP_TASK_PRIO,
                (TaskHandle_t*  )&EVENTGROUPTask_Handler);   

  	
	
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//eventsetbits_task
void eventsetbits_task(void *pvParameters)
{
	u8 keyvalue = 0;
	while(1)
    {
      keyvalue = KEY_Scan();
			switch(keyvalue)
			{
				case 1:
					xEventGroupSetBits(EventGroupHandler,EVENTBIT1);
					break;
				case 2:
					xEventGroupSetBits(EventGroupHandler,EVENTBIT2);
					break;
				
			}
	//		printf("eventsetbits_task \r\n");
      vTaskDelay(10);
			
    }
}   



//eventgroup_task任务函数 
void eventgroup_task(void *pvParameters)
{
	EventBits_t  EventValue;
	while(1)
    {
				if(EventGroupHandler != NULL)
				{
					EventValue = xEventGroupWaitBits( (EventGroupHandle_t) EventGroupHandler,
																					( EventBits_t) EVENTBIT1| EVENTBIT2,
																					( BaseType_t )pdTRUE,
																					( BaseType_t )pdTRUE,
																					(TickType_t) portMAX_DELAY )	;				
						printf("all bits set 1  EventValue = 0x%x\r\n",EventValue);
				}
				else
				{
					vTaskDelay(200);
				}		
   }
}   

实验结果

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小殷学长

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

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

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

打赏作者

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

抵扣说明:

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

余额充值