即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

uC/OS-III之事件标志组

编程语言 linuxweiyh 80℃ 0评论

1.当任务需要与多个事件的发生同步时,可以使用事件标志组。


等待多个事件时,任何一个事件发生,任务都被同步,这种同步机制称为“或”同步(逻辑“或运算”);


当所有事件都发生时,任务才被同步,这种同步机制被称为“与”同步(逻辑“与”运算)。

2.使用事件标志组前需要先配置事件标志组相关的宏定义,它们的定义位于os_cfg.h中

#define OS_CFG_FLAG_EN                  1u   // 事件标志组使能标志
#define OS_CFG_FLAG_DEL_EN              1u   // 包含函数OSFlagDel()的代码
#define OS_CFG_FLAG_MODE_CLR_EN         1u   // 
#define OS_CFG_FLAG_PEND_ABORT_EN       1u   // 包含函数OSFlagPendAbort()的代码    

3.事件标志组的使用


(1)当任务或ISR向事件标志组发布事件标志时,所有满足等待条件的任务都会进入就绪态。


(2)事件标志组的创建最好放在启动代码中,也就是main函数中。


(3)事件标志通常有两种用途:状态信息监控和瞬时事件监控。


状态信息监控一般通过非阻塞调用来监控相关的事件标志;瞬时事件监控则是通过阻塞等待的方式来实现。

4.事件标志组的类型为OS_FLAG_GRP,它的定义位于os.h中

typedef  struct  os_flag_grp         OS_FLAG_GRP;           // 617行

struct  os_flag_grp {                                       // 742行 - 753行,事件标志组
    OS_OBJ_TYPE          Type;                              // 类型必须设置成OS_OBJ_TYPE_FLAG
    CPU_CHAR            *NamePtr;                           // 名称
    OS_PEND_LIST         PendList;                          // 挂起标
#if OS_CFG_DBG_EN > 0u                                      // 调试相关
    OS_FLAG_GRP         *DbgPrevPtr;
    OS_FLAG_GRP         *DbgNextPtr;
    CPU_CHAR            *DbgNamePtr;
#endif
    OS_FLAGS             Flags;                             // 事件标志
    CPU_TS               TS;                                // 最近一次发布事件标志的时间戳
};

5.事件标志组的创建使用函数OSTaskCreate(),它的定义位于os_flag.c中。

