μC/OS-III---I笔记8---事件标志

摘要:
只有在任务A向任务B发送消息后,任务B才能继续运行。事件标志组的数据结构最简单。只需更改多值信号量的Ctr变量的名称。对于不同的处理器,标志的数量可能不同。时间标志组中的每个标志位对应于一个事件。创建时会描述其发生与否的标志。1.对于事件标志组的创建函数,相同的前提是定义一个事件标志组变量。第一个参数是时间标志组的变量地址,第二个参数是该时间标志租约的名称,第三个参数是初始化的Flags值。

   当任务需要同步时可以使用信号量。A任务给B任务发送消息后B任务才能继续运行。如果需要A任务给任务B传递数据的时候就可以采用消息队列。但对于繁杂任务的同步,比如多个时间发生以后执行一个事件,或者是C任务需要任务A和任务B都完成对应的处理任务后才能执行C任务的处理工作,这是用信号量就是等待多个内核对象,有没有一种更好的办法呢,操作系统的大神就创造出了时间标志来进行这类功能的实现。事件标志组的数据结构是最简单的,只需要将多值信号量的Ctr变量换个名字(Flags)就好了。

μC/OS-III---I笔记8---事件标志第1张

对于不同的处理器Flags的位数可能会有不同,时间标志组中的Flags的每一位都对应一个事件,对于其发生与否的标志在创建时进行了说明。

1,对于事件标志组的创建函数,同样前提是定义一个事件标志组变量,第一个参数是时间标志组的变量地址,第二个参数是时间标志租的Name了,第三个则是初始化的Flags值。样在创建了事件标志组的同时也初始化了其的等待队列。

μC/OS-III---I笔记8---事件标志第2张μC/OS-III---I笔记8---事件标志第3张
************************************************************************************************************************
*                                                 CREATE AN EVENT FLAG
*
* Description: This function is called to create an event flag group.
*
* Arguments  : p_grp          is a pointer to the event flag group to create
*
*              p_name         is the name of the event flag group
*
*              flags          contains the initial value to store in the event flag group (typically 0).
*
*              p_err          is a pointer to an error code which will be returned to your application:
*
*                                 OS_ERR_NONE                    if the call was successful.
*                                 OS_ERR_CREATE_ISR              if you attempted to create an Event Flag from an ISR.
*                                 OS_ERR_ILLEGAL_CREATE_RUN_TIME if you are trying to create the Event Flag after you
*                                                                   called OSSafetyCriticalStart().
*                                 OS_ERR_NAME                    if 'p_name' is a NULL pointer
*                                 OS_ERR_OBJ_CREATED             if the event flag group has already been created
*                                 OS_ERR_OBJ_PTR_NULL            if 'p_grp' is a NULL pointer
*
* Returns    : none
************************************************************************************************************************
*/

void  OSFlagCreate (OS_FLAG_GRP  *p_grp,
                    CPU_CHAR     *p_name,
                    OS_FLAGS      flags,
                    OS_ERR       *p_err)
{
    CPU_SR_ALLOC();



#ifdef OS_SAFETY_CRITICAL
    if (p_err == (OS_ERR *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == DEF_TRUE) {
       *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
        return;
    }
#endif

#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* See if called from ISR ...                             */
       *p_err = OS_ERR_CREATE_ISR;                          /* ... can't CREATE from an ISR                           */
        return;
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u
    if (p_grp == (OS_FLAG_GRP *)0) {                        /* Validate 'p_grp'                                       */
       *p_err = OS_ERR_OBJ_PTR_NULL;
        return;
    }
#endif

    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);

#if OS_CFG_DBG_EN > 0u
    OS_FlagDbgListAdd(p_grp);
#endif
    //事件标志组内核对象计数加1  
    OSFlagQty++;

    OS_CRITICAL_EXIT_NO_SCHED();
   *p_err = OS_ERR_NONE;
}
OSFlagCreate

2.等待事件标志组:

