文章目录
一、事件组的原理和功能
1、事件组与队列信号量特点
事件组是FreeRTOS中的一种对象,且FreeRTOS默认就可以使用事件组,无需设置相关参数,但是使用之前需要使用创建函数创建事件组对象。
事件标志组与队列信号量的区别:
2、事件组存储结构
事件组有一个内部变量存储事件标志,当configUSE_16_BIT_TICKS为0时,这个变量是32位的,否则是16位的,在STM32上处理器上是32位的。
使用了32位无符号的数据类型变量来存储事件标志,但其中的高8位用作存储事件标志组的控制信息,低24位用作存储事件标志,所以说一个事件组最多可以存储 24 个事件标志!
一个事件组中的所有事件位保存在一个EventBits_t类型的变量里,所以一个事件又称为一个"事件位"
3、事件组运行原理
(1)设置事件组中的位与某个事件对应,检测到事件发生时将相应的位置1,表示事件发生了。
(2)可以有1个或多个任务等待事件组中的事件发生,可以是各个事件都发生(事件位的与运算),或某个事件发生(事件位的或运算)。
(3)假设图中的Task1和Task2都以阻塞状态等待两个事件都发生,当Bit2和Bit0都被置为1后(不分先后顺序),两个任务都会被解除阻塞状态。所以 事件组具有广播功能。
二、事件组部分函数
函数所在文件如下图所示:
1、xEventGroupCreate()创建事件组函数
以动态分配内存方式创建事件组,无参数,返回值是创建的事件组句柄变量(一个指针变量),其他函数在操作事件组时都使用事件组句柄变量作为输入参数。
返回值类型EventGroupHandle_t的定义如下:
2、xEventGroupSetBits()事件组置位函数
c
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet ) PRIVILEGED_FUNCTION;
参数1:要操作的事件组句柄
参数2:要置位的事件位掩码
返回值:置位成功后事件组当前的值
类型EventBits_t的定义如下,也就是TickType_t,在STM32处理器上,等同于类型uint32_t
被置位的事件位为1,未被置位的事件位为0,一个事件只对应事件组中的一个事件位,一个事件发生只需要置位一个事件位
需要置位事件组中的bit7,则位掩码是0x80
需要置位事件组中的bit0,则位掩码是0x01
同时置位事件组中的bit7和bit0,则位掩码是0x81
官方代码段举例:
c
Example usage:
//想要置位哪一个事件位通过宏定义操作即可
#define BIT_0 ( 1 << 0 ) //宏定义:置位bit0对应的事件位
#define BIT_4 ( 1 << 4 ) //宏定义:置位bit4对应的事件位
void aFunction( EventGroupHandle_t xEventGroup )
{
EventBits_t uxBits; //存放置位函数返回值
//使用时间位0和事件位4进行置位操作
//对两个事件位的宏定义进行或操作,就是同时对两个位进行置位(也就是传递的参数2位掩码)
// Set bit 0 and bit 4 in xEventGroup.
//位掩码是0x11
uxBits = xEventGroupSetBits(
xEventGroup, // The event group being updated.
BIT_0 | BIT_4 );// The bits being set.
//函数返回值是置位成功后事件组当前的数值
if( ( uxBits & ( BIT_0 | BIT_4 ) ) == ( BIT_0 | BIT_4 ) )//bit0和bit4同时被置位
{
// Both bit 0 and bit 4 remained set when the function returned.
}
else if( ( uxBits & BIT_0 ) != 0 )//bit0被置位
{
// Bit 0 remained set when the function returned, but bit 4 was
// cleared. It might be that bit 4 was cleared automatically as a
// task that was waiting for bit 4 was removed from the Blocked
// state.
}
else if( ( uxBits & BIT_4 ) != 0 )//bit4被置位
{
// Bit 4 remained set when the function returned, but bit 0 was
// cleared. It might be that bit 0 was cleared automatically as a
// task that was waiting for bit 0 was removed from the Blocked
// state.
}
else//bit0和bit4均没有被置位
{
// Neither bit 0 nor bit 4 remained set. It might be that a task
// was waiting for both of the bits to be set, and the bits were
// cleared as the task left the Blocked state.
}
}
3、xEventGroupSetBitsFromISR()事件组置位函数ISR版本
ISR版本相对于任务版本多了最后一个参数:是否需要进行上下文切换的申请
根据参数configUSE_TRACE_FACILITY数值为1或0分为以下两个版本
c
#if( configUSE_TRACE_FACILITY == 1 )
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
#else
#define xEventGroupSetBitsFromISR( xEventGroup, uxBitsToSet, pxHigherPriorityTaskWoken ) xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken )
#endif
默认的函数原型:
pxHigherPriorityTaskWoken是指针BaseType_t*,是一个返回值(pdTRUE或pdFALSE),表示在退出ISR函数前是否需要申请进行一次任务调度。
c
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t *pxHigherPriorityTaskWoken );
/*
参数1:事件组句柄
参数2:置位掩码
参数3:退出ISR时是否需要上下文切换
*/
//示意代码如下:
BaseType_t highTaskWoken =pdFALSE;
xEventGroupSetBitsFromISR(xEventGroup, uxBitsToSet, &highTaskWoken);
portYIELD_FROM_ISR(highTaskWoken); //申请进行一次任务调度
Freeertos不允许中断或临界代码段进行不确定的操作,在ISR中进行事件组置位操作时FreeRTOS实际上向定时器守护任务发送了一个消息,将事件组置位操作延后到定时器守护任务里执行。
如果定时器优先值高于当前执行的任务,返回pdtrue,否则返回pdfalse
根据pdtrue手动的进行一次上下文切换,这个函数返回pdtrue表明延后处理的消息成功的发送给了定时器守护任务,当定时器守护任务的队列消息满时,函数会无法接收到新的消息,返回值为pdfalse
4、xEventGroupClearBits()事件位清零函数
函数xEventGroupClearBits()用于在任务函数中将事件组的某些事件位清零,其函数原型是
c
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
参数1:事件组句柄
参数2:要清零的事件位掩码(掩码意义与事件位置位中一样)
返回值:事件位被清零之前的事件组的值
uxBitsToClear是需要清零的事件位的掩码, 需要清零的位设置为1。
将bit0和bit4清零
5、xEventGroupClearBitsFromISR()事件位清零函数ISR版本
c
#if( configUSE_TRACE_FACILITY == 1 )
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear ) PRIVILEGED_FUNCTION;
#else
#define xEventGroupClearBitsFromISR( xEventGroup, uxBitsToClear ) xTimerPendFunctionCallFromISR( vEventGroupClearBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToClear, NULL )
#endif
在ISR函数中的事件位清零操作会被延后到定时器守护任务(timer daemon task) 中去处理,函数的返回值为pdTRUE或pdFALSE,如果返回值为pdTRUE表示延后处理的消息成功发送给了定时器守护任务,否则就是没有成功发送。
6、xEventGroupGetBits()读取事件组当前的值
传入事件组句柄(不清空任何位)
它实际上就是执行了函数xEventGroupClearBits(),只是传递的事件位掩码是0,也就是不清除任何事件位,而返回事件组当前的值
7、xEventGroupWaitBits()等待事件组成立
函数xEventGroupWaitBits()使当前任务进入阻塞状态,以等待事件组中多个事件位表示的事件成立时再退出阻塞状态。
事件组成立的条件可以是多个事件位都被置位(逻辑与运算) ,或其中某个事件位被置位(逻辑或运算)
c
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
/*
参数1:事件组句柄
参数2:所等待事件位的掩码(如果需要等待某个事件位置1,掩码中相应的位就设置为1)
参数3:设定值为pdTRUE或pdFALSE,退出时是否清除掩码位(清零)
pdTRUE则表明在事件组条件成立退出阻塞状态时,会将参数2掩码中指定的所有位全部清零
如果函数因为超时退出阻塞状态,即使设置为pdTRUE也不会将掩码事件位清零
参数4:设定值为pdTRUE或pdFALSE,是否等待所有位置位(所有同时成立还是某一个成立即可)
pdTRUE表示事件位全部置1条件成立(逻辑与运算),否则任意一个置1条件成立(逻辑或运算)
当事件条件成立时,函数就会退出,任务退出阻塞态
参数5:超时阻塞时间
返回值:
*/