void  OSFlagCreate (OS_FLAG_GRP  *p_grp,                    // 69行 - 120行,事件标志组的地址
                    CPU_CHAR     *p_name,                   // 名称
                    OS_FLAGS      flags,                    // 标志初始值
                    OS_ERR       *p_err)                    // 返回的错误码
{
    CPU_SR_ALLOC();                                         // 声明变量cpu_sr,用来临时存储CPU的状态寄存器

#ifdef OS_SAFETY_CRITICAL                                   // 允许进行系统安全性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508                          // 允许进行系统安全性检查--IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
       *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
        return;
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u                      // 允许进行ISR调用检查
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 查看是否是在ISR中调用该函数
       *p_err = OS_ERR_CREATE_ISR;                          // 不能再ISR中创建
        return;
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u                                  // 允许进行参数检查
    if (p_grp == (OS_FLAG_GRP *)0) {                        // 无效的事件标志组
       *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
#endif

    OS_CRITICAL_ENTER();                                    // 进入临界区
    p_grp->Type    = OS_OBJ_TYPE_FLAG;                      // 设置类型为OS_OBJ_TYPE_FLAG
    p_grp->NamePtr = p_name;
    p_grp->Flags   = flags;                                 // 设置事件标志初始值
    p_grp->TS      = (CPU_TS)0;
    OS_PendListInit(&p_grp->PendList);                      // 创建挂起表

#if OS_CFG_DBG_EN > 0u                                      // 调试相关
    OS_FlagDbgListAdd(p_grp);
#endif
    OSFlagQty++;                                            // 系统事件标志组的数目加1

    OS_CRITICAL_EXIT();                                     // 退出临界区
   *p_err = OS_ERR_NONE;
}

6.等待事件标志组使用OSFlagPend(),它的定义位于os_flag.c中。

OS_FLAGS  OSFlagPend (OS_FLAG_GRP *p_grp,                   // 313行 - 585行
                      OS_FLAGS     flags,                   // 等待的标志
                      OS_TICK      timeout,                 // 超时时间
                      OS_OPT       opt,                     // 等待选项
                      CPU_TS      *p_ts,                    // 返回的时间戳
                      OS_ERR      *p_err)                   // 返回的调用结果
{
    CPU_BOOLEAN   consume;
    OS_FLAGS      flags_rdy;
    OS_OPT        mode;
    OS_PEND_DATA  pend_data;
    CPU_SR_ALLOC();                                         // 声明变量cpu_sr,用来临时存储CPU的状态寄存器

#ifdef OS_SAFETY_CRITICAL                                   // 允许进行系统安全性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_FLAGS)0);
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u                      // 允许进行ISR调用检查
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 查看是否在ISR中调用该函数
       *p_err = OS_ERR_PEND_ISR;                            // 不能在ISR中调用
        return ((OS_FLAGS)0);
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u                                  // 允许进行参数检查
    if (p_grp == (OS_FLAG_GRP *)0) {                        // 无效的参数
        *p_err = OS_ERR_OBJ_PTR_NULL;
        return ((OS_FLAGS)0);
    }
#endif

#if OS_CFG_OBJ_TYPE_CHK_EN > 0u                             // 允许进行对象类型检查
    if (p_grp->Type != OS_OBJ_TYPE_FLAG) {                  // 无效的指向
        *p_err = OS_ERR_OBJ_TYPE;
        return ((OS_FLAGS)0);
    }
#endif

    if ((opt & OS_OPT_PEND_FLAG_CONSUME) != (OS_OPT)0) {    // 查看我们是否需要消耗标志
        consume = DEF_TRUE;
    } else {
        consume = DEF_FALSE;
    }

    if (p_ts != (CPU_TS *)0) {
        *p_ts = (CPU_TS)0;                                  // 初始化要返回的时间戳
    }

    mode = opt & OS_OPT_PEND_FLAG_MASK;
    CPU_CRITICAL_ENTER();                                   // 进入临界区
    switch (mode) {
        case OS_OPT_PEND_FLAG_SET_ALL:                      // 所有的标志置位
             flags_rdy = (OS_FLAGS)(p_grp->Flags & flags);  // 提取出需要事件标志
             if (flags_rdy == flags) {                      // 所有的事件都已发生
                 if (consume == DEF_TRUE) {                 // 查看是否需要消耗掉这些标志
                     p_grp->Flags &= ~flags_rdy;            // 仅仅清理掉那些我们需要的位
                 }
                 OSTCBCurPtr->FlagsRdy = flags_rdy;         // 保存已经准备就绪的位
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = p_grp->TS;
                 }
                 CPU_CRITICAL_EXIT();                       // 退出临界区
                 *p_err = OS_ERR_NONE;
                 return (flags_rdy);
             } else {                                       // 所有的事件没有全部发生
                 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {  // 不挂起任务
                     CPU_CRITICAL_EXIT();                   // 退出临界区
                     *p_err = OS_ERR_PEND_WOULD_BLOCK;
                     return ((OS_FLAGS)0);
                 } else {                                              //  挂起任务
                     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {  // 查看调度器是否已锁定
                         CPU_CRITICAL_EXIT();               // 退出临界区
                         *p_err = OS_ERR_SCHED_LOCKED;
                         return ((OS_FLAGS)0);
                     }
                 }
                 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();     // 进入临界区,使能中断
                 OS_FlagBlock(&pend_data,                   // 将任务挂起
                              p_grp,
                              flags,
                              opt,
                              timeout);
                 OS_CRITICAL_EXIT_NO_SCHED();               // 退出临界区,不调度
             }
             break;

        case OS_OPT_PEND_FLAG_SET_ANY:                      // 任意一个标志置位
             flags_rdy = (OS_FLAGS)(p_grp->Flags & flags);  // 提取需要的事件标志
             if (flags_rdy != (OS_FLAGS)0) {                // 有事件发生
                 if (consume == DEF_TRUE) {                 // 是否需要消耗掉这些位
                     p_grp->Flags &= ~flags_rdy;            // 清空掉这些标志
                 }
                 OSTCBCurPtr->FlagsRdy = flags_rdy;         // 保存已发生的事件标志
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = p_grp->TS;
                 }
                 CPU_CRITICAL_EXIT();                       // 退出临界区
                 *p_err = OS_ERR_NONE;
                 return (flags_rdy);
             } else {                                       // 没有任何事件发生
                 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {  // 不挂起
                     CPU_CRITICAL_EXIT();                              // 退出临界区
                     *p_err = OS_ERR_PEND_WOULD_BLOCK;
                     return ((OS_FLAGS)0);
                 } else {                                              // 挂起
                     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {  // 查看任务调度器是否锁定
                         CPU_CRITICAL_EXIT();                          // 退出临界区
                         *p_err = OS_ERR_SCHED_LOCKED;
                         return ((OS_FLAGS)0);
                     }
                 }
                 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();     // 进入临界区,使能中断
                 OS_FlagBlock(&pend_data,                   
                              p_grp,
                              flags,
                              opt,
                              timeout);
                 OS_CRITICAL_EXIT_NO_SCHED();               // 退出临界区,不调度
             }
             break;

#if OS_CFG_FLAG_MODE_CLR_EN > 0u
        case OS_OPT_PEND_FLAG_CLR_ALL:                      // 所有的标志清零
             flags_rdy = (OS_FLAGS)(~p_grp->Flags & flags); // 提取需要的事件标志位
             if (flags_rdy == flags) {                      // 所有的事件都已发生
                 if (consume == DEF_TRUE) {                 // 查看是否需要消耗这些事件标志位
                     p_grp->Flags |= flags_rdy;             // 仅仅设置需要的事件标志位
                 }
                 OSTCBCurPtr->FlagsRdy = flags_rdy;         // 保存这些事件标志位
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = p_grp->TS;
                 }
                 CPU_CRITICAL_EXIT();                       // 退出临界区
                 *p_err = OS_ERR_NONE;
                 return (flags_rdy);
             } else {                                       // 所有事件未全部发生
                 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {  // 不挂起
                     CPU_CRITICAL_EXIT();                   // 退出临界区
                     *p_err = OS_ERR_PEND_WOULD_BLOCK;
                     return ((OS_FLAGS)0);
                 } else {                                              // 挂起
                     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {  // 查看调度器是否锁定
                         CPU_CRITICAL_EXIT();               // 退出临界区
                         *p_err = OS_ERR_SCHED_LOCKED;
                         return ((OS_FLAGS)0);
                     }
                 }
                 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();     // 进入临界区,使能中断
                 OS_FlagBlock(&pend_data,                   // 挂起任务
                              p_grp,
                              flags,
                              opt,
                              timeout);
                 OS_CRITICAL_EXIT_NO_SCHED();               // 退出临界区,不调度
             }
             break;

        case OS_OPT_PEND_FLAG_CLR_ANY:                      // 某一个标志清零
             flags_rdy = (OS_FLAGS)(~p_grp->Flags & flags); // 提取出需要的事件标志位
             if (flags_rdy != (OS_FLAGS)0) {                // 有事件发生
                 if (consume == DEF_TRUE) {                 // 查看是否需要消耗掉这些标志位
                     p_grp->Flags |= flags_rdy;             // 仅仅设置需要的标志位
                 }
                 OSTCBCurPtr->FlagsRdy = flags_rdy;         // 保存事件标志位
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = p_grp->TS;
                 }
                 CPU_CRITICAL_EXIT();                       // 退出临界区
                 *p_err    = OS_ERR_NONE;
                 return (flags_rdy);
             } else {                                       // 没有任何事情发生
                 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {  // 不挂起
                     CPU_CRITICAL_EXIT();                   // 退出临界区
                     *p_err = OS_ERR_PEND_WOULD_BLOCK;
                     return ((OS_FLAGS)0);
                 } else {                                              // 挂起
                     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {  // 查看调度器是否锁定
                         CPU_CRITICAL_EXIT();               // 退出临界区
                         *p_err = OS_ERR_SCHED_LOCKED;
                         return ((OS_FLAGS)0);
                     }
                 }

                 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();     // 进入临界区,使能中断
                 OS_FlagBlock(&pend_data,                   // 挂起任务
                              p_grp,
                              flags,
                              opt,
                              timeout);
                 OS_CRITICAL_EXIT_NO_SCHED();               // 退出临界区,不调度
             }
             break;
