文章目录
一、事件标志组
1.1.简介
事件标志位是用一个位来表示时间是否发生;事件标志组是一组事件标志位的集合,可以看作一个整数。事件标志组的特点:
- 它的每一位表示一个事件(高 8 位不算,高 8 位用作存储时间标志组的控制信息)
- 每一位事件的含义,由用户自己决定,如:bit0 表示按键是否按下,bit1 表示是否接收到消息
- 任意任务或中断都可以读写这些位
- 可以等待某一位成立,或者等待多位同时成立
EventBits_t
实际上是一个 16 位或 32 位无符号的数据类型,一个事件组就包括了一个EventBits_t
数据类型的变量,变量类型定义如下:
//下面的宏默认为0,如果为1就进行if操作
#define configUSE_16_BIT_TICKS 0
typedef TickType_t EventBits_t;
#if(configUSE_16_BIT_TICKS == 1)
typedef uint16_t TickType_t;
#else
typedef uint32_t TickType_t;
#endif
虽然使用了 32 位无符号的数据类型变量来存储事件标志,但其中的高 8 位用作存储事件标志组的控制信息,低 24 位用作存储事件标志,因此一个事件组最多可以存储 24 个事件标志,如下图:
1.2.事件组和队列、信号量的区别
功能 | 唤醒对象 | 事件清除 |
---|---|---|
队列、信号量 | 事件发生时,只会唤醒一个任务 | 是消耗型的资源,队列的数据被读走了就没有了;信号量被获取后就减少 |
事件标志组 | 事件发生时,会唤醒所有符合条件的任务,可以理解为广播的作用 | 被唤醒的任务有两个选择,可以让事件保留不动,也可以清除事件 |
二、事件标志组的相关API函数
函数 | 描述 |
---|---|
xEventGroupCreate( ) | 使用动态方式创建事件标志组 |
xEventGroupCreateStstic( ) | 使用静态方式创建事件标志组 |
xEventGroupWaitBits( ) | 等待事件标志位 |
xEventGroupSetBits( ) | 设置事件标志位 |
xEventGroupSetBitsFromISR( ) | 在中断中设置事件标志位 |
xEventGroupClearBits( ) | 清零事件标志位 |
xEventGroupClearBitsFromISR( ) | 在中断中清零事件标志位 |
xEventGroupGetBits( ) | 获取事件组中各事件标志位的值 |
xEventGroupGetBitsFromISR( ) | 在中断中获取事件组中各事件标志位的值 |
xEventGroupSync( ) | 设置事件标志位,并等待事件标志位 |
2.1.使用动态方式创建事件标志组
动态方式创建事件标志组 API 函数的函数原型如下所示:
EventGroupHandle_t xEventGroupCreate(void);
下面表格是它的返回值:
返回值 | 描述 |
---|---|
NULL | 事件标志组创建失败 |
其他值 | 事件标志组创建成功,返回其句柄 |
2.2.清零事件标志位
在任务中清零事件标志位 API 函数的函数原型如下所示:
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToClear)
下面表格是它的形参和描述:
形参 | 描述 |
---|---|
xEventGroup | 待操作的事件标志组 |
uxBitsToSet | 待清零的事件标志位 |
下面表格是它的返回值:
返回值 | 描述 |
---|---|
整数 | 清零事件标志位之前事件组中事件标志位的值 |
2.3.设置事件标志位
在任务中设置事件标志位 API 函数的函数原型如下所示:
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet)
下面表格是它的形参和描述:
形参 | 描述 |
---|---|
xEventGroup | 待操作的事件标志组 |
uxBitsToSet | 待设置的事件标志位 |
下面表格是它的返回值:
返回值 | 描述 |
---|---|
整数 | 函数返回时,事件组中的事件标志位值 |
2.4.等待事件标志位
等待事件标志位使用的是函数 xEventGroupWaitBits( )
,其函数原型如下所示:
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait)
下面表格是它的形参和描述:
形参 | 描述 |
---|---|
xEvenrGroup | 等待的事件标志组 |
uxBitsToWaitFor | 等待的事件标志位,可以用逻辑或等待多个事件标志位 |
xClearOnExit | 成功等待到事件标志位后,清除事件组中对应的事件标志位,pdTRUE:清除 uxBitsToWaitFor 指定位;pdFALSE:不清除 |
xWaitForAllBits | 等待 uxBitsToWaitFor 中的所有事件标志位(逻辑与),pdTRUE:等待的位,全都为 1;pdFALSE:等待的位,某个为 1 |
xTicksToWait | 获取等待的阻塞时间 |
下面表格是它的返回值:
返回值 | 描述 |
---|---|
等待的事件标志位值 | 等待事件标志位成功,返回等待到的事件标志位 |
其他值 | 等待事件标志位失败,返回事件组中的事件标志位 |
2.5.同步函数
此函数一般用于多任务同步,其中每个任务都必须等待其他任务达到同步点,然后才能继续执行。函数xEventGroupSync( )
的函数原型如下所示:
EventBits_t xEventGroupSync(EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait)
下面表格是它的形参和描述:
形参 | 描述 |
---|---|
xEventGroup | 等待事件标志所在事件组 |
uxBitsToSet | 达到同步点后,要设置的事件标志 |
uxBitsToWaitFor | 等待的事件标志 |
xTicksToWait | 等待的阻塞时间 |
下面表格是它的返回值:
返回值 | 描述 |
---|---|
等待的事件标志位值 | 等待事件标志位成功,返回等待到的事件标志位 |
其他值 | 等待事件标志位失败,返回事件组中的事件标志位 |
三、实验
3.1.实验设计
本实验将设计三个任务:
- start_task:创建 task1 和 task2,并创建事件标志组
- task1:读取按键按下键值,根据不同键值将事件标志组相应事件位置 1,模拟事件发生
- task2:同时等待事件标志组中的多个事件位,当这些事件位都置 1 就执行相应的处理
3.2.软件设计
在 start_task 创建事件标志组:
//全局变量和宏定义
EventGroupHandle_t eventGroup_handle;
#define Bit0 1 << 0
#define Bit1 1 << 1
void start_task(void *pvParameters)
{
taskENTER_CRITICAL();
eventGroup_handle = xEventGroupCreate();
if(eventGroup_handle != NULL)
{
printf("事件标志组创建成功\r\n");
}
xTaskCreate((TaskFunction_t) task1,
(char*) "task1",
(uint16_t) TASK1_STACK_SIZE,
(void*) NULL,
(UBaseType_t) TASK1_PRIO,
(TaskHandle_t*) &task1_handler);
xTaskCreate((TaskFunction_t) task2,
(char*) "task2",
(uint16_t) TASK2_STACK_SIZE,
(void*) NULL,
(UBaseType_t) TASK2_PRIO,
(TaskHandle_t*) &task2_handler);
vTaskDelete(NULL);
taskEXIT_CRITICAL();
}
下面是实现设置事件标志位和等待标志位,task2 的等待事件标志位需要 Bit0 和 Bit1 都置 1 才能打印下面句子:
void task1(void *pvParameters)
{
uint8_t key = 0;
while(1)
{
key = key_scan(0);
if(key == KEY0_PRES)
{
xEventGroupSetBits(eventGroup_handle, Bit0);
}else if(key == KEY1_PRES)
{
xEventGroupSetBits(eventGroup_handle, Bit1);
}
}
}
void task2(void *pvParameters)
{
EventBits_t event_bits = 0;
while(1)
{
event_bits = xEventGroupWaitBits(eventGroup_handle, Bit0 | Bit1, pdTRUE, pdTRUE, portMAX_DELAY);
printf("等待到的事件标志位值为:%#x\r\n",event_bits);
}
}
下图是程序运行的结果图,0x3 = 0x1 + 0x2。