...
µC/OS-II provides a number of services to manage timers as summarized in the table below.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||
|
A timer needs to be created before it can be used. You create a timer by calling OSTmrCreate()
and specify a number of arguments to this function based on how the timer is to operate. Once the timer operation is specified, its operating mode cannot be changed unless the timer is deleted and recreated. The function prototype for OSTmrCreate()
is shown below as a quick reference:
Code Block | ||
---|---|---|
| ||
OS_TMR OSTmrCreate (INT32U dly, /* Initial delay */
INT32U period, /* Repeat period */
INT8U opt, /* Options */
OS_TMR_CALLBACK callback, /* Fnct to call at 0 */
void *callback_arg, /* Arg. to callback */
CPU_CHAR *pname, /* Name of timer, ASCII */
INT8 *perr) |
Once created, a timer can be started (or restarted) and stopped as often as is necessary. Timers can be created to operate in one of three modes: One-shot, Periodic (no initial delay), and Periodic (with initial delay).
...
You terminate the countdown process of a timer (before it reaches zero) by calling OSTmrStop()
. In this case, you can specify that the callback function be called or not.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
As shown in the figure below, a one-shot timer can be re-triggered by calling OSTmrStart()
before the timer reaches zero. This feature can be used to implement watchdogs and similar safeguards.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
Periodic (no initial delay)
As indicated in the figure below, timers can be configured for periodic mode. When the countdown expires, the callback function is called, the timer is automatically reloaded, and the process is repeated. If specifying a delay of zero (i.e., dly == 0
) when the timer is created and, when started, the timer immediately uses the “period
” as the reload value. You can call OSTmrStart()
at any point in the countdown to restart the process.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
Periodic (with initial delay)
As shown in the figure below, timers can be configured for periodic mode with an initial delay that is different than its period. The first countdown count comes from the “dly
” argument passed in the OSTmrCreate()
call, and the reload value is the “period
”. You can call OSTmrStart()
to restart the process including the initial delay.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
Timer Management Internals
...
Tasks can call OSTmrStateGet()
to find out the state of a timer. Also, at any time during the countdown process, the application code can call OSTmrRemainGet()
to find out how much time remains before the timer reaches zero (0). The value returned is expressed in “timer ticks.” If timers are decremented at a rate of 10 Hz then a count of 50 corresponds to 5 seconds. If the timer is in the stop state, the time remaining will correspond to either the initial delay (one shot or periodic with initial delay), or the period if the timer is configured for periodic without initial delay.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
Panel | ||
---|---|---|
| ||
(1) The “Unused” state is a timer that has not been created or has been “deleted.” In other words, µC/OS-IIdoes not know about this timer. (2) When creating a timer or calling (3) A timer is placed in running state when calling (4) The “Completed” state is the state a one-shot timer is in when its delay expires. |
OS_TMR
A timer is a kernel object as defined by the OS_TMR
data type (see ucos_ii.h
) as shown in the listing below:
The services provided by µC/OS-II to manage timers are implemented in the file os_tmr.c
. Timer services are enabled at compile time by setting the configuration constant OS_TMR_EN
to 1
in os_cfg.h
.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
typedef struct os_tmr { (1)
INT8U OSTmrType; (2)
OS_TMR_CALLBACK_PTR OSTmrCallback; (3)
void *OSTmrCallback; (4)
OS_TMR *OSTmrNextPtr; (5)
OS_TMR *OSTmrPrevPtr;
OS_TICK OSTmrMatch; (6)
OS_TICK OSTmrDly; (7)
OS_TICK OSTmrPeriod; (8)
CPU_CHAR *OSTmrNamePtr; (9)
OS_OPT OSTmrOpt; (10)
OS_STATE OSTmrState; (11)
} OS_TMR; |
Panel | ||
---|---|---|
| ||
(1) In µC/OS-II, all structures are given a data type. In fact, all data types start with “ (2) The structure starts with a “ (3) The (4) If there is a non- (5) (6) The (7) The (8) The (9) Each kernel object can be given a name for easier recognition by debuggers or µC/Probe. This member is simply a pointer to an ASCII string which is assumed to be NUL terminated. (10) The (11) The |
Even if the internals of the OS_TMR
data type are understood, the application code should never access any of the fields in this data structure directly. Instead, you should always use the Application Programming Interfaces (APIs) provided with µC/OS-II.
...
OSTmr_Task()
is a periodic task and uses the same interrupt source used to generate clock ticks. However, timers are generally updated at a slower rate (i.e., typically 10 Hz or so) and thus, the timer tick rate is divided down in software. If the tick rate is 1000 Hz and the desired timer rate is 10 Hz then the timer task will be signaled every 100th tick interrupt as shown in the figure below.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
The figure below shows timing diagram associated with the timer management task.
Anchor | ||||
---|---|---|---|---|
|
Panel | ||||
---|---|---|---|---|
| ||||
Panel | ||
---|---|---|
| ||
(1) The tick ISR occurs and assumes interrupts are enabled and executes. (2) The tick ISR signals the tick task that it is time for it to update timers. (3) The tick ISR terminates, however there might be higher priority tasks that need to execute (assuming the timer task has a lower priority). Therefore, µC/OS-IIruns the higher priority task(s). (4) When all higher priority tasks have executed, µC/OS-II switches to the timer task and determines that there are three timers that expired. (5) The callback for the first timer is executed. (6) The callback for the second expired timer is executed. (7) The callback for the third expired timer is executed. |
There are a few interesting things to notice:
...
Timers are inserted in a list by calling OSTmrStart()
and, a timer must be created before it can be used.
Anchor Listing - Creating and Starting a timer Listing - Creating and Starting a timer
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
OS_TMR MyTmr1;
OS_TMR MyTmr2;
void MyTmrCallbackFnct1 (void *p_arg)
{
/* Do something when timer #1 expires */
}
void MyTmrCallbackFnct2 (void *p_arg)
{
/* Do something when timer #2 expires */
}
void MyTask (void *p_arg)
{
INT8U err;
while (DEF_ON) {
:
MyTmr1 = OSTmrCreate((INT32U )1,
(INT32U )0,
(INT8U )OS_TMR_OPT_ONE_SHOT,
(OS_TMR_CALLBACK)MyTmrCallbackFnct1,
(void *)0,
(INT8U *)"My Timer #1",
(INT8U *)&err);
/* Check 'err" */
OSTmrStart ((OS_TMR *)&MyTmr1,
(INT8U *)&err);
/* Check "err" */
// Continues in the next code listing! |
The code below shows creating and starting another timer. This is performed “before” the timer task is signaled.
Anchor Listing - Creating and Starting a timer - continued Listing - Creating and Starting a timer - continued
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
// Continuation of code from previous code listing. : : MyTmr2 = OSTmrCreate((INT32U )1, (INT32U )0, (INT8U )OS_TMR_OPT_ONE_SHOT, (OS_TMR_CALLBACK)MyTmrCallbackFnct2, (void *)0, (INT8U *)"My Timer #2", (INT8U *)&err); /* Check 'err" */ OSTmrStart ((OS_TMR *)&MyTmr2, (INT8U *)&err); /* Check 'err" */ } } |
When the timer task executes (see OSTmr_Task()
in os_tmr.c
), it starts by incrementing OSTmrTime
and goes through the list of timers and checks to see which timer matches the OSTmrTime value. Upon match, the timer manager executes the callback function associated with the timer and, if the timer is set to periodic, determines what the next match value is based on the .OSTmrPeriod
(assuming periodic mode). If the timer is configured as a one-shot timer then the timer is removed from the list upon expiration.
Timer management occurs at the task level. The list is protected by locking the scheduler. Locking the scheduler impacts task responsiveness of other, higher priority tasks in your application.