📄 chapter5.htm
字号:
<head>
<title>Timers</title>
</head>
<body>
<h1>Chapter 5 Timers</h1>
<p> The timer subsystem on the M68HC16Y1 consists of two parts. The first is the
General Purpose Timer, <a href="appendxb.htm#gpt_h">GPT</a>, and the second is the Timer Processor Unit, TPU. This
chapter is devoted to the use of the GPT. The GPT has four output compare units, three
input capture units and one timer that can be programmed as either. We shall write a
code module that provides program access to all four input captures and also, code will
be written that permits input capture system measurement of relative event times. Input
capture control code will be written to cover the three independent input capture timer
subsystems. The single timer that can be programmed as either an input capture or an
output compare will not programmed. It is an easy matter to add this channel to either
input or output classes depending on the system need. This addition can be done by
inheritance.
<h3><a name="output_compare_subsystem">Output Compare Subsystem</a></h3>
<p> Operation of an output compare timer is simple. The basic timer has a free-
running counter that is being clocked at some fraction of the system clock frequency.
This register is called the Timer Counter Register, or the <a href="appendxb.htm#tcnt">TCNT</a> and is used as a time
base for the entire timer subsystem. A value is placed in one of several output compare
registers. These registers are given the names <a href="appendxb.htm#ocrs">OC1,...OC4</a>. With only minor exceptions,
these registers are the same in both function and operation. When the content of the
TCNT matches the value in the output compare register, several things can happen
depending upon the set-up of the system. An internal flag is set to indicate that the
output compare has occurred. This flag can be polled by the program to determine
whether the output compare event has occurred, the corresponding output pin can
change to a programmed state, and if properly enabled, an interrupt can be requested. All
of these events happen synchronous with the match of the <a href="appendxb.htm#tcnt">TCNT</a> contents with that of the
appropriate OCx register.
<p> Both the <a href="appendxb.htm#tcnt">TCNT</a> and the OCx registers are sixteen bit registers. The timer
subsystem prescaller can cause the <a href="appendxb.htm#tcnt">TCNT</a> to be incremented at any binary division of the
system clock frequency between 4 and 256. The default prescaller value is 4. There is
only one TCNT, so all clocking functions for the General Purpose Timer subsystem must
work from the same time base.
<p> OC1 has some unique properties. This subsystem can be coupled to any other
output compare. When OC1 occurs in these cases, the coupled OCx pin will go to a
programmed state. This type of operation is very convenient for operations like a pulse
width modulator. In this case, OC1 will be used to establish the base time period of the
PWM system, and the coupled output compare will be used to determine the duty factor.
With this arrangement, output pulses as small as one timer clock cycle can be created.
<p> Here is a case where there are several on-board devices that all operate similarly,
and a class can be created that will allow the programmer to make use of any selected
output compare subsystem. This choice is made by making an appropriate constructor
call. Remember in Chapter 4, we saw a case where there were several similar peripheral
components on the microcontroller. It was there decided that a special class should be
written for each of the two SCI interfaces rather than attempt to create a single class that
could create instances of either of the two hardware serial ports. Here, all of the
components are set-up by a single class. The timer class will embody the complete
output compare system and will demonstrate that a class can provide complete coverage
and control of a peripheral.
<h3><a name="timer_class">Timer Class</a></h3>
<p> What are we going to do with these timers? I do not know now, and in fact, there
is no way to know, so an approach must be used that will allow for very flexible
extension of the basic timer classes. This flexibility will permit the connection of objects
instantiated from other classes, or perhaps standard applications code created by the
programmer. This flexibility is implemented by the inclusion of two attributes in the
timer object. One is a call to an external function and the other is a parameter to be
passed to this function. With these external accesses, the actions that can be performed
by the timer during an interrupt service routine is essentially unlimited.
<p> Shown below is the header file for the class timer. Six parameters must be passed
to the timer constructor. These parameters are all pulled together into a single structure
type and a pointer to this structure will be passed to the constructor. The five parameters
found in the Timer_parameter structure are all that are needed to set-up completely any
of the four output compare subsystems. The first value, number, is simply the number of
the timer and it can have a value between 1 and 4. The second parameter, tick, is the
value that is added to the specific output compare register whenever there is an interrupt
caused by an output compare. The next parameter determines the output that will occur
whenever an output compare on OC2 through OC4 happens. The table below is taken
from (1) and it summarizes the possible actions that can occur. The contents of action
will be given a value of 0 through 3 and the proper bits in the timer registers will be set to
cause the action shown in the table to occur.
<table>
<th> OMx-OLx <th> Action taken on compare <tr><tr>
<td> 00 <td> Timer disconnected from output (Default)<tr>
<td> 01 <td> Toggle OCx line <tr>
<td> 10 <td> Clear OCx line to zero <tr>
<td> 11 <td> Set OCx line to 1 <tr>
</table>
<p><h4> Table 5.1 OMx,OLx Bits</h4>
<p> The contents of the above table are collected into an enumeration in the header
file so that the programmer can use mnemonic descriptions of the output rather than
trying to remember the meanings of the seveal numbers above.
<p> Output compare 1 works somewhat differently from the remainder of the output
compares. OC1 can be connected to any other output compare, and when OC1 occurs,
the connected output compare will go to a designated state. The parameter OC1_connect
will be give a value of 0 to 4. If the value is 0, the OC1 is connected to neither an output
nor another output compare. If it is 1, OC1 is connected to its own output pin.
Otherwise, the number is the output compare to which OC1 is connected. The
connect_data input will be given a value of ON or OFF which is the state that the
connected output compare will go to when OC1 occurs.
<p> The last entry in the type Timer_parameters is a Boolean value named interrupt.
This parameter can have a value of TRUE or FALSE, or YES or NO as defined in the
defines.h file. If the value is YES, an interrupt will be set-up to occur when the proper
output compare occurs. Otherwise, there will be no interrupt, and either the program or
perhaps the external hardware must respond to the occurrence of the output compare.
<p> The timer class is derived from the error handler, and it has three attributes:
who_am_I, ms_tick and a pointer to a type void called a hook_object. There are two
class methods. The first is identified as a pointer to hook_method and the second is a
pointer to an internal function called reset. The timer class is defined as Timer, and it
has both a constructor and a destructor. The constructor requires a parameter that is a
pointer to a type Timer_parameters.
<p> There are two methods needed to assign values to hook_object and hook_method.
These functions are created as macros which are included in the header file. As such, the
two assign functions will always be used as inline code rather than function calls. In
addition to the usual two functions, the constructor and the destructor, there is needed an
additional class method. This method, reset(), will be used to reset a particular timer so
that the output compare will occur a specified time after the current time. The reset also
forces an output event to the outside world, if it is set up to be delivered to the outside,
when the reset method is executed. It does not cause the output compare flag to be set or
an output compare interrupt to occur.
<pre><code>
#ifndef TIMER_H
#define TIMER_H
#include "defines.h"
#include "error.h"
#ifndef GPT_IARB
#define GPT_IARB 12 /* iarb value of 12 for the GPT */
#define GPT_VBA 5 /* GPT vectors start at 0x50 */
#define GPT_LEVEL 6 /* use interrupt level 6 */
#endif
typedef enum BYTE
{
DISCONNECT,
TOGGLE,
CLEAR,
SET
}Output;
enum output_compares(OC1=1,OC2,OC3,OC4);
typedef struct
{
WORD number,
tick;
Output action;
BYTE OC1_connect,
connect_data;
Boolean interrupt;
} Timer_parameters;
#define TIMER_CLASS \
ERROR_HANDLER \
WORD who_am_I;\
WORD ms_tick; \
void (*reset)(struct time *); \
void *hook_object;\
void (*hook_method)(void*);
typedef struct time
{
TIMER_CLASS
}Timer;
#ifndef ATTACH
#define ATTACH
#define attach_object(a,b) ((a)->hook_object=(b))
#define attach_method(a,b) ((a)->hook_method=(b))
#endif
Timer* timer_(Timer_parameters *);
void timer__(Timer*);
#endif
</code></pre>
<h4><pre>
Listing 5.1 Timer Class Definition File
</pre></h4>
<p> There are several pieces of business that must be completed whenever the timer
subsystem is to be used. The interrupt arbitration level, the vector base address and the
interrupt level have all been seen before. It was decided in this case that these values
would be assigned specific values. If this approach is not acceptable, it is an easy matter
to expand the number of parameters passed to the constructor to include these values. It
is important to note that these three values must remain the same for each of the different
timers, so perhaps, it is best to preassign these values and not worry about them any
further. There are four interrupt service routines, each named OCxIsr(). There is also a
static function named do_hook(). The prototypes for these several functions are listed
next in the file below.
<pre><code>
#include "hc16y1.h"
#include "gpt.h"
#include "timer.h"
#define GPT_IARB 12 /* iarb value of 12 for the GPT */
#define GPT_VBA 5 /* GPT vectors start at 0x50 */
#define GPT_LEVEL 6 /* use interrupt level 6 */
#define OC1_offset 4 /* output compare vector offsets */
#define OC2_offset 5
#define OC3_offset 6
#define OC4_offset 7
@port void OC1Isr(void);
@port void OC2Isr(void);
@port void OC3Isr(void);
@port void OC4Isr(void);
static void do_hook(Timer *);
</code></pre><p>
The reset function is shown below. Each of the four timers, if instantiated as
objects, can be reset. A reset will cause an output compare to occur if an external
connection between the output compare and its output pin is set-up, or there is a
connection between OC1 or any other output compare. Also, a reset will calculate a new
value that is equal to the current content of the timer counter register plus the object
specified tick value and place this value in the proper output compare register. The code
to implement these operations is shown below.
<pre><code>
static void reset(Timer *this)
{
switch(this->who_am_I)
{
case 1 : TOC1=TCNT+this->ms_tick; /* restart output
comp count */
CFORC.FOC1=ON; /* and force an output
compare */
break;
case 2 : TOC2=TCNT+this->ms_tick;
CFORC.FOC2=ON;
break;
case 3 : TOC3=TCNT+this->ms_tick;
CFORC.FOC3=ON;
break;
case 4 : TOC4=TCNT+this->ms_tick;
CFORC.FOC4=ON;
break;
}
}
</code></pre><p>
The constructor for the output compare subsystem is shown below. There are
four pointers to the type Timer defined as external variables. These variables will hold
pointers to the four possible instances of timer objects. They are needed to implement
the basic interrupt service routines that follow. The first executable code in the
constructor is a series of tests that check for appropriate parameter values. If a parameter
is found that is out of the acceptable range, a FALSE value is returned to the calling
program indicating that there has been a program error. Memory is allocated to hold the
new object; an error object is instantiated; the error object is copied onto the new timer
object, and the error object is destroyed. The preassigned values or IARB, LEVEL and
VBA are placed in the appropriate registers in the timer subsystem. Note in the
preceding listing that copies of hc16y1.h and gpt.h were included. It is in these files that
the parameters such as GPT_MCR, IARB, etc. are defined. The parameters passed as
arguments to the constructor are next put into the attributes locations. Here number is
the number of the output compare and can have a value of 1 through 4. The value ticks is
the number that is added to the content of the output compare register with each
interrupt. This number sets the basic timing of the timer being instantiated. If it is
intended to connect the output of OC1 to another timer, this connection is made, and the
output action of the connection is put into place at this point in the code. The parameters
hook_object, a pointer to a type void, and hook_method, a pointer to a void function, are
each assigned the value of a NULL which is a pointer with a value zero. These
parameters will be changed when it is necessary to connect an applications function to
the timer.
<pre><code>
Timer *OC1_T,*OC2_T,*OC3_T,*OC4_T;
Timer* timer_(Timer_parameters *tp)
{
Timer* this;
Error_handler *temp = error_();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -