一、简介
事件是一种实现任务间通信的机制,可用于实现任务间的同步。但事件通信只能是事件类型的通信,无数据传输。一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。事件集合用32位无符号整型变量来表示,每一位代表一个事件。
多任务环境下,任务之间往往需要同步操作。事件可以提供一对多、多对多的同步操作。一对多同步模型:一个任务等待多个事件的触发;多多对同步模型:多个任务等待多个事件的触发。
任务可以通过创建事件控制块来实现对事件的触发和等待操作。LiteOS的事件仅用于任务间的同步。
更多事件标记的概念可以参考:FreeRTOS学习七(事件标志组)_portmax_delay_t_guest的博客-CSDN博客
二、运行机制
读事件时,可以根据入参事件掩码类型uwEventMask读取事件的单个或者多个事件类型。事件读取成功后,如果设置LOS_WAITMODE_CLR会清除已读取到的事件类型,反之不会清除已读到的事件类型,需手动清除。可以通过参数选择读取模式,读取事件掩码类型中所有事件还是读取事件掩码类型中任意事件。
写事件时,对指定事件写入指定的事件类型,可以一次同时写多个事件类型。写事件会触发任务调度。
清除事件时,根据入参事件和待清除的事件类型,对事件对应位进行清零操作。
三、API介绍
osEventFlagsNew
函数功能:
创建事件标志。不能在中断中调用。
函数原型:
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr)
参数:
attr:属性。自定义内存时才用的到。默认设置NULL
返回值:
NULL:失败
其他值:事件标志ID
实例:
osEventFlagsId_t evt_id; // event flags id
evt_id = osEventFlagsNew(NULL);
osEventFlagsSet
函数功能:
设置事件标志。可以在中断中使用。
函数原型:
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
参数:
ef_id:事件ID。创建事件标志组osEventFlagsNew时获得。
flags:事件值
返回值:
如果设置了最高位,则返回设置后的事件标志或错误代码
实例:
osEventFlagsId_t evt_id;
uint32_t rst = osEventFlagsSet(evt_id, 0x10001111);
osEventFlagsWait
函数功能:
等待事件发生。可以在中断中调用。
函数原型:
uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout)
参数:
ef_id:事件ID。创建事件标志组osEventFlagsNew时获得。
flags:待触发的事件值。
options:指定标志选项
osFlagsWaitAny | 0,等待任何标志(默认),即满足任意标志即可 |
osFlagsWaitAll | 1,等待所有标志,即需要满足所有标志。 |
osFlagsNoClear | 2,不清除已经指定等待的标志。需要使用 osEventFlagsClear 手动清除标志。 |
timeout:超时时间。osWaitForever 死等
返回值:
清除前的事件标志或设置最高位时的错误代码
实例:
osEventFlagsId_t evt_id;
uint32_t flags;
flags = osEventFlagsWait(evt_id, 0x000000ff, osFlagsWaitAny, osWaitForever);
osEventFlagsDelete
函数功能:
删除事件标志组。不能在中断中调用
函数原型:
osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id)
参数:
ef_id:事件标志ID。创建事件标志组osEventFlagsNew时获得。
返回值:
osOK:成功
其他值:失败
实例:
osEventFlagsId_t evt_id;
osEventFlagsDelete(evt_id);
四、实例
这里创建2个任务,任务1设置事件组,任务2等待事件组。其中,任务1设置完事件组后,立刻移交控制权。
#define LOG_I(fmt, args...) printf("<%8ld> - [TIMER]:"fmt"\r\n",osKernelGetTickCount(),##args);
#define LOG_E(fmt, args...) printf("<%8ld>-[TIMER_ERR]>>>>>>>>>>>>:"fmt"\r\n",osKernelGetTickCount(), ##args);
osEventFlagsId_t evt_id; // event flags id
/***** 发送事件 *****/
void Thread_EventSender(void *argument)
{
(void)argument;
while (1)
{
LOG_I("thread1 send event before");
uint32_t rst = osEventFlagsSet(evt_id, 0x80001111);
LOG_I("thread1 send event after,rst = 0x%.8x,yield!!",rst);
//suspend thread
osThreadYield();
LOG_I("thread1 send event delay 1S");
osDelay(100);
}
}
/***** 接收事件 *****/
void Thread_EventReceiver(void *argument)
{
(void)argument;
uint32_t flags;
while (1)
{
flags = osEventFlagsWait(evt_id, 0x000000ff, osFlagsWaitAny, osWaitForever);
LOG_I("Receive2 Flags is 0x%.8x\n", flags);
}
}
void Hello_World(void)
{
LOG_I("Test event");
evt_id = osEventFlagsNew(NULL);
if (evt_id == NULL)
{
LOG_E("Falied to create EventFlags!");
}
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.priority = osPriorityNormal;
attr.name = "Thread_EventSender";
if (osThreadNew(Thread_EventSender, NULL, &attr) == NULL)
{
LOG_E("Falied to create Thread_EventSender!");
}
attr.name = "Thread_EventReceiver";
if (osThreadNew(Thread_EventReceiver, NULL, &attr) == NULL)
{
LOG_E("Falied to create Thread_EventReceiver!");
}
}
看结果:
从结果可以看到,任务2等待0x000000ff事件。而任务1释放的是0x80001111。此时因为设置的等待类型为osFlagsWaitAny,即满足任意条件即触发。所以,直接触发事件,且读出的事件组为0x00000011。
任务1和任务2优先级相同,但是任务1在设置完事件后,立马释放了控制权。导致任务2可以获取控制权执行代码。