等待时间标志组的具体操作从函数的签名可以看出,主要是有一下几个条件,第一对应标志组内Flags的哪几位代表请求的时间,第二每一位是置位标志着事件发生了还是复位表明事件已经发生了,第三就是前面提到的是多个时间全部发生(ALL)还是任何一个事件(ANY)发生就标志事件标志组满足条件,最后还要选择满足条件后是否要进行取反(CONSUME)操作。

μC/OS-III---I笔记8---事件标志第4张μC/OS-III---I笔记8---事件标志第5张
************************************************************************************************************************
*                                             WAIT ON AN EVENT FLAG GROUP
*
* Description: This function is called to wait for a combination of bits to be set in an event flag group.  Your
*              application can wait for ANY bit to be set or ALL bits to be set.
*
* Arguments  : p_grp         is a pointer to the desired event flag group.
*
*              flags         Is a bit pattern indicating which bit(s) (i.e. flags) you wish to wait for.
*                            The bits you want are specified by setting the corresponding bits in 'flags'.
*                            e.g. if your application wants to wait for bits 0 and 1 then 'flags' would contain 0x03.
*
*              timeout       is an optional timeout (in clock ticks) that your task will wait for the
*                            desired bit combination.  If you specify 0, however, your task will wait
*                            forever at the specified event flag group or, until a message arrives.
*
*              opt           specifies whether you want ALL bits to be set or ANY of the bits to be set.
*                            You can specify the 'ONE' of the following arguments:
*
*                                OS_OPT_PEND_FLAG_CLR_ALL   You will wait for ALL bits in 'flags' to be clear (0)
*                                OS_OPT_PEND_FLAG_CLR_ANY   You will wait for ANY bit  in 'flags' to be clear (0)
*                                OS_OPT_PEND_FLAG_SET_ALL   You will wait for ALL bits in 'flags' to be set   (1)
*                                OS_OPT_PEND_FLAG_SET_ANY   You will wait for ANY bit  in 'flags' to be set   (1)
*
*                            You can 'ADD' OS_OPT_PEND_FLAG_CONSUME if you want the event flag to be 'consumed' by
*                                      the call.  Example, to wait for any flag in a group AND then clear
*                                      the flags that are present, set 'wait_opt' to:
*
*                                      OS_OPT_PEND_FLAG_SET_ANY + OS_OPT_PEND_FLAG_CONSUME
*
*                            You can also 'ADD' the type of pend with 'ONE' of the two option:
*
*                                OS_OPT_PEND_NON_BLOCKING   Task will NOT block if flags are not available
*                                OS_OPT_PEND_BLOCKING       Task will     block if flags are not available
*
*              p_ts          is a pointer to a variable that will receive the timestamp of when the event flag group was
*                            posted, aborted or the event flag group deleted.  If you pass a NULL pointer (i.e. (CPU_TS *)0)
*                            then you will not get the timestamp.  In other words, passing a NULL pointer is valid and
*                            indicates that you don't need the timestamp.
*
*              p_err         is a pointer to an error code and can be:
*
*                                OS_ERR_NONE                The desired bits have been set within the specified 'timeout'
*                                OS_ERR_OBJ_PTR_NULL        If 'p_grp' is a NULL pointer.
*                                OS_ERR_OBJ_TYPE            You are not pointing to an event flag group
*                                OS_ERR_OPT_INVALID         You didn't specify a proper 'opt' argument.
*                                OS_ERR_PEND_ABORT          The wait on the flag was aborted.
*                                OS_ERR_PEND_ISR            If you tried to PEND from an ISR
*                                OS_ERR_PEND_WOULD_BLOCK    If you specified non-blocking but the flags were not
*                                                           available.
*                                OS_ERR_SCHED_LOCKED        If you called this function when the scheduler is locked
*                                OS_ERR_TIMEOUT             The bit(s) have not been set in the specified 'timeout'.
*
* Returns    : The flags in the event flag group that made the task ready or, 0 if a timeout or an error
*              occurred.
************************************************************************************************************************
*/

OS_FLAGS  OSFlagPend (OS_FLAG_GRP  *p_grp,
                      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();



#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
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* See if called from ISR ...                             */
       *p_err = OS_ERR_PEND_ISR;                            /* ... can't PEND from an ISR                             */
        return ((OS_FLAGS)0);
    }
