...
µC/OS-III provides a number of services to manage time as summarized in the table below, and the code is found in os_time.c
.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||
|
The application programmer should refer to µC-OS-III API Reference for a detailed description of these services.
...
The listing below shows how to use OSTimeDly()
in relative mode.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
void MyTask (void *p_arg)
{
OS_ERR err;
:
:
while (DEF_ON) {
:
:
OSTimeDly(2, (1)
OS_OPT_TIME_DLY, (2)
&err); (3)
/* Check "err" */ (4)
:
:
}
} |
Panel | ||
---|---|---|
| ||
(1) The first argument specifies the amount of time delay (in number of ticks) from when the function is called. For the example above, if the tick rate ( (2) Specifying (3) As with most µC/OS-III services an error return value will be returned. The example should return (4) You should always check the error code returned by µC/OS-III. If “ |
As mentioned above, the delay is not accurate. Refer to the figure below and its description below to understand why.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
Panel | ||
---|---|---|
| ||
(1) We get a tick interrupt and µC/OS-III services the ISR. (2) At the end of the ISR, all Higher Priority Tasks (HPTs) execute. The execution time of HPTs is unknown and can vary. (3) Once all HPTs have executed, µC/OS-III runs the task that has called (4) The task calls (5) The next tick occurs. If there are HPTs waiting for this particular tick, µC/OS-III will schedule them to run at the end of the ISR. (6) The HPTs execute. (7) The next tick interrupt occurs. This is the tick that the LPT was waiting for and will now be made ready-to-run by µC/OS-III. (8) Since there are no HPTs to execute on this tick, µC/OS-III switches to the LPT. (9) Given the execution time of the HPTs, the time delay is not exactly two ticks, as requested. In fact, it is virtually impossible to obtain a delay of exactly the desired number of ticks. You might ask for a delay of two ticks, but the very next tick could occur almost immediately after calling |
OSTimeDly()
can also be called with the OS_OPT_TIME_PERIODIC
option as shown in the listing below . This option allows delaying the task until the tick counter reaches a certain periodic match value and thus ensures that the spacing in time is always the same as it is not subject to CPU load variations.
µC/OS-III determines the “match value” of OSTickCtr
to determine when the task will need to wake up based on the desired period. This is shown in the figure below. µC/OS-III checks to ensure that if the match is computed such that it represents a value that has already gone by then, the delay will be zero.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{
OS_ERR err;
:
:
while (DEF_ON) {
OSTimeDly(4, (1)
OS_OPT_TIME_PERIODIC, (2)
&err);
/* Check "err" */ (3)
:
:
}
} |
Panel | ||
---|---|---|
| ||
(1) The first argument specifies the period for the task to execute, specifically every four ticks. Of course, if the task is a low-priority task, µC/OS-III only schedules and runs the task based on its priority relative to what else needs to be executed. (2) Specifying (3) You should always check the error code returned by µC/OS-III. |
Relative and Periodic modes might not look different, but they are. In Relative mode, it is possible to miss one of the ticks when the system is heavily loaded, missing a tick or more on occasion. In Periodic mode, the task may still execute later, but it will always be synchronized to the desired number of ticks. In fact, Periodic mode is the preferred mode to use to implement a time-of-day clock.
In V3.07, the behavior of Periodic mode was altered slightly. Rather than schedule the next delay based on when the previous delay completed, we always assume the previous delay completed at a multiple of the period specified. In other words, both versions synchronize the delays to an imagined function which has the specified period, but prior versions have the function beginning at the time when the first periodic delay was requested whereas V3.07 has it beginning at time 0. Future versions may provide support for both behaviors.
Finally, you can use the absolute mode to perform a specific action at a fixed time after power up. For example, turn off a light 10 seconds after the product powers up. In this case, you would specify OS_OPT_TIME_MATCH
while “dly
” actually corresponds to the desired value of OSTickCtr
you want to reach. However, you should use the OS_OPT_TIME_MATCH
with care because somewhere else in your code you can change the value of OSTickCtr
by calling OSTimeSet()
as described in Time Services.
...
The listing below indicates how to use OSTimeDlyHMSM()
.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
void MyTask (void *p_arg)
{
OS_ERR err;
:
:
while (DEF_ON) {
:
:
OSTimeDlyHMSM(0, (1)
0,
1,
0,
OS_OPT_TIME_HMSM_STRICT, (2)
&err); (3)
/* Check "err" */
:
:
}
} |
Panel | ||
---|---|---|
| ||
(1) The first four arguments specify the amount of time delay (in hours, minutes, seconds, and milliseconds) from this point in time. In the above example, the task should delay for 1 second. The resolution greatly depends on the tick rate. For example, if the tick rate ( (2) Specifying If specifying The reason hours is limited to 999 is that time delays typically use 32-bit values to keep track of ticks. If the tick rate is set at 1000 Hz then, it is possible to only track 4,294,967 seconds, which corresponds to 1,193 hours, and therefore 999 is a reasonable limit. (3) As with most µC/OS-III services the user will receive an error return value. The example should return |
Even though µC/OS-III allows for very long delays for tasks, it is actually not recommended to delay tasks for a long time. The reason is that there is no indication that the task is actually “alive” unless it is possible to monitor the amount of time remaining for the delay. It is better to have the task wake up approximately every minute or so, and have it “tell you” that it is still ok.
...
A task can resume another task that called OSTimeDly()
or OSTimeDlyHMSM()
by calling OSTimeDlyResume()
. The listing below shows how to use OSTimeDlyResume()
. The task that delayed itself will not know that it was resumed, but will think that the delay expired. Because of this, use this function with great care.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
OS_TCB MyTaskTCB;
void MyTask (void *p_arg)
{
OS_ERR err;
:
:
while (DEF_ON) {
:
:
OSTimeDly(10,
OS_OPT_TIME_DLY,
&err);
/* Check "err" */
:
:
}
}
void MyOtherTask (void *p_arg)
{
OS_ERR err;
:
:
while (DEF_ON) {
:
:
OSTimeDlyResume(&MyTaskTCB,
&err);
/* Check "err" */
:
:
}
} |
OSTimeGet() – Get Value of the Tick Counter
...
The tick Interrupt Service Routine (ISR) must call this function every time a tick interrupt occurs. μC/OS-III uses this function to update time delays and timeouts used by other system calls. OSTimeTick() is considered an internal function to μC/OS-III.
OSTimeDynTick() – Signal multiple
...
Ticks (Dynamic Tick Mode Only)
The dynamic tick Interrupt Service Routine (ISR) must call this function with the number of ticks that timer was last configured to delay. μC/OS-III uses this function to update time delays and timeouts used by other system calls. OSTimeDynTick() is considered an internal function to μC/OS-III.
...