0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

freeRTOS用于任务之间同步的手段事件标志组

汽车电子技术 来源:嵌入式之入坑笔记 作者:嵌入式之入坑笔记 2023-02-10 11:10 次阅读

freeRTOS中还有一种可以用于任务之间同步的手段 — 事件标志组。

假如在项目中,有些任务或者动作需要等到某种条件成立的时候才能被执行,不成立的时候不执行,这种情况就可以考虑使用事件标志组。设定一个事件标志,在项目运行过程中监控某种条件是否成立,如果条件成立了就设置这个事件标志位,另外一个地方如果发现这个标志位有效了,就执行这个任务或者动作,完成这个同步的过程。

0、事件标志组的配置 & 原理

FreeRTOS 中事件标志的实现,是在 FreeRTOSConfig.h 文件中配置的,如下:

1)选择 8 个可用的事件标志组

#define configUSE_16_BIT_TICKS   1

配置宏定义 configUSE_16_BIT_TICKS 为 1 时,每创建一个事件标志组,用户可以使用的事件标志是 8 个。

2)选择 24 个可用的事件标志组

#define configUSE_16_BIT_TICKS   0

配置宏定义 configUSE_16_BIT_TICKS 为 0 时,每创建一个事件标志组,用户可以使用的事件标志是 24 个。

上面说的 8 个和 24 个事件标志是怎么回事呢?

首选看看宏 configUSE_16_BIT_TICKS ** 定义了之后做了些什么吧?在文件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

注意这个 TickType_t 这个类型重声明!!!

以及下面这个类型重定义:

typedef TickType_t EventBits_t;

再看时间标志组的结构体:

typedef struct xEventGroupDefinition{  EventBits_t uxEventBits;      // 看这个、看这个、看这个!!!嘿嘿!!!  List_t xTasksWaitingForBits;    /*< List of tasks waiting for a bit to be set. */
#if( configUSE_TRACE_FACILITY == 1 ) UBaseType_t uxEventGroupNumber; #endif
} EventGroup_t;

注意看 EventBits_t uxEventBits;

最后看时间标志组的创建过程,代码如下:

EventGroupHandle_t xEventGroupCreate( void ){   EventGroup_t *pxEventBits;
pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) ); if( pxEventBits != NULL ) { pxEventBits->uxEventBits = 0; // 记得看我、记得看我、记得看我!!!嘻嘻!! vListInitialise( &( pxEventBits->xTasksWaitingForBits ) ); traceEVENT_GROUP_CREATE( pxEventBits ); } else { traceEVENT_GROUP_CREATE_FAILED(); }
return ( EventGroupHandle_t ) pxEventBits;}

看上面代码的 pxEventBits->uxEventBits = 0; 应该就明白了吧!!!

其实freeRTOS的事件标志组的实现原理就是定义了一个变量,如果是 16 位变量,就仅使用了低 8bit ;如果定义了一个 32 位变量,就仅使用了低 24bit。

每一个 bit 用 0 和 1 两种状态来代表事件标志。

2、事件标志组的API管理函数

2.1、事件标志组的创建

函数原型:

EventGroupHandle_t xEventGroupCreate( void );

函数描述:

函数 xEventGroupCreate 用于创建事件标志组。

返回值,如果创建成功,此函数返回事件标志组的句柄,失败会返回 NULL。

2.2、事件标志组的位设置

(1)在任务中设置

函数原型:

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,   /* 事件标志组句柄 */                      const EventBits_t uxBitsToSet );   /* 事件标志位设置 */

函数描述:

函数 xEventGroupSetBits 用于设置指定的事件标志位为 1。

第 1 个参数是事件标志组句柄。

第 2 个参数表示 24 个可设置的事件标志位,EventBits_t 是定义的 32 位变量,低 24 位用于事件标志设置。变量 uxBitsToSet 的低 24 位的某个位设置为 1,那么被设置的 事件标志组的相应位就设置为 1。变量 uxBitsToSet 设置为 0 的位对事件标志相应位没有影响。比 如设置变量 uxBitsToSet = 0x0003 就表示将事件标志的位 0 和位 1 设置为1,其余位没有变化。

返回当前的事件标志组数值。

(2)在中断中设置

函数原型:

BaseType_t xEventGroupSetBitsFromISR(                      EventGroupHandle_t xEventGroup,       /* 事件标志组句柄 */                      const EventBits_t uxBitsToSet,       /* 事件标志位设置 */                      BaseType_t *pxHigherPriorityTaskWoken ); /* 高优先级任务是否被唤醒的状态保存 */

函数描述:

函数 xEventGroupSetBits 用于设置指定的事件标志位为 1。

第 1 个参数是事件标志组句柄。