#endif

#if OS_CFG_ARG_CHK_EN > 0u
    if (p_grp == (OS_FLAG_GRP *)0) {                        /* Validate 'p_grp'                                       */
       *p_err = OS_ERR_OBJ_PTR_NULL;
        return ((OS_FLAGS)0);
    }
    switch (opt) {                                          /* Validate 'opt'                                         */
        case OS_OPT_PEND_FLAG_CLR_ALL:
        case OS_OPT_PEND_FLAG_CLR_ANY:
        case OS_OPT_PEND_FLAG_SET_ALL:
        case OS_OPT_PEND_FLAG_SET_ANY:
        case OS_OPT_PEND_FLAG_CLR_ALL | OS_OPT_PEND_FLAG_CONSUME:
        case OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_FLAG_CONSUME:
        case OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_FLAG_CONSUME:
        case OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_FLAG_CONSUME:
        case OS_OPT_PEND_FLAG_CLR_ALL | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_CLR_ALL | OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING:
        case OS_OPT_PEND_FLAG_SET_ANY | OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_NON_BLOCKING:
             break;

        default:
            *p_err = OS_ERR_OPT_INVALID;
             return ((OS_OBJ_QTY)0);
    }
#endif

#if OS_CFG_OBJ_TYPE_CHK_EN > 0u
    if (p_grp->Type != OS_OBJ_TYPE_FLAG) {                  /* Validate that we are pointing at an event flag         */
       *p_err = OS_ERR_OBJ_TYPE;
        return ((OS_FLAGS)0);
    }
#endif
    //取反标志位检查 
    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);
                     }
                 }
                                                            /* Lock the scheduler/re-enable interrupts                */
                 OS_CRITICAL_ENTER_CPU_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);  /* 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);
                     }
                 }
                                                            /* Lock the scheduler/re-enable interrupts                */
                 OS_CRITICAL_ENTER_CPU_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:                      /* See if all required flags are cleared                  */
             //注意这里的区别 
             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;             /* Set 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_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_CLR_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 cleared                                */
                 if (consume == DEF_TRUE) {                 /* See if we need to consume the flags                    */
                     p_grp->Flags |= flags_rdy;             /* Set 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_EXIT();              /* Lock the scheduler/re-enable interrupts                */
                 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();                                              /* 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;
             break;

        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;
             break;

        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;
             break;

        default:
             CPU_CRITICAL_EXIT();
            *p_err = OS_ERR_STATUS_INVALID;
             break;
    }
    if (*p_err != OS_ERR_NONE) {
        return ((OS_FLAGS)0);
    }
    //任务在POST时已经将事件标志组放入任务控制块的FlagsRdy里了 
    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;

#if OS_CFG_FLAG_MODE_CLR_EN > 0u
            case OS_OPT_PEND_FLAG_CLR_ALL:
            case OS_OPT_PEND_FLAG_CLR_ANY:                  /* Set   ONLY the flags we got                            */
                 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;                                    /* Event(s) must have occurred                            */
    return (flags_rdy);
}
OSFlagPend ()

 这是事件标志组特有的阻塞函数,其实原理还是一样就是多了一部分向任务控制块写入的操作。

