Read the ucosII source code again (Shao Beibei): time management

time management

As described above,
the interrupt service routine of the clock calls the tick clock tick function OSTimeTick - this function is used to notify µC/OS-II that a clock tick interrupt has occurred.
The related functions are shown below, and the source code is in os_time.c.

Task delay function, OSTimeDly()

µC/OS-II provides such a system service:
the task applying for this service can be delayed for a period of time, and the length of this period is determined by the number of clock ticks. The function that implements this system service is called OSTimeDly().
Calling this function will cause µC/OS-II to schedule a task and execute the next highest-priority ready state task.
After the task calls OSTimeDly(), once the specified time expires or another task cancels the delay by calling OSTimeDlyResume(), it will enter the ready state immediately. Note that this task will only run immediately if it has the highest priority of all ready tasks.
Listing L5.1 shows the code for the task delay function OSTimeDly(). The user's application calls this function by supplying the number of clock ticks to delay, a number between 1 and 65535. If the user specifies a value of 0 [L5.1(1)], it indicates that the user does not want to delay the task, and the function returns immediately to the caller.
A non-zero value causes the task delay function OSTimeDly() to remove the current task from the ready list [L5.1(2)]. Then, this delay tick count will be stored in the OS_TCB of the current task [L5.1(3)], and the delay tick count will be reduced by OSTimeTick() every other clock tick.
Finally, now that the task is no longer ready, the task scheduler executes the next highest-priority ready task.
Program Listing L 5.1 OSTimeDly().:

void OSTimeDly (INT16U ticks)
{
    if (ticks > 0) {                                                         (1)
        OS_ENTER_CRITICAL();
        if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {     (2)
            OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
        }
        OSTCBCur->OSTCBDly = ticks;                                        (3)
        OS_EXIT_CRITICAL();
        OSSched();                                                            (4)
    }
}

It is very important to clearly recognize the delay process between 0 and one beat.
In other words, if the user only wants to delay one clock tick, it actually ends the delay between 0 and one tick.
Even if the user's processor is not heavily loaded, this situation still exists.
Figure F5.1 details the entire process. The system generates a clock beat interrupt [F5.1(1)] every 10ms. If the user does not execute other interrupts and the interrupt is open at this time, the clock tick interrupt service will occur [F5.1(2)]. Maybe the user has several high-priority tasks (HPT) waiting for the delay to expire, and they will then execute [F5.1(3)]. Next, the low-priority task (LPT) shown in Figure 5.1 gets a chance to execute, and the task calls OSTimeDly(1) shown in [F5.1(4)] immediately after execution. µC/OS-II will put the task to sleep until the next beat. When the next tick comes, the clock tick interrupt service subroutine will execute [F5.1(5)], but this time, since no high-priority tasks are executed, µC/OS-II will immediately execute the request to delay a clock tick task [F5.1(6)].
As the user can see, the actual latency of the task is less than one beat!
In a heavily loaded system, the task might even call STimeDly(1) just before a clock interrupt is about to occur, in which case the task gets almost no delay because the task is rescheduled immediately.
If the user's application has to delay at least one beat, it must call OSTimeDly(2), specifying a delay of two beats!
1write picture description here

Delay function OSTimeDlyHMSM() by hour, minute and second

Although OSTimeDly() is a very useful function, the user's application needs to know the number of clock ticks corresponding to the delay time. The user can convert time into clock segments by defining the global constant OS_TICKS_PER_SEC (see OS_CFG.H), but this method is sometimes clumsy. After the author adds the OSTimeDlyHMSM() function, the user can define the time in hours (H), minutes (M), seconds (S) and milliseconds (m), which will appear more natural.
Like OSTimeDly(), calling the OSTimeDlyHMSM() function will also cause µC/OS-II to schedule a task and execute the next highest-priority ready state task. After the task calls OSTimeDlyHMSM(), once the specified time expires or another task cancels the delay by calling OSTimeDlyResume() (see 5.02, Resume Delayed Task OSTimeDlyResume()), it will be in the ready state immediately. Likewise, the task will run immediately only if it has the highest priority among all ready tasks.
Listing L5.2 shows the code for OSTimeDlyHMSM(). As you can see, the application calls the function by specifying a delay in hours, minutes, seconds, and milliseconds. In practice, the user should avoid delaying tasks for too long, because it is often nice to get some feedback behavior from tasks (such as decrementing counters, clearing LEDs, etc.). However, if the user really needs a long delay, µC/OS-II can delay the task for up to 256 hours (nearly 11 days). . . .
OSTimeDlyHMSM() initially checks to see if the user has defined a valid value for the parameter [L5.2(1)]. Like OSTimeDly(), OSTimeDlyHMSM() exists even if the user does not define a delay [L5.2(9)]. Since µC/OS-II only knows the beat, the total beat is calculated from the specified time [L5.2(3)]. Obviously, the program in program listing L5.2 is not very efficient. I just use this method to tell you a formula, so that the user can know how to calculate the total number of beats. All that really makes sense is OS_TICKS_PER_SEC.
[L5.2(3)] determines the total number of clock ticks closest to the time that the delay is required. The value of 500/OS_TICKS_PER_SECOND is basically the same as the number of milliseconds corresponding to 0.5 ticks. For example, if the clock frequency (OS_TICKS_PER_SEC) is set to 100Hz (10ms), a delay of 4ms will not cause any delay! A delay of 5ms is equivalent to a delay of 10ms.
The delay supported by µC/OS-II is generally no more than 65,535 beats. Of course, to support longer delays, as shown in L5.2(2), OSTimeDlyHMSM() determines how many times the user wants to delay The number of beats over 65,535 [L5.2(4)] and the number of beats remaining [L5.2(5)]. For example, if the value of OS_TICKS_PER_SEC is 100 and the user wants to delay 15 minutes, OSTimeDlyHMSM() will delay 15x60x100=90,000 clocks. This delay is split into two delays of 32,768 beats (because the user can only delay 65,535 beats instead of 65536 beats) and one delay of 24,464 beats. In this case, OSTimeDlyHMSM() considers the remaining beats first, then the beat numbers L5.2(7) and (8) over 65,535 .
Program Listing L 5.2 OSTimeDlyHMSM().

INT8U OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U milli)
{
    INT32U ticks;
    INT16U loops;


    if (hours > 0 || minutes > 0 || seconds > 0 || milli > 0) {         (1)
        if (minutes > 59) {
            return (OS_TIME_INVALID_MINUTES);
        }
        if (seconds > 59) {
            return (OS_TIME_INVALID_SECONDS);
        }
        If (milli > 999) {
            return (OS_TIME_INVALID_MILLI);
        } 
        ticks = (INT32U)hours    * 3600L * OS_TICKS_PER_SEC                 (2)
              + (INT32U)minutes  *   60L * OS_TICKS_PER_SEC
              + (INT32U)seconds  *         OS_TICKS_PER_SEC
              + OS_TICKS_PER_SEC * ((INT32U)milli
              + 500L/OS_TICKS_PER_SEC) / 1000L; (3)
        loops = ticks / 65536L;                                     (4)
        ticks = ticks % 65536L;                                          (5)
        OSTimeDly(ticks);                                                  (6)
        while (loops > 0) {                                              (7)
            OSTimeDly(32768);                                             (8)
            OSTimeDly(32768);
            loops--;
        }
        return (OS_NO_ERR);
    } else {
        return (OS_TIME_ZERO_DLY);                                         (9)
    }
}

Delay the end of the task in the delay period, OSTimeDlyResume()

µC/OS-II allows the user to end a task whose delay is in the delay period. Delayed tasks can not wait for the delay to expire, but can make themselves in the ready state by canceling the delay by other tasks. This can be done by calling OSTimeDlyResume() and specifying the priority of the task to resume. In fact, OSTimeDlyResume() can also wake up tasks that are waiting for an event (see Chapter 6 - Intertask Communication and Synchronization), although this is not mentioned. In this case, the task waiting for the event to occur will consider whether to terminate the waiting event.
The code for OSTimeDlyResume(), shown in Listing L5.3, first ensures that the specified task priority is valid [L5.3(1)]. Next, OSTimeDlyResume() confirms that the task to end the delay actually exists [L5.3(2)]. If the task exists, OSTimeDlyResume() checks whether the task is waiting for the delay to expire [L5.3(3)]. As long as OSTCBDly in the OS_TCB field contains a non-zero value, it indicates that the task is waiting for the delay to expire because the task called OSTimeDly(), OSTimeDlyHMSM(), or other PEND functions described in Chapter 6. The delay can then be canceled by forcing the command OSTCBDly to 0 [L5.3(4)]. Delayed tasks may have been suspended, so that the task can only be in the ready state if it is not suspended [L5.3(5)]. When the above conditions are met, the task is placed in the ready list [L5.3(6)]. At this point, OSTimeDlyResume() will call the task scheduler to see if the resumed task has a higher priority than the current task [L5.3(7)]. This results in a task switch.
Listing L 5.3 Resume a deferred task

INT8U OSTimeDlyResume (INT8U prio)
{
    OS_TCB *ptcb;

    if (prio >= OS_LOWEST_PRIO) {                                        (1)
        return (OS_PRIO_INVALID);
    }
    OS_ENTER_CRITICAL();
    ptcb = (OS_TCB *)OSTCBPrioTbl[prio];    
    if (ptcb != (OS_TCB *)0) {                                          (2)
        if (ptcb->OSTCBDly != 0) {                                      (3)
            ptcb->OSTCBDly  = 0;                                          (4)
            if (!(ptcb->OSTCBStat & OS_STAT_SUSPEND)) {                (5)
                OSRdyGrp               |= ptcb->OSTCBBitY;              (6)
                OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                OS_EXIT_CRITICAL();
                OSSched();                                              (7)
            } else {
                OS_EXIT_CRITICAL();
            }
            return (OS_NO_ERR);
        } else {
            OS_EXIT_CRITICAL();
            return (OS_TIME_NOT_DLY); 
        }
    } else {
        OS_EXIT_CRITICAL();
        return (OS_TASK_NOT_EXIST); 
    }
}

System time, OSTimeGet() and OSTimeSet()

Whenever a clock tick occurs, µC/OS-II increments a 32-bit counter. This counter starts from 0 when the user calls OSStart() to initialize the multitasking and 4,294,967,295 ticks are executed once. When the frequency of the clock beat is equal to 100Hz, the 32-bit counter restarts counting every 497 days. The user can obtain the current value of the counter by calling OSTimeGet(). The value of this counter can also be changed by calling OSTimeSet(). The codes of the OSTimeGet() and OSTimeSet() functions are shown in the program listing L5.4. Note that interrupts are turned off when accessing OSTime. This is because adding and copying a 32-bit number requires several instructions on most 8-bit processors, and these instructions generally need to be executed once and cannot be interrupted by factors such as interrupts.
Code slightly:

INT32U OSTimeGet (void)
void OSTimeSet (INT32U ticks)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325400214&siteId=291194637