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

📄 chapter6.htm

📁 嵌入式软件开发.rar
💻 HTM
📖 第 1 页 / 共 4 页
字号:
measurement and the second t3 is a pointer to a Timer that interrupts each millisecond.  
Within get_baud() an instance of a Timer1 will be created.  The input capture associated 
with this Timer1 is assumed to be connected to the serial line.  The serial data format is 
shown below.  The default serial definition is usually n, meaning no parity, 8, meaning 
eight data bits, and 1, meaning 1 stop bit.  The serial line in its idle condition is high.  
The first bit that transmitted is called the start bit and it is labled S in the figure below.  
There follows a series of eight data bits each labled 0, 1,...7.  These data are transmitted 
least significant bit first. After the last data bit there is one additional bit that is held high 
for one bit time.  This bit is also labled S and it is called the stop bit.  There can be either 
1 or 2 stop bits depending upon the system set-up.  
<p>	The beginning of the stop bit is sensed when the input falls from an idle or high 
state to a low state.  After the eighth bit, the signal is set to high for at least one bit time 
corresponding to the stop bit.  In high-speed transmission, a new start bit can occur 
immediately after completion of the stop bit.  
<p>	A character is surrounded by start and stop bits.  The beginning of the character 
can be sensed by the high-to-low transion that marks the beginning of the start bit.  The 
end of the character can be sensed by a low-to-high transition that signals the beginning 
of the stop bit.  In total, the time from the first falling edge to the beginning of the stop 
bit is nine bit times. Of course, the data bits will have changing values, but it is the last 
transition that is necessary to be seen.  All printable characters and standard control 
characters that can be sent from the keyboard have a value of zero for bit seven.  
Therefore, the transition from bit seven to the stop bit will always be a low-to-high 
transition and it will always be seen.  
<p><img align=middle src="fig6-1.jpgf">
	
<h4>	Figure 6.1  Serial Data Character Format</h4>
<p>	Let us now examine the operation of the input capture timer and the MCCI 
subsystems.  In the MCCI, the baud rate is set by placing a thirteen bit value in 
<a href="appendxb.htm#sccr0a">SCCR0A</a>.<a href=appendxb.htm#sccr0>BR</a> field. 
 This value is found by the equation
<pre><code>
     	BR = fs / 32 Baud                                           (1)
</code></pre><p>
where BR is the bit field value and Baud is the baud rate in bits per second.  The value fs 
is the system clock frequency.  With the input capture subsystem, the total time for a 
single character can be measured.  This time is actually the time for nine bits.  The time 
is expressed in counts of the system clock that has been prescaled.  The default prescale 
value that is used in this example is 4.  Therefore, the measured time is 
<pre><code>
		Baud = (9/Count) ( fs / 4 )
</code></pre><p>
When this value is substituted into the first expression and cleaned up it is found that 
<pre><code>
		BR = Count / 72
</code></pre><p>
which is somewhat surprisingly independent of the system clock frequency.  
<p>	Our code must measure the count time from the beginning of the start bit to the 
beginning of the stop bit and divide this value by 72 to find the value needed to be placed 
in the <a href="appendxb.htm#sccr0a">SCCR0A</a>.<a href=appendxb.htm#sccr0>BR</a> field.  The code below will accomplish this task.  The first task is to 
instantiate a semaphore that will be used with a delay.  Then input capture timer is 
instantiated.  This timer will be the number specified by the calling program, its event 
will be a falling edge, and no interrupt will be used.  The program is then stalled until an 
event occurs by the statement
<pre><code>
	while(!get_status(t))
    		;                   /* wait until an event occurs */
</code></pre><p>
This statement will hang on itself until a falling edge is sensed.  At that time control is 
returned to the next statement in which the measured start time is saved.  The edge 
sensitivity of the Timer1 is then changed to rising to sense the transition to the stop bit 
and an eleven millisecond delay is implemented.  Eleven milliseconds was chosen to be 
longer than one would expect with a 1200 baud system.  The program then waits until 
delay releases the specified semaphore.  At that time, the value stored in the output 
compare register should be the time, relative to the TCNT register, of the beginning of 
the stop bit.  The difference between the time of the start bit and this measured time is 
saved and the instance of the Timer1 and the semaphore are deleted.  The measured 
value is then divided by 72 and returned to the calling program.  At high baud rates, the 
value returned becomes relatively small.  When the calculated value by the division is 
always rounded down, a noticable error can occur, so the code that calculates the return 
value rounds the result to the nearest integer value.  

