Академический Документы
Профессиональный Документы
Культура Документы
The measurement of time is exteremely important for the control of systems, because
the state of a system typically evolves as time advances. We therefore may need to
determine the duration of a given event, or respond to changes of the system within
an allocate time period. The consequences of missing a deadline or errors in keeping
track of the time (for instance in order to measure the duration of an event, or in order
to produce a specified delay) may result in complete failure of the system.
C code:
void delay(void)
{ int i,j;
for (i=0; i<200; i++)
for (j=0; j<30; j++)
{}
}
1
//USE OF DELAY SUBROUTINE
void main(void)
{
int time=0; //Says the frog
for (;;) //the main (infinite) loop
{
data=scan_pond(); //Call some functions
targets=process(data); //process data to find fly
move_towards(targets); //and somehow move towards it
time++; //Keep track of time
if (time%100==0) //every second
eat_fly(); //eat a Re: fly
delay(10); //Delay 10 ms
}
}
The goal of the delay statement is to ensure the main loop executes once ever 10 ms.
(assuming that the subroutines take less than this time to execute!). The frog assumes
that the variable time will be incremented every 10 ms, so it can eat a fly every second
and avoid starving to death.
Unfortunately for the frog this will not be the case (even if the delay subroutine ex-
ecutes for exactly 10 ms.), as the other statements and subroutines in the code will take
some time to execute. The frog dies.
The frog should have used a hardware timer. All that is required is to make a note
of the current timer value at the beginning (or end) of the loop, and then wait until the
timer has advanced its count by a given amount. With the excitement of such a clever
idea, the frog resurrects and writes:
2
//Now wait till our 10 millisecond period ends (POLL):
while(timer()!=timestamp);
So all seems fine for our frog! It lives happily in the pond and eats a rather large number
of flies. However it suddenly drops dead! What could be wrong?
Well, the frog was quite busy waiting for the timer to become 13005 when (exactly)
at T=13003 an interrupt arrived. The interrupt routine took 5 milliseconds and finished
at T=13008! Oh, well, perhaps I should have used a “<=” comparison rather than “!=”.
However, the frog reconsiders, since timer() and timestamp are both “circular”; i.e. they
roll-over from 65535 to 0 it will be difficult to tell which is the largest, time 10 or time
65525!!
Way too complicated for a frog.
The frog remembers from its University courses that the hardware timer has got some
other logic associated with it. In particular it has got a modulus comparator, which
resets the timer when a particular count (or equivalently, when a particular length of
time) has ellapsed. Furthermore this action also sets a flag. Could the frog then, not just
set things up and look at the flag? It rapidly looks at the timer implementation of the
HCS08 on pages 153-166 of the MC9s08GB manual and writes:
//HARDWARE TIMER
//FLAG POLLING METHOD
#define TOF 0x80 //Location of flag in TPM2SC
void main(void)
{
3
while(TPM2SC & TOF == 0); //by looking at the flag
TPM2SC=TPM2SC & ~TOF; //and reset the flag to 0
}
}
With this code the frog lives a happy but busy life in the pond. If I could only stop
looking at that flag and enjoy Coronation street more often! Grief!
So as things stands we have a poor, bored beyond comprehension frog watching (polling)
a flag. It is so busy that it cannot find happines. It spends its winters frozen solid then
thawed during spring, constantly looking at the flag. One day a gardner decapitates
the frozen frog. If it only would have had some free time, it might have found a warm
place to spend winter!
The gardner, who was also an expert programmer, tells the frog that it should have
used interrupts (instead of polling) like this:
//USING INTERRUPTS
#define TOF 0x80 //Location of flag in TPM2SC
volatile int time=0;
void main(void)
{
//startup
time=0; //Says the frog
TPM2SC=0x4A; //Use Fbus divided by 4 (Fbus=4MHz)
//and enable overflow interrupts
TPM2MOD=10000; //10 ms= 10000*1us
//So interrupt will be called every 10ms
for (;;) //the main (infinite) loop
{
watch_coronation_street();
go_to_the_pub();
sleep();
}
}
interrupt 14 void Timer2overflowISR(void)
{
//This interrupt routine is called every time there
//is a timer overflow (i.e. every 10 ms).
// 14 is the number of the Timer 2 overflow vector
TPM2SC=TPM2SC&~TOF; //CLEAR INTERRUPT!
data=scan_pond(); //Call some functions
targets=process(data); //process data to find fly
4
move_towards(targets); //and somehow move towards it
time++; //Keep track of time
if (time%100==0) //every second
eat_fly(); //eat a fly
}
//NOTE that we no longer wait inside this routine at all!
//we just rely on the fact that another interrupt will
//occur at the specified time interval.
//
//WARNING: The importance of clearing the interrupt cannot be
//over-emphazised. This process (which is entirely dependent
//on the specific peripheral/micro used), acknowledges and
//clears the interrupt. If this is not performed, one would
//find itself back into the interrupt handler routine
//immediatly after exiting the routine (forever!)
This way when the timer overflows, it generates an interrupt; which causes our handler
to be executed. In this case that is ever 10ms. Once our handler (i.e. our interrupt
service routine, ISR) finishes executing, the program returns to the normal flow, which
is as it may be, to watch tv and go to the pub.
The frog wonders, am I dead, or will I be so when I am thawed in spring?