当前位置 博文首页 > freemote的博客:FreeRTOS事件标志组与事件标志位使用

    freemote的博客:FreeRTOS事件标志组与事件标志位使用

    作者:[db:作者] 时间:2021-07-18 19:10

    事件标志位

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

    可用位表示:当信息收到且准备好处理时,设置为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) //软件定时器任务堆栈大小

    再次编译,通过。

    运行结果

    ?

    cs