目录
(6)函数xTaskNotifyAndQueryFromISR()
一、事件标志组
事件是一种实现任务通信的机制,主要用于实现多任务间通信,这与信号量类似,与信号量不同的是事件可以实现一对多,多对多同步,即一个任务可以等待多个事件发生后再执行,也可以是其中任一个事件发生就执行。
一个事件组由多个事件位组成,一个事件位就是一个二进制位,当某个事件发生就将对应事件位置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
{
eNoAction = 0, /* 通知但不更新值 */
eSetBits, /* 更新指定位*/
eIncrement, /* 通知值加1*/
eSetValueWithOverwrite, /* 覆写通知值*/
eSetValueWithoutOverwrite /* 不覆写通知值*/
} eNotifyAction;
(1)函数xTaskNotify()
/*函数原型*/
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction )
/*
*参数:
* xTaskToNotify:任务句柄,要发向的任务;
* ulValue: 任务通知值;
*/eAction: 任务通知更新方法;
*返回值:
* pdPASS: 成功;
* pdFAIL: 失败;
*/
/*函数宏定义*/
#define xTaskNotify( xTaskToNotify, ulValue, eAction ) \
xTaskGenericNotify( ( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( ulValue ),
( eAction ),
NULL )
(2)函数xTaskNotifyFromISR()
/*函数原型*/
BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
BaseType_t *pxHigherPriorityTaskWoken );
/*
*参数:
* xTaskToNotify: 任务句柄,要发向的任务;
* ulValue: 任务通知值;
*/eAction: 任务通知更新方法;
* pxHigherPriorityTaskWoken:标记退出此函数后是否进行任务切换,只需提供变量来保存即可,当该值为
pdTRUE时退出前需要进行一次任务切换。
*返回值:
* pdPASS:成功;
* pdFAIL:失败;
*/
/*函数宏定义*/
#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) \
xTaskGenericNotifyFromISR( ( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( ulValue ),
( eAction ),
NULL,
( pxHigherPriorityTaskWoken ) )
(3)函数xTaskNotifyGive()
该函数将任务通知值加1。(任务级)
/*函数原型*/
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );
/*
*参数:
* xTaskToNotify: 任务句柄,要发向的任务;
*返回值:
* pdPASS: 此函数只返回该值;
*/
/*函数宏定义*/
#define xTaskNotifyGive( xTaskToNotify ) \
xTaskGenericNotify( ( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( 0 ),
eIncrement,
NULL )
(4)函数vTaskNotifyGiveFromISR()
该函数将任务通知值加1。(中断级)
/*函数原型*/
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskHandle,
BaseType_t *pxHigherPriorityTaskWoken );
/*
*参数:
* xTaskHandle: 任务句柄,要发向的任务;
* pxHigherPriorityTaskWoken:标记退出此函数后是否进行任务切换,只需提供变量来保存即可,当该值为
pdTRUE时退出前需要进行一次任务切换。
*返回值: 无;
*/
/*函数宏定义*/
#define vTaskNotifyGiveFromISR( xTaskToNotify, pxHigherPriorityTaskWoken ) \
vTaskGenericNotifyGiveFromISR( ( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( pxHigherPriorityTaskWoken ) );
(5)函数xTaskNotifyAndQuery()
此函数与xTaskNotify()类似,仅多一个参数用于保存更新前的通知值。
/*函数原型*/
BaseType_t xTaskNotifyAndQuery( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t *pulPreviousNotifyValue );
/*
*参数:
* xTaskToNotify: 任务句柄,要发向的任务;
* ulValue: 任务通知值;
*/eAction: 任务通知更新方法;
* pulPreviousNotifyValue:保存更新前的任务通知值;
*返回值:
* pdPASS: 成功;
* pdFAIL: 失败;
*/
/*函数宏定义*/
#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction, pulPreviousNotifyValue ) \
xTaskGenericNotify( ( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( ulValue ),
( eAction ),
( pulPreviousNotifyValue ) )
(6)函数xTaskNotifyAndQueryFromISR()
xTaskNotifyAndQuery()的中断版本(中断服务函数中使用)。
/*函数原型*/
BaseType_t xTaskNotifyAndQueryFromISR( TaskHandle_t xTaskToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t *pulPreviousNotificationValue,
BaseType_t *pxHigherPriorityTaskWoken );
/*
*参数:
* xTaskToNotify: 任务句柄,要发向的任务;
* ulValue: 任务通知值;
*/eAction: 任务通知更新方法;
* pulPreviousNotifyValue: 保存更新前的任务通知值;
* pxHigherPriorityTaskWoken: 标记退出此函数后是否进行任务切换,只需提供变量来保存即可,当该值
为pdTRUE时退出前需要进行一次任务切换。
*返回值:
* pdPASS: 成功;
* pdFAIL: 失败;
*/
/*函数宏定义*/
#define xTaskNotifyAndQueryFromISR( xTaskToNotify,
ulValue,
eAction,
pulPreviousNotificationValue,
pxHigherPriorityTaskWoken ) \
xTaskGenericNotifyFromISR( ( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( ulValue ),
( eAction ),
( pulPreviousNotificationValue ),
( pxHigherPriorityTaskWoken ) )
2、获取任务通知函数
(1)函数ulTaskNotifyTake()
/*函数原型*/
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
/*
*参数:
* xClearCountOnExit: pdFALSE时,退出前将任务通知值减1(计数型信号量),pdTRUE时,退
* 出前将任务通知值清零(二值信号量);
* xTicksToWait:xTicksToWait: 阻塞时间,无通知时的等待时间;
*
*返回值: 返回减1或清零前的通知值;
*/
/*函数宏定义*/
#define ulTaskNotifyTake( xClearCountOnExit, xTicksToWait ) \
ulTaskGenericNotifyTake( ( tskDEFAULT_INDEX_TO_NOTIFY ),
( xClearCountOnExit ),
( xTicksToWait ) )
(2)函数xTaskNotifyWait()
/*函数原型*/
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t *pulNotificationValue,
TickType_t xTicksToWait );
/*
*参数:
* ulBitsToClearOnEntry: 使用通知之前将哪些位清零(可用于屏蔽某些位吧);
* ulBitsToClearOnExit: 退出前将哪些位清零;
* pulNotificationValue: 用于保存接收到的任务通知值;
* xTicksToWait: 阻塞时间,无通知时的等待时间;
*返回值:
*pdTRUE: 成功;
*pdFALSE: 失败;
*/
/*在新版源码中函数是一个宏*/
#define xTaskNotifyWait( ulBitsToClearOnEntry,
ulBitsToClearOnExit,
pulNotificationValue,
xTicksToWait ) \
xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY,
( ulBitsToClearOnEntry ),
( ulBitsToClearOnExit ),
( pulNotificationValue ),
( xTicksToWait ) )