• 【FreeRTOS】事件组的使用


    ❤️作者主页:凉开水白菜
    ❤️作者简介:共同学习,互相监督,热于分享,多加讨论,一起进步!
    ❤️专栏资料:https://pan.baidu.com/s/1nc1rfyLiMyw6ZhxiZ1Cumg?pwd=free
    ❤️点赞 👍 收藏 ⭐再看,养成习惯

    订阅的粉丝可通过PC端左侧加我微信,可对文章的内容进行一对一答疑!



    前言

    事件组与信号量类似,我们可以把事件组理解为一个整数(在FreeRTOSConfig.h文件中),用其中一位来表示一个任务的状态0-1,我们可以通过这些任务的组合来进行任务执行的判断标准;他与信号量不同的是事件组能针对1对多,多对多的任务,例如我们按键按下事件组可以通知多个任务开始执行,或者某个任务可以等待多个任务完成后在执行等;

    如果configUSE_16_BIT_TICKS是1,那么这个整数就是16位的,低8位用来表示事件
    如果configUSE_16_BIT_TICKS是0,那么这个整数就是32位的,低24位用来表示事件该整数

    创建、删除事件

    // 创建事件组
    EventGroupHandle_t xEventGroupCreate( void );
    
    // 删除事件组
    void vEventGroupDelete( EventGroupHandle_t xEventGroup )
    
    • 1
    • 2
    • 3
    • 4
    • 5

    事件组的创建非常简单直接调用xEventGroupCreate就可以返回一个事件组的句柄,删除事件组也只需要调用vEventGroupDelete传入事件组句柄即可;

    设置、同步事件

    EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
                                        const EventBits_t uxBitsToSet );
    
    • 1
    • 2

    EventGroupHandle_t xEventGroup:指定完成的事件组
    const EventBits_t uxBitsToSet:指定完成的事件的标志位(这里一般用移位来表示)
    在中断中应该使用xEventGroupSetBitsFromISR来设置;

    EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
                                     const EventBits_t uxBitsToWaitFor,
                                     const BaseType_t xClearOnExit,
                                     const BaseType_t xWaitForAllBits,
                                     TickType_t xTicksToWait );
    
    • 1
    • 2
    • 3
    • 4
    • 5

    EventGroupHandle_t xEventGroup:指定完成的事件组
    const EventBits_t uxBitsToWaitFor:等待的事件的标志位(这里可以使用或符号APP1|APP2表示这两个事件都能唤醒这个等待)
    const BaseType_t xClearOnExit:pdTRUE表示事件执行完成后清楚事件标志位,pdFALSE则是保留
    const BaseType_t xWaitForAllBits:pdTRUE判断等待的位都为1,pdFALSE判断等待的位某一个为1即可
    TickType_t xTicksToWait:可设置为portMAX_DELAY:一定等到成功才返回,可以设置为期望的Tick Count,一般用pdMS_TO_TICKS()把ms转换为Tick Count

    EventBits_t xEventGroupSync(    EventGroupHandle_t xEventGroup,
                                    const EventBits_t uxBitsToSet,
                                    const EventBits_t uxBitsToWaitFor,
                                    TickType_t xTicksToWait );
    
    • 1
    • 2
    • 3
    • 4

    EventGroupHandle_t xEventGroup:指定完成的事件组
    const EventBits_t uxBitsToSet:设置自己的事件标志位
    const EventBits_t uxBitsToWaitFor:等待的事件的标志位(这里可以使用或符号APP1|APP2表示这两个事件都能唤醒这个等待)
    TickType_t xTicksToWait:可设置为portMAX_DELAY:一定等到成功才返回,可以设置为期望的Tick Count,一般用pdMS_TO_TICKS()把ms转换为Tick Count

    示例

    等待多个事件用法

    我们创建三个线程app1为优先级1,app2为优先级2,app3为优先级3;在这里如果我们给每个任务延时切换时间的话理论上是app3->app2->app1的执行顺序,但是当我们的任务三在特定情况下需要等任务1和任务2的某些处理做完了才能执行的话这里就可以用到事件组,这里引用韦东山老师的例子,本示例相当于做饭的一个做成,app1相当于洗菜,app2相当于生火,app3相当于炒菜;当我们菜洗好了锅里才能生火,火生好了后才能继续炒菜,所以最终的执行顺序就是app1->app2->app3;

      event_group = xEventGroupCreate( );
        
      /* 创建app_task任务 */
      xTaskCreate((TaskFunction_t )app1_task,"app1",512,NULL,1,NULL);
      xTaskCreate((TaskFunction_t )app2_task,"app2",512,NULL,2,NULL);
      xTaskCreate((TaskFunction_t )app3_task,"app3",512,NULL,3,NULL);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    EventGroupHandle_t event_group;
    
    /*
    * bit0: app1执行完成
    * bit1: app2执行完成
    * bit2: app3执行完成
    */
    #define APP1  (1<<0)
    #define APP2  (1<<1)
    #define APP3  (1<<2)
    
    static void app1_task(void *par)
    {
        printf("优先级最低:app1\r\n");
        while(1)
        {
            printf("app1_task ok\r\n");
            xEventGroupSetBits(event_group, APP1);	                                /* APP1 执行完成 */
            xEventGroupWaitBits( event_group,APP3,pdTRUE,pdTRUE,portMAX_DELAY);     /* 等待 APP3 执行完成 */
        }
    }
    
    static void app2_task(void *par)
    {
        printf("优先级中等:app2\r\n");
        while(1)
        {
            xEventGroupWaitBits( event_group,APP1,pdFALSE,pdTRUE,portMAX_DELAY);    /* 等待 APP1 执行完成 */
            printf("app2_task ok\r\n");
            xEventGroupSetBits(event_group, APP2);                                  /* APP2 执行完成 */
        }
    }
    
    static void app3_task(void *par)
    {
        printf("优先级最高:app3\r\n");
        while(1)
        {
            xEventGroupWaitBits( event_group,APP1|APP2,pdTRUE,pdTRUE,portMAX_DELAY);/* 等待APP1和APP2 执行完成 */
            printf("app3_task ok\r\n");
            xEventGroupSetBits(event_group, APP3);                                  /* APP3 执行完成 */
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    我们可以看到在没获取事件的前提下我们的printf(“优先级最高:app3\r\n”);打印还是按照线程优先级执行的,当进入事件组xEventGroupWaitBits等待的时候就线程就进入阻塞状态切换到其他线程执行,当任务一发出完成事件后开始唤醒两个任务,任务二和任务三进入事件判断,任务二只需要任务一执行完成就可以执行所以满足条件,然而任务三需要任务一和任务二同时满足才能执行所以这里不满足条件不执行,等任务二发出执行完成信号后两个任务开始进行事件判断,优先级高的任务三开始判断任务一和任务二的事件是否执行完成,满足条件开始执行然后发出任务三完成信号然后继续响应判断,如此往复;
    在这里插入图片描述

    同步用法

    当我们遇到三个线程需要工程完成后才能执行的情况下使用该种方法,例如任务一是负责煮饭的人、任务二是负责炒菜的人、任务三是负责洗碗的人,如果要吃饭就必须三个人都完成了才满足吃饭条件才能让三个任务的人吃饭,示例代码如下;

    /*
    * bit0: app1执行完成
    * bit1: app2执行完成
    * bit2: app3执行完成
    */
    #define APP1  (1<<0)
    #define APP2  (1<<1)
    #define APP3  (1<<2)
    
    static void app1_task(void *par)
    {
        printf("优先级最低:app1\r\n");
        while(1)
        {
            #if FLAG
            printf("app1_task ok\r\n");
            xEventGroupSetBits(event_group, APP1);	                                /* APP1 执行完成 */
            xEventGroupWaitBits( event_group,APP3,pdTRUE,pdTRUE,portMAX_DELAY);     /* 等待 APP3 执行完成 */
            #else
            printf("我煮好饭了!\r\n");
            xEventGroupSync(event_group, APP1, APP1 | APP2 |APP3, portMAX_DELAY);
            printf("煮饭人开始吃饭\r\n");
            vTaskDelay(100); /* 等他们吃 */ 
            #endif
        }
    }
    
    static void app2_task(void *par)
    {
        printf("优先级中等:app2\r\n");
        while(1)
        {
            #if FLAG
            xEventGroupWaitBits( event_group,APP1,pdFALSE,pdTRUE,portMAX_DELAY);    /* 等待 APP1 执行完成 */
            printf("app2_task ok\r\n");
            xEventGroupSetBits(event_group, APP2);                                  /* APP2 执行完成 */
            #else
            printf("我炒好菜了!\r\n");
            xEventGroupSync(event_group, APP2, APP1 | APP2 |APP3, portMAX_DELAY);
            printf("炒菜人开始吃饭\r\n");
            vTaskDelay(100); /* 等他们吃 */ 
            #endif
        }
    }
    
    static void app3_task(void *par)
    {
        printf("优先级最高:app3\r\n");
        while(1)
        {
            #if FLAG
            xEventGroupWaitBits( event_group,APP1|APP2,pdTRUE,pdTRUE,portMAX_DELAY);/* 等待APP1和APP2 执行完成 */
            printf("app3_task ok\r\n");
            xEventGroupSetBits(event_group, APP3);                                  /* APP3 执行完成 */
            #else
            printf("我洗好碗筷了!\r\n");
            xEventGroupSync(event_group, APP3, APP1 | APP2 |APP3, portMAX_DELAY);
            printf("洗碗人开始吃饭\r\n");
            vTaskDelay(100); /* 等他们吃 */ 
            #endif
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    在这里插入图片描述

    结尾

    我是凉开水白菜,我们下文见~

  • 相关阅读:
    算法:(贪心算法)-独木舟问题
    【jvm】虚拟机之本地方法接口与本地方法库
    Hive优化
    牛掰!“基础-中级-高级”Java程序员面试集结,看完献出我的膝盖
    火焰图简介
    HC-SR501传感器制作一个报警系统
    创建TypeScript代码模板(NVS+Yarn+ESLint+Prettier+Husky)
    TPH-YOLOv5: 基于Transformer预测头的改进YOLOv5用于无人机捕获场景目标检测
    二十六、【颜色调整】
    跨域问题,无法得到数据,啾啾我把
  • 原文地址:https://blog.csdn.net/qq_43581670/article/details/127688267