第 2 个参数表示 24 个可设置的事件标志位,EventBits_t 是定义的 32 位变量,低 24 位用于事件标志设置。变量 uxBitsToSet 的低 24 位的某个位设置为 1,那么被设置的 事件标志组的相应位就设置为 1。变量 uxBitsToSet 设置为 0 的位对事件标志相应位没有影响。比 如设置变量 uxBitsToSet = 0x0003 就表示将事件标志的位 0 和位 1 设置为 1,其余位没有变化。

第3个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是pdTRUE, 说明有高优先级任务要执行,否则没有。

返回值,如果消息成功发送给 daemon 任务(就是 FreeRTOS 的定时器任务)返回 pdPASS,否则 返回 pdFAIL,另外 daemon 任务中的消息队列满了也会返回 pdFAIL。

使用前一定要保证事件标志已经通过函数 xEventGroupCreate 创建了。同时要在 FreeRTOSConfig.h 文件中使能如下三个宏定义:

#define INCLUDE_xEventGroupSetBitFromISR     1#define configUSE_TIMERS             1#define INCLUDE_xTimerPendFunctionCall     1

3、事件标志组的位清除

(1)在任务中设置

EventBits_t xEventGroupClearBits(                                 EventGroupHandle_t xEventGroup,                                 const EventBits_t uxBitsToClear );

函数描述:

xEventGroup:需要操作的事件标志组;

uxBitsToClear:要清零的事件位,比如要清楚bit2就设置为0x04。

返回值:将指定事件位清零之前的事件组值。

(2)在中断中设置

BaseType_t xEventGroupClearBitsFromISR(                                EventGroupHandle_t xEventGroup,                                const EventBits_t uxBitsToClear );

xEventGroup:需要操作的事件标志组;

uxBitsToClear:要清零的事件位,比如要清楚bit2就设置为0x04。

返回值:将指定事件位清零之前的事件组值。

4、等待时间标志组中的指定位被设置

(1)在任务中等待

函数原型:

EventBits_t xEventGroupWaitBits(                            const EventGroupHandle_t xEventGroup,  /* 事件标志组句柄 */                            const EventBits_t uxBitsToWaitFor,     /* 等待被设置的事件标志位 */                            const BaseType_t xClearOnExit,         /* 选择是否清零被置位的事件标志位 */                            const BaseType_t xWaitForAllBits,      /* 选择是否等待所有标志位都被设置 */                            TickType_t xTicksToWait );             /* 设置等待时间 */

函数描述:

函数 xEventGroupWaitBits 等待事件标志被设置。

第 1 个参数是事件标志组句柄。

第 2 个参数表示等待 24 个事件标志位中的指定标志,EventBits_t 是定义的 32 位变量,低 24 位用于事件标志设置。比如设置变量 uxBitsToWaitFor = 0x0003 就表示等待事 件标志的位 0 和位 1 设置为 1。 此参数切不可设置为 0

第 3 个参数选择是否清除已经被置位的事件标志,如果这个参数设置为 pdTRUE,且函数 xEventGroupWaitBits 在参数 xTicksToWait 设置的溢出时间内返回,那么相应被设置的事件标志 位会被清零。如果这个参数设置为 pdFALSE,对已经被设置的事件标志位没有影响。

第 4 个参数选择是否等待所有的标志位都被设置,如果这个参数设置为 pdTRUE,要等待第 2 个参 数 uxBitsToWaitFor 所指定的标志位全部被置 1,函数才可以返回。当然,超出了在参数 xTicksToWait 设置的溢出时间也是会返回的。如果这个参数设置为 pdFALSE,第 2 个参数 uxBitsToWaitFor 所指定的任何标志位被置 1,函数都会返回,超出溢出时间也会返回。

第 5 个参数设置等待时间,单位时钟节拍周期。如果设置为 portMAX_DELAY,表示永久等待。

返回值:由于设置的时间超时或者指定的事件标志位被置 1,导致函数退出时返回的事件标志组数值。

5、删除事件标志组

void vEventGroupDelete( EventGroupHandle_t xEventGroup );

xEventGroup:要删除的时间标志组

6、事件标志组的示例demo

代码中创建了两个任务和一个24bit可用的时间标志组,一个任务通过按键扫描设置事件标志组的值,通过按键按三下设置事件标志组的值为0x00000008,然后另外一个任务阻塞等待,直到检测到事件标志组被设置为0x00000008之后翻转LED的闪烁。