#endif

        default:
             CPU_CRITICAL_EXIT();                           // 退出临界区
             *p_err = OS_ERR_OPT_INVALID;
             return ((OS_FLAGS)0);
    }

    OSSched();                                              // 执行调度程序

    CPU_CRITICAL_ENTER();                                   // 进入临界区
    switch (OSTCBCurPtr->PendStatus) {
        case OS_STATUS_PEND_OK:                             // 目标事件标志位被置位(清零)
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
             *p_err = OS_ERR_NONE;
             break;
        case OS_STATUS_PEND_ABORT:                          // 等待操作被其他任务取消了
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
             CPU_CRITICAL_EXIT();                           // 退出临界区
             *p_err = OS_ERR_PEND_ABORT;
             return ((OS_FLAGS)0);
        case OS_STATUS_PEND_TIMEOUT:                        // 等待超时
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = (CPU_TS  )0;
             }
             CPU_CRITICAL_EXIT();                           // 退出临界区
             *p_err = OS_ERR_TIMEOUT;
             return ((OS_FLAGS)0);
        case OS_STATUS_PEND_DEL:                            // 事件标志组被删除了
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
             CPU_CRITICAL_EXIT();                           // 退出临界区
             *p_err = OS_ERR_OBJ_DEL;
             return ((OS_FLAGS)0);
        default:
             CPU_CRITICAL_EXIT();                           // 退出临界区
             *p_err = OS_ERR_STATUS_INVALID;
             return ((OS_FLAGS)0);
    }

    flags_rdy = OSTCBCurPtr->FlagsRdy;
    if (consume == DEF_TRUE) {                              // 查看是否需要消耗掉这些标志
        switch (mode) {
            case OS_OPT_PEND_FLAG_SET_ALL:
            case OS_OPT_PEND_FLAG_SET_ANY:                  // 清空事件标志位
                 p_grp->Flags &= ~flags_rdy;
                 break;

#if OS_CFG_FLAG_MODE_CLR_EN > 0u
            case OS_OPT_PEND_FLAG_CLR_ALL:
            case OS_OPT_PEND_FLAG_CLR_ANY:                  // 置位事件标志位
                 p_grp->Flags |=  flags_rdy;
                 break;
#endif
            default:
                 CPU_CRITICAL_EXIT();                       // 退出临界区
                 *p_err = OS_ERR_OPT_INVALID;
                 return ((OS_FLAGS)0);
        }
    }
    CPU_CRITICAL_EXIT();                                    // 退出临界区
    *p_err = OS_ERR_NONE;
    return (flags_rdy);
}

