uC/OS-III之事件标志组

来源:互联网 发布:在线淘宝网 编辑:程序博客网 时间:2024/05/29 04:37

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);}
原创粉丝点击