EventGroupHandle_t FlagEventGroup;  //事件标志组FlagEventGroup = xEventGroupCreate();   //创建事件标志组 24bit可用
//task1任务函数void task1_task(void *pvParameters) //prio = 2{ u8 keyVal = 0; EventBits_t FlagVal; u32 setVal = 0x0001; while(1) { keyVal = KEY_Scan(0); if(keyVal == KEY0_PRES) { FlagVal = xEventGroupSetBits(FlagEventGroup, setVal); printf("事件标志组设置值为:%d\\r\\n",FlagVal); xEventGroupClearBits(FlagEventGroup, setVal); //清除标志位 setVal <<= 1; } LED1 ^= 1; vTaskDelay(200); //延时n个时钟节拍 }}
//task2任务函数void task2_task(void *pvParameters) //prio = 3{ u32 i,j; u32 TxStr[3] = {0}; while(1) { xEventGroupWaitBits(FlagEventGroup, //事件标志组句柄 0x0008, //等待 24 个事件标志位中的指定标志 pdFALSE, //是否清除已经被置位的事件标志,pdTRUE - 清除,pdFALSE - 不清除 pdFALSE, //是否等待所有的标志位都被设置,pdTRUE - 是,pdFALSE - 不是 portMAX_DELAY //等待时间,单位时钟节拍周期 ); LED0 ^= 1;
vTaskDelay(500); //延时n个时钟节拍 }}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 同步
    +关注

    关注

    0

    文章

    89

    浏览量

    19167
  • FreeRTOS
    +关注

    关注

    12

    文章

    484

    浏览量

    62140
  • 事件标志组
    +关注

    关注

    0

    文章

    3

    浏览量

    1287
收藏 人收藏

    评论

    相关推荐

    基于FreeRTOS的STM32F103系统—队列

    FreeRTOS中,队列是实现任务之间同步、互斥和通信的一种重要方法(其他的实现方法有:任务通知、事件
    的头像 发表于 11-10 11:37 1129次阅读
    基于<b class='flag-5'>FreeRTOS</b>的STM32F103系统—队列

    FreeRTOS信号量的使用与实例

    在嵌入式系统中,任务管理是一个重要的部分,它涉及到任务之间的通信和同步,信号量,队列,互斥锁和事件标志
    的头像 发表于 12-12 15:25 2541次阅读

    使用STM32CubeMX生成的FreeRTOS系统中,似乎没有新封装的事件标志,怎么解决?

    使用STM32CubeMX生成的FreeRTOS系统中,似乎没有新封装的事件标志,如果按照原生的FreeRTOS使用事件标志
    发表于 03-22 08:34

    使用FreeRTOS系统事件标志有些收不到是怎么回事?

    教下,使用FreeRTOS的的件标志, 任务貌似有些标志位收不到,是怎么回事啊 ? 比如事件标志
    发表于 04-26 06:53

    转:freeRTOS事件学习

    像其他RTOS一样,freeRTOS同样有对事件标志位的创建和处理,在中断中可以通过事件传递信息给其他的任务,那么如何创建事件呢?要使用
    发表于 08-12 18:29

    转:第18章 FreeRTOS事件标志

    问题。18.1.2 FreeRTOS任务间事件标志的实现 任务间事件标志
    发表于 09-02 12:40

    转:第26章 FreeRTOS任务事件标志

    本章节为大家讲解FreeRTOS事件标志的另一种实现方式----基于任务通知(Task Notifications)的事件标志
    发表于 09-08 06:48

    第13章 事件标志

    转rtx操作系统前面的章节我们已经讲解了任务管理和时间管理,从本章节开始讲解任务间的通信和同步机制。首先讲解任务间的通信和同步机制之一,事件
    发表于 10-05 09:15

    【NUCLEO-F412ZG试用体验】FreeRTOS_事件标志实现任务和中断的同步

    使用事件标志可以实现任务任务之间以及任务和中断之间
    发表于 12-28 21:19

    怎么才能让任务等待到事件标志后一直执行并且还要把事件标志清零?

    一个任务等待事件标志执行有挂起和不挂起之分,等待到事件标志就执行一次并且把事件标志清零,等待
    发表于 09-20 03:49

    怎样去设置FreeRTOS事件标志的事件位呢

    事件标志是什么意思呢?怎样去设置FreeRTOS事件标志的事件位呢?
    发表于 02-28 06:44

    FreeRTOS中如何在多任务中访问外设?

    FreeRTOS中两个任务需要轮流使用通过一个SPI获取外部ADC的采集数据,如何保证两个任务同步?用队列,互斥,信号量还是事件标志
    发表于 11-10 06:23

    FreeRTOS的事件标志

    之前介绍了使用信号量来完成同步,但是使用信号量来同步的话,任务只能与单个的事件或任务进行同步。有时候某个
    的头像 发表于 02-10 15:58 1111次阅读

    FreeRTOS的消息队列

    基于 FreeRTOS 的应用程序由一独立的任务构成——每个任务都是具有独立权限的程序。这些独立的任务
    的头像 发表于 02-14 09:56 886次阅读
    <b class='flag-5'>FreeRTOS</b>的消息队列

    FreeRTOS创建事件标志

    创建事件标志 3、设置事件位 4、获取事件标志值 5、等待指定的事件位 某个任务可能需要与多个事件进行
    的头像 发表于 07-06 17:23 524次阅读
    <b class='flag-5'>FreeRTOS</b>创建事件<b class='flag-5'>标志</b><b class='flag-5'>组</b>