📄 chapter5.htm
字号:
return this;
}
</code></pre><p>
The delay destructor is a little different from most destructors seen so far in this
discussion. Of course, the memory allocated to the delay must be released back to the
system by execution of the free(this) function. Also, semaphore attached to the delay
object must be released so that the calling function will be able to proceed. Finally, since
this delay will no longer exist after execution of the destructor, it is important to remove
its presence from the timer object to which it was attached. The two calls
attach_method(this->Time,NULL) and attach_object(this->Time,NULL) replace the data
stored in hook_object and hook_method within the timer object with NULL which is a
pointer to a nonexistant memory location. When the timer interrupt service routine is
executed, the value of hook_method is tested and there is no attempt to execute this
function if it contains a NULL.
<pre><code>
void delay__(Delay *this)
{
release_semaphore(this->semaphore); /* Release the semaphore */
attach_method(this->Time,NULL); /* release timer */
attach_object(this->Time,NULL);
free(this);
}
</code></pre><p>
We will next demonstrate the use of the delay class in a very simple program.
This program will start execution, delay operation for 10 seconds and quit. It will run on
an <a href="appendxb.htm#hc16y1_h">M68HC16Y1</a> chip. This chip has a general purpose timer so the timer class that we
wrote earlier can be executed. We include the standard header files which include
hc16y1.h and scim.h, which are chip related headers along with the delay.h, the
semaphor.h, the timer.h and the delay.h headers which are class header files.
<p> The next two lines of code define TIMECOUNT as 4000 and DELAY_TIME as
10000. TIMECOUNT is the number of timer clock cycles that will be executed prior to
each timer interrupt. DELAY_TIME is the number of interrupts that will occur during
the total delay. One millisecond requires 4000 timer clock cycles. Therefore, there will
be a timer interrupt each millisecond. The delay time of 10000 interrupts will expire in
10 seconds.
<pre><code>
#include "hc16y1.h"
#include "semaphor.h"
#include "timer.h"
#include "delay.h"
#include "scim.h"
#include "defines.h"
#define TIMECOUNT 4000
#define DELAY_TIME 10000
</code></pre><p>
When running a timer, we must control the basic clock frequency of the system if
the timing is to be accurate. This control is through the Clock Synchronization Register
which is a part of the SCIM--Single Chip Integration Module. The
<a href="appendxb.htm#syncr">SYNCR</a> controls the
operation of a frequency synthesizer. This synthesizer locks a high frequency oscillator
to the phase of a low frequency crystal oscillator and allows the programmer or hardware
engineer wide flexibility in choice of a system frequency. The
<a href="appendxb.htm#syncr">SYNCR</a> register is shown
below. The important bit fields in this register are the
<a href="appendxb.htm#syncrbits">W, X, and Y</a> fields. Depending
upon the crystal frequency, there are two equations that can be used to calculate the
system frequency. When the crystal frequency, or the reference frequency, is between 25
and 50 kilohertz, the following equation is used to determine the system frequency.
<pre><code>
FSYSTEM = FREFERENCE ( 4 ( Y+1 )( 2 2W+X ))
</code></pre><p>
where W, X and Y are the values contained in the corresponding bit fields. The most
common crystal used in this frequency range is a watch crystal which runs at 32768 Hz.
The default condition of these bit fields, after reset, are shown in the register description
below. Note both W and X contain a value 0 and Y contains a value 63. Therefore, if
the crystal frequency is 32768, the system frequency will be 32768*256 or 8388608. If
the operation requires a frequency near 16 mHz, this value must be doubled. It can be
doubled easily by placing a value of 1 in the X bit field of the SYNCR. This setup will
cause the system frequency to be 16.777216 mHz.
<p> Alternatively, it is possible to use a higher frequency crystal. In this case, the
equation to determine the system frequency is given by
<pre><code>
FSYSTEM = ( 4 ( Y+1 )( 2 2W+X ))FREFERENCE /128
</code></pre><p>
This equation holds for reference frequencies between 3.2 and 6.4 mHz. You can think
of the operation as being the same with either range of frequencies with the higher
frequency being divided by 128 prior to the adjustment by the frequency synthesizer.
The hardware automatically determines the when the division by 128 is needed. The
development board used to test programs for this book is the MC68HC16Y1MPB. This
board uses a 4.00 mHz crystal oscillator. Therefore, if the value of the X bit is set to 1,
the system frequency should be 16.00 mHz.
<p> Also, the default timer clock prescaler is set to a value of 4. Thus, the input to the
GPT should be running at a frequency of 4.00 mHz when the reference frequency is 4.00
mHz, the X bit of the SYNCR register is set to 1, and the Y field in this register has its
default value.
<p> There are two popular development boards that you will find for the M68HC16
family of components. The one mentioned above supports the larger HC16Y1 chip.
Alternatively, the MC68HC16Z1EVB supports the HC16Z1 chip. This chip has different
on-board peripheral components. The board itself has a 32768 Hz crystal to provide the
reference frequency for the chip. In that case, with the same set-up discussed above, the
input to the GPT will be 4.194304 mHz rather than 4.00 mHz. This difference in system
frequency will cause significant differences in any delay or clock operation that you
might program into the part.
<p><img align=middle src="fig5-1.jpg">
<p> The main program here is relatively simple once the various classes are properly
created. The first three instructions define pointers to a Timer, a Semaphore, and a Delay
object. A timer parameter block is also created. The <a href="appendxb.htm#scim_h">SIM</a>--System Integration Module--
registers are set-up. The clock speed is set to 16.00 mHz, the watch dog is disabled and
the built-in wait state generator for the boot memory chip select is set to 0 wait states.
The system interrupts are then enabled.
The timer parameter block is properly filled. I arbitrarily chose the output
compare number 3 to be the timer for this system. The tick count is set to provide 1 ms
interrupts. There is no external action when these interrupts occur. Also, OC1 is not
being used with this program. We will need an interrupt to occur. These appropriate
values are placed in the timer parameter block, and a pointer to this block is sent to the
timer constructor.
The program then gets an instance of a semaphore and creates an instance of the
delay component. The delay constructor receives pointers to the timer, the semaphore
and the delay time as arguments. The operation of this program returns the value from
delay_(), but the semaphore is attached to delay. Therefore, the wait_for_semaphore()
call will lock up the operation of the program until the semaphore is released by the
object d. When the semaphore is released by delay, it is destroyed, and the timer object
is also destroyed. Recall that it is not necessary to destroy the delay because the exercise
program contained within the delay takes care of this little piece of business.
<pre><code>
#include "hc16y1.h"
#include "semaphor.h"
#include "timer.h"
#include "delay.h"
#include "scim.h"
#include "defines.h"
#define TIMECOUNT 4000
#define DELAY_TIME 10000
main()
{
Timer *t;
Semaphore *sem;
Delay *d;
Timer_parameters tp;
/* initialize the SIM registers */
/* set the clock to 16.00 mHz, disable the watchdog, and 0
wait state */
SYNCR.X=ON; /* double the clock speed--16.00 mHz */
SYPCR.SWE=OFF; /* disable the watchdog */
CSORBT.DSACK=0; /* use zero wait states for now */
cli(); /* enable the system interrupts */
tp.number=3; /* set up the timer parameter structure */
tp.tick=TIMECOUNT; /* 1 ms interrupts */
tp.action=0; /* no output action */
tp.OC1_connect=0; /* OC1 not connected to another OC */
tp.connect_data=0;
tp.interrupt=YES; /* need an interrupt here */
t=timer_(&tp);
sem=semaphore_(); /* make the semaphore */
d=delay_(t,sem,DELAY_TIME);
wait_for_semaphore(sem);
semaphore__(sem);
timer__(t);
}
</code></pre>
<h4><pre>
Listing 5.4 Delay Test Program
</pre></h4>
<p> The above program demonstrates the operation of the timer, the semaphore, and
the delay objects. Shown below is a series of programs. These programs will show the
operation of a timer component in a slightly more complicated operation. The program
is written is three phases. These phases, clock, clock1 and clock2, first build a simple
time of day clock. There is only one piece of business processed with each timer
interrupt. The time output is sent out of the computer through the serial port. There is no
provision that allows setting the clock from the external system. In other words, the only
way that the clock can be set to a specific time is to modify the time values in memory
with a debug system. We will start with this simple system and later add more features
that will make our clock more useful.
<h3><a name="clock">Clock</a></h3>
<p> The routine clock is a simple clock that cannot do much more than tell time. In
clock2, this routine is expanded to allow two distinct operations to be executed during
the interrupt service routine of the timer. These two operations are contained on a linked
list, and if more items were needed, the linked list could be extended. Finally, in clock3,
it is shown how to add the capability of setting the clock through the keyboard.
<p> The header files for the program are listed below. The first four header files has
to do with the chip. The <a href="appendxb.htm#hc16y1_h">M68HC16Y1</a>
chip contains, among other modules, the general
purpose timer, <a href="appendxb.htm#gpt_h">GPT</a>,
the multichannel communications interface, <a href="appendxb.htm#mcci_h">MCCI</a>, and the single
chip integration module, <a href="appendxb.htm#scim_h">SCIM</a>. These headers are each included. We will also make
use of the serial input/output object along with the timer object. These headers are also
included along with the usual defines.h header.
<pre><code>
#include "HC16Y1.H"
#include "gpt.h"
#include "mcci.h"
#include "scim.h"
#include "serio.h"
#include "timer.h"
#include "defines.h"
</code></pre><p>
Next follows a series of definitions needed by the program. You will remember
that the hardware parameters for the serial i/o operation are all determined by the
program. These same parameters were locked into specific values in the timer object.
There is no correct or incorrect approach to where the system parameters are delivered to
the program. The parameters must be provided. In the case of the timer class, the
programmer has no choice as to the location of the interrupt vector, the IARB and the
interrupt level. These parameters are established within the class definition. In the case
of the serial i/o class, the interrupt parameters along with the serial i/o baud rate must be
passed to the class as arguments to the class constructor. The set of defines that establish
these values are shown below. Remember, it is always better to use a series of defines or
an enumerate statement to create these values for the program rather than to use the
actual numbers within the function calls. Such numbers used as function arguments and
so forth, are called magic numbers. When inserted as numbers, there is no connection to
their real meaning. When defined, all numbers are inserted into the program as
mnemonics with some program meaning.
<pre><code>
#define SERIO_BAUD_19200 19200
#define SERIO_INT_VECTOR 0x40
#define SERIO_IARB 10
#define SERIO_INT_LEVEL 3
#define TIMECOUNT 4000
#define ONE_SECOND 1000
</code></pre><p>
The next program items are the function prototypes. There are only four
functions used for this program. The first count_ticks() is a simple function that merely
increments the content of the address passed to the function as a parameter. This
function is quite important because it is the another example of use of the do_hook
approach that we use to add a function to the interrupt service routine of an instance of
the timer class. The remaining three functions are used to convert the integer type data
stored in memory into an character form that can be sent to the serial port. This function
is convert_itoa(). build_time() creates a complete message to be sent to the serial port
and uses convert_itoa() and output_time() sends the message to the serial port.
<pre><code>
/* function prototypes */
void count_ticks(WORD *);
void output_time(void);
void build_time(void);
void convert_itoa(WORD a,BYTE *p);
</code></pre><p>
Next to follow in the program are the variable definition statements. The first is a
string variable in which the message to be sent to the serial port is placed. This string is
followed by parameter blocks, and pointers to objects needed for the program. Also, the
variables hours, minutes, seconds, and count are defined as external variables to the
program.
<pre><code>
BYTE pszMessage[]=" \r"; /* a place to store the time */
io_command_block *oob1,ob1; /* i/o command block */
Timer_parameters tp; /* timer parameter block */
WORD hours, minutes, seconds;
WORD count;
Serial_io *sio;
Timer *t3;
</code></pre><p>
The main() function starts with the usual initialization routines. The <a href="appendxb.htm#scim_h">SIM</a> is
initialized to give a 16.00 mHz system clock frequency, the watchdog is disabled and the
memory wait states associated with the boot chip select are set to zero. Any other
initialization needed within the <a href="appendxb.htm#scim_h">SIM</a> will use the default, reset value, values.
<p> The serial input/output is then set-up. The object sio is a pointer to a type
Serial_io. This pointer is given a value by the call to the serial_io_() constructor. Note
that the arguments passed to this constructor are all defined earlier, so that anybody who
is reading the program should be able to understand which argument is given the specific
value. It is not really important to the program at this point the values assigned to these
parameters. However, if it is necessary at some time later to change any of these values,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -