📄 chapter5.htm
字号:
Error_handler *temp = error_();
if(tp->number >4) /* error must be between 1 and 4 */
return FALSE;
if(tp->OC1_connect>4)
return FALSE; /* got a bad OC1_connect */
if(tp->connect_data >4)
return FALSE; /* got bad connect_data*/
this=(Timer*) malloc(sizeof(Timer));
if(this==NULL)
error_handler(temp,TYPE_1,TIMER);
memmove(this, temp, sizeof(Error_handler));
error__(temp);
/* initialize the GPT */
GPT_MCR.IARB=GPT_IARB; /* pick an IARB for the timers */
ICR.IRL=GPT_LEVEL; /* interrupt level 6 */
ICR.VBA=GPT_VBA; /* vectors start at 0x50 */
this->who_am_I=tp->number; /* save the number of the timer */
this->ms_tick=tp->tick;
this->reset=reset; /* put reset function in place */
if(tp->OC1_connect>0 && tp->OC1_connect<5) /* set up the OC1
connections */
{
switch(tp->OC1_connect)
{
case 1 : OC1M.OC1M3=ON;
OC1D.OC1D3=tp->connect_data;
break;
case 2 : OC1M.OC1M4=ON;
OC1D.OC1D4=tp->connect_data;
break;
case 3 : OC1M.OC1M5=ON;
OC1D.OC1D5=tp->connect_data;
break;
case 4 : OC1M.OC1M6=ON;
OC1D.OC1D6=tp->connect_data;
break;
}
}
this->hook_object=NULL;
this->hook_method=NULL;
switch(tp->number)
{
case 1: TFLG1.OC1F=OFF; /* reset event flag */
TOC1=TCNT+tp->tick; /* set output compare register */
vector(OC1Isr,VAL*(GPT_VBA*0x10+OC1_offset));
/* put vector in place */
if(tp->interrupt) /* do we need an interrupt? */
TMSK1.OC1I=ON; /* enable the interrupt*/
OC1_T=this; /* keep Timer pointer */
break;
case 2: TFLG1.OC2F=OFF;
OMLREG.OML2=tp->action;
TOC2=TCNT+tp->tick;
vector(OC2Isr,VAL*(GPT_VBA*0x10+OC2_offset));
if(tp->interrupt)
TMSK2.OC2I=ON;
OC2_T=this;
break;
case 3: TFLG1.OC3F=OFF;
OMLREG.OML3=tp->action;
TOC3=TCNT+tp->tick;
vector(OC3Isr,VAL*(GPT_VBA*0x10+OC3_offset));
if(tp->interrupt)
TMSK2.OC3I=ON;
OC3_T=this;
break;
case 4: TFLG1.OC4F=OFF;
OMLREG.OML4=tp->action;
TOC4=TCNT+tp->tick;
vector(OC4Isr,VAL*(GPT_VBA*0x10+OC4_offset));
if(tp->interrupt)
TMSK2.OC4I=ON;
OC4_T=this;
break;
}
return this;
}
void timer__(Timer* this)
{
switch(this->who_am_I)
{
case 1 : TMSK1.OC1I=OFF; /* turn off the timer interrupt */
break;
case 2 : TMSK1.OC2I=OFF;
break;
case 3 : TMSK1.OC3I=OFF;
break;
case 4 : TMSK1.OC4I=OFF;
break;
}
free(this);
}
/* interrupt service routines */
@port void OC1Isr(void)
{
TFLG1.OC1F=OFF;
TOC1+=OC1_T->ms_tick;
do_hook(OC1_T);
}
@port void OC2Isr(void)
{
TFLG1.OC2F=OFF;
TOC2+=OC2_T->ms_tick;
do_hook(OC2_T);
}
@port void OC3Isr(void)
{
TFLG1.OC3F=OFF;
TOC3+=OC3_T->ms_tick;
do_hook(OC3_T);
}
@port void OC4Isr(void)
{
TFLG1.OC4F=OFF;
TOC4+=OC4_T->ms_tick;
do_hook(OC4_T);
}
/* function that allows external access to isr */
static void do_hook(Timer *time)
{
if(time->hook_method !=NULL)
(*time->hook_method)(time->hook_object);
}
</code></pre>
<h4><pre>
Listing 5.2 Timer Class Implementation File
</pre></h4>
<p> The above basic timer class will provide a starting point for several other example
classes to be developed in the following examples. Timer is a very good example of a
software component. It will be used in conjunction with several other classes that are all
based on working in time. Assuming that the class has been completely debugged, object
of the type Timer can be used without fear of either failure to perform its designated task
or unexpected side effects caused by leakage between memory areas. None of the
attributes of Timer should be accessed except through the methods provided. If it
becomes necessary to access an attribute, a separate method, perhaps created in an
inherited class, should be created to handle this contingency. Usually, the code in a
header file and its associated implementation file should never be changed. A case
where we will allow such a change is for the addition of macro methods. These cases
pose a dilemma. Such a change should be associated with the class code, and we do not
want to alter the class code directly. Use inheritance in any but the most basic of
changes, and then put any new macros into the header file of the affected class. Do not
change the implementation file ever. If it is necessary to change features found in the
implementation file, use inheritance to isolate the changed code from the known working
and debugged code.
<h3><a name="delay">Delay</a></h3>
<p> The first example that will make use of Timer is to create a delay. Often it is
necessary to delay execution of a program by a specified amount of time. It is expected
that in these cases, a Timer can be made available to effect the delay. Recall, Timer
needs a tick value that is usually aimed to produce an event on a relatively short time
basis. Certainly, the size of the number to be added to the output compare register should
be represented in an unsigned integer which is the size of the Timer Counter Register.
With the microcontroller running at 16 mHz, the time required to overflow this register is
16 milliseconds. With proper set-up of the timer prescaler, this time can be extended to
approximately 4000 milliseconds. Therefore, most timers have periods that lie in this
range of values. Also, you should have noted that if a Timer is properly instantiated, it
will run periodically with an interrupt occurring each time the Timer Counter Register
matches the corresponding Output Compare Register. This arrangement makes Timer a
perfect base for a delay. A Timer will be created that has some convenient base
frequency or time of interrupt. The delay is set up to count the number of interrupts, and
when the specified number of interrupts occur, the delay is released. Here is a case
where the <a href="chapter7.htm#semaphore">semaphore</a> as discussed in Chapter 3 can be used to an advantage. The calling
program that initiates the delay will create a semaphore. This semaphore will be
attached to the delay, and the calling program will be put into a wait_for_semaphore()
call which will stop the execution of the calling program until the semaphore is released
by the delay program. The delay program will wait until the proper number of ticks from
the base Timer and then delete itself which will automatically release the semaphore
allowing the calling program to proceed.
<p> In the delay header file shown below, you will note that these objects will access
error.h, timer.h, semaphore.h and defines.h. The class is set-up to have delay inherit the
error_handler. There are three attributes, the delay time, a pointer to the specified timer
and a pointer to the semaphore. These three parameters are passed to the delay
constructor as arguments.
<pre><code>
#ifndef DELAY_H
#define DELAY_H
#include "error.h"
#include "timer.h"
#include "semaphor.h"
#include "defines.h"
#define DELAY_CLASS \
ERROR_HANDLER \
unsigned int delay_time; \
struct time *Time;\
Semaphore *semaphore;
typedef struct delay
{
DELAY_CLASS
}Delay;
struct delay *delay_(struct time*, Semaphore*,unsigned int);
void delay__(struct delay *);
#endif
<h4>
Listing 5.3 Delay Class Definition File
</h4>
</code></pre><p>
The implementation of delay needs access to a function that we will call
exercise(). The Timer interrupt occurs at a rate specified when the timer is instantiated.
Normally, this rate is relatively fast, and when a program delay is needed, that time is
usually longer than the timer interrupt rate. Therefore, we must pass a number to the
delay that is the number of timer interrupts needed to be executed during the delay time.
This number is the third argument of the delay constructor. This number, called
delay_time, is stored in the object. The function exercise() decrements this number until
it becomes zero. At that time, the delay object is deleted. The operations done during
delete are discussed below.
<p> The delay constructor, delay_(), follows the general plan used in most other
constructors. Delay is inherited from the Error_handler, so, a temporary Error_handler
object is created . Space is allocated to hold the delay object and the temporary
Error_handler is moved into this space. The Error_handler is then deleted. The timer
pointer and the semaphore pointer are moved into the newly created object and the
semaphore is attached to the delay. The delay time passed into the constructor is stored
in the delay_time location of the new object. Finally, a pointer to the delay is placed in
the hook object location of the timer object and a pointer to the function exercise is put
into the hook method location in the timer object. Therefore, the function exercise for
this delay will be executed during each timer interrupt service routine. Lastly, a pointer to
the newly created delay object is returned to the calling program.
<pre><code>
#include "delay.h"
static void exercise(Delay *delay)
{
if(--delay->delay_time==0)
{
delay__(delay); /* delete the delay */
}
}
Delay* delay_(Timer *Time,Semaphore *sem, unsigned int delay_time)
{
Delay *this;
Error_handler *temp=error_();
this = (Delay* ) malloc(sizeof(Delay));
if(this==NULL)
error_handler(temp,TYPE_1,DELAY);
memmove(this,temp,sizeof(Error_handler));
error__(temp);
this->Time=Time;
this->semaphore=sem;
attach_semaphore(this->semaphore); /* attach semaphore
to process */
this->delay_time=delay_time;
attach_object(Time,(void*)this); /* put hook object in
place */
attach_method(Time,exercise); /* and the hook method */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -