本文介绍: ISR的函数,如队列函数xQueueSendToBackFromISR、信号函数xSemaphoreGiveFromISR,它们会唤醒某个任务,最多只会唤醒一个任务。如果configUSE_16_BIT_TICKS是0,就表示该处理器使用32位更高效,则整数是32位,低24位表示事件。如果configUSE_16_BIT_TICKS是1,就表示该处理使用16位更高效,则整数是16位,低8位表示事件可以等待某一位,或等待某些位的任意一个,或等待多位。每一位的值:1表示事件发生,0表示事件还没发生。

目录

事件组

创建事件组

删除事件组

设置事件

等待事件

同步点

应用场景:等待多个事件

应用场景:任务同步


事件

事件组可看成一个整形数,每一位代表一个事件

每一位事件的含义由程序员决定,如位0表示串口是否就绪,位1表示按键是否被按下。

每一位的值:1表示事件发生,0表示事件还没发生。

一个或多个任务、ISR都可以去读、写位。

可以等待某一位,或等待某些位的任意一个,或等待多位。

事件组用一个整数表示,其中高8位留给内核使用,其他位可表示为事件。

如果configUSE_16_BIT_TICKS是1,就表示该处理使用16位更高效,则整数是16位,低8位表示事件。

如果configUSE_16_BIT_TICKS是0,就表示该处理使用32位更高效,则整数是32位,低24位表示事件。

创建事件组

/* 创建一个事件组,返回它的句柄。此函数内部会分配事件组结构体。
 * 返回值: 返回句柄,非NULL表示成功
*/
EventGroupHandle_t xEventGroupCreate( void );

/* 创建一个事件组,返回它的句柄。
 * 此函数无需动态分配内存,所以需要先有一个StaticEventGroup_t结构体,并传入它的指针
 * 返回值: 返回句柄,非NULL表示成功
*/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer );

删除事件组

对于动态创建的事件组,不再需要它们时,可以删除它们以回收内存

/* xEventGroup: 事件组句柄,你要删除哪个事件组 */
void vEventGroupDelete( EventGroupHandle_t xEventGroup );

设置事件

/* 设置事件组中的位
 * xEventGroup: 哪个事件组
 * uxBitsToSet: 设置哪些位?
 * 返回值: 返回原来的事件值(没什么意义, 因为很可能已经被其他任务修改了)
*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );

/* 设置事件组中的位
 * xEventGroup: 哪个事件组
 * uxBitsToSet: 设置哪些位?
 * pxHigherPriorityTaskWoken: 有没有导致更高优先级任务进入就绪态? pdTRUE-有, pdFALSE-没有
 * 返回值: pdPASS-成功, pdFALSE-失败
*/
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t * pxHigherPriorityTaskWoken );

注意:

ISR的函数,如队列函数xQueueSendToBackFromISR、信号量函数xSemaphoreGiveFromISR,它们会唤醒某个任务,最多只会唤醒一个任务

设置事件组时,可能导致多个任务被唤醒,会带来很大的不确定性。所以xEventGroupSetBitsFromISR函数不是直接去设置事件组,而是给一个FreeRTOS后台任务(daemon task发送队列数据,由这个任务来设置事件组。

如果后台任务的优先级当前中断的任务优先级高,xEventGroupSetBitsFromISR会设置*ppxHigherPriorityTaskWoken为pdTRUE。

如果后台任务成功把队列数据发送给了后台任务,xEventGroupSetBitsFromISR的返回值就是pdPASS。

等待事件

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,	// 等待某个事件组
                                 const EventBits_t uxBitsToWaitFor,	// 等待某些位
                                 const BaseType_t xClearOnExit,		// pdTRUE:等待的位全部为1;pdFALSE:等待的位某个为1即可
                                 const BaseType_t xWaitForAllBits,	// pdTRUE:清除uxBitsToWaitFor指定的位;pdFALSE:不清除
                                 TickType_t xTicksToWait );			// 阻塞时间。0表示立即返回,portMAX_DELAY表示直到成功才返回。也可使用pdMS_TO_TICKS(ms)
// 返回值:返回事件值
//		如果期待的事件发生了,返回的是非阻塞条件成立的事件组
//		如果超时退出,返回的是超时时刻的事件值

可以使用xEventGroupWaitBits()等待期待的时间,发生之后再使用xEventGroupClearBits()来清除。但是这两个函数间有可能被其他任务或中断抢占,它们有可能会修改事件组。

可以使用设置xclearOnExit为pdTRUE,使得对事件组的测试、清零都在xEventGroupWaitBits()函数内部完成,这是一个原子操作

同步

EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,	// 指定事件组
							 const EventBits_t uxBitsToSet,		// 设置事件(位)
							 const EventBits_t uxBitsToWaitFor,	// 等待事件(位)
							 TickType_t xTicksToWait );			// 阻塞时间。0表示立即返回,portMAX_DELAY表示直到成功才返回。可使用pdMS_TO_TICKS(ms)