<pre><code>
	/* 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.5  get_baud() Bit Rate Measuring Function</h4>
</code></pre><p>
	The above function uses several software components.  The semaphore, delay, 
timer and finally timer1  components are all used together to measure the bit rate of the 
serial port.  These components all work together smoothly and you should expect no bad 
interaction between these components because they have each been encapsulated as 
tightly as the C language will allow.  
<p>	The final portion of the program is to build a program that calls the get_baud() 
function to determine the speed of the serial port.  This program is shown below in 
Listing 6.6.  The function listed above is to be compiled with this program, so all of the 
necessary header files are #included here.  Recall that in the case of the serial 
input/output subsystem components, the various interrupt parameters are specified by the 
calling program rather than being specifiec within the componet itself.  Either approach 
is useful.  All of the necessray parameters are defined by the calling program for the 
serial input/output as shown below.  This way, the programmer has complete flexibility 
to choose these parameters when the system is designed.  The approach used with the 
Timer and with the Timer1 components was to specify these similar parameters within 
the class itself, and then the programmer did not need to have any worry about the choice 
of these values.
<p>	Is one approach better than the other?  Probably, but it depends more upon the 
shop standards set up by the orginization where the coding is being done.  Many groups 
will deplore the arbitrary choice of things like interrupt vectors and levels by the code.  
This approach takes away the flexibility of the programmer to do his job.  On the other 
hand, many programmers really dislike the need to get into the nature of the 
microcontroller being programmed.  We can hide this nature inside of the components 
that are developed for the system as was done with the timer.  
<pre><code>
	#include &ltHC16Y1.H>
	#include &ltscim.h>
	#include &ltmcci.h>
	#include &lttimer.h>
	#include &lttimer1.h>  
	#include &ltdelay.h>
	#include &ltserio1.h>
	#include &ltsemaphor.h>
	#include &ltdefines.h>

	/* serial port parameters */

	#define SERIO_BAUD_19200 19200  
	#define SERIO_INT_VECTOR 0x40
	#define SERIO_IARB 10
	#define SERIO_INT_LEVEL 3
	#define TIMECOUNT 4000	

	/* function prototypes */

	void printd(unsigned long);	 
	WORD get_baud(BYTE number, Timer *t3);
</code></pre><p>
	While discussing philosophy there is another styling thing that is shown in the 
following code.  A parameter block has been used to pass data to the Timer constructor.  
This block is a structure and you will note that it is filled with tp.tick=xxx; type 
statements.  In this case we use the structure name.  A little further down, a similar 
parameter block that is called an io_command_block is filled for use with the serial1 
component.  In that case, the pointer assignment mechanism, oob1->call_complete=xxx; 
was used.  In both cases, pointers to the parameter blocks were sent to the object when 
needed.  Which approach is better?  Here is another case where both approaches work 
equally well, there is no clear winner in regard to code space or execution speed, and 
both are equally easy to read and understand.  Within a programming team or a group 
standard, one and only one of these approaches should be chosen and used.  Regardless 
of the approach, the idea of object oriented programming is to make the interface 
between the various components uniform and easy to follow.  The coding approach 
shown below works well, but it is in no way a uniform approach to the problem.  
<pre><code>
	void main(void)
	{
	    Timer  *t3;
	    Timer_parameters tp;
	    Serial_io *sio;
	    io_command_block *oob1,ob1;
	    BYTE pszMessage[]="The selected baud rate is ";
	    BYTE pszMessage1[]=" bits per second\n\r";
	    WORD baud;
	    unsigned long baud_rate;
		
		/* 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 timer parameter structure and instantiate a timer */
	    tp.number=3;    	/* use output compare number 3 */
	    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;  /* therefore no connect data needed */
	    tp.interrupt=YES;   /* need an interrupt here */
	    t3=timer_(&tp);	  	/* instantiate the timer */
	    baud=get_baud(1,t3);/* measure the baud rate */
	    timer__(t3);        /*don't need timer any more */
</code></pre><p>
After the system is set-up, the timer is programmed to provide a 1 ms interrupt 
and then started.  The function shown above, get_baud() is then executed.  Upon return 
from the get_baud() routine, the timer is no longer needed so it is destroyed.  The serial 
port is then instantiated with serial1_io_() and the baud value retruned by get_baud() is 
used.  The messaged "The selected baud rate is " is sent to the screen.  The baud rate is 
then claculated using Equation 1 above.  Here we need to know that the system 
frequency, fs, is 16 mHz.  This value divided by 32 provides the numerator of 500000 
used to calculate the baud_rate.  The calculated valued is sent to the screen and then the 
message " bits per second\r\n" is sent to the screen.  This program was executed many 
times at many different standard baud rates between 1200 and  57600.  The chip is 
incapable of providing a 57600 bit per second rate. Return to Equation 1 and observe that
<pre><code>
	16000000 / 32 * 57600 = 8.68
</code></pre><p>
This value will be rounded to 9.  In that case, the baud rate will be
<pre><code>
	16000000 / 32 * 9 = 55555.555
</code></pre><p>
If you execute the program, this is the baud rate value printed out when requesting a 
57600 b/s rate.     
<pre><code>
	    /* set up the serial communications */
		sio=serial1_io_(baud,             /* set the baud rate   */ 
		  		     SERIO_INT_VECTOR,  /* interrupt vector */
		                SERIO_IARB,        /* iarb   */
			           SERIO_INT_LEVEL);  /* and interrupt level */
	                   
	    /* set up the io blocks */      
	    oob1=&ob1;                  /* output block */
	    oob1->call_complete=TRUE;   /* have no message going out */
	    oob1->io_command=OUTPUT;    /* oob1 is always output  */
	    oob1->buffer=pszMessage;    /* select the message  */
	    oob1->buffer_length= sizeof pszMessage;
	    serial_io(sio,oob1);        /* message to the i/o object */
	    while(!oob1->call_complete)
			;                     /* wait until transmission is done */
	    baud_rate=500000ul/baud;
	    printd(baud_rate);          /* send baud rate to screen */
	    oob1->buffer=pszMessage1;
	    oob1->buffer_length= sizeof pszMessage1;
	    serial_io(sio,oob1);        /* send out rest of message */
	    while(!oob1->call_complete)
	        ;
	}
