天天看點

UCOSIII---事件标志組

事件标志組

當任務需要與多個事件的發生同步時,可以使用事件标志組。等待多個事件時,任何一個事件發生,任務才被同步,這種同步機制稱為“或”同步,當所有的事件都發生時,任務才能被同步,這種同步機制被稱為“與”同步。

這兩種同步機制如下圖所示:

UCOSIII---事件标志組

1 UCOSIII中的事件标志組就是OS_FLAG_GRP類型中的核心對象,由一串事件标志組組成。

2 任務和ISR都可以釋出事件标志。

3 任務可以等待事件标志組中的任意個事件标志。

4 任務可以設定使用或同步機制還是與同步機制。

事件标志組API函數

UCOSIII---事件标志組

如何建立事件标志組

在使用事件标志組之前,需要調用函數OSFlagCreate()建立一個事件标志組

void  OSFlagCreate (OS_FLAG_GRP  *p_grp,                        //指向事件标志組
                    CPU_CHAR     *p_name,                        //事件标志組的名字
                    OS_FLAGS      flags,                        //定義事件标志組的初始值
                    OS_ERR       *p_err)
{
    CPU_SR_ALLOC();
 
    OS_CRITICAL_ENTER();
    p_grp->Type    = OS_OBJ_TYPE_FLAG;                      /* Set to event flag group type                           */
    p_grp->NamePtr = p_name;
    p_grp->Flags   = flags;                                 /* Set to desired initial value                           */
    p_grp->TS      = (CPU_TS)0;
    OS_PendListInit(&p_grp->PendList);
 
    OSFlagQty++;
 
    OS_CRITICAL_EXIT_NO_SCHED();
   *p_err = OS_ERR_NONE;
}
           

事件标志組的結構體OS_FLAG_GRP:

struct  os_flag_grp {                                       /* Event Flag Group                                       */
                                                            /* ------------------ GENERIC  MEMBERS ------------------ */
    OS_OBJ_TYPE          Type;                              /* Should be set to 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
                                                            /* ------------------ SPECIFIC MEMBERS ------------------ */
    OS_FLAGS             Flags;                             /* 8, 16 or 32 bit flags                                  */
    CPU_TS               TS;                                /* Timestamp of when last post occurred                   */
};
           

Flags是32位,它的每一位都代表着一個任務的狀态,每個任務有1和0兩種狀态。也就是說,我們可以同時最多完成一個任務和32個任務的任務同步!我們可以設定:Falgs的第0、1兩個任務為1的時候,完成任務同步,也就是說,Flags變成0x03的時候,完成同步。當然,OSFlagCreate()函數中的flags參數隻是确定一個初始值。

等待事件标志組

等待一個事件标志組需要調用函數OSFlagPend()