// 返回值:
// 		如果期待的事件发生了,返回的是非阻塞条件成立时的事件值
//		如果超时退出,返回的是超时时刻的事件值

成功返回后,会清除事件。

应用场景:等待多个事件

int main( void )
{
	prvSetupHardware();
	
	/* 创建递归锁 */
	xEventGroup = xEventGroupCreate( );
	if( xEventGroup != NULL )
	{
		/* 创建3个任务: 洗菜/生火/炒菜 */
		xTaskCreate( vWashingTask, "Task1", 1000, NULL, 1, NULL );
		xTaskCreate( vFiringTask, "Task2", 1000, NULL, 2, NULL );
		xTaskCreate( vCookingTask, "Task3", 1000, NULL, 3, NULL );
		
		/* 启动调度器 */
		vTaskStartScheduler();
	} else
	{
		/* 无法创建事件组 */
	} 
	
	/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
	return 0;
}

static void vWashingTask( void *pvParameters )
{
	int i = 0;
	
	/* 无限循环 */
	for(;;)
	{
		printf("I am washing %d time...rn", i++);
		
		/* 发出事件:我洗完菜了 */
		xEventGroupSetBits(xEventGroup, WASHING);
		
		/* 等待大厨炒完菜,再继续洗菜 */
		xEventGroupWaitBits(xEventGroup, COOKING, pdTRUE, pdTRUE, portMAX_DELAY);
	}
}

static void vFiringTask( void *pvParameters )
{
	int i = 0;
	
	/* 无限循环 */
	for(;;)
	{
		/* 等待洗完菜,才生火 */
		xEventGroupWaitBits(xEventGroup, WASHING, pdTRUE, pdTRUE, portMAX_DELAY);
		
		printf("I am firing %d time...rn", i++);
		
		/* 发出事件:我生好火了 */
		xEventGroupSetBits(xEventGroup, FIRING);		
	}
}

static void vCookingTask( void *pvParameters )
{
	int i = 0;
	
	/* 无限循环 */
	for(;;)
	{
		/* 等待两件事:洗完菜,生完火 */
		xEventGroupWaitBits(xEventGroup, WASHING | FIRING, pdTRUE, pdTRUE, portMAX_DELAY);
		
		printf("I am cooking %d time...rn", i++);
		
		/* 发出事件:我炒完菜了 */
		xEventGroupSetBits(xEventGroup, WASHING);
	}
}

实验现象:

I am washing 0 time…

I am firing 0 time…

I am cooking 0 time…

I am washing 1 time…

I am firing 1 time…

I am cooking 1 time…

应用场景:任务同步

int main( void )
{
	prvSetupHardware();
	
	/* 创建递归锁 */
	xEventGroup = xEventGroupCreate( );
	if( xEventGroup != NULL )
	{
		/* 创建3个任务: 洗菜/买酒/摆台 */
		xTaskCreate( vCookingTask, "task1", 1000, "A", 1, NULL );
		xTaskCreate( vBuyingTask, "task2", 1000, "B", 2, NULL );
		xTaskCreate( vTableTask, "task3", 1000, "C", 3, NULL );
		
		/* 启动调度器 */
		vTaskStartScheduler();
	} else
	{
		/* 无法创建事件组 */
	} 
	
	/* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
	return 0;
}

static void vCookingTask( void *pvParameters )
{
	const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
	int i = 0;
	
	/* 无限循环 */
	for( ;; )
	{
		/* 做自己的事 */
		printf("%s is cooking %d time....rn", (char *)pvParameters, i);
		
		/* 表示我做好了, 还要等别人都做好 */
		xEventGroupSync(xEventGroup, COOKING, ALL, portMAX_DELAY);
		
		/* 别人也做好了, 开饭 */
		printf("%s is eating %d time....rn", (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....rn", (char *)pvParameters, i);
		
		/* 表示我做好了, 还要等别人都做好 */
		xEventGroupSync(xEventGroup, BUYING, ALL, portMAX_DELAY);
		
		/* 别人也做好了, 开饭 */
		printf("%s is eating %d time....rn", (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....rn", (char *)pvParameters, i);
		
		/* 表示我做好了, 还要等别人都做好 */
		xEventGroupSync(xEventGroup, TABLING, ALL, portMAX_DELAY);
		
		/* 别人也做好了, 开饭 */
		printf("%s is eating %d time....rn", (char *)pvParameters, i++);
		
		vTaskDelay(xTicksToWait);
	}
}

实验现象:

C is do the table 0 time….

B is buying 0 time….

A is cooking 0 time….

C is eating 0 time….

B is eating 0 time….

A is eating 0 time….

C is do the table 1 time….

B is buying 1 time….

A is cooking 1 time….

C is eating 1 time….

B is eating 1 time….

A is eating 1 time….

原文地址:https://blog.csdn.net/weixin_47077788/article/details/134693578

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_6875.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注