6.发送事件标志组使用OSFlagPost(),它的定义位于os_flag.c中。

OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *p_grp,                  // 790行 - 856行
                      OS_FLAGS      flags,                  // 事件标志
                      OS_OPT        opt,                    // 事件标志的选项
                      OS_ERR       *p_err)                  // 调用的结果
{
    OS_FLAGS  flags_cur;
    CPU_TS    ts;

#ifdef OS_SAFETY_CRITICAL                                   // 允许执行系统安全性检查
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_FLAGS)0);
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u                                  // 允许进行参数检查
    if (p_grp == (OS_FLAG_GRP *)0) {                        // 检查p_grp
       *p_err  = OS_ERR_OBJ_PTR_NULL;
        return ((OS_FLAGS)0);
    }
    switch (opt) {                                          // 检查opt
        case OS_OPT_POST_FLAG_SET:
        case OS_OPT_POST_FLAG_CLR:
        case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED:
        case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED:
             break;
        default:
             *p_err = OS_ERR_OPT_INVALID;
             return ((OS_FLAGS)0);
    }
#endif

#if OS_CFG_OBJ_TYPE_CHK_EN > 0u                             // 允许进行对象类型检查
    if (p_grp->Type != OS_OBJ_TYPE_FLAG) {                  // 确保是事件标志组
        *p_err = OS_ERR_OBJ_TYPE;
        return ((OS_FLAGS)0);
    }
#endif

    ts = OS_TS_GET();                                       // 获取时间戳
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u                        // 延时发布模式
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              // 查看是否是在ISR中调用
        OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_FLAG,          // 发布到ISR队列中
                    (void      *)p_grp,
                    (void      *)0,
                    (OS_MSG_SIZE)0,
                    (OS_FLAGS   )flags,
                    (OS_OPT     )opt,
                    (CPU_TS     )ts,
                    (OS_ERR    *)p_err);
        return ((OS_FLAGS)0);
    }
#endif
    flags_cur = OS_FlagPost(p_grp,                          // 发布事件标志组
                            flags,
                            opt,
                            ts,
                            p_err);
    return (flags_cur);
}

转载请注明:CodingBlog » uC/OS-III之事件标志组

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情