【FreeRTOS】详细讲解FreeRTOS中事件(event)并通过具体示例讲述其用法

这篇具有很好参考价值的文章主要介绍了【FreeRTOS】详细讲解FreeRTOS中事件(event)并通过具体示例讲述其用法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

事件

  事件,实际上是一种任务间通信的机制,主要用于实现多任务间的同步其只能是事件类型的通信,无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。即可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理;同样,也可以是多个任务同步多个事件。
  FreeRTOS中任务可以通过设置事件位来实现事件的触发和等待操作。但FreeRTOS的事件仅用于同步,不提供数据传输功能,其具有如下特点:

  • 事件只与任务相关联事件相互独立,一个32位的事件集合(EventBits_t类型的变量,实际可用与表示事件的只有24位),用于标识该任务发生的事件类型,其中每一位表示一种事件类型(0表示该事件类型未发生、1表示该事件类型已经发生),一共24种事件类型;
  • 事件仅用于同步不提供数据传输功能;
  • 事件无排队性,即多次向任务设置同一事件(如果任务还未来得及读走),等效于只设置一次;
  • 允许多任务对同一事件进行读写操作;
  • 支持事件等待超时机制

应用

  事件在一定程度上可以代替信号量,用于任务与任务间、中断与任务间同步
  与信号量不同之处在于,事件是不可累计的,而信号量是可累计。并且,一个任务使用事件同步时,可以等待多个事件产生才进行同步;而信号量是单一的同步操作,只能与一个中断或任务同步,无法与多个中断或任务同步。

freertos 事件,# FreeRTOS,操作系统,单片机,stm32,c语言,嵌入式硬件事件运行机制示意图

  实际使用事件相关函数前,需要将configSUPPORT DYNAMIC ALLOCATION置1。


函数解析

前奏

  • 定义事件控制权柄所用的EventGroupHandle_t其实是一个结构体指针,其声明为typedef struct EventGroupDef_t * EventGroupHandle_t
  • 事件控制块EventGroup_t,内部最多含有四个变量,其中两个变量uxEventBitsxTasksWaitingForBits是一直可使用,但变量uxEventGroupNumberucStaticallyAllocated收到FreeRTOS配置管理
typedef struct EventGroupDef_t
{
    EventBits_t uxEventBits;
    List_t xTasksWaitingForBits; 
    
    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxEventGroupNumber;
    #endif

    #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) \
     && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
        uint8_t ucStaticallyAllocated;
    #endif
} EventGroup_t;

   EventBits_t事件标志组存储在EventBits_t 类型的变量中。
   若FreeRTOS配置时,将configUSE_16_BIT_TICKS定义为1,那么EventBits_t就为16位,其中只有8位存储时间组;否则,若configUSE_16_BIT_TICKS定义为0,那么EventBits_t就为32位,其中24位存储事件组。每一位代表一个事件是否发生(事件发生为1,否则为0)。倘若兄弟认为8位或24位事件组不够用,还可以使用与或非等逻辑运算来组成更多事件。🤣🤣🤣
   xTasksWaitingForBits:该变量是一个列表,内部存储等待此事件的所有任务
   uxEventGroupNumber:记录事件组数量。
   ucStaticallyAllocated:记录时间组分配方式,如果事件组是静态分配的,则设置为 pdTRUE,以确保不尝试释放内存。

动态创建事件

原函数

EventGroupHandle_t xEventGroupCreate( void );

参数解析

  • 返回值:类型为EventGroupHandle_t,其为事件的控制权柄。

函数说明
  动态创建一个事件。

静态创建事件

原函数

EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer );

参数解析

  • StaticEventGroup_t * pxEventGroupBuffer:为事件组分配的空间;
  • 返回值:类型为EventGroupHandle_t,其为事件的控制权柄

函数说明
   静态创建事件组,创建时需要传入存储空间。

创建事件

原函数

void vEventGroupDelete( EventGroupHandle_t xEventGroup );

参数解析

  • EventGroupHandle_t xEventGroup:传入事件组控制权柄;

函数说明
 &esnp;删除事件组,只要将事件组控制权柄传入即可。删除只能删除已经创建成功的事件组

事件触发

原函数


EventBits_t xEventGroupSetBits( 
								EventGroupHandle_t xEventGroup,
                                const EventBits_t uxBitsToSet
                              );

参数解析

  • EventGroupHandle_t xEventGroup:事件组的控制权柄;
  • const EventBits_t uxBitsToSet:需要触发事件的,也就是其在事件组的位置;
  • 返回值:返回函数操作的事件组的值;