μC/OS-III---I笔记8---事件标志第6张μC/OS-III---I笔记8---事件标志第7张
************************************************************************************************************************
*                         SUSPEND TASK UNTIL EVENT FLAG(s) RECEIVED OR TIMEOUT OCCURS
*
* Description: This function is internal to uC/OS-III and is used to put a task to sleep until the desired
*              event flag bit(s) are set.
*
* Arguments  : p_pend_data    is a pointer to an object used to link the task being blocked to the list of task(s)
*              -----------    pending on the desired event flag group.
*
*              p_grp         is a pointer to the desired event flag group.
*              -----
*
*              flags         Is a bit pattern indicating which bit(s) (i.e. flags) you wish to check.
*                            The bits you want are specified by setting the corresponding bits in
*                            'flags'.  e.g. if your application wants to wait for bits 0 and 1 then
*                            'flags' would contain 0x03.
*
*              opt           specifies whether you want ALL bits to be set/cleared or ANY of the bits
*                            to be set/cleared.
*                            You can specify the following argument:
*
*                                OS_OPT_PEND_FLAG_CLR_ALL   You will check ALL bits in 'mask' to be clear (0)
*                                OS_OPT_PEND_FLAG_CLR_ANY   You will check ANY bit  in 'mask' to be clear (0)
*                                OS_OPT_PEND_FLAG_SET_ALL   You will check ALL bits in 'mask' to be set   (1)
*                                OS_OPT_PEND_FLAG_SET_ANY   You will check ANY bit  in 'mask' to be set   (1)
*
*              timeout       is the desired amount of time that the task will wait for the event flag
*                            bit(s) to be set.
*
* Returns    : none
*
* Note(s)    : This function is INTERNAL to uC/OS-III and your application should not call it.
************************************************************************************************************************
*/

void  OS_FlagBlock (OS_PEND_DATA  *p_pend_data,
                    OS_FLAG_GRP   *p_grp,
                    OS_FLAGS       flags,
                    OS_OPT         opt,
                    OS_TICK        timeout)
{
    //事件标志组的特别操作 
    OSTCBCurPtr->FlagsPend = flags;                         /* Save the flags that we need to wait for                */
    OSTCBCurPtr->FlagsOpt  = opt;                           /* Save the type of wait we are doing                     */
    OSTCBCurPtr->FlagsRdy  = (OS_FLAGS)0;
    //加入内核对象等待队列,并阻塞任务 
    OS_Pend(p_pend_data,
            (OS_PEND_OBJ *)((void *)p_grp),
             OS_TASK_PEND_ON_FLAG,
             timeout);
}
OS_FlagBlock ()

3.对应到发布事件组,同样是如此,对应那个几个位,怎么操作,最后就是post函数内的共性就是检查等待列表里是否有满足条件的任务这里区分任何一个还是所有位满足,如果满足就将任务加入到就绪列表里。这里需要注意理解的就是函数内关于位操作的一些写法。

μC/OS-III---I笔记8---事件标志第8张μC/OS-III---I笔记8---事件标志第9张
************************************************************************************************************************
*                                                POST EVENT FLAG BIT(S)
*
* Description: This function is called to set or clear some bits in an event flag group.  The bits to set or clear are
*              specified by a 'bit mask'.
*
* Arguments  : p_grp         is a pointer to the desired event flag group.
*
*              flags         If 'opt' (see below) is OS_OPT_POST_FLAG_SET, each bit that is set in 'flags' will
*                            set the corresponding bit in the event flag group.  e.g. to set bits 0, 4
*                            and 5 you would set 'flags' to:
*
*                                0x31     (note, bit 0 is least significant bit)
*
*                            If 'opt' (see below) is OS_OPT_POST_FLAG_CLR, each bit that is set in 'flags' will
*                            CLEAR the corresponding bit in the event flag group.  e.g. to clear bits 0,
*                            4 and 5 you would specify 'flags' as:
*
*                                0x31     (note, bit 0 is least significant bit)
*
*              opt           indicates whether the flags will be:
*
*                                OS_OPT_POST_FLAG_SET       set
*                                OS_OPT_POST_FLAG_CLR       cleared
*
*                            you can also 'add' OS_OPT_POST_NO_SCHED to prevent the scheduler from being called.
*
*              p_err         is a pointer to an error code and can be:
*
*                                OS_ERR_NONE                The call was successful
*                                OS_ERR_OBJ_PTR_NULL        You passed a NULL pointer
*                                OS_ERR_OBJ_TYPE            You are not pointing to an event flag group
*                                OS_ERR_OPT_INVALID         You specified an invalid option
*
* Returns    : the new value of the event flags bits that are still set.
*
* Note(s)    : 1) The execution time of this function depends on the number of tasks waiting on the event flag group.
************************************************************************************************************************
*/

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;



#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) {                        /* Validate 'p_grp'                                       */
       *p_err  = OS_ERR_OBJ_PTR_NULL;
        return ((OS_FLAGS)0);
    }
    switch (opt) {                                          /* Validate '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) {                  /* Make sure we are pointing to an event flag grp         */
       *p_err = OS_ERR_OBJ_TYPE;
        return ((OS_FLAGS)0);
    }
#endif

    ts = OS_TS_GET();                                       /* Get timestamp                                          */
    //延迟发布 
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
    if (OSIntNestingCtr > (OS_NESTING_CTR)0) {              /* See if called from an ISR                              */
        OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_FLAG,          /* Post to ISR queue                                      */
                    (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);
}
OSFlagPost()
μC/OS-III---I笔记8---事件标志第10张μC/OS-III---I笔记8---事件标志第11张
************************************************************************************************************************
*                                                POST EVENT FLAG BIT(S)
*
* Description: This function is called to set or clear some bits in an event flag group.  The bits to set or clear are
*              specified by a 'bit mask'.
*
* Arguments  : p_grp         is a pointer to the desired event flag group.
*
*              flags         If 'opt' (see below) is OS_OPT_POST_FLAG_SET, each bit that is set in 'flags' will
*                            set the corresponding bit in the event flag group.  e.g. to set bits 0, 4
*                            and 5 you would set 'flags' to:
*
*                                0x31     (note, bit 0 is least significant bit)
*
*                            If 'opt' (see below) is OS_OPT_POST_FLAG_CLR, each bit that is set in 'flags' will
*                            CLEAR the corresponding bit in the event flag group.  e.g. to clear bits 0,
*                            4 and 5 you would specify 'flags' as:
*
*                                0x31     (note, bit 0 is least significant bit)
*
*              opt           indicates whether the flags will be:
*
*                                OS_OPT_POST_FLAG_SET       set
*                                OS_OPT_POST_FLAG_CLR       cleared
*
*                            you can also 'add' OS_OPT_POST_NO_SCHED to prevent the scheduler from being called.
*
*              ts            is the timestamp of the post
*
*              p_err         is a pointer to an error code and can be:
*
*                                OS_ERR_NONE                The call was successful
*                                OS_ERR_OBJ_PTR_NULL        You passed a NULL pointer
*                                OS_ERR_OBJ_TYPE            You are not pointing to an event flag group
*                                OS_ERR_OPT_INVALID         You specified an invalid option
*
* Returns    : the new value of the event flags bits that are still set.
*
* Note(s)    : 1) The execution time of this function depends on the number of tasks waiting on the event flag group.
************************************************************************************************************************
*/

OS_FLAGS  OS_FlagPost (OS_FLAG_GRP  *p_grp,
                       OS_FLAGS      flags,
                       OS_OPT        opt,
                       CPU_TS        ts,
                       OS_ERR       *p_err)
{
    OS_FLAGS        flags_cur;
    OS_FLAGS        flags_rdy;
    OS_OPT          mode;
    OS_PEND_DATA   *p_pend_data;
    OS_PEND_DATA   *p_pend_data_next;
    OS_PEND_LIST   *p_pend_list;
    OS_TCB         *p_tcb;
    CPU_SR_ALLOC();



    CPU_CRITICAL_ENTER();
    switch (opt) {
        case OS_OPT_POST_FLAG_SET:
        case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED:
             p_grp->Flags |=  flags;                            /* Set   the flags specified in the group             */
             break;

        case OS_OPT_POST_FLAG_CLR:
        case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED:
             p_grp->Flags &= ~flags;                            /* Clear the flags specified in the group             */
             break;

        default:
             CPU_CRITICAL_EXIT();                               /* INVALID option                                     */
            *p_err = OS_ERR_OPT_INVALID;
             return ((OS_FLAGS)0);
    }
    //记录发布时间 
    p_grp->TS   = ts;
    //取出等待队列 
    p_pend_list = &p_grp->PendList;
    if (p_pend_list->NbrEntries == 0u) {                        /* Any task waiting on event flag group?              */
        CPU_CRITICAL_EXIT();                                    /* No                                                 */
       *p_err = OS_ERR_NONE;
        return (p_grp->Flags);
    }

    OS_CRITICAL_ENTER_CPU_EXIT();
    p_pend_data = p_pend_list->HeadPtr;
    p_tcb       = p_pend_data->TCBPtr;
    //依次查找等待队列,找出满足条件的任务 
    while (p_tcb != (OS_TCB *)0) {                              /* Go through all tasks waiting on event flag(s)      */
        p_pend_data_next = p_pend_data->NextPtr;
        mode             = p_tcb->FlagsOpt & OS_OPT_PEND_FLAG_MASK;
        switch (mode) {
            case OS_OPT_PEND_FLAG_SET_ALL:                      /* See if all req. flags are set for current node     */
                 flags_rdy = (OS_FLAGS)(p_grp->Flags & p_tcb->FlagsPend);
                 if (flags_rdy == p_tcb->FlagsPend) {
                    //将任务就绪 ,同时从等待队列删除,下同 
                     OS_FlagTaskRdy(p_tcb,                      /* Make task RTR, event(s) Rx'd                       */
                                    flags_rdy,
                                    ts);
                 }
                 break;

            case OS_OPT_PEND_FLAG_SET_ANY:                      /* See if any flag set                                */
                 flags_rdy = (OS_FLAGS)(p_grp->Flags & p_tcb->FlagsPend);
                 if (flags_rdy != (OS_FLAGS)0) {
                     OS_FlagTaskRdy(p_tcb,                      /* Make task RTR, event(s) Rx'd                       */
                                    flags_rdy,
                                    ts);
                 }
                 break;

#if OS_CFG_FLAG_MODE_CLR_EN > 0u
            case OS_OPT_PEND_FLAG_CLR_ALL:                      /* See if all req. flags are set for current node     */
                 flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
                 if (flags_rdy == p_tcb->FlagsPend) {
                     OS_FlagTaskRdy(p_tcb,                      /* Make task RTR, event(s) Rx'd                       */
                                    flags_rdy,
                                    ts);
                 }
                 break;

            case OS_OPT_PEND_FLAG_CLR_ANY:                      /* See if any flag set                                */
                 flags_rdy = (OS_FLAGS)(~p_grp->Flags & p_tcb->FlagsPend);
                 if (flags_rdy != (OS_FLAGS)0) {
                     OS_FlagTaskRdy(p_tcb,                      /* Make task RTR, event(s) Rx'd                       */
                                    flags_rdy,
                                    ts);
                 }
                 break;
#endif
            default:
                 OS_CRITICAL_EXIT();
                *p_err = OS_ERR_FLAG_PEND_OPT;
                 return ((OS_FLAGS)0);
        }
        p_pend_data = p_pend_data_next;                         /* Point to next task waiting for event flag(s)       */
        if (p_pend_data != (OS_PEND_DATA *)0) {
            p_tcb = p_pend_data->TCBPtr;
        } else {
            p_tcb = (OS_TCB *)0;
        }
    }
    OS_CRITICAL_EXIT_NO_SCHED();

    if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
        OSSched();
    }

    CPU_CRITICAL_ENTER();
    flags_cur = p_grp->Flags;
    CPU_CRITICAL_EXIT();
   *p_err     = OS_ERR_NONE;
    return (flags_cur);
}
OS_FlagPost ()

这是事件标志组特有的任务就绪函数,其实原理还是一样还是多了一部分向任务控制块写入的操作。

μC/OS-III---I笔记8---事件标志第12张μC/OS-III---I笔记8---事件标志第13张
************************************************************************************************************************
*                                        MAKE TASK READY-TO-RUN, EVENT(s) OCCURRED
*
* Description: This function is internal to uC/OS-III and is used to make a task ready-to-run because the desired event
*              flag bits have been set.
*
* Arguments  : p_tcb         is a pointer to the OS_TCB of the task to remove
*              -----
*
*              flags_rdy     contains the bit pattern of the event flags that cause the task to become ready-to-run.
*
*              ts            is a timestamp associated with the post
*
* Returns    : none
*
* Note(s)    : This function is INTERNAL to uC/OS-III and your application should not call it.
************************************************************************************************************************
*/

void   OS_FlagTaskRdy (OS_TCB    *p_tcb,
                       OS_FLAGS   flags_rdy,
                       CPU_TS     ts)
{
    p_tcb->FlagsRdy   = flags_rdy;
    p_tcb->PendStatus = OS_STATUS_PEND_OK;                  /* Clear pend status                                      */
    p_tcb->PendOn     = OS_TASK_PEND_ON_NOTHING;            /* Indicate no longer pending                             */
    p_tcb->TS         = ts;
    switch (p_tcb->TaskState) {
        case OS_TASK_STATE_RDY:
        case OS_TASK_STATE_DLY:
        case OS_TASK_STATE_DLY_SUSPENDED:
        case OS_TASK_STATE_SUSPENDED:
             break;

        case OS_TASK_STATE_PEND:
        case OS_TASK_STATE_PEND_TIMEOUT:
             OS_TaskRdy(p_tcb);
             p_tcb->TaskState = OS_TASK_STATE_RDY;
             break;

        case OS_TASK_STATE_PEND_SUSPENDED:
        case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
             p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
             break;

        default:
             break;
    }
    OS_PendListRemove(p_tcb);
}
#endif
OS_FlagTaskRdy ()

时间标志组 最重要的是将位和任务联系起来,同时继续了信号量的等待任务管理。 

免责声明:文章转载自《μC/OS-III---I笔记8---事件标志》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇2019 家居云java面试笔试题 (含面试题解析)quick lua 3.3常用方法和学习技巧之functions.lua目录下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java消息系统简单设计与实现

前言:由于导师在我的毕设项目里加了消息系统(本来想水水就过的..),没办法...来稍微研究研究吧..简单简单... 需求分析 我的毕设是一个博客系统,类似于简书这样的,所以消息系统也类似,在用户的消息里包含了有:喜欢和赞、评论、关注、私信这样的一类东西,这样的一个系统应该包含以下的功能: 当用户评论/关注/点赞时能够通知到被评论/关注/点赞的用户,并...

Golang: 接收GET和POST参数

GET 和 POST 是我们最常用的两种请求方式,今天结合前端 axios 请求库来讲一讲,如何在 golang 服务中,正确接收这两种请求的参数信息。 一、搭建一个简单的服务 首先,我们来创建一个最简单的静态页面,将 axios 引进来: <!DOCTYPE html> <html> <head> <...

VC++ 定时器使用总结

VC++    WM_TIMER   定时器使用方法       在编程时,会经常使用到定时器。使用定时器的方法比较简单,通常告诉Windows一个时间间隔,然后WINDOWS以此时间间隔周期性触发程序。通常有两种方法来实现:发送WM_TIMER消息和调用应用程序定义的回调函数。   1.1 用WM_TIMER来设置定时器   先请看SetTimer这个A...

常用快捷键大全

一、系统快捷键 F1 帮助F2 改名F3 搜索 F4 地址F5 刷新F6 切换F8 安全模式F10 菜单F11 全屏INS 插入模式PRTSCSYSRQ 截屏CAPSLOCK 大写字母锁定DELETE 删除ESC 退出HOME 到开始或主程序END 到结尾PAGEUP 向上翻页PAGEDOWN 向下翻页TAB 改变焦点 CTRL+C 复制CTRL+X...

XMPP协议的原理介绍

XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,它用于即时消息(IM)以及在线现场探測。它在促进server之间的准即时操作。这个协议可能终于同意因特网用户向因特网上的其它不论什么人发送即时消息,即使其操作系统和浏览器不同。 XMPP的前身是Jabber,一个开源形式组织产生的网络即时通信协议。XMPP眼下被IETF国际标准组织完...

4wpa_supplicant适配层 详解

适配层是 通用的wpa_supplicant的 封装,在Android中 作为 WiFi部分的 硬件抽象层来使用。wpa_supplicant适配层 主要用于 与wpa_supplicant守护进程 的 通信,以提供给Android框架使用,它实现了 加载、控制 和 消息监控等功能。           1、当java层调用 loadDriver时, 它...