</code></pre><p>
	The standard printd() function is used to print the numerical value to the screen.  
This function shown below is probably the simplest integer to ascii conversion available 
for microcontrollers.  The controller as well as the compiler used with this function must 
support recursion. 
<pre><code>
	void printd(unsigned long x)
	{
		if(x/10)
	    	 	printd(x/10);
	      putch(x%10+'0');
	}
</code></pre><p>
	The program above was not only broken into pieces for description, but the order 
of functions was switched around.  Therefore, the whole program is listed below. 
<pre><code>
	#include &ltHC16Y1.H>
	#include &ltscim.h>
	#include &ltmcci.h>
	#include &lttimer.h>
	#include &lttimer1.h>  
	#include &ltdelay.h>
	#include &ltserio1.h>
	#include &ltsemaphor.h>
	#include &ltdefines.h>
		
	/* serial port parameters */

	#define SERIO_BAUD_19200 19200  
	#define SERIO_INT_VECTOR 0x40
	#define SERIO_IARB 10
	#define SERIO_INT_LEVEL 3
	#define TIMECOUNT 4000	

	/* function prototypes */

	void printd(unsigned long);	 
	WORD get_baud(BYTE number, Timer *t3);

	void main(void)
	{
	    Timer  *t3;
	    Timer_parameters tp;
	    Serial_io *sio;
	    io_command_block *oob1,ob1;
	    BYTE pszMessage[]="The selected baud rate is ";
	    BYTE pszMessage1[]=" bits per second\n\r";
	    WORD baud;
	    unsigned long baud_rate;
		
		/* 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 timer parameter structure and instantiate a timer */
	    tp.number=3;    	/* use output compare number 3 */
	    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;  /* therefore no connect data needed */
	    tp.interrupt=YES;   /* need an interrupt here */
	    t3=timer_(&tp);	  	/* instantiate the timer */
	    baud=get_baud(1,t3);/* measure the baud rate */
	    timer__(t3);        /*don't need timer any more */
	    
	    /* set up the serial communications */
		sio=serial1_io_(baud,             /* set the baud rate   */ 
		  		       SERIO_INT_VECTOR,  /* interrupt vector */
		               SERIO_IARB,        /* iarb   */
			           SERIO_INT_LEVEL);  /* and interrupt level */
	                   
	    /* set up the io blocks */      
	    oob1=&ob1;                  /* output block */
	    oob1->call_complete=TRUE;   /* have no message going out */
	    oob1->io_command=OUTPUT;    /* oob1 is always output  */
	    oob1->buffer=pszMessage;    /* select the message  */
	    oob1->buffer_length= sizeof pszMessage;
	    serial_io(sio,oob1);        /* message to the i/o object */
	    while(!oob1->call_complete)
			;                       /* wait until transmission is done */
	    baud_rate=500000ul/baud;
	    printd(baud_rate);          /* send baud rate to screen */
	    oob1->buffer=pszMessage1;
	    oob1->buffer_length= sizeof pszMessage1;
	    serial_io(sio,oob1);        /* send out rest of message */
	    while(!oob1->call_complete)

⌨️ 快捷键说明

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