函数说明
  触发事件组中某个事件(事件对应事件组的位置),其位置由uxBitsToSet的值决定。
  该函数内部有判断机制,即的判断该事件是否创建,只有事件组创建成功以及操作位有效,该函数才能正常运作

中断中唤醒事件

原函数

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

参数解析

  • EventGroupHandle_t xEventGroup:事件组的操作句柄;
  • const EventBits_t uxBitsToSet:需要触发事件的,也就是其在事件组的位置;
  • BaseType_t * pxHigherPriorityTaskWoken:在使用之前必须初始化成pdFALSE;
  • 返回值:类型为BaseType_t。若其值为pdFalse,则消息已经发送成功;否则,发送失败。

函数说明
  是xEventGroupSetBits函数的中断版,其功能是中断中唤醒某个事件。

等待事件唤醒

原函数

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

参数解析

  • EventGroupHandle_t xEventGroup:事件的操作句柄;
  • const EventBits_t uxBitsToWaitFor:等待的事件,这里可以是多个事件,使用或运算即可连接;
  • const BaseType_t xClearOnExit:当其值为pdTRUE时,一旦监测到匹配的事件,系统就会将删除由该事件引起的标志位;否则,当其值为pdFALSE时,将删除标志位;
  • const BaseType_t xWaitForAllBits:当其值为pdTURE时,相应的uxBitsToWaitFor中多个事件应该使用&连接;否则当其值为pdFALSE时,uxBitsToWaitFor中多个事件应该使用|连接。这样函数返回值才是对应标志位的值,事件才能够触发。
  • TickType_t xTicksToWait:最大超时时间,单位为系统节拍时间,使用portMAX_DELAY即相当于一直阻塞;
  • 返回值:类型为EventBits_t,返回事件中事件标志位,但是返回值很可能并不是用户指定的事件位,需要再进行判断再处理。

函数说明
  xEventGroupWaitBits函数的作用是等待事件触发。若需要等待的事件一直未触发,函数就会阻塞,阻塞时间为最大超时时间xTicksToWait

清除事件标志位

原函数

EventBits_t xEventGroupClearBits( 
									EventGroupHandle_t xEventGroup, 
									const EventBits_t uxBitsToClear
							    );

参数解析

  • EventGroupHandle_t xEventGroup:事件组操作句柄;
  • const EventBits_t uxBitsToClear:时间组中需要清除的位置;
  • 返回值:类型EventBits_t,返回事件清除前的值;

函数说明
  清除事件组中对应位置的标志位。在获取事件时对应标志位未擦除,那么可以使用该函数做显示擦除

中断中清除事件标志位

原函数

BaseType_t xEventGroupClearBitsFromISR( 
										EventGroupHandle_t xEventGroup,
										const EventBits_t uxBitsToSet 
									  );

参数解析

  • EventGroupHandle_t xEventGroup:事件组操作句柄;
  • const EventBits_t uxBitsToClear:时间组中需要清除的位置;
  • 返回值:类型EventBits_t,返回事件清除前的值;

函数说明
  是函数xEventGroupClearBits的中断版,功能上与之一样。


示例

  声明8个事件,并且创建一个FreeRTOS事件,用于任务同步,再创建两个任务。完成:任务1,等待事件触发,7个事件中触发一个事件后反转对应LED的状态,当事件8触发时,统计其触发次数并且显示到LCD屏上; 任务2,每个1s发送一个事件触发请求,并且反转LED8的状态。

核心源码

//任务控制权柄
TaskHandle_t xHandleTsak[2];
// 事件控制权柄
EventGroupHandle_t myxEventGroupHandle_t = NULL;
// 声明事件
#define EVENT1 (0x01 << 0)
#define EVENT2 (0x01 << 1)
#define EVENT3 (0x01 << 2)
#define EVENT4 (0x01 << 3)
#define EVENT5 (0x01 << 4)
#define EVENT6 (0x01 << 5)
#define EVENT7 (0x01 << 6)
#define EVENT8 (0x01 << 7)

int main(void)
{	
	//存储创建任务的返回值
	BaseType_t xReturn[2] ;
	
	// 创建事件
	myxEventGroupHandle_t = xEventGroupCreate();
	if(myxEventGroupHandle_t == 0)
		//点亮LED7
		changeLedStateByLocation(LED8,ON);
	
	//动态创建任务
	xReturn[0] = xTaskCreate(
						(TaskFunction_t )eventTask1,(const char *)"task1",
						(uint16_t)128,(void*) NULL,1,&xHandleTsak[0]);
	xReturn[1] = xTaskCreate(
						(TaskFunction_t )eventTask2,(const char *)"task2",
						(uint16_t)128,(void*) NULL,1,&xHandleTsak[1]);
						
	if (pdPASS != xReturn[0])
		//点亮LED6
		changeLedStateByLocation(LED6,ON);				
	if (pdPASS != xReturn[1])
		//点亮LED7
		changeLedStateByLocation(LED7,ON);				
	if (pdPASS == xReturn[1] == xReturn[0])
		vTaskStartScheduler();
	
	return 0;
}

/********************************************
* 函数功能:事件测试函数1
* 函数参数:无
* 函数返回值:无
********************************************/
void eventTask1(void)
{
	// 设置变量接收事件
	EventBits_t r_event;
	// 保存LED的状态
	int ledState[] = {0,0,0,0,0,0,0};
	// 记录LED的位置
	uint16_t ledLocation[] = {LED1,LED2,LED3,LED4,LED5,LED6,LED7};
	// 记录EVENT8触发次数
	uint16_t eventTriggerCount = 0;
	// 保存显示到LCD中的数据
	char temp[30];
	// 用于循环
	int i = 0;
	
	while(1)
	{
		//阻塞等待8个事件中任意一个事件
		r_event = xEventGroupWaitBits(myxEventGroupHandle_t,EVENT1|EVENT2|EVENT3|EVENT4|EVENT5|EVENT6|EVENT7|EVENT8,
									  pdTRUE,pdFALSE,portMAX_DELAY);
		//判断事件类型
		if((r_event&EVENT1) !=0)
			++ledState[0];
		else if((r_event&EVENT2) !=0)
			++ledState[1];
		else if((r_event&EVENT3) !=0)
			++ledState[2];
		else if((r_event&EVENT4) !=0)
			++ledState[3];
		else if((r_event&EVENT5) !=0)
			++ledState[4];
		else if((r_event&EVENT6) !=0)
			++ledState[5];
		else if((r_event&EVENT7) !=0)
			++ledState[6];
		else
		{ 
			sprintf(temp," Event8 count:%d",++eventTriggerCount);
			LCD_DisplayStringLine(Line4,(uint8_t*)temp);
			changeAllLedByStateNumber(OFF);
		}
		
		// 设置每个LED灯状态
		for(i=0;i<7;++i)
			// 显示7个LED灯目前的状态
			changeLedStateByLocation(ledLocation[i],ledState[i]%2);
	}
}

/********************************************
* 函数功能:事件测试函数2
* 函数参数:无
* 函数返回值:无
********************************************/
void eventTask2(void)
{
	// 记录本次需要触发事件
	uint16_t event[] = {EVENT1,EVENT2,EVENT3,EVENT4,EVENT5,EVENT6,EVENT7,EVENT8};
	int	i = -1;
	// 保存系统时间
	static portTickType myPreviousWakeTime;
	// 保存阻塞时间
	const volatile TickType_t xDelay1000ms = pdMS_TO_TICKS( 1000UL );
	// 获取当前时间
	myPreviousWakeTime = xTaskGetTickCount();
	while(1)
	{
		// 每次执行都翻转LED8状态 以保证肉眼看到该任务在运行
		rollbackLedByLocation(LED8);
		// 发送事件同步
		xEventGroupSetBits(myxEventGroupHandle_t,event[++i%8]);
		// 非阻塞延时1s
		xTaskDelayUntil( &myPreviousWakeTime,xDelay1000ms );
	}
}

结果

freertos 事件,# FreeRTOS,操作系统,单片机,stm32,c语言,嵌入式硬件
事件测试结果图


  小编也有其他的一些相关文章,欢迎各位看官点击观看😉😉😉文章来源地址https://www.toymoban.com/news/detail-687612.html

  • 【FreeRTOS】详细讲解FreeRTOS中任务管理并通过示例讲述其用法
  • 【FreeRTOS】详细讲解FreeRTOS的软件定时器及通过示例讲述其用法
  • 【FreeRTOS】详细讲解FreeRTOS中消息队列并通过示例讲述其用法

    最后 ,欢迎大家留言或私信交流,共同进步!😁😁😁

到了这里,关于【FreeRTOS】详细讲解FreeRTOS中事件(event)并通过具体示例讲述其用法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包