【FreeRTOS】事件标志与任务通知
⽬录
⼀、事件标志组
事件是⼀种实现任务通信的机制,主要⽤于实现多任务间通信,这与信号量类似,与信号量不同的是事件可以实现⼀对多,多对多同步,即⼀个任务可以等待多个事件发⽣后再执⾏,也可以是其中任⼀个事件发⽣就执⾏。
⼀个事件组由多个事件位组成,⼀个事件位就是⼀个⼆进制位,当某个事件发⽣就将对应事件位置1,表明这个事件已经发⽣了。
事件标志组的数据类型为EventGroupHandle_t(事件标志组句柄类型),是⼀个结构体指针变量,在"event_groups.h"⽂件有定义如下:
struct EventGroupDef_t;
typedef struct EventGroupDef_t * EventGroupHandle_t; //控制块句柄(指针)
typedef struct EventGroupDef_t //事件标志组结构体(控制块)
{
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
#if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */
#endif
} EventGroup_t;
事件标志组所存储的事件位个数有关的宏定义"FreeRTOSConfig.h"⽂件中:
#define configUSE_16_BIT_TICKS 0
当为1时,为16位
当为0时,为32位(STM32为32位的所以为0)
分别对应可存储的事件位个数为8个和24个,其中⾼8位⽤作其他不可⽤。
1、创建事件标志组
(1)动态⽅法
/*函数原型*/
EventGroupHandle_t xEventGroupCreate( void );
/*
*参数:⽆;
*返回值:创建失败NULL,创建成功返回事件标志组句柄;
*/
(2)静态⽅法
/*函数原型*/
EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer );
/*
*参数:
* pxEventGroupBuffer:指向StaticEventGroup_t类型的变量,⽤于保存事件标志组结构体;
*返回值:创建失败NULL,创建成功返回事件标志组句柄;
*/
2、设置标志位
(1)清零操作
任务级:
/*函数原型*/
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear )
/*
*参数:
* xEventGroup:事件标志组句柄;
* uxBitsToClear:要清零的事件位,清除bit3(0000 1000),则为0x08;清除bit2和bit3(0000 1100);则
为0x0c。
*返回值:清零前的事件组值;
*/
中断级
/*函数原型*/
BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear )
/*
*参数:
* xEventGroup:事件标志组句柄;
* uxBitsToClear:要清零的事件位,清除bit3(0000 1000),则为0x08;清除bit2和bit3(0000 1100);则为
0x0c。
*返回值:
*pdPASS:事件位清零成功;
*pdPALSE:事件位清零失败;
*/
/*此处为条件编译,使⽤需要将以下宏定义为1*/
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( INCLUDE_xTimerPendFunctionCall == 1 ) && ( configUSE_TIMERS == 1 ) )(2)置位操作
任务级
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet )
/*
*参数:
* xEventGroup:事件标志组句柄;
* uxBitsToSet :要置1的事件位,置位bit3(0000 1000),则为0x08;置位bit2和bit3(0000 1100);则为
0x0c。
*返回值:置1后的事件组值;
*/
中断级
/*函数原型*/
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t * pxHigherPriorityTaskWoken )
/*
*参数:
* xEventGroup:事件标志组句柄;
* uxBitsToSet :要置1的事件位,置位bit3(0000 1000),则为0x08;置位bit2和bit3(0000 1100);则为
0x0c。
*pxHigherPriorityTaskWoken:标记退出此函数后是否进⾏任务切换,只需提供变量来保存即可,当该值为 pdTRUE时退出前需要进⾏⼀次任务切换。
*返回值:
*pdPASS:事件位置1成功
*pdPALSE:事件位置1失败
*/
3、获取事件标志组值
(1)任务级
/*函数原型*/
EventBits_t xEventGroupGetBits( EventGroupHandle_t xEventGroup )
/*参数
*xEventGroup:事件标志组句柄;
*返回值:事件组值(不执⾏清零操作);
*/
/*此函数为⼀个宏,调⽤的时清零函数*/
#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )
(2)中断级
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
/*参数
*xEventGroup:事件标志组句柄;
*返回值:事件组值;
*/
/*操作时读取事件标志组结构体中的uxEventBits */
uxReturn = pxEventBits->uxEventBits;
4、等待指定的事件位
/*函数原型*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait )
/*参数
*xEventGroup:事件标志组句柄;
* uxBitsToWaitFor:等待的指定位,要置1的事件位,等待位bit3(0000 1000),则为0x08;等待位bit2和
bit3(0000 1100);则为0x0c;
* xClearOnExit:退出后是否将等到的事件位清零,pdTRUE清零,pdFALSE不清零;
* xWaitForAllBits:是否等待所有位,pdTRUE等待所有指定位满⾜(置1)才返回,pdFALSE等待指定位中任⼀
位满⾜(置1)就返回;
* xTicksToWait:等待阻塞时间;
*返回值:
* 返回所等指定位满⾜(置1)后的事件标志组值,如果因为阻塞时间到则返回值⽆意义;
*/
⼆、任务通知
任务通知也是⼀种信号量(事件),不需要创建,它是存在于任务控制块的⼀个32位的(数组)变量ulNotifiedValue:
#if ( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];//任务通知组值
volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];//任务通知状态
#endif
⼤多数情况下,任务通知可以替代⼆值信号量、计数信号量、事件组,也可以替代长度为1的队列(可以保存⼀个32位的整数或指针值)。使⽤任务通知相较于其他信号量可以提⾼效率。
发送通知给任务的⼏种⽅式:
(1)直接覆盖通知值
(1)如果有未处理通知,不覆盖通知值
(3)设置通知值的⼀个或多个位,当事件组使⽤
(4)增加通知值,当计数型信号量使⽤
任务通知的限制:
(1)只能有⼀个任务接收通知消息,信号量可以由多个任务接收;
(2)只有等待通知的任务可以被阻塞,发送通知的任务不会进⼊阻塞态。
相关函数及定义在"tasks.c"和"task.h"⽂件中。
1、发送通知函数
以上任务都是宏定义的,调⽤的函数为以下两个函数:
/*任务级*/
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, //任务句柄 UBaseType_t uxIndexToNotify, //通知值
uint32_t ulValue,
eNotifyAction eAction, //发送通知⽅式
uint32_t * pulPreviousNotificationValue )
/*中断级*/
BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue,
BaseType_t * pxHigherPriorityTaskWoken )
/*更新⽅法的枚举值列表*/
typedef enum
notify for mi band
{
eNoAction = 0, /* 通知但不更新值 */
eSetBits, /* 更新指定位*/
eIncrement, /* 通知值加1*/
eSetValueWithOverwrite, /* 覆写通知值*/
eSetValueWithoutOverwrite /* 不覆写通知值*/
} eNotifyAction;
(1)函数xTaskNotify()
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论