事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能是事件类型的通信,没有数据传输。与信号量不同的是,他可以实现一对多,多对多的同步。用事件做标志位判断某些事件是否发生了,然后根据结果进行处理。
一对多同步模型:一个任务等待多个事件的触发。
多对多同步模型:多个任务等待多个事件的触发。
使用全局变量做标志位可能引起的问题。
1.如何对全局变量进行保护,当多个任务同时尝试访问和修改全局标志变量时,可能会导致数据竞争或死锁。
2.如何让内核对事件进行有效的管理,使用全局变量需要在任务之间轮询的进行查看这个事件是否发生,这种非常浪费 CPU的资源。以及超时机制。
事件组
事件组是一组事件标志的集合。(事件标志是一个用来指示事件是否发生的布尔值,0或1)一个事件组的数据类型为EventBits_t。
当configUSE_16_BIT_TICKS 配置为 0 时,EventBits_t是一个32位无符号的数据类型。
当configUSE_16_BIT_TICKS 配置为 1 时,EventBits_t 是一个 16 位无符号的数据类型。
当配置为0时,并不意味着一个EventBits_t数据类型可以存储32个事件。其中高8位用于存储控制信息。低24位用于表示事件标志,某一位被置为一时,表示这一位对应的事件发生了。
API 函数
创建
EventGroupHandle_t xEventGroupCreate(void);
创建成功返回句柄,失败NULL
删除
void vEventGroupDelete(EventGroupHandle_t xEventGroup);
参数要删除的事件标志组句柄。
设置
任务中:
EventBits_t xEventGroupSetBits(
EventGroupHandle_t xEventGroup,
constEventBits_t uxBitsToSet)
参数一:句柄,待操作的事件标志组。
参数二:待设置的事件标志位。
返回值:事件组中的事件标志位值。
中断中:
BaseType_t xEventGroupSetBitsFromISR(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t * pxHigherPriorityTaskWoken)
参数一:句柄,待操作的事件标志组。
参数二:待设置的事件标志位。
参数三:用于标记函数退出后是否需要进行任务切换。
返回值:设置成功返回pdPASS。失败返回pdFALL;
清零
任务中:
EventBits_t xEventGroupClearBits(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear)
参数一:待操作的事件标志组。
参数二:待清零的事件标志位。
返回值:清零事件标志位之前事件组中事件标志位的值。
中断中:
BaseType_t xEventGroupClearBitsFromISR(
EventGroupHandle_t EventGroup,
const EventBits_t uxBitsToClear)
参数一:待操作的事件标志组。
参数二:待清零的事件标志位。
返回值:清除成功pdPASS,失败pdFAIL 。
等待
EventBits_t xEventGroupWaitBits(
EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait)
参数一:等待的事件标志组句柄。
参数二:等待的事件标志位,可以用逻辑或等待多个事件标志位。
参数三:为pdTRUE:成功等待到事件标志位后,清除事件组中对应的事件标志位。
为pdFALSE:不清除事件组中所对应的事件标志位。
参数四:为 pdTRUE,任务会等待所有指定的位都设置为 TRUE。
为 pdFALSE,则任务会在任何一个指定的位被设置为 TRUE 时立即返回。
参数五:任务等待的最大时间(以滴答为单位)。如果设置为 0,任务将不会等待,函数将立即返回。
获取
任务中:
EventBits_t xEventGroupGetBits(xEventGroup);
参数:待获取事件标志位值的事件组句柄。
返回值:事件组的事件标志位的值。
中断中:
EventBits_t xEventGroupGetBitsFromISR(EventGroupHandle_t xEventGroup);
参数:待获取事件标志位值的事件组句柄。
返回值:事件组的事件标志位的值。
实验
定义各任务的标志位
#define key1_event (0x01<<0)
#define key2_event (0x01<<1)
#define key3_event (0x01<<2)
创建事件句柄(创建)
EventGroupHandle_t Event_Handle =NULL;
Event_Handle=xEventGroupCreate();
if(Event_Handle == NULL)
{
OLED_ShowString(1,5,"fail");
}
else
{
OLED_ShowString(1,5,"succeed");
}
实验现象:
一:屏幕第4行第一列显示当前事件标志值。(获取)
void OLED2_task(void *pvParameters)
{
EventBits_t event_val = 0;
while(1)
{
/* 获取事件组的所有事件标志值 */
event_val = xEventGroupGetBits(Event_Handle);
OLED_ShowNum(4,1,event_val,2);
vTaskDelay(20);
}
}
若第1位和第2位为1,0000 0011 结果显示3。若1到3位都为1,显示0000 0111结果显示7。
二:按键1和按键2都有按下时执行任务oled,oled屏幕上显示k加一。(等待)
void OLED_task(void *pvParameters)
{
static u8 k=0;
EventBits_t event_val = 0;
while(1)
{
//句柄,位,是否清零,是否同时满足,等待时间
xEventGroupWaitBits(Event_Handle,key1_event|key2_event,pdTRUE,pdTRUE,portMAX_DELAY);
OLED_ShowNum(2,1,++k,3);
vTaskDelay(20);
}
}
三:按键3按下执行任务oled3,oled屏幕显示k加一,并清除按键1和按键2的标志位。(清除)
void OLED3_task(void *pvParameters)
{
static u8 k=0;
while(1)
{
xEventGroupWaitBits(Event_Handle,key3_event,pdTRUE,pdTRUE,portMAX_DELAY);
xEventGroupClearBits(Event_Handle,key1_event|key2_event);
OLED_ShowNum(2,10,++k,2);
vTaskDelay(20);
}
}