鸿蒙Hi3861学习八-Huawei LiteOS-M(事件标记)

一、简介

        事件是一种实现任务间通信的机制,可用于实现任务间的同步。但事件通信只能是事件类型的通信,无数据传输。一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。事件集合用32位无符号整型变量来表示,每一位代表一个事件

        多任务环境下,任务之间往往需要同步操作。事件可以提供一对多、多对多的同步操作。一对多同步模型:一个任务等待多个事件的触发;多多对同步模型:多个任务等待多个事件的触发。

        任务可以通过创建事件控制块来实现对事件的触发和等待操作。LiteOS的事件仅用于任务间的同步

        更多事件标记的概念可以参考:FreeRTOS学习七(事件标志组)_portmax_delay_t_guest的博客-CSDN博客

Event Flags

 二、运行机制

        读事件时,可以根据入参事件掩码类型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可以获取控制权执行代码。

猜你喜欢

转载自blog.csdn.net/qq_26226375/article/details/130529833