从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十八)事件 NO.2 事件函数接口讲解

从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(十八)事件 NO.2 事件函数接口讲解

目录

一、事件创建函数 xEventGroupCreate()

二、事件删除函数 vEventGroupDelete()

三、事件组置位函数 xEventGroupSetBits()(任务)

四、事件组置位函数 xEventGroupSetBitsFromISR()(中断)

五、等待事件函数 xEventGroupWaitBits()

六、xEventGroupClearBits()与 xEventGroupClearBitsFromISR()


一、事件创建函数 xEventGroupCreate()

① xEventGroupCreate()用于创建一个事件组,并返回对应的句柄。 要想使用该函数必须在头文件 FreeRTOSConfig.h 定义宏 configSUPPORT_DYNAMIC_ALLOCATION 为 1(在FreeRTOS.h 中默认定义为 1) 且需要把 FreeRTOS/source/event_groups.c 这个 C 文件添加到工程中。
② FreeRTOS 给我们提供了一个创建事件的函数 xEventGroupCreate(),当创建一个事件时, 系统会首先给我们分配事件控制块的内存空间,然后对该事件控制块进行基本的初始化,创建成功返回事件句柄;创建失败返回 NULL。

static EventGroupHandle_t Event_Handle =NULL;
/* 创建 Event_Handle */
Event_Handle = xEventGroupCreate();
if (NULL != Event_Handle)
printf("Event_Handle 事件创建成功!\r\n");
else
/* 创建失败,应为内存空间不足 */

二、事件删除函数 vEventGroupDelete()

       vEventGroupDelete()用于删除事件传入要删除事件的句柄,在删除的时候,如果有任务阻塞在这个事件上,那么就要把事件从等待事件列表中移

       当事件组被删除之后,阻塞在该事件组上的任务都会被解锁,并向等待事件的任务返回事件组的值为0

       当系统不再使用事件对象时,可以通过删除事件对象控制块来释放系统资源。

       该函数不允许在中断里面使用。 当事件组被删除之后,阻塞在该事件组上的任务都会被解锁,并向等待事件的任务返回事件组的值为 0。

static EventGroupHandle_t Event_Handle =NULL;
/* 创建 Event_Handle */
Event_Handle = xEventGroupCreate();
if (NULL != Event_Handle)
{
printf("Event_Handle 事件创建成功!\r\n");
/* 创建成功,可以删除 */
xEventGroupCreate(Event_Handle);
} else
/* 创建失败,应为内存空间不足 */

三、事件组置位函数 xEventGroupSetBits()(任务)

       xEventGroupSetBits()用于置位事件组中指定的位, 当位被置位之后,阻塞在该位上的任务将会被解锁。 使用该函数接口时,通过参数指定的事件标志来设定事件的标志位,然后遍历等待在事件对象上的事件等待列表,判断是否有任务的事件激活要求与当前事件对象标志值匹配,如果有,则唤醒该任务。简单来说,就是设置我们自己定义的事件标志位为 1,并且看看有没有任务在等待这个事件,有的话就唤醒它。

函数原型

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,

 

                                                          const EventBits_t uxBitsToSet );

功能

置位事件组中指定的位。

参数

xEventGroup

事件句柄。

uxBitsToSet

指定事件中的事件标志位。如设置uxBitsToSet0x08则只置位位3

 

如果设置uxBitsToSet0x09则位3和位0都需要被置位。

返回值

返回调用xEventGroupSetBits() 时事件组中的值。

       xEventGroupSetBits()用于置位事件组中指定的位,当位被置位之后,阻塞在该位上的任务将会被解锁。使用该函数接口时,通过参数指定的事件标志来设定事件的标志位,然后遍历等待在事件对象上的事件等待列表,判断是否有任务的事件激活要求与当前事件对象标志值匹配,如果有,则唤醒该任务。

       为了便于理解,一般操作我们都是用宏定义来实现    #define  EVENT  (0x01 << x)    “<< x”表示写入事件集合的bit x。

#define KEY1_EVENT (0x01 << 0)//设置事件掩码的位 0
#define KEY2_EVENT (0x01 << 1)//设置事件掩码的位 1
static EventGroupHandle_t Event_Handle =NULL;
/* 创建 Event_Handle */
Event_Handle = xEventGroupCreate();
if (NULL != Event_Handle)
printf("Event_Handle 事件创建成功!\r\n");
static void KEY_Task(void* parameter)
{
/* 任务都是一个无限循环,不能返回 */
while (1) {
//如果 KEY1 被按下
if ( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON ) {
printf ( "KEY1 被按下\n" );
/* 触发一个事件 1 */
xEventGroupSetBits(Event_Handle,KEY1_EVENT);
}
//如果 KEY2 被按下
if ( Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON ) {
printf ( "KEY2 被按下\n" );
/* 触发一个事件 2 */
xEventGroupSetBits(Event_Handle,KEY2_EVENT);
}
vTaskDelay(20); //每 20ms 扫描一次
}
}

