|
It's about time to discuss the ISR, what should happen in
there? Well, it is very straightforward, we just decrement the delay for
every task since another scheduler period has been elapsed and we mark
the tasks that are ready to run. Note that the ISR does not actually call
any tasks and it shouldn't since it has to be quick, it just marks tasks
and the dispatch routine invokes them within the main loop.
SIGNAL(SIG_OVERFLOW0)
{
u8 m;
// load timer
TCNT0 = StartFrom;
// traverse task array
for (m=0; m<MAXnTASKS; m++)
{
// for each task
if (TaskArray[m].pfunc)
{
// if it is time to run
if (TaskArray[m].delay == 0)
{
TaskArray[m].run = 1;
TaskArray[m].delay = TaskArray[m].period;
}
else TaskArray[m].delay--;
}
}
}
Each time we reload the timer for the next interrupt and
we traverse the task array looking for pointers to functions (residing
not at 0x0000). If the delay is zero the task has to run therefore the
flag is set. It puzzles you, right? You would expect checking if the delay
is greater than zero, then checking if the task period is greater than
zero and if both are zero then execute the task otherwise decrease the
non-zero variable. Well, if we do that we would forget what the desired
task period is so, we would have to introduce another variable in the
structure possibly with the name ticks2execute. However, we can do the
job by relying only on the delay variable. On each task execution we copy
the period to the delay. Now, as you would expect a task will either run
and its delay will be initialized or its delay will be decreased by one.
The dispatch should look reasonable, it just invokes the required routines
and clears their run flag.
void DispatchTask (void)
{
u8 k;
for (k=0; k<MAXnTASKS; k++)
{
if (TaskArray[k].run == 1)
{
// run the task
(*TaskArray[k].pfunc)();
// clear its run flag
TaskArray[k].run = 0;
}
}
}
|