精华内容
下载资源
问答
  • 事件标志组是一组事件位,事件标志组中的事件位通过编号来访问。 事件标志组和事件标志位的数据类型 configUSE_16_BIT_TICKS这个宏设置为1,那么数据类型是8位;设置为0,那么数据类型是2...

    事件标志位

    事件位用于指示事件是否发生。也叫做事件标志位。

    可用位表示:当信息收到且准备好处理时,设置为1;当没有收到信息且等待处理时,设置为0。

     事件标志组

    事件标志组是一组事件位,事件标志组中的事件位通过编号来访问。

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

    configUSE_16_BIT_TICKS这个宏设置为1,那么数据类型是8位;设置为0,那么数据类型是24位。

    事件标志组里面的事件标志位存在EventBits类型的变量中,事件标志位0存在这个变量的0位,事件标志位1存在这个变量的1位,以此类推。

    特性

    事件标志组API允许任务或其他事情设置、清除事件标志组中的1位或多位,也允许任务进入阻塞态等待。

    部分API

    typedef void * EventGroupHandle_t;           //事件标志组句柄
    EventGroupHandle_t xEventGroupCreate( void );//创建事件标志组
    EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
                                   const EventBits_t uxBitsToSet );
    //设置标志位,参数uxBitsToSet是要设置的值
    BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, 
                                           const EventBits_t uxBitsToSet, 
                                   BaseType_t *pxHigherPriorityTaskWoken );
    //设置标志位,同于中断函数里面
    EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
                                     const EventBits_t uxBitsToWaitFor,
                                     const BaseType_t xClearOnExit,
                                     const BaseType_t xWaitForAllBits,
    		                 const TickType_t xTicksToWait );
    //读取标志位,参数uxBitsToWaitFor表示要读取的位,xClearOnExit表示读取之后是否清除,
    //xWaitForAllBits表示是否等待所有位就绪,参数xTicksToWait 表示阻塞时间。

    测试程序

    总体设计:2个任务,1个事件标志组;

    counttask:打印计数值,到50的时候设置事件标志1;

    串口中断:收到数据后,设置事件标志0;

    serialtask:读取事件标志位,打印相应的事件类型。

    创建任务和事件标志组

    #define COUNT_TASK_PRIO		            1	   //任务优先级
    #define COUNT_TASK_STK_SIZE 		    80     //任务堆栈大小
    TaskHandle_t CountTaskHandler;                     //任务句柄
    void CountTaskFunc(void *pvParameters);            //任务函数
    
    #define SERIAL_TASK_PRIO	            4	   //任务优先级
    #define SERIAL_TASK_STK_SIZE 		    80     //任务堆栈大小
    TaskHandle_t SerialTaskHandler;                    //任务句柄
    void SerialTaskFunc(void *pvParameters);           //任务函数
    
    EventGroupHandle_t  TestEventGroup;
    
    #define BIT_0   1<<0
    #define BIT_1   1<<1
    #define BIT_2   1<<2
    
    void OtherTest(void )
    {
        BaseType_t ret;
    	
        BoardInitMcu();
        BoardInitPeriph();
    
        TestEventGroup=xEventGroupCreate();
    
        ret=xTaskCreate( (TaskFunction_t )CountTaskFunc,     	
    		     (const char*    )"counttask",   	
    		     (uint16_t       )COUNT_TASK_STK_SIZE, 
    		     (void*          )NULL,				
    		     (UBaseType_t    )COUNT_TASK_PRIO,	
    		     (TaskHandle_t*  )&CountTaskHandler); 
    				
        ret=xTaskCreate((TaskFunction_t )SerialTaskFunc,     
    		    (const char*    )"serialtask",   
    		    (uint16_t       )SERIAL_TASK_STK_SIZE, 
    		    (void*          )NULL,
    		    (UBaseType_t    )SERIAL_TASK_PRIO,
    		    (TaskHandle_t*  )&SerialTaskHandler); 
    				
        vTaskStartScheduler(); 
    }

    任务函数

    void  CountTaskFunc(void *pvParameters)
    {
        static uint8_t i;
    	
        for(;;)
        {
    	i++;
    		
    	printf("count =%d\r\n",i);
    
    	if(i==50)
    	{
    	    i=0;
    	    xEventGroupSetBits( TestEventGroup, BIT_1 );
    	}
    						
    	vTaskDelay(500);                 //延时500ms,也就是500个时钟节拍	
        }
    }
      
    void SerialTaskFunc(void *pvParameters)
    {
        EventBits_t value;
    	
        for(;;)
        {
    	value =xEventGroupWaitBits( TestEventGroup,
    	        BIT_0|BIT_1,  //位0和位1
    	        pdTRUE ,      //读取之后,清除相应的位,若设置为pdFALSE则不清除
    	        pdFALSE,      //任意一个位置1,如果设置为pdTRUE,则要等待全部的位0和位1都置1
    	        portMAX_DELAY ); //阻塞时间
    
    	if((value&BIT_0)==BIT_0)
    	{
                printf("serial \r\n");
    	}
    	else
    	{
    	    if((value&BIT_1)==BIT_1)
    	    {
    		printf("count \r\n");
    	    }
    	    else
    	    {
    		printf("default");
    	    }
    	}			
    	vTaskDelay(10);
        }
    }

    串口中断

    void USART1_IRQHandler( void )
    {
        BaseType_t pxHigherPriorityTaskWoken=pdFALSE;
    
        //省略部分代码,列出关键部分
    
        if(RESET != __HAL_UART_GET_FLAG(&UartHandle,UART_FLAG_IDLE))//空闲中断
        {                   
    	__HAL_UART_CLEAR_IDLEFLAG(&UartHandle);
    
            /*事件标志组*/
    	xEventGroupSetBitsFromISR(TestEventGroup,(1<<0),&pxHigherPriorityTaskWoken );
    	portYIELD_FROM_ISR(pxHigherPriorityTaskWoken);
        }
    }

    编译报错

    Error: L6218E: Undefined symbol xEventGroupSetBitsFromISR (referred from uart-board.o).

    搜索发现xEventGroupSetBitsFromISR这个函数是条件编译,需要configUSE_TRACE_FACILITY、INCLUDE_xTimerPendFunctionCall、configUSE_TIMERS都设置为1。

    再次编译报错

    ..\src\FreeRTOS\include\FreeRTOS.h(286): error:  #35: #error directive: If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined.

      #error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined.

    搜索代码发现,如果configUSE_TIMERS 设置为1,那么就需要设置timer任务的优先级、堆大小、队列长度等。

    #define configTIMER_TASK_PRIORITY    (configMAX_PRIORITIES-1)     //软件定时器优先级
    #define configTIMER_QUEUE_LENGTH     5                            //软件定时器队列长度
    #define configTIMER_TASK_STACK_DEPT  (configMINIMAL_STACK_SIZE*2) //软件定时器任务堆栈大小

    再次编译,通过。

    运行结果

     

    展开全文
  • FreeRTOS事件标志组

    千次阅读 2019-03-11 22:47:42
    但是在操作系统中,涉及到多个任务同时访问的问题,因此FreeRTOS提供了事件标志组机制。 先看一下事件标志组结构体 /* 事件标志组结构体 */ typedef struct EventGroupDef_t { EventBits_t uxEventBits; /* ...

    在裸机编程过程中,经常会用到标志位。但是在操作系统中,涉及到多个任务同时访问的问题,因此FreeRTOS提供了事件标志组机制。

     

     

    先看一下事件标志组结构体

    /* 事件标志组结构体 */
    typedef struct EventGroupDef_t
    {
    	EventBits_t uxEventBits;	/* 事件标志位 */
    	List_t xTasksWaitingForBits;	/* 等待事件标志位而阻塞的任务列表 */
    
    	......
    }EventGroup_t;

    事件标志位可以选择16位/32位,其中高8位作为控制位,低8位/24位作为事件标志位。

    #if configUSE_16_BIT_TICKS == 1
    	#define eventCLEAR_EVENTS_ON_EXIT_BIT	0x0100U
    	#define eventUNBLOCKED_DUE_TO_BIT_SET	0x0200U
    	#define eventWAIT_FOR_ALL_BITS		0x0400U
    	#define eventEVENT_BITS_CONTROL_BYTES	0xff00U
    #else
    	#define eventCLEAR_EVENTS_ON_EXIT_BIT	0x01000000UL    /* 在退出前清除等待位 */
    	#define eventUNBLOCKED_DUE_TO_BIT_SET	0x02000000UL    /* 因为等待位置位而退出阻塞 */
    	#define eventWAIT_FOR_ALL_BITS		0x04000000UL    /* 所有位都要被置位 */
    	#define eventEVENT_BITS_CONTROL_BYTES	0xff000000UL    /* 所有的控制位掩码 */
    #endif

     

     

    创建事件标志组

    创建事件标志组的步骤:

    1.为事件标志组申请内存空间

    2.初始化事件标志位为0,初始化等待事件标志位任务列表

    /* 创建事件组 */
    EventGroupHandle_t xEventGroupCreate(void)
    {
    	EventGroup_t *pxEventBits;
    
    	/* 为事件组分配内存空间 */
    	pxEventBits = (EventGroup_t *)pvPortMalloc(sizeof(EventGroup_t));
    	if(pxEventBits != NULL)
    	{
    		/* 初始化事件标志位 */
    		pxEventBits->uxEventBits = 0;
    		/* 初始化等待事件标志位而阻塞的任务列表 */
    		vListInitialise(&(pxEventBits->xTasksWaitingForBits));
    
    		#if (configSUPPORT_STATIC_ALLOCATION == 1)
    		{
    			pxEventBits->ucStaticallyAllocated = pdFALSE;
    		}
    		#endif
    
    		traceEVENT_GROUP_CREATE(pxEventBits);
    	}
    	else
    	{
    		traceEVENT_GROUP_CREATE_FAILED();
    	}
    
    	/* 返回事件组指针 */
    	return pxEventBits;
    }

     

     

    设置事件标志位

    设置事件标志位就是将事件标志组中相应的事件位置位,并且将满足该事件的等待任务可以解除阻塞

    /* 设置事件标志位 */
    EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet)
    {
    	ListItem_t *pxListItem, *pxNext;
    	ListItem_t const *pxListEnd;
    	List_t const *pxList;
    	EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
    	EventGroup_t *pxEventBits = xEventGroup;
    	BaseType_t xMatchFound = pdFALSE;
    
    	configASSERT(xEventGroup);
    	configASSERT((uxBitsToSet & eventEVENT_BITS_CONTROL_BYTES) == 0);
    
    	/* 等待事件标志位而阻塞的任务列表 */
    	pxList = &(pxEventBits->xTasksWaitingForBits);
    	/* 尾节点 */
    	pxListEnd = listGET_END_MARKER(pxList);
    	/* 挂起调度器 */
    	vTaskSuspendAll();
    	{
    		traceEVENT_GROUP_SET_BITS(xEventGroup, uxBitsToSet);
    
    		/* 头结点 */
    		pxListItem = listGET_HEAD_ENTRY(pxList);
    
    		/* 设置事件标志位 */
    		pxEventBits->uxEventBits |= uxBitsToSet;
    
    		/* 遍历所有等待事件的任务 */
    		while(pxListItem != pxListEnd)
    		{
    			/* 获取下一个列表项指针 */
    			pxNext = listGET_NEXT(pxListItem);
    			
    			/* 获取等待的事件标志位值 */
    			uxBitsWaitedFor = listGET_LIST_ITEM_VALUE(pxListItem);
    			/* 初始化为不匹配 */
    			xMatchFound = pdFALSE;
    
    			/* 取出控制位 */
    			uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
    			/* 取出等待的事件标志位 */
    			uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;
    
    			/* uxBitsToWaitFor所设置的事件位,任意一位置位即可 */
    			if((uxControlBits & eventWAIT_FOR_ALL_BITS) == (EventBits_t)0)
    			{
    				/* 至少有一位被置位 */
    				if((uxBitsWaitedFor & pxEventBits->uxEventBits) != (EventBits_t)0)
    				{
    					/* 已经匹配 */
    					xMatchFound = pdTRUE;
    				}
    				else
    				{
    					mtCOVERAGE_TEST_MARKER();
    				}
    			}
    			/* uxBitsToWaitFor所设置的事件位,所有都被置位才行 */
    			/* 所有都被置位 */
    			else if((uxBitsWaitedFor & pxEventBits->uxEventBits) == uxBitsWaitedFor)
    			{
    				/* 已经匹配 */
    				xMatchFound = pdTRUE;
    			}
    			else
    			{
    
    			}
    
    			/* 已经匹配 */
    			if(xMatchFound != pdFALSE)
    			{
    				/* 要求在退出时清除事件位 */
    				if((uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT) != (EventBits_t)0)
    				{
    					/* 所有已经匹配过的事件位 */
    					uxBitsToClear |= uxBitsWaitedFor;
    				}
    				else
    				{
    					mtCOVERAGE_TEST_MARKER();
    				}
    
    				/* 设置事件列表项值为事件标志位,将任务从等待事件标志位而阻塞的任务列表中移除,重新挂接到就绪列表 */
    				vTaskRemoveFromUnorderedEventList(pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET);
    			}
    
    			pxListItem = pxNext;
    		}
    
    		/* 清空事件位 */
    		pxEventBits->uxEventBits &= ~uxBitsToClear;
    	}
    	(void)xTaskResumeAll();
    
    	/* 返回事件标志位 */
    	return pxEventBits->uxEventBits;
    }

     

     

    等待事件标志位

    xClearOnExit参数用来决定匹配之后,是否清除相关事件标志位

    xWaitForAllBits用来决定匹配方式:所有的位都被置位才能匹配、只要其中一位被置位就能够匹配

    1.事件标志位如果匹配,直接退出。

    2.事件标志位如果不匹配,但是允许阻塞,则将当前任务加入事件列表并等待相关位被置位。

    3.事件标志位如果不匹配且不允许阻塞,则直接退出

    其中,使用函数prvTestWaitCondition来检查是否匹配。

    /* 等待事件标志位 */
    EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait)
    {
    	EventGroup_t *pxEventBits = xEventGroup;
    	EventBits_t uxReturn, uxControlBits = 0;
    	BaseType_t xWaitConditionMet, xAlreadyYielded;
    	BaseType_t xTimeoutOccurred = pdFALSE;
    
    	configASSERT(xEventGroup);
    	configASSERT((uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES) == 0);
    	configASSERT(uxBitsToWaitFor != 0);
    
    	#if ((INCLUDE_xTaskGetSchedulerState == 1) || (configUSE_TIMERS == 1))
    	{
    		configASSERT(!((xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) && (xTicksToWait != 0)));
    	}
    	#endif
    
    	/* 挂起调度器 */
    	vTaskSuspendAll();
    	{
    		/* 事件标志位 */
    		const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;
    
    		/* 判断等待条件是否满足 */
    		xWaitConditionMet = prvTestWaitCondition(uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits);
    		/* 满足条件 */
    		if(xWaitConditionMet != pdFALSE)
    		{
    			/* 返回值为事件标志位 */
    			uxReturn = uxCurrentEventBits;
    
    			/* 将等待时间改成0 */
    			xTicksToWait = (TickType_t)0;
    
    			/* 返回之前将等待的位都清零 */
    			if(xClearOnExit != pdFALSE)
    			{
    				/* 将事件标志位相应的位清空 */
    				pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
    			}
    			/* 不用清零 */
    			else
    			{
    				mtCOVERAGE_TEST_MARKER();
    			}
    		}
    		/* 不满足条件,但是非阻塞 */
    		else if(xTicksToWait == (TickType_t)0)
    		{
    			/* 返回值为事件标志位 */
    			uxReturn = uxCurrentEventBits;
    			/* 已经超时 */
    			xTimeoutOccurred = pdTRUE;
    		}
    		/* 不满足条件,且允许阻塞 */
    		else
    		{
    			/* 返回之前将等待的位都清零 */
    			if(xClearOnExit != pdFALSE)
    			{
    				/* 返回之前要清零存到控制位中 */
    				uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
    			}
    			else
    			{
    				mtCOVERAGE_TEST_MARKER();
    			}
    
    			/* uxBitsToWaitFor所设置的事件位,所有都被置位才行 */
    			if(xWaitForAllBits != pdFALSE)
    			{
    				/* 所有都被置位才行存到控制位中 */
    				uxControlBits |= eventWAIT_FOR_ALL_BITS;
    			}
    			else
    			{
    				mtCOVERAGE_TEST_MARKER();
    			}
    
    			/* 将当前任务挂接到事件列表 */
    			vTaskPlaceOnUnorderedEventList(&(pxEventBits->xTasksWaitingForBits), (uxBitsToWaitFor | uxControlBits), xTicksToWait);
    
    			uxReturn = 0;
    
    			traceEVENT_GROUP_WAIT_BITS_BLOCK(xEventGroup, uxBitsToWaitFor);
    		}
    	}
    	/* 解除调度器挂起 */
    	xAlreadyYielded = xTaskResumeAll();
    
    	/* 等待时间不为0 */
    	if(xTicksToWait != (TickType_t)0)
    	{
    		/* 解除调度器挂起时没进行调度 */
    		if(xAlreadyYielded == pdFALSE)
    		{
    			/* 申请切换任务 */
    			portYIELD_WITHIN_API();
    		}
    		else
    		{
    			mtCOVERAGE_TEST_MARKER();
    		}
    
    		/* 程序跑到这儿说明解除了阻塞 */
    		/* 返回事件列表项值(事件标志位)并复位事件列表项值为任务优先级 */
    		uxReturn = uxTaskResetEventItemValue();
    		/* 不是因为相关的位被设置而解除阻塞,因为超时 */
    		if((uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET) == (EventBits_t)0)
    		{
    			/* 进入临界区 */
    			taskENTER_CRITICAL();
    			{
    				/* 返回事件标志位 */
    				uxReturn = pxEventBits->uxEventBits;
    
    				/* 判断等待条件是否满足 */
    				if(prvTestWaitCondition(uxReturn, uxBitsToWaitFor, xWaitForAllBits) != pdFALSE)
    				{
    					/* 返回之前将等待的位都清零 */
    					if(xClearOnExit != pdFALSE)
    					{
    						pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
    					}
    					else
    					{
    						mtCOVERAGE_TEST_MARKER();
    					}
    				}
    				else
    				{
    					mtCOVERAGE_TEST_MARKER();
    				}
    				/* 已经超时 */
    				xTimeoutOccurred = pdTRUE;
    			}
    			/* 退出临界区 */
    			taskEXIT_CRITICAL();
    		}
    		/* 因为相关的位被设置而解除阻塞 */
    		else
    		{
    
    		}
    
    		/* 将所有控制位清除 */
    		uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
    	}
    	traceEVENT_GROUP_WAIT_BITS_END(xEventGroup, uxBitsToWaitFor, xTimeoutOccurred);
    
    	(void)xTimeoutOccurred;
    
    	/* 返回清除之前的事件位 */
    	return uxReturn;
    }

    prvTestWaitCondition检查事件标志位是否匹配

    /* 判断等待条件是否满足 */
    static BaseType_t prvTestWaitCondition(const EventBits_t uxCurrentEventBits, const EventBits_t uxBitsToWaitFor, const BaseType_t xWaitForAllBits)
    {
    	BaseType_t xWaitConditionMet = pdFALSE;
    
    	/* uxBitsToWaitFor所设置的事件位,任意一位置位即可 */
    	if(xWaitForAllBits == pdFALSE)
    	{
    		/* 至少有一位被置位 */
    		if((uxCurrentEventBits & uxBitsToWaitFor) != (EventBits_t)0)
    		{
    			xWaitConditionMet = pdTRUE;
    		}
    		/* 没有位被置位 */
    		else
    		{
    			mtCOVERAGE_TEST_MARKER();
    		}
    	}
    	/* uxBitsToWaitFor所设置的事件位,所有都被置位才行 */
    	else
    	{
    		/* 所有都被置位 */
    		if((uxCurrentEventBits & uxBitsToWaitFor) == uxBitsToWaitFor)
    		{
    			xWaitConditionMet = pdTRUE;
    		}
    		/* 没有全被置位 */
    		else
    		{
    			mtCOVERAGE_TEST_MARKER();
    		}
    	}
    
    	/* 返回情况是否满足 */
    	return xWaitConditionMet;
    }

     

     

    同步事件标志位

    每个任务都设置不同的事件标志位uxBitsToSet,最后一个任务设置完刚好匹配上uxBitsToWaitFor,然后将所有任务解除阻塞。

    /* 事件标志位同步 */
    EventBits_t xEventGroupSync(EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait)
    {
    	EventBits_t uxOriginalBitValue, uxReturn;
    	EventGroup_t *pxEventBits = xEventGroup;
    	BaseType_t xAlreadyYielded;
    	BaseType_t xTimeoutOccurred = pdFALSE;
    
    	configASSERT((uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES) == 0);
    	configASSERT(uxBitsToWaitFor != 0);
    	#if ((INCLUDE_xTaskGetSchedulerState == 1) || (configUSE_TIMERS == 1))
    	{
    		configASSERT(!((xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) && (xTicksToWait != 0)));
    	}
    	#endif
    
    	/* 调度器挂起 */
    	vTaskSuspendAll();
    	{
    		uxOriginalBitValue = pxEventBits->uxEventBits;
    
    		/* 设置事件标志位 */
    		(void)xEventGroupSetBits(xEventGroup, uxBitsToSet);
    
    		/* 刚好所有位都被设置了 */
    		if(((uxOriginalBitValue | uxBitsToSet) & uxBitsToWaitFor) == uxBitsToWaitFor)
    		{
    			/* 返回事件标志位 */
    			uxReturn = (uxOriginalBitValue | uxBitsToSet);
    
    			/* 将事件位清除 */
    			pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
    
    			/* 等待时间还剩0 */
    			xTicksToWait = 0;
    		}
    		/* 还有位没有被设置 */
    		else
    		{
    			/* 等待时间不为0 */
    			if(xTicksToWait != (TickType_t)0)
    			{
    				traceEVENT_GROUP_SYNC_BLOCK(xEventGroup, uxBitsToSet, uxBitsToWaitFor);
    
    				/* 将当前任务挂接到等待事件标志位而阻塞的任务列表 */
    				vTaskPlaceOnUnorderedEventList(&(pxEventBits->xTasksWaitingForBits), (uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS), xTicksToWait);
    
    				uxReturn = 0;
    			}
    			/* 等待时间为0 */
    			else
    			{
    				/* 返回事件标志位 */
    				uxReturn = pxEventBits->uxEventBits;
    				
    				/* 已经超时 */
    				xTimeoutOccurred = pdTRUE;
    			}
    		}
    	}
    	/* 解除调度器挂起 */
    	xAlreadyYielded = xTaskResumeAll();
    
    	/* 等待时间不为0 */
    	if(xTicksToWait != (TickType_t)0)
    	{
    		/* 解除调度器时没有切换任务 */
    		if(xAlreadyYielded == pdFALSE)
    		{
    			/* 切换任务 */
    			portYIELD_WITHIN_API();
    		}
    		else
    		{
    			mtCOVERAGE_TEST_MARKER();
    		}
    
    		/* 运行到这儿说明解除阻塞了 */
    		uxReturn = uxTaskResetEventItemValue();
    
    		/* 不是因为事件位被设置而解除阻塞,说明是因为超时 */
    		if((uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET) == (EventBits_t)0)
    		{
    			taskENTER_CRITICAL();
    			{
    				/* 返回事件标志位 */
    				uxReturn = pxEventBits->uxEventBits;
    
    				/* 所有位已经匹配 */
    				if((uxReturn & uxBitsToWaitFor) == uxBitsToWaitFor)
    				{
    					/* 清除事件标志位 */
    					pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
    				}
    				else
    				{
    					mtCOVERAGE_TEST_MARKER();
    				}
    			}
    			taskEXIT_CRITICAL();
    
    			/* 已经超时 */
    			xTimeoutOccurred = pdTRUE;
    		}
    		/* 事件位被设置 */
    		else
    		{
    
    		}
    
    		/* 清除控制位 */
    		uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
    	}
    
    	traceEVENT_GROUP_SYNC_END(xEventGroup, uxBitsToSet, uxBitsToWaitFor, xTimeoutOccurred);
    
    	(void)xTimeoutOccurred;
    
    	return uxReturn;
    }

     

    展开全文
  • FreeRTOS 事件标志组

    千次阅读 2018-05-09 15:40:17
    事件标志组与多个事件或任务进行同步 //动态方法创建事件标志组 EventGroupHandle_t xEventGroupCreate( void ) //设置事件位 EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_...

    信号量同步只能与单个的事件或任务进行同步。事件标志组与多个事件或任务进行同步
    事件位用来表明某个事件是否发生,事件组是一组事件位
    1

    //动态方法创建事件标志组
    EventGroupHandle_t xEventGroupCreate( void )
    
    //设置事件位
    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 )
    
    //事件查询
    #define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
    EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
    展开全文
  • ucosii 事件标志组

    2016-07-17 21:41:45
    ucosii 事件标志组
  • μC/OS-II的事件标志组在任务间的同步和通信中有着不可忽视的作用。在应用过程中,发现事件标志组存在系统缺陷,通过对其进行深入分析,提出了解决问题的方案,本文详细地描述了解决方案的具体方式及步骤。
  • 【UCOSIII】UCOSIII的事件标志组

    万次阅读 2018-07-05 19:10:09
    UCOSIII事件标志组 前面讲述了UCOSIII的信号量、互斥信号量,它们都可以完成任务的同步。但是有时候一个任务可能需要和多个事件同步,这个时候就需要使用事件标志组事件标志组与任务之间有两种同步机制: “或”...

    UCOSIII事件标志组

    前面讲述了UCOSIII的信号量、互斥信号量,它们都可以完成任务的同步。但是有时候一个任务可能需要和多个事件同步,这个时候就需要使用事件标志组。事件标志组与任务之间有两种同步机制:

    • “或”同步:等待多个事件时,任何一个事件发生 ,任务都被同步,这个就称为“或”同步;
    • “与”同步:当所有的事件都发生时任务才被同步,这种同步机制被称为“与”同步。

    在UCOSIII中事件标志组为OS_FLAG_GRP,如果需要使用事件标志组的时候需要将宏OS_CFG_FLAG_EN置1。

    这两种同步机制如下图所示:

    1. 在UCOSIII中事件标志组是OS_FLAG_GRP,在os.h文件中有定义,事件标志组中也包含了一串任务,这些任务都在等待着事件标志组中的部分(或全部)事件标志被置1或被清零,在使用之前,必须创建事件标志组;
    2. 任务和ISR(中断服务程序)都可以发布事件标志,但是,只有任务可以创建、删除事件标志组以及取消其他任务对事件标志组的等待
    3. 任务可以通过调用函数OSFlagPend()等待事件标志组中的任意个事件标志,调用函数OSFlagPend()的时候可以设置一个超时时间,如果过了超时时间请求的事件还没有被发布,那么任务就会重新进入就绪态;
    4. 我们可以设置同步机制为“或”同步还是“与”同步。

     

    UCOSIII事件标志组API函数

    UCOSIII事件标志组API函数
    函数说明
    OSFlagCreate()创建事件标志组
    OSFlagDel()删除事件标志组
    OSFlagPend()等待事件标志组
    OSFlagPendAbort()取消等待事件标志组
    OSFlagPendGetFlagsRdy()获取使任务就绪的事件标志
    OSFlagPost()向事件标志组发布标志

    创建事件标志组

    在使用事件标志组之前,需要调用函数OSFlagCreate()创建一个事件标志组,OSFlagCreate()函数原型如下:

    void  OSFlagCreate (OS_FLAG_GRP  *p_grp,                        //指向事件标志组
                        CPU_CHAR     *p_name,                        //事件标志组的名字
                        OS_FLAGS      flags,                        //定义事件标志组的初始值
                        OS_ERR       *p_err)
    {
        CPU_SR_ALLOC();
    
        OS_CRITICAL_ENTER();
        p_grp->Type    = OS_OBJ_TYPE_FLAG;                      /* Set to event flag group type                           */
        p_grp->NamePtr = p_name;
        p_grp->Flags   = flags;                                 /* Set to desired initial value                           */
        p_grp->TS      = (CPU_TS)0;
        OS_PendListInit(&p_grp->PendList);
    
        OSFlagQty++;
    
        OS_CRITICAL_EXIT_NO_SCHED();
       *p_err = OS_ERR_NONE;
    }

    我们可以先看看事件标志组的结构体OS_FLAG_GRP:

    struct  os_flag_grp {                                       /* Event Flag Group                                       */
                                                                /* ------------------ GENERIC  MEMBERS ------------------ */
        OS_OBJ_TYPE          Type;                              /* Should be set to OS_OBJ_TYPE_FLAG                      */
        CPU_CHAR            *NamePtr;                           /* 事件标志组的名称    */
        OS_PEND_LIST         PendList;                          /* 等待事件标志组的任务组    */
    #if OS_CFG_DBG_EN > 0u
        OS_FLAG_GRP         *DbgPrevPtr;
        OS_FLAG_GRP         *DbgNextPtr;
        CPU_CHAR            *DbgNamePtr;
    #endif
                                                                /* ------------------ SPECIFIC MEMBERS ------------------ */
        OS_FLAGS             Flags;                             /* 8, 16 or 32 bit flags                                  */
        CPU_TS               TS;                                /* Timestamp of when last post occurred                   */
    };

    事件标志组的结构体和之前的信号量、互斥信号量、消息队列比较类似,关键的一个成员变量是Flags:

    typedef   CPU_INT32U      OS_FLAGS;                    /* Event flags,                                      8/16/<32> */

    我们可以看到定义,Flags是一个32位无符号的整型。我们在OSFlagCreate()函数中的flags参数的值就是赋值给它的,那么它代表的含义是什么呢?

    Flags是32位,它的每一位都代表着一个任务的状态,每个任务有1和0两种状态。也就是说,我们可以同时最多完成一个任务和32个任务的任务同步!我们可以设置:Falgs的第0、1两个任务为1的时候,完成任务同步,也就是说,Flags变成0x03的时候,完成同步。当然,OSFlagCreate()函数中的flags参数只是确定一个初始值。

    等待事件标志组

    等待一个事件标志组需要调用函数OSFlagPend(),函数原型如下:

    OS_FLAGS  OSFlagPend (OS_FLAG_GRP  *p_grp,                            //指向事件标志组
                          OS_FLAGS      flags,                            //bit序列
                          OS_TICK       timeout,                        //指定等待事件标志组的超时时间(时钟节拍数)
                          OS_OPT        opt,                            //决定任务等待的条件
                          CPU_TS       *p_ts,                            //指向一个时间戳
                          OS_ERR       *p_err)
    {
        CPU_BOOLEAN   consume;
        OS_FLAGS      flags_rdy;
        OS_OPT        mode;
        OS_PEND_DATA  pend_data;
        CPU_SR_ALLOC();
    
        if ((opt & OS_OPT_PEND_FLAG_CONSUME) != (OS_OPT)0) {    /* See if we need to consume the flags                    */
            consume = DEF_TRUE;
        } else {
            consume = DEF_FALSE;
        }
    
        if (p_ts != (CPU_TS *)0) {
           *p_ts = (CPU_TS)0;                                   /* Initialize the returned timestamp                      */
        }
    
        mode = opt & OS_OPT_PEND_FLAG_MASK;
        CPU_CRITICAL_ENTER();
        switch (mode) {
            case OS_OPT_PEND_FLAG_SET_ALL:                      /* See if all required flags are set                      */
                 flags_rdy = (OS_FLAGS)(p_grp->Flags & flags);  /* Extract only the bits we want                          */
                 if (flags_rdy == flags) {                      /* Must match ALL the bits that we want                   */
                     if (consume == DEF_TRUE) {                 /* See if we need to consume the flags                    */
                         p_grp->Flags &= ~flags_rdy;            /* Clear ONLY the flags that we wanted                    */
                     }
                     OSTCBCurPtr->FlagsRdy = flags_rdy;         /* Save flags that were ready                             */
                     if (p_ts != (CPU_TS *)0) {
                        *p_ts  = p_grp->TS;
                     }
                     CPU_CRITICAL_EXIT();                       /* Yes, condition met, return to caller                   */
                    *p_err = OS_ERR_NONE;
                     return (flags_rdy);
                 } else {                                       /* Block task until events occur or timeout               */
                     if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {
                         CPU_CRITICAL_EXIT();
                        *p_err = OS_ERR_PEND_WOULD_BLOCK;       /* Specified non-blocking so task would block             */
                         return ((OS_FLAGS)0);
                     } else {                                   /* Specified blocking so check is scheduler is locked     */
                         if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* See if called with scheduler locked ...      */
                             CPU_CRITICAL_EXIT();
                            *p_err = OS_ERR_SCHED_LOCKED;                 /* ... can't PEND when locked                   */
                             return ((OS_FLAGS)0);
                         }
                     }
                                                                
                     OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();     /* Lock the scheduler/re-enable interrupts                */
                     OS_FlagBlock(&pend_data,
                                  p_grp,
                                  flags,
                                  opt,
                                  timeout);
                     OS_CRITICAL_EXIT_NO_SCHED();
                 }
                 break;
    
            case OS_OPT_PEND_FLAG_SET_ANY:
                 flags_rdy = (OS_FLAGS)(p_grp->Flags & flags);  /* Extract only the bits we want                          */
                 if (flags_rdy != (OS_FLAGS)0) {                /* See if any flag set                                    */
                     if (consume == DEF_TRUE) {                 /* See if we need to consume the flags                    */
                         p_grp->Flags &= ~flags_rdy;            /* Clear ONLY the flags that we got                       */
                     }
                     OSTCBCurPtr->FlagsRdy = flags_rdy;         /* Save flags that were ready                             */
                     if (p_ts != (CPU_TS *)0) {
                        *p_ts  = p_grp->TS;
                     }
                     CPU_CRITICAL_EXIT();                       /* Yes, condition met, return to caller                   */
                    *p_err = OS_ERR_NONE;
                     return (flags_rdy);
                 } else {                                       /* Block task until events occur or timeout               */
                     if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {
                         CPU_CRITICAL_EXIT();
                        *p_err = OS_ERR_PEND_WOULD_BLOCK;       /* Specified non-blocking so task would block             */
                         return ((OS_FLAGS)0);
                     } else {                                   /* Specified blocking so check is scheduler is locked     */
                         if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* See if called with scheduler locked ...      */
                             CPU_CRITICAL_EXIT();
                            *p_err = OS_ERR_SCHED_LOCKED;                 /* ... can't PEND when locked                   */
                             return ((OS_FLAGS)0);
                         }
                     }
                                                                
                     OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();     /* Lock the scheduler/re-enable interrupts                */
                     OS_FlagBlock(&pend_data,
                                  p_grp,
                                  flags,
                                  opt,
                                  timeout);
                     OS_CRITICAL_EXIT_NO_SCHED();
                 }
                 break;
    
            default:
                 CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_OPT_INVALID;
                 return ((OS_FLAGS)0);
        }
    
        OSSched();                                              /* Find next HPT ready to run                             */
    
        CPU_CRITICAL_ENTER();
        switch (OSTCBCurPtr->PendStatus) {
            case OS_STATUS_PEND_OK:                             /* We got the vent flags                                  */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = OSTCBCurPtr->TS;
                 }
                *p_err = OS_ERR_NONE;
                 break;
    
            case OS_STATUS_PEND_ABORT:                          /* Indicate that we aborted                               */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = OSTCBCurPtr->TS;
                 }
                 CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_PEND_ABORT;
                 return ((OS_FLAGS)0);
    
            case OS_STATUS_PEND_TIMEOUT:                        /* Indicate that we didn't get semaphore within timeout   */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = (CPU_TS  )0;
                 }
                 CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_TIMEOUT;
                 return ((OS_FLAGS)0);
    
            case OS_STATUS_PEND_DEL:                            /* Indicate that object pended on has been deleted        */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = OSTCBCurPtr->TS;
                 }
                 CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_OBJ_DEL;
                 return ((OS_FLAGS)0);
    
            default:
                 CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_STATUS_INVALID;
                 return ((OS_FLAGS)0);
        }
    
        flags_rdy = OSTCBCurPtr->FlagsRdy;
        if (consume == DEF_TRUE) {                              /* See if we need to consume the flags                    */
            switch (mode) {
                case OS_OPT_PEND_FLAG_SET_ALL:
                case OS_OPT_PEND_FLAG_SET_ANY:                  /* Clear ONLY the flags we got                            */
                     p_grp->Flags &= ~flags_rdy;
                     break;
    
                default:
                     CPU_CRITICAL_EXIT();
                    *p_err = OS_ERR_OPT_INVALID;
                     return ((OS_FLAGS)0);
            }
        }
        CPU_CRITICAL_EXIT();
       *p_err = OS_ERR_NONE;                                    /* Event(s) must have occurred                            */
        return (flags_rdy);
    }

    flags:bit序列,任务需要等待事件标志组的哪个位就把这个序列对应的位置1,根据设置这个序列可以是8bit、16bit或者32bit。比如任务需要等待时间标志组的bit0和bit1时(无论是等待置位还是清零),flag是的值就为0X03。

    opt:决定任务等待的条件是所有标志置位、所有标志清零、任意一个标志置位还是任意一个标志清零,具体的定义如下。

    OS_OPT_PEND_FLAG_CLR_ALL:等待事件标志组所有的位清零;
    OS_OPT_PEND_FLAG_CLR_ANY:等待事件标志组中任意一个标志清零;
    OS_OPT_PEND_FLAG_SET_ALL:等待事件标志组中所有的位置位;
    OS_OPT_PEND_FLAG_SET_ANY:等待事件标志组中任意一个标志置位。

    调用上面四个选项的时候还可以搭配下面三个选项:

    OS_OPT_PEND_FLAG_CONSUME:用来设置是否继续保留该事件标志的状态;
    OS_OPT_PEND_NON_BLOCKING:标志组不满足条件时不挂起任务;
    OS_OPT_PEND_BLOCKING:标志组不满足条件时挂起任务。

    这里应该注意选项OS_OPT_PEND_FLAG_CONSUME的使用方法,如果我们希望任务等待事件标志组的任意一个标志置位,并在满足条件后将对应的标志清零那么就可以搭配使用选项OS_OPT_PEND_FLAG_CONSUME。

    OSFlagPend()允许将事件标志组里事件标志的“与或”组合状态设置成任务的等待条件。任务等待的条件可以是标志组里任意一个标志置位或清零,也可以是所有事件标志都置位或清零。如果任务等待的事件标志组不满足设置的条件,那么该任务被置位挂起状态,直到等待的事件标志组满足条件、指定的超时时间到、事件标志被删除或另一个任务终止了该任务的挂起状态。

    向事件标志组发布标志

    调用函数OSFlagPost()可以对事件标志组进行置位或清零,函数原型如下:

    OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *p_grp,                    //指向事件标志组
                          OS_FLAGS      flags,                    //决定对哪些位清零和置位
                          OS_OPT        opt,                    //决定对标志位的操作
                          OS_ERR       *p_err)
    {
        OS_FLAGS  flags_cur;
        CPU_TS    ts;
    
        ts = OS_TS_GET();                                       /* Get timestamp                                          */
    
        flags_cur = OS_FlagPost(p_grp,
                                flags,
                                opt,
                                ts,
                                p_err);
    
        return (flags_cur);
    }

    flags:决定对哪些位清零和置位,当opt参数为OS_OPT_POST_FLAG_SET的时,参数flags中置位的位就会在事件标志组中对应的位也将被置位;当opt为OS_OPT_POST_FLAG_CLR的时候参数flags中置位的位在事件标志组中对应的位将被清零。

    opt:决定对flags选定的标志位的操作,有两种选项可供选择。OS_OPT_POST_FLAG_SET:对标志位进行置位操作;OS_OPT_POST_FLAG_CLR:对标志位进行清零操作。

    这个函数的返回值时当前的flags值,通过该返回值,可以查到此时本任务在flags中的哪一个位有没有被置位,或者其他还有哪些任务在flags中的标志。

    一般情况下,需要进行置位或者清零的标志由一个掩码确定(参数flags)。OSFlagPost()修改完事件标志后,将检查并使那些等待条件已经满足的任务进入就绪态。该函数可以对已经置位或清零的标志进行重复置位和清零操作。

     

    UCOSIII实际例程

    时间标志组实验

    例程要求:设计一个程序,只有按下KEY0和KEY1(不需要同时按下)时任务flagsprocess_task任务才能执行。

    例子:

    #include "sys.h"
    #include "delay.h"
    #include "usart.h"
    #include "led.h"
    #include "lcd.h"
    #include "key.h"
    #include "malloc.h"
    #include "sram.h"
    #include "beep.h"
    #include "includes.h"
    
    //UCOSIII中以下优先级用户程序不能使用,ALIENTEK
    //将这些优先级分配给了UCOSIII的5个系统内部任务
    //优先级0:中断服务服务管理任务 OS_IntQTask()
    //优先级1:时钟节拍任务 OS_TickTask()
    //优先级2:定时任务 OS_TmrTask()
    //优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
    //优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
    
    //任务优先级
    #define START_TASK_PRIO		3
    //任务堆栈大小	
    #define START_STK_SIZE 		128
    //任务控制块
    OS_TCB StartTaskTCB;
    //任务堆栈	
    CPU_STK START_TASK_STK[START_STK_SIZE];
    //任务函数
    void start_task(void *p_arg);
    
    //任务优先级
    #define MAIN_TASK_PRIO		4
    //任务堆栈大小	
    #define MAIN_STK_SIZE 		128
    //任务控制块
    OS_TCB Main_TaskTCB;
    //任务堆栈	
    CPU_STK MAIN_TASK_STK[MAIN_STK_SIZE];
    void main_task(void *p_arg);
    
    //任务优先级
    #define FLAGSPROCESS_TASK_PRIO	5
    //任务堆栈大小	
    #define FLAGSPROCESS_STK_SIZE 	128
    //任务控制块
    OS_TCB Flagsprocess_TaskTCB;
    //任务堆栈	
    CPU_STK FLAGSPROCESS_TASK_STK[FLAGSPROCESS_STK_SIZE];
    //任务函数
    void flagsprocess_task(void *p_arg);
    
    //LCD刷屏时使用的颜色
    int lcd_discolor[14]={	WHITE, BLACK, BLUE,  BRED,      
    						GRED,  GBLUE, RED,   MAGENTA,       	 
    						GREEN, CYAN,  YELLOW,BROWN, 			
    						BRRED, GRAY };
    
    事件标志组//
    #define KEY0_FLAG		0x01
    #define KEY1_FLAG		0x02
    #define KEYFLAGS_VALUE	0X00						
    OS_FLAG_GRP	EventFlags;		//定义一个事件标志组
    												
    //加载主界面
    void ucos_load_main_ui(void)
    {
    	POINT_COLOR = RED;
    	LCD_ShowString(30,10,200,16,16,"ALIENTEK STM32F1");	
    	LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 12-1");
    	LCD_ShowString(30,50,200,16,16,"Event Flags");
    	LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
    	LCD_ShowString(30,90,200,16,16,"2015/3/19");
    	POINT_COLOR = BLACK;
    	LCD_DrawRectangle(5,130,234,314);	//画矩形
    	POINT_COLOR = BLUE;
    	LCD_ShowString(30,110,220,16,16,"Event Flags Value:0");
    }
    
    int main(void)                                //主函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	
    	delay_init();  //时钟初始化
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
    	uart_init(115200);   //串口初始化
    	LED_Init();         //LED初始化	
    	LCD_Init();			//LCD初始化	
    	KEY_Init();			//按键初始化
    	BEEP_Init();		//初始化蜂鸣器
    	FSMC_SRAM_Init();	//初始化SRAM
    	my_mem_init(SRAMIN);//初始化内部RAM
    	ucos_load_main_ui();//加载主UI
    	
    	OSInit(&err);		    //初始化UCOSIII
    	OS_CRITICAL_ENTER();	//进入临界区			 
    	//创建开始任务
    	OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块
    				 (CPU_CHAR	* )"start task", 		//任务名字
                     (OS_TASK_PTR )start_task, 			//任务函数
                     (void		* )0,					//传递给任务函数的参数
                     (OS_PRIO	  )START_TASK_PRIO,     //任务优先级
                     (CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址
                     (CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位
                     (CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小
                     (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                     (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                     (void   	* )0,					//用户补充的存储区
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                     (OS_ERR 	* )&err);				//存放该函数错误时的返回值
    	OS_CRITICAL_EXIT();	//退出临界区	 
    	OSStart(&err);      //开启UCOSIII
    }
    
    void start_task(void *p_arg)                            //开始任务函数
    {
    	OS_ERR err;
    	CPU_SR_ALLOC();
    	p_arg = p_arg;
    	
    	CPU_Init();
    #if OS_CFG_STAT_TASK_EN > 0u
       OSStatTaskCPUUsageInit(&err);  	//统计任务                
    #endif
    	
    #ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
        CPU_IntDisMeasMaxCurReset();	
    #endif
    	
    #if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
    	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
    	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
    #endif	
    		
    	OS_CRITICAL_ENTER();	//进入临界区
    	//创建一个事件标志组
    	OSFlagCreate((OS_FLAG_GRP*)&EventFlags,		//指向事件标志组
                     (CPU_CHAR*	  )"Event Flags",	//名字
                     (OS_FLAGS	  )KEYFLAGS_VALUE,	//事件标志组初始值
                     (OS_ERR*  	  )&err);			//错误码
    
    	OSTaskCreate((OS_TCB*     )&Main_TaskTCB,	                	//创建主任务	
    				 (CPU_CHAR*   )"Main task", 		
                     (OS_TASK_PTR )main_task, 			
                     (void*       )0,					
                     (OS_PRIO	  )MAIN_TASK_PRIO,     
                     (CPU_STK*    )&MAIN_TASK_STK[0],	
                     (CPU_STK_SIZE)MAIN_STK_SIZE/10,	
                     (CPU_STK_SIZE)MAIN_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void*       )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR*     )&err);						
    
    	OSTaskCreate((OS_TCB*     )&Flagsprocess_TaskTCB,			//创建MSGDIS任务
    				 (CPU_CHAR*   )"Flagsprocess task", 		
                     (OS_TASK_PTR )flagsprocess_task, 			
                     (void* 	  )0,					
                     (OS_PRIO	  )FLAGSPROCESS_TASK_PRIO,     
                     (CPU_STK* 	  )&FLAGSPROCESS_TASK_STK[0],	
                     (CPU_STK_SIZE)FLAGSPROCESS_STK_SIZE/10,	
                     (CPU_STK_SIZE)FLAGSPROCESS_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void* 	  )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR* 	  )&err);	
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void main_task(void *p_arg)                        //主任务的任务函数
    {    
    	u8 key,num;
    	OS_FLAGS flags_num;
    	OS_ERR err;
    	while(1)
    	{
    		key = KEY_Scan(0);  //扫描按键
    		if(key == KEY0_PRES)
    		{
    			//向事件标志组EventFlags发送标志
    			flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,
    								 (OS_FLAGS	  )KEY0_FLAG,
    								 (OS_OPT	  )OS_OPT_POST_FLAG_SET,
    					             (OS_ERR*	  )&err);
    			LCD_ShowxNum(174,110,flags_num,1,16,0);
    			printf("事件标志组EventFlags的值:%d\r\n",flags_num);
    		}
    		else if(key == KEY1_PRES)
    		{
    			//向事件标志组EventFlags发送标志
    			flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,
    								 (OS_FLAGS	  )KEY1_FLAG,
    								 (OS_OPT	  )OS_OPT_POST_FLAG_SET,
    								 (OS_ERR*     )&err);
    			LCD_ShowxNum(174,110,flags_num,1,16,0);
    			printf("事件标志组EventFlags的值:%d\r\n",flags_num);
    		}
    		num++;
    		if(num==50)
    		{
    			num=0;
    			LED0 = ~LED0;
    		}
    		OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   //延时10ms
    	}
    }
    
    void flagsprocess_task(void *p_arg)                        //事件标志组处理任务
    {
    	u8 num;
    	OS_ERR err; 
    	while(1)
    	{
    		//等待事件标志组
    		OSFlagPend((OS_FLAG_GRP*)&EventFlags,
    				   (OS_FLAGS	)KEY0_FLAG+KEY1_FLAG,
    		     	   (OS_TICK     )0,
    				   (OS_OPT	    )OS_OPT_PEND_FLAG_SET_ALL+OS_OPT_PEND_FLAG_CONSUME,
    				   (CPU_TS*     )0,
    				   (OS_ERR*	    )&err);
    		num++;
    		LED1 = ~LED1;
    		LCD_Fill(6,131,233,313,lcd_discolor[num%14]);
    		printf("事件标志组EventFlags的值:%d\r\n",EventFlags.Flags);
    		LCD_ShowxNum(174,110,EventFlags.Flags,1,16,0);
    	}
    }
    	//创建主任务	
    				 (CPU_CHAR*   )"Main task", 		
                     (OS_TASK_PTR )main_task, 			
                     (void*       )0,					
                     (OS_PRIO	  )MAIN_TASK_PRIO,     
                     (CPU_STK*    )&MAIN_TASK_STK[0],	
                     (CPU_STK_SIZE)MAIN_STK_SIZE/10,	
                     (CPU_STK_SIZE)MAIN_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void*       )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR*     )&err);						
    
    	OSTaskCreate((OS_TCB*     )&Flagsprocess_TaskTCB,			//创建MSGDIS任务
    				 (CPU_CHAR*   )"Flagsprocess task", 		
                     (OS_TASK_PTR )flagsprocess_task, 			
                     (void* 	  )0,					
                     (OS_PRIO	  )FLAGSPROCESS_TASK_PRIO,     
                     (CPU_STK* 	  )&FLAGSPROCESS_TASK_STK[0],	
                     (CPU_STK_SIZE)FLAGSPROCESS_STK_SIZE/10,	
                     (CPU_STK_SIZE)FLAGSPROCESS_STK_SIZE,		
                     (OS_MSG_QTY  )0,					
                     (OS_TICK	  )0,  					
                     (void* 	  )0,					
                     (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
                     (OS_ERR* 	  )&err);	
    	OS_CRITICAL_EXIT();	//退出临界区
    	OSTaskDel((OS_TCB*)0,&err);	//删除start_task任务自身
    }
    
    void main_task(void *p_arg)                        //主任务的任务函数
    {    
    	u8 key,num;
    	OS_FLAGS flags_num;
    	OS_ERR err;
    	while(1)
    	{
    		key = KEY_Scan(0);  //扫描按键
    		if(key == KEY0_PRES)
    		{
    			//向事件标志组EventFlags发送标志
    			flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,
    								 (OS_FLAGS	  )KEY0_FLAG,
    								 (OS_OPT	  )OS_OPT_POST_FLAG_SET,
    					             (OS_ERR*	  )&err);
    			LCD_ShowxNum(174,110,flags_num,1,16,0);
    			printf("事件标志组EventFlags的值:%d\r\n",flags_num);
    		}
    		else if(key == KEY1_PRES)
    		{
    			//向事件标志组EventFlags发送标志
    			flags_num=OSFlagPost((OS_FLAG_GRP*)&EventFlags,
    								 (OS_FLAGS	  )KEY1_FLAG,
    								 (OS_OPT	  )OS_OPT_POST_FLAG_SET,
    								 (OS_ERR*     )&err);
    			LCD_ShowxNum(174,110,flags_num,1,16,0);
    			printf("事件标志组EventFlags的值:%d\r\n",flags_num);
    		}
    		num++;
    		if(num==50)
    		{
    			num=0;
    			LED0 = ~LED0;
    		}
    		OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   //延时10ms
    	}
    }
    
    void flagsprocess_task(void *p_arg)                        //事件标志组处理任务
    {
    	u8 num;
    	OS_ERR err; 
    	while(1)
    	{
    		//等待事件标志组
    		OSFlagPend((OS_FLAG_GRP*)&EventFlags,
    				   (OS_FLAGS	)KEY0_FLAG+KEY1_FLAG,
    		     	   (OS_TICK     )0,
    				   (OS_OPT	    )OS_OPT_PEND_FLAG_SET_ALL+OS_OPT_PEND_FLAG_CONSUME,
    				   (CPU_TS*     )0,
    				   (OS_ERR*	    )&err);
    		num++;
    		LED1 = ~LED1;
    		LCD_Fill(6,131,233,313,lcd_discolor[num%14]);
    		printf("事件标志组EventFlags的值:%d\r\n",EventFlags.Flags);
    		LCD_ShowxNum(174,110,EventFlags.Flags,1,16,0);
    	}
    }

     

    展开全文
  • ucosiii之事件标志组

    2019-04-11 16:56:33
    事件标志组 有时候一个任务需要多个事件同步时,就需要用到事件标志组了。 相关函数 一般情况下只用到OSFlagPost(),OSFlagPend(),OSFlagCreate()三个函数 OSFlagPost()函数的返回值是当前的事件标志组的事件...
  • 第七章 事件标志组

    2019-08-28 16:58:28
    事件位(事件标志) 活动组 事件组和事件位数据类型 ... 事件标志组,某个任务与多个事件或任务进行同步。 1.1为什么要使用事件标志 事件标志组是实现多任务同步的有效机制之一。也...
  • FreeRTOS xEventGroup事件标志组

    千次阅读 2019-04-05 23:20:37
    事件标志组属于任务间的通信以及同步机制之一。 1、什么是时间标志组? 事件标志组可以实现多任务间的任务同步,简单来说就是在不同的任务间传递简单的标志位(这里之前被esp吐槽说我们的代码还处在51阶段,到处...
  • 2.2 题目组合 2 程序设计题目-事件标志组编程 目标设计三个任务当时间到且独立按健被按下过让LED 闪耀一下设LED 任务为高 优先级任务三个任务的处理流程如图下面是三个任务的处理流程 按键中断 定时发送标志任务 LED...
  • 事件标志组是实现多任务同步的有效机制之一。任务间事件标志组的实现是指各个任务之间使用事件标志组实现任务的通信或者同步机制。FreeRTOS在event_groups.c/h文件中提供了事件标志组的具体实现。   根据具体平台...
  • 文章目录1 事件标志组的原理与创建1.1 问题概述1.2 设计原理1.3 设计实现 1 事件标志组的原理与创建 1.1 问题概述 如何在中断ISR与任务之间传递多个事件标志? 可以通过事件标志组事件标志组可以提供类似前后台...
  • V5-409_RTX实验_事件标志组.7z
  • UCOSIII事件标志组

    2016-11-14 13:44:23
    我们可以使用信号量来完成任务同步,这里我们再讲解一下另外一种任务同步的方法,就是事件标志组事件标志组用来解决一个恩物和多个事件之间的同步 事件标志组 有时候一个任务可能需要和多个事件同步,这个时候就...
  • V5-312_FreeRTOS实验_ 事件标志组
  • V5-410_RTX实验_事件标志组(中断方式).7z
  • 任务通知用作事件标志组 任务通知用作事件标志组的优点 任务通知用作事件标志组的缺点 部分API 测试程序 特性 每个任务都有一个32位的任务任务通知值,任务通知是直接发送到任务的事件,可以解除接收任务的...
  • 信号量能使单个事件或者任务进行同步, 但是当需要某个任务和多个事件或任务同步时,信号量就无能为力, 所以FreeRTOS提供一个可选的解决方法, 那就是事件标志组. 1, 创建事件标志组 xEventGroupCreate() // 使用...
  • 介绍FreeRTOS中事件标志组的创建、删除、获取、设置、清除、同步等等功能,通过分析源代码分析其原理。
  • STM32学习之:事件标志组

    千次阅读 2017-10-18 17:55:02
    事件标志组是实现多任务同步的有效机制之一。也许有不理解的初学者会问采用事件标志组多麻烦, 搞个全局变量不是更简单?其实不然,在裸机编程时,使用全局变量的确比较方便,但是在加上 RTOS 后 就是另一种情况了...
  • V5-313_FreeRTOS实验_事件标志组 (中断方式)
  • UC/OS II 事件标志组管理(一)

    千次阅读 2015-09-14 22:20:03
    如果任务要等待多个事情的发生,或多个事情中的某一个发生,那么就应该采用事件标志组管理。 1:事件标志组数据结构 事件标志组的主要数据结构包括事件标志组、事件标志节点、事件标志组实体、链表等。 事件标志组OS...
  • 2016-07-07 LT 事件标志组: 用来保存当前事件组中各事件状态的一些标志。 等待这些标志位置位或清除的任务列表。
  • 事件标志组相关实验
  • UCOS2:对于信号量,互斥信号量,事件标志组的个人理解,看起来挺好的。
  • ucos ii的事件标志组原理分析

    千次阅读 2016-08-11 11:33:42
    很早以前就开始学习移植USOS ii了,移植倒没什么难的,主要是要清楚自己的单片机,最好是将启动代码分析一遍,那么在移植的时候,很多概念就不会陌生了。...那么切入正题吧,我是先从事件标志组开始分析的。首先看

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 104,690
精华内容 41,876
关键字:

事件标志组