四、事件组置位函数 xEventGroupSetBitsFromISR()(中断)

       xEventGroupSetBitsFromISR()是 xEventGroupSetBits()的中断版本,用于置位事件组中指定的位。置位事件组中的标志位是一个不确定的操作,因为阻塞在事件组的标志位上的任务的个数是不确定的。 FreeRTOS 是不允许不确定的操作在中断和临界段中发生的, 所以xEventGroupSetBitsFromISR()给 FreeRTOS 的守护任务发送一个消息,让置位事件组的操作在守护任务里面完成,守护任务是基于调度锁而非临界段的机制来实现的。
       其实 xEventGroupSetBitsFromISR()函数真正调用的也是 xEventGroupSetBits()函数,只不过是在守护任务中进行调用的,所以它实际上执行的上下文环境依旧是在任务中。

       要想使用该函数,必须把configUSE_TIMERS 和INCLUDE_xTimerPendFunctionCall 这些宏在 FreeRTOSConfig.h 中都定义为 1,并且把FreeRTOS/source/event_groups.c 这个 C 文件添加到工程中编译。

函数原型

BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,

 

                                                                        const EventBits_t uxBitsToSet,

 

                                                                        BaseType_t *pxHigherPriorityTaskWoken);

功能

置位事件组中指定的位,在中断函数中使用。

参数

xEventGroup

事件句柄。

uxBitsToSet

指定事件组中的哪些位需要置位。如设置uxBitsToSet0x08则只置位位3,如果设置

 

uxBitsToSet0x09则位3和位0都需要被置位。

pxHigherPriorityTaskWoken

pxHigherPriorityTaskWoken在使用之前必须初始化成pdFALSE

 

调用xEventGroupSetBitsFromISR()会给守护任务发送一个消息,如果守护任务

 

优先级高于当前被中断的任务的优先级的话(一般情况下都需要将守护任务的

 

级设置为所有任务中最高优先级),pxHigherPriorityTaskWoken会被置

 

pdTRUE,然后在中断退出前执行一次上下文切换。

返回值

消息成功发送给守护任务之后则返回pdTRUE,否则返回pdFAIL。如果定时器服务队列满了将返回pdFAIL

#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
/* 假定事件组已经被创建 */
EventGroupHandle_t xEventGroup;
/* 中断 ISR */
void anInterruptHandler( void )
{
BaseType_t xHigherPriorityTaskWoken, xResult;
/* xHigherPriorityTaskWoken 在使用之前必须先初始化为 pdFALSE */
xHigherPriorityTaskWoken = pdFALSE;
/* 置位事件组 xEventGroup 的的 Bit0 和 Bit4 */
xResult = xEventGroupSetBitsFromISR(
xEventGroup,
BIT_0 | BIT_4,
&xHigherPriorityTaskWoken );
/* 信息是否发送成功 */
if ( xResult != pdFAIL ) {
/* 如果 xHigherPriorityTaskWoken 的值为 pdTRUE
则进行一次上下文切换*/
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
}

五、等待事件函数 xEventGroupWaitBits()

       FreeRTOS提供了一个等待指定事件的函数——xEventGroupWaitBits(),通过这个函数,任务可以知道事件标志组中的哪些位,有什么事件发生了,然后通过 “逻辑与”、“逻辑或”等操作对感兴趣的事件进行获取,并且这个函数实现了等待超时机制,当且仅当任务等待的事件发生时,任务才能获取到事件信息

       注意:如果等待到对应的事件,就会返回对应的事件标志位,由用户判断再做处理,因为在事件超时的时候也会返回一个不能确定的事件值,所以需要判断任务所等待的事件是否真的发生。

       EventGroupWaitBits()用于获取事件组中的一个或多个事件发生标志,当要读取的事件标志位没有被置位时任务将进入阻塞等待状态 。 要想使用该函数必须把FreeRTOS/source/event_groups.c 这个 C 文件添加到工程中。 

      简单分析处理过程:当用户调用这个函数接口时,系统首先根据用户指定参数和接收选项来判断它要等待的事件是否发生,如果已经发生,则根据参数 xClearOnExit 来决定是否清除事件的相应标志位,并且返回事件标志位的值,但是这个值并不是一个稳定的值,所以在等待到对应事件的时候,还需我们判断事件是否与任务需要的一致 如果事件没有发生,则把任务添加到事件等待列表中, 把任务感兴趣的事件标志值和等待选项填用列表项的值来表示,直到事件发生或等待时间超时

static void LED_Task(void* parameter)
{
EventBits_t r_event; /* 定义一个事件接收变量 */
/* 任务都是一个无限循环,不能返回 */
while (1) {
/****************************************************************
* 等待接收事件标志
*
* 如果 xClearOnExit 设置为 pdTRUE,那么在 xEventGroupWaitBits()返回之前,
* 如果满足等待条件(如果函数返回的原因不是超时),那么在事件组中设置
* 的 uxBitsToWaitFor 中的任何位都将被清除。
* 如果 xClearOnExit 设置为 pdFALSE,
* 则在调用 xEventGroupWaitBits()时,不会更改事件组中设置的位。
*
* xWaitForAllBits 如果 xWaitForAllBits 设置为 pdTRUE,则当 uxBitsToWaitFor 中
* 的所有位都设置或指定的块时间到期时, xEventGroupWaitBits()才返回。
* 如果 xWaitForAllBits 设置为 pdFALSE,则当设置 uxBitsToWaitFor 中设置的任何
* 一个位置 1 或指定的块时间到期时, xEventGroupWaitBits()都会返回。
* 阻塞时间由 xTicksToWait 参数指定。
*********************************************************/
r_event = xEventGroupWaitBits(Event_Handle, /* 事件对象句柄 */
KEY1_EVENT|KEY2_EVENT,/* 接收任务感兴趣的事件 */
pdTRUE, /* 退出时清除事件位 */
pdTRUE, /* 满足感兴趣的所有事件 */
portMAX_DELAY);/* 指定超时事件,一直等 */
if ((r_event & (KEY1_EVENT|KEY2_EVENT)) == (KEY1_EVENT|KEY2_EVENT)) {
/* 如果接收完成并且正确 */
printf ( "KEY1 与 KEY2 都按下\n");
LED1_TOGGLE; //LED1 反转
} else
printf ( "事件错误! \n");
}
}

六、xEventGroupClearBits()与 xEventGroupClearBitsFromISR()

        xEventGroupClearBits()xEventGroupClearBitsFromISR()都是用于清除事件组指定的位,如果在获取事件的时候没有将对应的标志位清除,那么就需要用这个函数来进行显式清除

       具有中断保护功能的xEventGroupClearBitsFromISR() ,中断清除事件标志位的操作在守护任务(也叫定时器服务任务)里面完成 。 守护进程的优先级由 FreeRTOSConfig.h 中的宏configTIMER_TASK_PRIORITY 来定义 。 要想使用该函数必须把FreeRTOS/source/event_groups.c 这个 C 文件添加到工程中。

函数原型

EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,

 

                                                             const EventBits_t uxBitsToClear );

 

BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,

 

                                                                            const EventBits_t uxBitsToClear );

功能

清除事件组中指定的位。

参数

xEventGroup

事件句柄。

uxBitsToClear

指定事件组中的哪个位需要清除。如设置uxBitsToSet0x08则只清除位3如果

 

设置uxBitsToSet0x09则位3和位0都需要被清除。

返回值

事件在还没有清除指定位之前的值。

xEventGroupClearBits()函数使用实例

#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
void aFunction( EventGroupHandle_t xEventGroup )
{
EventBits_t uxBits;
/* 清楚事件组的 bit 0 and bit 4 */
uxBits = xEventGroupClearBits(
xEventGroup,
BIT_0 | BIT_4 );
if ( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) ) {
/* 在调用 xEventGroupClearBits()之前 bit0 和 bit4 都置位
但是现在是被清除了*/
} else if ( ( uxBits & BIT_0 ) != 0 ) {
/* 在调用 xEventGroupClearBits()之前 bit0 已经置位
但是现在是被清除了*/
} else if ( ( uxBits & BIT_4 ) != 0 ) {
/* 在调用 xEventGroupClearBits()之前 bit4 已经置位
但是现在是被清除了*/
} else {
/* 在调用 xEventGroupClearBits()之前 bit0 和 bit4 都没被置位 */
}
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS(Real Time Operating System)是一个开源的实时操作系统内核,专门为嵌入式系统设计。它提供了多任务调度、任务通信、时间管理和内存管理等功能,能够有效地管理资源并提供实时性能。 FreeRTOS内核主要由以下几个组件构成: 1. 任务(Task):FreeRTOS使用任务作为最基本的执行单元。每个任务都有自己的优先级,并通过调度器进行任务切换。任务可以是周期性的、一次性的或者阻塞的。 2. 任务通信(Task Communication):FreeRTOS提供了一系列的机制来实现任务之间的通信,例如消息队列、信号量、互斥锁和事件标志等。这些机制可以用于任务之间的同步和数据交换。 3. 时间管理(Time Management):FreeRTOS提供了定时器功能,可以用于按照一定的时间间隔触发事件或者执行特定任务。定时器可以用于周期性任务、超时检测和时间相关的操作。 4. 内存管理(Memory Management):FreeRTOS提供了内存管理机制,用于动态分配和释放内存。开发者可以选择使用标准库的内存分配函数或者自定义的内存管理函数。 5. 中断处理(Interrupt Handling):FreeRTOS支持中断处理,并提供了中断安全的任务通信机制。开发者可以在中断服务程序中使用FreeRTOS提供的功能。 FreeRTOS内核设计简单、灵活,并且具有可移植性。它支持多种处理器架构和编译器,并且有广泛的应用范围,包括工业控制、汽车电子、医疗设备和消费电子等领域。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值