⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chapter5.htm

📁 嵌入式软件开发.rar
💻 HTM
📖 第 1 页 / 共 5 页
字号:
	      
	    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>=2 && tp->OC1_connect>=4)	 /* 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; /* put action in place */
	    			  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;
	}
</code></pre><p>
	The switch statement shown above is used to set-up the proper interrupt for the 
specific output compare being instantiated.  The value of OCxF is turned off to avoid an 
immediate entry into an unwanted interrupt when the interrupt mask is enabled later in 
the code.  For output compares 2 through 4, the action value passed in through the 
parameter block is placed in the proper OMx and OLx bits in the <a href="appendxb.htm#tctl1">TCTL1</a> register.  This 
register has been given the duplicate name of <a href="appendxb.htm#omlreg">OMLREG</a> to ease the proper setting of the 
control bits.  The proper output compare is given a value equal to the contents of the 
<a href="appendxb.htm#tcnt">TCNT</a> register plus the tick value.  The next interrupt for this timer will occur when 
<a href="appendxb.htm#tcnt">TCNT</a> equals this value.  The statement
<pre><code>
	vector(OCxIsr,VAL*(GPT_VBA*0x10+y))
</code></pre><p>
invokes the vector macro found in the header hc16y1.h. Table 6.1 shown below is a copy 
of Table 7-1 from (1).  This table shows the interrupt vector lay-out for the timer 
subsystem.  Each vector address starts with a $X indicating that this value is 

<table>
<th>Name <th>	Interrupt Source Function <th>		Priority <th>		Vector<tr><tr>
			

<td>  <td>			Adjustable Channel<td>					0 (highest)<td>		$X0<tr>				
<td>IC1			<td>Input Capture 1						<td>1	   <td>			$X1<tr>
<td>ICI			<td>Input Capture 2						<td>2		<td>		$X2<tr>
<td>ICI			<td>Input Capture 3						<td>3				<td>$X3<tr>
<td>OC1			<td>Output Compare 1					<td>4				<td>$X4<tr>
<td>OC2			<td>Output Compare 2					<td>5				<td>$X5<tr>
<td>OC3			<td>Output Compare 3					<td>6				<td>$X6<tr>
<td>OC4			<td>Output Compare 4					<td>7				<td>$X7<tr>
<td>IC4/OC5		<td>Input Capture 4/Output Compare5		<td>8				<td>$X8<tr>
<td>TOF		   	<td>Timer Overflow Flag				   <td>	9			   <td>	$X9<tr>
<td>PAOVF		<td>Pulse Accumulator Overlfow Flag		<td>10			   <td>	$XA<tr>
<td>PAIF		<td>Pulse Accumulator Input Flag		<td>11 (Lowest)		<td>$XB<tr>
</table>

<p><h4>Table 5.2 Timer Interrupt Priorities and Vectors </h4>
<p>programmable. X is replaced by the value found in 
<a href="appendxb.htm#icr">ICR</a>.<a href="appendxb.htm#icrreg">VBA</a> bit field.  We earlier 
put the #defined value GPT_VBA into this bit field.  The value y in the above expression 
will have a value 4 through 7.  Therefore, the term
<pre><code>
	GPT_VBA*0x10+y
</code></pre><p>
is the correct vector for the interrupt and the vector is converted into an address when it 
is multiplied by the value VAL.  VAL is either 2 or 4 depending on the microcontroller 
being used and it is defined in the core microprocessor header file.  The address of the 
OCxIsr interrupt service routine is placed at this location by the macro vector().

<p>	The remainder of the set-up for the several interrupts is completed when the 
corresponding interrupt enable bit is set by an instruction
<pre><code>
	<a href="appendxb.htm#tmsk1">TMSK1</a>.<a href="appendxb.htm#tmsk1bits">OCxI</a> = ON;
</code></pre><p>
and the value of this is saved in the external variable OCx_T.  This value is needed to 
properly execute the interrupt service routine.  
<p>	Next to follow is the destructor.  In this case, the destructor must free the memory 
allocated to the object, and it must also disable the interrupt for the object being 
discarded.  The switch statement selects the proper interrupt to disable, and the free(this) 
function call deletes the memory allocation.
<pre><code>
    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);
    }
</code></pre><p>

	The interrupt service routines are quite simple.  In each case, the corresponding 
interrupt flag bit is turned OFF.  Then, the contents of TOC1 is incremented by the 
corresponding tick value so that the next interrupt will occur when expected.  Finally, the 
function do_hook(OCx_T) is executed.  There are four interrupt service routines: one for 
each of the four output compare subsystems.  	
<pre><code>
    /* 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);       
    }
</code></pre><p>
	Each instance of a timer contains two attributes that can be altered by the 
program that instantiates the timer.  The functions attach_object() and attach_method() 
place a value and a pointer to a function into the locations hook_object and hook_method 
in the object attribute list.  It is assumed that (*hook_method)() is a function that can use 
hook_object as a parameter.  If these values have been provided by the calling program, 
it is possible for the interrupt service routine to execute any practical function associated 
with the calling program as a part of the interrupt service routine.  When program control 
returns after execution of this function, the control of the computer will be returned to 
the interrupted program.
<p>	The function do_hook() that is executed in each interrupt service routine is shown 
below.  This simple program executes the corresponding (*hook_method)() function with 
hook_object as a parameter.  This function is executed only if the value of hook_method 
is not a NULL.   We will see a couple of examples in the programs that follow where 
functions or objects are attached to the timer interrupt service routines.
<pre><code>
   static void do_hook(Timer *time)
   {
       if(time->hook_method !=NULL)
          (*time->hook_method)(time->hook_object);
   }
</code></pre><p>  
  	The above description of the timer implementation file has been broken into 
several small pieces to help with description of the various parts.  The following listing is 
a  complete, contiguous listing of the program.
<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 reset(Timer *);
    static void do_hook(Timer *);

    Timer *OC1_T,*OC2_T,*OC3_T,*OC4_T;

    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;
    	}
    }

    Timer* timer_(Timer_parameters *tp)
    {
        Timer* this;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -