Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2012 / uCOS / uCOSII_ebook.pdf
Скачиваний:
90
Добавлен:
10.02.2015
Размер:
1.08 Mб
Скачать

Chapter 5

Time Management

We saw in section 3.10 that µC/OS-II (as do other kernels) requires that you provide a periodic interrupt to keep track of time delays and timeouts. This periodic time source is called a Clock Tick and should occur between 10 and 100 times per second, or Hertz. The actual frequency of the clock tick depends on the desired tick resolution of your application. However, the higher the frequency of the ticker, the higher the overhead.

Section 3.10 discussed the tick ISR (Interrupt Service Routine) as well as the function that it needs to call to notify µC/OS-II about the tick interrupt, OSTimeTick(). This chapter will describe five services that deal with time

issues:

1)OSTimeDly(),

2)OSTimeDlyHMSM(),

3)OSTimeDlyResume(),

4)OSTimeGet() and,

5)OSTimeSet().

The functions described in this chapter are found in the file OS_TIME.C.

5.00 Delaying a task, OSTimeDly()

µC/OS-II provides a service that allows the calling task to delay itself for a user specified number of clock ticks. This function is called OSTimeDly(). Calling this function causes a context switch and forces µC/OS -II to execute the next highest priority task that is ready-to-run. The task calling OSTimeDly() will be made ready-to-run as soon as the time specified expires o r, if another task cancels the delay by calling OSTimeDlyResume(). You should note that this task will run only when it’s the highest priority task.

Listing 5.1 shows the code for OSTimeDly(). As can be seen, your application calls this function by supplying the number of ticks to delay and can be a value between 1 and 65535. If you specify a value of zero L5.1(1), you are

indicating that you don’t want to delay the task and thus the function will immediately return to the caller. A non zero value will cause OSTimeDly() to remove the current task from the ready list L5.1(2). Next, the number of ticks are

stored in the OS_TCB of the current task L5.1(3) where it will be decremented on every clock tick by OSTimeTick(). Finally, since the task is no longer ready, the scheduler is called L5.1(4) so that the next highest priority task that is ready-to-run gets executed.

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)

}

}

Listing 5.1, OSTimeDly()

It is important to realize that the resolution of a delay is between 0 and 1 tick. In other words, if you try to delay for only one tick, you could end up with a delay between 0 and 1 tick. This is assuming, however, that your processor is not heavily loaded. Figure 5-1 illustrates what happens. A tick interrupt occurs every 10 mS F5-1(1). Assuming that you are not servicing any other interrupts and you have interrupts enabled, the tick ISR will be invoked F5-1(2). You may have a few high priority tasks (i.e. HPTs) that were waiting for time to expire so they will get to execute next F5-1(3). The low priority task (i.e. LPT) shown in figure 5-1 then gets a chance to execute and, upon completion, calls OSTimeDly(1) at the moment shown at F5-1(4). µC/OS-II puts the task to sleep until the next tick. When the next tick arrives, the tick ISR executes F5-1(5) but this time, there are no HPTs to execute and thus, µC/OS-II executes the

task that delayed itself for 1 tick F5-1(6). As you can see, the task actually delayed for less than one tick! On heavily loaded systems, the task may call OSTimeDly(1) a few tens of microseconds before the tick occurs and thus the

delay would result in almost no delay because the task would immediately be rescheduled. If your application must delay for at least one tick, you must call OSTimeDly(2) thus specifying a delay of 2 ticks!

10 mS

 

 

 

 

Tick interrupt

 

 

 

 

 

 

 

(2)

 

(1)

 

(5)

 

 

 

 

 

OSTickISR()

 

 

(3)

 

 

 

 

 

 

 

 

 

 

 

All HPT

 

 

 

 

 

 

 

 

 

 

(6)

Low Priority Task

(4)

Task calls OSTimeDly(1) here!

5 mS

Figure 5-1, Delay resolution

5.01 Delaying a task, OSTimeDlyHMSM()