OS_FLAGS  OSFlagPend (OS_FLAG_GRP  *p_grp,                            //指向事件标志組
                      OS_FLAGS      flags,                            //bit序列
                      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();
 
    if ((opt & OS_OPT_PEND_FLAG_CONSUME) != (OS_OPT)0) {    /* See if we need to consume the flags                    */
        consume = DEF_TRUE;
    } else {
        consume = DEF_FALSE;
    }
 
    if (p_ts != (CPU_TS *)0) {
       *p_ts = (CPU_TS)0;                                   /* Initialize the returned timestamp                      */
    }
 
    mode = opt & OS_OPT_PEND_FLAG_MASK;
    CPU_CRITICAL_ENTER();
    switch (mode) {
        case OS_OPT_PEND_FLAG_SET_ALL:                      /* See if all required flags are set                      */
             flags_rdy = (OS_FLAGS)(p_grp->Flags & flags);  /* Extract only the bits we want                          */
             if (flags_rdy == flags) {                      /* Must match ALL the bits that we want                   */
                 if (consume == DEF_TRUE) {                 /* See if we need to consume the flags                    */
                     p_grp->Flags &= ~flags_rdy;            /* Clear ONLY the flags that we wanted                    */
                 }
                 OSTCBCurPtr->FlagsRdy = flags_rdy;         /* Save flags that were ready                             */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = p_grp->TS;
                 }
                 CPU_CRITICAL_EXIT();                       /* Yes, condition met, return to caller                   */
                *p_err = OS_ERR_NONE;
                 return (flags_rdy);
             } else {                                       /* Block task until events occur or timeout               */
                 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {
                     CPU_CRITICAL_EXIT();
                    *p_err = OS_ERR_PEND_WOULD_BLOCK;       /* Specified non-blocking so task would block             */
                     return ((OS_FLAGS)0);
                 } else {                                   /* Specified blocking so check is scheduler is locked     */
                     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* See if called with scheduler locked ...      */
                         CPU_CRITICAL_EXIT();
                        *p_err = OS_ERR_SCHED_LOCKED;                 /* ... can't PEND when locked                   */
                         return ((OS_FLAGS)0);
                     }
                 }
                                                            
                 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();     /* Lock the scheduler/re-enable interrupts                */
                 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);  /* Extract only the bits we want                          */
             if (flags_rdy != (OS_FLAGS)0) {                /* See if any flag set                                    */
                 if (consume == DEF_TRUE) {                 /* See if we need to consume the flags                    */
                     p_grp->Flags &= ~flags_rdy;            /* Clear ONLY the flags that we got                       */
                 }
                 OSTCBCurPtr->FlagsRdy = flags_rdy;         /* Save flags that were ready                             */
                 if (p_ts != (CPU_TS *)0) {
                    *p_ts  = p_grp->TS;
                 }
                 CPU_CRITICAL_EXIT();                       /* Yes, condition met, return to caller                   */
                *p_err = OS_ERR_NONE;
                 return (flags_rdy);
             } else {                                       /* Block task until events occur or timeout               */
                 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) {
                     CPU_CRITICAL_EXIT();
                    *p_err = OS_ERR_PEND_WOULD_BLOCK;       /* Specified non-blocking so task would block             */
                     return ((OS_FLAGS)0);
                 } else {                                   /* Specified blocking so check is scheduler is locked     */
                     if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* See if called with scheduler locked ...      */
                         CPU_CRITICAL_EXIT();
                        *p_err = OS_ERR_SCHED_LOCKED;                 /* ... can't PEND when locked                   */
                         return ((OS_FLAGS)0);
                     }
                 }
                                                            
                 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();     /* Lock the scheduler/re-enable interrupts                */
                 OS_FlagBlock(&pend_data,
                              p_grp,
                              flags,
                              opt,
                              timeout);
                 OS_CRITICAL_EXIT_NO_SCHED();
             }
             break;
 
        default:
             CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_OPT_INVALID;
             return ((OS_FLAGS)0);
    }
 
    OSSched();                                              /* Find next HPT ready to run                             */
 
    CPU_CRITICAL_ENTER();
    switch (OSTCBCurPtr->PendStatus) {
        case OS_STATUS_PEND_OK:                             /* We got the vent flags                                  */
             if (p_ts != (CPU_TS *)0) {
                *p_ts  = OSTCBCurPtr->TS;
             }
            *p_err = OS_ERR_NONE;
             break;
 
        case OS_STATUS_PEND_ABORT:                          /* Indicate that we aborted                               */
             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:                        /* Indicate that we didn't get semaphore within 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:                            /* Indicate that object pended on has been deleted        */
             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) {                              /* See if we need to consume the flags                    */
        switch (mode) {
            case OS_OPT_PEND_FLAG_SET_ALL:
            case OS_OPT_PEND_FLAG_SET_ANY:                  /* Clear ONLY the flags we got                            */
                 p_grp->Flags &= ~flags_rdy;
                 break;
 
            default:
                 CPU_CRITICAL_EXIT();
                *p_err = OS_ERR_OPT_INVALID;
                 return ((OS_FLAGS)0);
        }
    }
    CPU_CRITICAL_EXIT();
   *p_err = OS_ERR_NONE;                                    /* Event(s) must have occurred                            */
    return (flags_rdy);
}
           

flags:bit序列,任務需要等待事件标志組的哪個位就把這個序列對應的位置1

opt:決定任務等待的條件是所有标志置位

向事件标志組釋出标志

調用函數OSFlagPost()可以對事件标志組進行置位或清零

OS_FLAGS  OSFlagPost (OS_FLAG_GRP  *p_grp,                    //指向事件标志組
                      OS_FLAGS      flags,                    //決定對哪些位清零和置位
                      OS_OPT        opt,                    //決定對标志位的操作
                      OS_ERR       *p_err)
{
    OS_FLAGS  flags_cur;
    CPU_TS    ts;
 
    ts = OS_TS_GET();                                       /* Get timestamp                                        */
 
    flags_cur = OS_FlagPost(p_grp,
                            flags,
                            opt,
                            ts,
                            p_err);
 
    return (flags_cur);
}
           

flags:決定對哪些位清零和置位

opt:決定對flags標明的标志位的操作

小結

ISR和任務都可以通過三種方式向一個或者多個任務發信号:信号量,任務信号量,事件标志組。

當任務需要與一個或者多個事件的發生同步時,可以使用事件标志組。但是事件标志不支援信用記錄功能,因為在事件标志組中的每個事件用一個資料位表示。

繼續閱讀