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

📄 chapter6.htm

📁 嵌入式软件开发.rar
💻 HTM
📖 第 1 页 / 共 4 页
字号:
	        ;
	}

	void printd(unsigned long x)
	{
		if(x/10)
	    	printd(x/10);
	    putch(x%10+'0');
	}

	/* This routine returns the value to be placed in SCCR0A.BR to
	   make the baud rate match that measured by an input capture.
	   The measured value may not match the book value exactly.  */

	WORD get_baud(BYTE number, Timer *t3)
	{
	    WORD start_time;
	    Delay *d;
	    Semaphore *s;
	    Timer1 *t;

	    s=semaphore_();
	    t=timer1_(number,       /* Build input capture--number */
	              FALLING,      /* capture falling edge */
	              NO);          /* no interrupt */
	    while(!get_status(t))
	    	;                   /* wait until an event occurs */
	    start_time=capture_time(t); /* get event time immediately */
	    new_edge(t,RISING);     /* set the sensitivity to rising edge */
	    d=delay_(t3,s,11);      /* t3 must be 1 ms timer to delay 11 ms */
	    wait_for_semaphore(s);  /* wait out the delay */
	    start_time=capture_time(t)-start_time;
	    timer1__(t);            /* get rid of this timer */
	    semaphore__(s);         /* don't need semaphore any more */
	    return  start_time%72>36?start_time/72+1: start_time/72;
	}

<h4>	Listing 6.6 Baud Rate Measuring Program  (end )</h4>
</code></pre>


<h3><a name="internal_pulse_width_modulator">Internal Pulse Width Modulators</a></h3>

<p>	In Chapter 5 we developed a pulse width modulation system that made use of two 
input capture subsystems.  One input capture was used to set the period of the signal and 
the other controlled the on-time.  This scheme can be used effeciently and it offers some 
flexibility beyond that available from the two built-in pulse width modulators, PWM, 
found in the <a href="appendxb.htm#gpt_h">GPT</a>.  Specifically, these two PWMs are both eight-bit devices and the 
PWM developed in Chapter 5 provided at lease 15 bit accuracy and resolution if needed.  
On the other hand, the Chapter 5 PWM was very slow and the internal PWMs can run 
considerably faster.  But, this value is also flexible because a prescaler can be applied to 
the PWM counter that will allow very precise PWM rates down to as slow as 4 Hz. 
<p>	This PWM system performs the same type of operation as that described in 
Chapter 5.  There is one major difference however; these two different approaches use 
completely different internal portions of the microcontroller.  Therefore, if we should 
decide to make this PWM system inherit the attributes and methods of the system 
described in Chapter 5, we would be causing peripheral components to be tied up that 
would never be used.  For example, the Chapter 5 system uses Output Compare 1 timer 
and another timer specified by the programmer.  This system does not employ any timer 
functions other than the built-in PWM subsystems.
<p>The internal pwm systems are driven by the system clock through the PWM 
Prescaler. There are three bits in the <a href="appendxb.htm#pwmc">PWMC</a>, 
<a href="appendxb.htm#pwmcbits">PWM Control</a> register, that control the 
level of the prescaler, and there is also in the same register a pair of bits called SFA and 
SFB. These bits set the speed mode of the pwm to either slow or fast.  The table shown 
below contains a summary of the operation of the prescaler along with the slow/fast bits 
for each of the pwm devices.  There is only one prescaler for both pwms, so the two 
pwms must run at the same basic clock speed.  However, the slow/fast bit can be set for 
each individual pwm.
<table>

<th>PPR[2:0] <th>Prescaler Tap <th>Fast Mode <th>Slow Mode<tr>

<td>0 <td>Div 2=8.39 MHz <td>32.8 kHz <td>256 Hz<tr>
<td>1 <td>Div 4=4.19 MHz <td>16.4 kHz <td>128 Hz<tr>
<td>10 <td>Div 8=2.10 MHz <td>8.19 kHz <td>64.0 Hz<tr>
<td>11 <td>Div 16=1.08 Mhz <td>4.09 kHz	<td>32.0 Hz<tr>
<td>100	<td>Div 32=524 kHz <td>2.05 kHz	<td>16.0 Hz<tr>
<td>101	<td>Div 64=262 kHz <td>1.02 kHz	<td>8.0 Hz<tr>
<td>110	<td>Div 128=131 kHz <td>512 Hz <td>4.0 Hz<tr>
<td>111	<td>PCLK <td>PCLK/256 <td>PCLK/32768<tr>
</table>
<h4>	Table 6.2 PWM Frequency Range Using 16.78 MHz System Clock</h4>


<p>
	The header file, shown below, has some new items for a heade file.  The first, is 
the enumeration of some values to be used is labled static.  The mnemonics A and B can 
be used in this program, and any file where pwmi.h is included, but these names are 
hidden from the rest of the program.  Several times a bit-field definition contained within 
a general header file is not quite that needed for a specific program.  In this case, the 
register PWMC is defined as a type Register, sixteen individual bits, in the header file 
gpt.h.  In this case it will make the code simpler if a bit-field that is three bits wide and 
contains bits 9 through 11 in this memory location were available.  Shown below is an 
example of how such a modification is made.  A structure that has the desired bit-field 
arrangement is typedefed and then the desired address is cast onto a pointer to this new 
type.  Then, in the program, this new pointer can be used the same as the one defined in 
the header file.
<pre><code>
	#ifndef PWMI_H
	#define PWMI_H

	#include &lthc16y1.h>
	#include &ltdefines.h>
	#include &ltgpt.h>
	#include &lttimer.h>

	static enum {A,B};

	typedef struct
	{
	    unsigned PWM_NULL0 : 9;
	    unsigned PR02 :3;
	    unsigned PWM_NULL1 : 4;
	}  Pwmcspec;

	#define PWMCSPEC (*(@far Pwmcspec*)(GPT_Register+0x24))

	#define PWMI_CLASS   \
			ERROR_HANDLER  \
			WORD time_on;  \
			BYTE channel;  

	typedef struct
	{
		PWMI_CLASS
	} Pwmi;

	#define ON_TIME(a,b) ((a)->channel==A)?(PWMA.PWA=(b)) : (PWMB.PWB=(b))

	Pwmi *pwmi_(BYTE channel,BYTE time_on,
				BYTE prescale,Boolean speed);
	void pwmi__(Pwmi *);

	#endif

<h4>	Listing 6.7 Internal PWM Object Header File</h4>
</code></pre><p>
	The remainder of this header file is about the same as usual.  The parameter 
on_time in the object must be set by the program.  Therefore, a macro function to set the 
proper value in the object is included.  The parameter, a, above s a pointer to an instance 
of the specific pwmi to be changed, and b is the new value for the on_time.  
<p>	The warning shown in the listing below bears mentioning again.  Each PWM 
within the system is turned on and running whenever an object that contains it is 
instantiated.  If more than one instance of the PWM were created, the hardware would 
have no mechanism for sorting out which values to use.  The tests upon entering the 
constructor returns an error to the calling program when an improper PWM is 
instantiated.  You should note that this error is a program error not a system error.  
Therefore, the error handler will not be needed to take care of this type of error.  A 
simple return to the calling program with an error flag set is superior to our using the 
error handler in cases such as these.  The calling program can test the pointer that is 
returned by the constructor, and if there is an error, the pointer will have a NULL value.
<p>	The remainder of this constructor follows the usual approach for the creation of 
an object.  A Pwmi is derived from the error_handler class.  An instance of the error 
handler is created when the variable temp is defined, and this variable is initialized by the 
call to the error constructor following the initial tests to determine if there is a calling 
error.  It is important that the instance of error be created after these tests because if it 
were called prior to the tests, program control would be returned to the calling program 
with an unused error handler object that would never be destroyed.  
<pre><code>	
	#include &ltpwmi.h>

	/* WARNING  Only one pwm per channel can be instantiated 
	   from this class at a time.  The system has two channels. 
	   Also, the prescaller must have the same value for both.  */

	static Boolean ach,bch;

	Pwmi *pwmi_(BYTE channel,BYTE time_on ,
				BYTE prescale,Boolean speed)
	{
	    Pwmi *this;
	    Error_handler *temp;

	    if(channel==A && ach==ON)
	        return NULL;
	    if(channel==B && bch==ON)
	        return NULL;
	    temp=error_();
	    this=(Pwmi*) malloc(sizeof(Pwmi));
	    if(this==NULL)
	   	  error_handler(temp,TYPE_1,PWM);
	    memmove(this, temp, sizeof(Error_handler));
	    error__(temp);
	    this->time_on=(WORD)time_on;
	    this->channel=channel;
	    PWMCSPEC.PR02=prescale;
	    switch (channel)
	    {
	        case A  :   PWMC.SFA=speed;
	                    PWMC.FPWMA=0;  /* normal pwm output */
	                    PWMC.PPROUT=0; /* normal pwm output */
	                    PWMA.PWA=time_on; /* start with correct time-on*/
	                    ach=ON;
	                    break;
	        case B  :   PWMC.SFB=speed;
	                    PWMC.FPWMB=0;
	                    PWMB.PWB=time_on;
	                    bch=ON;
	    }
	    return this;
	}

	void pwmi__(Pwmi * this)
	{
	    if(this->channel==A)
	        ach=OFF;
	    else
	        bch=OFF;
	    free(this);
	}

<h4>	Listing 6.8 PWMI Object Implementation File</h4>
</code></pre><p>
	After the object has been created, its parameters are initialized with the values 
time on and channel that are passed into the constructor as arguments.  The value of the 
prescale is put into the bit field defined in the header file, and the switch statement 
selects the proper internal channel and provides them with values. 
<p>	In addition to the usual job of destroying the memory allocated for the instance of 
the component, the destructor in this case must also turn the static memory flag ach or 
bch off whenever an instance of a PWMI is destroyed. 
<p>	A very simple test program follows.  This program implements both of the 
internal pulse width modulators.  This program will implement a serial port and read data 
from this port toobtain the pwm value.  A range of value 0 to 500 can be input into the 
serial port.  This value is one hundred times the voltage that will be output from the pwm 
system.  In an attempt to make this program simple, the passing in of data is rather 
clumsy.  The data are read into a buffer and the buffer contents, which is assumed to be a 
series of digits, is converted into an integer.  Only three characters are converted.  If any 
character converted is not a digit, the conversion is terminated and the value already 
created is used.  
The voltage value read in is converted to a range 0 to 255 where 255 corresponds to 5.0 
volts and this pwm on-time value is sent to both pwm outputs. 
<p>Pwma is set to high speed, and pwmb is set to slow speed.  Both of these devices 
are set at a prescale division value of 2.  Of course, they must both be set at the same 
prescale value, but one can run high speed and the other low.  For this demonstration, we 
will run pwma at the high speed and pwmb at low speed.  The clocking speeds, as found 
from Table 6.2, are  8.19 kHz and 64.0 Hz respectively.
<pre><code>
	#include &ltHC16Y1.h>
	#include &ltscim.h>
	#include &ltpwmi.h>
	#include &ltserkb.h>
	#include &ltdefines.h>
	#include &ltctype.h>

	#define SERIO_BAUD_19200 19200
	#define SERIO_INT_VECTOR 0x40
	#define SERIO_IARB 10
	#define SERIO_INT_LEVEL 3
	#define MAX_ON 0xff

	io_command_block *iob1,ib1;
	BYTE pszMessage[]="                           ";
	Pwmi *pwa, *pwb;
	Serial_io *sio;
	BYTE *msg;

	main()
	{
	    WORD value;
	    /* initialize the program */
		 
	    /* initialize the SIM registers */
	    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 system interrupts */
	    
	    /* set up the serial communications */
	    sio=serkb_io_(SERIO_BAUD_19200,     /* set the baud rate   */ 
				SERIO_INT_VECTOR,     /* interrupt vector */
			      SERIO_IARB,           /* iarb   */
			      SERIO_INT_LEVEL);     /* and interrupt level */
	                                    
	    /* set up the io block */      
	    iob1=&ib1;                /* a block for inputs */
	    iob1->io_command=INPUT;   /* iob1 is always input */
	    iob1->call_complete=FALSE;/* need to have no message in progress */
	    iob1->buffer_length=sizeof pszMessage;
	    pwa=pwmi_(A,0x80,2,FAST);              
	    pwb=pwmi_(B,0x80,2,SLOW);

	    FOREVER
	    {
	        while(kbhit())	   /* execute this code after a key is */
		  {				   /* depressed */
			int i;
			putch('\r');                  /* do a carriage return and */
			putch('\n');				  /* line feed */
			iob1->buffer=pszMessage;      /* must reset the buffer */
			serial_io(sio,iob1);
			while(!iob1->call_complete)	/* read in volts */
				;				/* wait until data is in */
			i=0;
			value=0;
			while(isdigit(pszMessage[i])&&i<3) /* convert to binary */
	      		value=pszMessage[i++]-'0'+10*value;
		    	if(value>500)   			/* 5 volts(*100) maximum */
		    		break;
			value=value*255/500;          /* convert volts to binary */
			ON_TIME(pwa,(BYTE)value);	/* send data to the pwms */
			ON_TIME(pwb,(BYTE)value);
		 }
	    }
	}

<h4>	Listing 6.9 PWMI Test Program</h4>

</code></pre><p>

	 Here again, we have an example of the ease of use of a software component.  The 
serial input/output program used in this case is the serkb_io system designed to send 
messages to and receive messages from a terminal.  The code needed to implement this 
interface is simply the serkb_io constructor followed by the construction of a 
input/output parameter block.  When the actual serial port access is executed, the method 
serial_io() is executed with pointers to the object and the parameter block as arguments.  

<h3><a name="summary">Summary</a></h3>

	This chapter contains descriptions of components that make use of the input 
capture subsystem and the built in pulse width modulation system found in the General 
Purpose Timer system.  This timer is used on the M68HC11, the M68HC16 and the 
M683XX families of components.  
<hr>
<p>
<a href="copyrite.htm#copyright">Copyright</a>

⌨️ 快捷键说明

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