OSTimeDly() is a very useful function but, your application needs to know time in term of ticks. You can use the global #define constant OS_TICKS_PER_SEC (see OS_CFG.H) to convert time to ticks but this is somewhat awkward. The function OSTimeDlyHMSM() has been added so that you can specify time in hours ( H), minutes ( M),

seconds (S) and milliseconds (M) which is more ‘natural’. Like OSTimeDly(), calling this function causes a context switch and forces µC/OS-II to execute the next highest priority task that is ready-to-run. The task calling OSTimeDlyHMSM() will be made ready-to-run as soon as the time specified expires or if another task cancels the delay by calling OSTimeDlyResume() (see section 5.02). Again, this task will run only when it’s the highest priority task.

Listing 5.2 shows the code for OSTimeDlyHMSM(). As can be seen, your application calls this function by supplying the delay in hours, minutes, seconds and milliseconds. In practice, you should avoid delaying a

task for long periods of time because, it’s always a good idea to get some ‘feedback activity’from a task (incrementing counter, blinking an LED, etc.). If however, you do need long delays, µC/OS-II can delay a task for 256 hours (close to 11 days)!

OSTimeDlyHMSM() starts by checking that you have specified valid values for its arguments L5.2(1). As with OSTimeDly(), OSTimeDlyHMSM() exits if you specify no delay L5.2(9). Because µC/OS-II only knows about ticks, the t otal number of ticks is computed from the specified time L5.2(3). The code shown in listing 5.2 is obviously not very inefficient. I just showed the equation this way so you can see how the total ticks are computed. The actual code efficiently factors in OS_TICKS_PER_SEC. L5.2(3) determines the number of ticks given the specified milliseconds with rounding to the nearest tick. The value 500/OS_TICKS_PER_SECOND basically correspond to 0.5 tick converted to milliseconds. For example, if the tick rate (i.e. OS_TICKS_PER_SEC) is set to 100 Hz (10 mS) then a delay of 4 mS would result in no delay! A delay of 5 mS would result in a delay of 10 mS, etc.

µC/OS-II only supports delays of 65535 ticks. To support potentially long delays obtained by L5.2(2), OSTimeDlyHMSM() determines how many times we need to delay for more than 65535 ticks L5.2(4) as well as the remaining number of ticks L5.2(5). For example, if OS_TICKS_PER_SEC was 100 and you wanted a delay of 15 minutes then OSTimeDlyHMSM() would have to d elay for 15 * 60 * 100 or, 90000 ticks. This delay is broken down into two delays of 32768 ticks (because we can’t do a delay of 65536 ticks, only 65535) and one delay of 24464 ticks. In this case, we would first take care of the remainder L5.2(6) and then, the number of times we exceeded 65536 L5.2(7)-(8) (i.e. done with two 32768 tick delays).

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 {

(9)

return (OS_TIME_ZERO_DLY);

}

 

}

Listing 5.2, OSTimeDlyHMSM()

Because of the way OSTimeDlyHMSM() is implemented, you cannot resume (see next section) a task that has called OSTimeDlyHMSM() with a combined time that exceeds 65535 clock ticks. In other words, if the clock tick runs at 100 Hz then, you will not be able to resume a delayed task that called OSTimeDlyHMSM(0, 10, 55, 350) or higher.

5.02 Resuming a delayed task, OSTimeDlyResume()

µC/OS-II allows you to resume a task that delayed itself. In other words, instead of waiting for the time to expire, a delayed task can be made ready-to-run by another task which ‘cancels’the delay. This is done by calling OSTimeDlyResume() and specifying the priority of the task to resume. In fact, OSTimeDlyResume() can also

resume a task that is waiting for an event (see Chapter 6,Intertask Communication & Synchronization) although this is not recommended. In this case, the task pending on the event will think it timed out waiting for the event.

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

}

}

Listing 5.3, Resuming a delayed task.

The code for OSTimeDlyResume() is shown in listing 5.3 and starts by making sure you specify a valid priority L5.3(1). Next, we verify that the task to resume does in fact exist L5.3(2). If the task exist, we check to see if the task

Соседние файлы в папке uCOS