zoukankan      html  css  js  c++  java
  • FreeRTOS_事件标志组

    FreeRTOS事件标志组

    事件标志组简介

    1. 事件位(事件标志)

    事件位用于表明某个事件是否发生,事件位通常用作事件标志,比如下面的几个例子:

      当收到一条消息并且把这条消息处理掉以后就可以将某个位(标志)置1,当队列中没有消息需要处理的时候就可以将这个位(标志)置0。

      当把队列中的消息通过网络发送输出以后就可以将某个位(标志)置1,当没有数据需要从网络发送出去的话就将这个位(标志)置0。

      现在需要向网络中发送一个心跳信息,将某个位(标志)置1。现在不需要项网络中发送心跳信息,这个位(标志)置0。

    2. 事件组

    一个事件组就是一组的事件位,事件组中的事件位通过位编号来访问,同样,以上面列出的三个例子为例:

      事件标志组bit0 表示队列中的消息是否处理掉。

      事件标志组bit1 表示是否有纤细需要从网络中发送出去。

      事件标志组bit2 表示现在是否需要向网路发送心跳信息。

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

      事件标志组的数据类型为 EventBits_t,当configUSE_16_BIT_TICKS为1的时候,事件标志组可以存储8个事件位,当configUSE_16_BIT_TICKS为0的时候,事件标志组存储24个事件位。

      事件标志组中所有事件位都存储在一个无符号的EventBits_t类型的变量中,EventBits_t在event_groups.h中有如下定义:

    typedef TickType_t EventBits_t;

      数据类型TickType_t在文件portmacro.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
    
        /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
        not need to be guarded with a critical section. */
        #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个事件位,如下图:

    创建事件标志组

       FreeRTOS提供了两个用于创建事件标志组的函数:

    函数 描述
    xEventGroupCreate() 使用动态方法创建事件标志组
    xEventGroupCreateStatic() 使用静态方法创建事件标志组

    1. 函数 xEventGroupCreate()

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

    EventGroupHandle_t xEventGroupCreate( void )

    参数:

      无。

    返回值:

      NULL:事件标志组创建失败。

      其他值:创建成功的事件标志组句柄。

    2. 函数xEventGroupCreateStatic()

    此函数用于创建一个事件标志组,所需要的内存需要用于自行分配,此函数原型如下:

    EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t *pxEventGroupBuffer )

    参数:

      pxEventGroupBuffer:参数指向一个StaticEventGroup_t类型的变量,用来保存时间组结构体。

    返回值:

      NULL:事件标志组创建失败。

      其他值:创建成功的事件标志组句柄。

    设置事件位

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

    函数 描述
    xEventGroupClearBits() 将指定的事件位清零,用在任务中。
    xEventGroupClearBitsFromISR() 将指定的事件位清零,用在中断服务函数中。
    xEventGroupSetBits() 将指定的事件位置1,用在任务中。
    xEventGroupSetBitsFromISR() 将指定的事件位置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:要操作的事件标志组句柄。

      uxBitsToSet:指定要置1的事件位,比如要将bit3 置1的话就设置为0x08。可以同时将多个bit置1,如设置为0x09的话就是同时将bit3和bit0置1。

    返回值:

      任何值:在将指定事件位置1后的事件组值。

    3. 函数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失败。

    获取事件标志组值

      我们可以通过FreeRTOS提供的API函数来查询事件标志组值。FreeRTOS一共提供了两个这样的API函数。

    函数 描述
    xEventGroupGetBits() 获取当前事件标志组的值(各个事件位的值),用在任务中
    xEventGroupGetBitsFromISR() 获取当前事件标志组的值,用在中断服务函数中。

    1. 函数xEventGroupGetBits()

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

    EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup )

    参数:

      xEventGroup:要获取的事件标志组的句柄。

    返回值:

      任何值:当前时间标志组的值。

    2. 函数xEventGroupGetBitsFromISR()

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

    EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )

    参数:

      xEventGroup:要获取的事件标志组的句柄。

    返回值:

      任何值:当前事件标志组的值。

    等待指定的事件位

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

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

    参数:

      xEventGroup:指定要等待的事件标志组。

      uxBitsToWaitFor:指定要等待的事件位,比如要等待bit0和(或)bit2的时候,此参数就是0x05,如果要等待bit0和(或)bit1和(或)bit2的时候此函数就是0x07,以此类推。

      xClearOnExit:此参数要是pdTRUE的话,那么在退出此函数之前有由参数uxBitsToWaitFor所设置的这些事件位就会清零。如果设置为pdFALSE的话这些事件位就不会改变。

      xWaitForAllBits:此参数如果设置为pdTRUE的话,当uxBitsToWaitFor所设置的这些事件位都置1,或者指定的阻塞时间到的时候函数xEventGroupWaitBits()才会返回。当此参数为pdFALSE的话,只要uxBitsToWaitFor所设置的这些事件位其中的任意一个置1,或者指定的阻塞时间到的话函数xEventGroupWaitBits()就会返回。

      xTicksToWait:设置阻塞时间,单位为节拍数。

    返回值:

      任何值:返回当所等待的事件位置1以后的事件标志组的值,或者阻塞时间到。根据这个值我们就知道哪些事件位置1了。如果函数因为阻塞时间到而返回的话,那么这个返回值就不代表任何的含义。

    事件标志组实验

    创建事件标志组、将相应的事件位置1、等待相应事件位置1的操作。

    实验设置三个任务:start_task、eventsetbit_task、eventgroup_task。

    start_task:用来创建其他两个任务,创建时间标志组。

    eventsetbit_task:通过不同按键值,将事件标志组中相应事件位置1。

    eventgroup_task:等待事件标志组中的事件位,当这些事件位都置1,执行相应的处理。

    EventGroupHandler:创建的事件标志组句柄。使用事件标志组的事件位:bit0 bit1 bit2

    任务分配:

    //任务优先级
    #define START_TASK_PRIO        1
    //任务堆栈大小    
    #define START_STK_SIZE         128  
    //任务句柄
    TaskHandle_t StartTask_Handler;
    //任务函数
    void start_task(void *pvParameters);
    
    //任务优先级
    #define EVENTSETBIT_TASK_PRIO        2
    //任务堆栈大小    
    #define EVENTSETBIT_STK_SIZE         50  
    //任务句柄
    TaskHandle_t EventSetbitTask_Handler;
    //任务函数
    void eventsetbit_task(void *pvParameters);
    
    //任务优先级
    #define EVENTGROUP_TASK_PRIO        3
    //任务堆栈大小    
    #define EVENTGROUP_STK_SIZE         50  
    //任务句柄
    TaskHandle_t EventGroupTask_Handler;
    //任务函数
    void eventgroup_task(void *pvParameters);
    
    EventGroupHandle_t EventGroupHandle;    // 事件标志组句柄
    
    // 定义事件位
    #define BIT_0    (1<<0)
    #define BIT_1    (1<<1)
    #define BIT_2    (1<<2)

    main() 函数:

    int main(void)
    {
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4     
        delay_init();                        //延时函数初始化      
        uart_init(115200);                    //初始化串口
        LED_Init();                              //初始化LED
        KEY_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();           //进入临界区
        
        EventGroupHandle =  xEventGroupCreate();            // 创建事件标志组
        if(EventGroupHandle == NULL)
        {
            printf("EventGroup Create Failed!
    ");
        }
        
        //创建eventsetbit任务
        xTaskCreate((TaskFunction_t )eventsetbit_task,         
                    (const char*    )"eventsetbit_task",       
                    (uint16_t       )EVENTSETBIT_STK_SIZE, 
                    (void*          )NULL,                
                    (UBaseType_t    )EVENTSETBIT_TASK_PRIO,    
                    (TaskHandle_t*  )&EventSetbitTask_Handler);   
        //创建eventgroup任务
        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();            //退出临界区
    }
    
    //eventsetbit_task任务函数 
    void eventsetbit_task(void *pvParameters)
    {
        u8 key = 0;
        
        while(1)
        {
            key = KEY_Scan(0);
            switch(key)
            {
                case KEY1_PRES:
                    if(EventGroupHandle != NULL)
                    {
                        xEventGroupSetBits(EventGroupHandle,BIT_0);    // 设置事件标志组 BIT_0 置1
                    }
                    break;
                case KEY2_PRES:
                    if(EventGroupHandle != NULL)
                    {
                        xEventGroupSetBits(EventGroupHandle,BIT_1);    // 设置事件标志组 BIT_0 置1
                    }
                    break;
            }
            vTaskDelay(10);
        }
    }   
    
    //eventgroup_task任务函数
    void eventgroup_task(void *pvParameters)
    {
        EventBits_t EventBitsVal = 0;
        
        while(1)
        {
            if(EventGroupHandle != NULL)
            {
                EventBitsVal = xEventGroupWaitBits(
                                                    EventGroupHandle,        // 要等待的事件标志组
                                                    (BIT_0|BIT_1),            // 等待的事件位
                                                    pdTRUE,                    // 清零
                                                    pdFALSE,                // 只要事件位其一得到就退出
                                                    portMAX_DELAY );        // 死等
                
                printf("EventBitsVal = %#x
    ",EventBitsVal);
            }else{
                vTaskDelay(10);
            }
            
        }
    }

    运行结果:

    按下KEY1,输出 EventBitsVal = 0x1

    按下KEY2,输出  EventBitsVal = 0x2

  • 相关阅读:
    HDU5418.Victor and World(状压DP)
    POJ2686 Traveling by Stagecoach(状压DP)
    POJ3254Corn Fields(状压DP)
    HDU5407.CRB and Candies(数论)
    CodeForces 352D. Jeff and Furik
    CodeForces 352C. Jeff and Rounding(贪心)
    LightOj 1282 Leading and Trailing
    Ural 1057. Amount of Degrees(数位DP)
    HDU 2089 不要62 (数位DP)
    HDU5366 The mook jong (DP)
  • 原文地址:https://www.cnblogs.com/doitjust/p/11058293.html
Copyright © 2011-2022 走看看