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

📄 chapter 1 program structure -- valvano.htm

📁 介绍了在嵌入式系统中如何用c来设计嵌入式软件
💻 HTM
📖 第 1 页 / 共 5 页
字号:
<P><CODE>short add(short x, short y){ return (x+y);}<BR>short add(x,y)short x; 
short y;{ return (x+y);}<BR>short add(x,y)short x,y;{ return 
(x+y);}</CODE></P></DIR>
<P>The parentheses are required even when there are no arguments. When there are 
no parameters a <CODE>void</CODE> or nothing can be specified. The following 
four statements are equivalent:</P>
<DIR>
<P><CODE>void 
OpenSCI(void){BAUD=0x30;SCCR2=0x0C;}<BR>OpenSCI(void){BAUD=0x30;SCCR2=0x0C;}<BR>void 
OpenSCI(){BAUD=0x30;SCCR2=0x0C;}<BR>OpenSCI(){BAUD=0x30;SCCR2=0x0C;}</CODE></P></DIR>
<P>I prefer to include the <CODE>void</CODE> because it is a positive statement 
that there are no parameters. For more information on functions see <A 
href="http://www.ece.utexas.edu/~valvano/embed/chap10/chap10.htm">Chapter 
10</A>. </P>
<P>The body of a function consists of a statement that performs the work. 
Normally the body is a compound statement between a {} pair. If the function has 
a return parameter, then all exit points must specify what to return. In the 
following median filter function shown in Listing 1-4, there are six possible 
exit paths that all specify a return parameter.</P>
<P>The programs created by ICC11 and ICC12 actually begin execution at a place 
called <B>_start</B>. After a power on or hardware reset, the embedded system 
will initialize the stack, initialize the heap, and clear all RAM-based global 
variables. After this brief initialization sequence the function named 
<B>main()</B> is called. Consequently, there must be a<FONT face=Monaco> 
</FONT><B>main()</B> function somewhere in the program. If you are curious about 
what really happens, look in the assembly file crt11.s or crt12.s. For programs 
not in an embedded environment (e.g., running on your PC) a return from 
<B>main()</B> transfers control back to the operating system. As we saw earlier, 
software for an embedded system usually does not quit. Software systems 
developed with Hiware also perform initialization before calling 
<B>main()</B>.</P>
<P><B><I><FONT face=Helvetica,Arial><A name=COMPOUND></A>Compound 
Statements</FONT></I></B></P>
<P>A <I>compound statement</I> (or <I>block</I>) is a sequence of statements, 
enclosed by braces, that stands in place of a single statement. Simple and 
compound statements are completely interchangeable as far as the syntax of the C 
language is concerned. Therefore, the statements that comprise a compound 
statement may themselves be compound; that is, blocks can be nested. Thus, it is 
legal to write</P>
<DIR>
<P><CODE>// 3 wide 16 bit signed median filter<BR>short median(short n1,short 
n2,short 
n3){<BR>&nbsp;&nbsp;&nbsp;&nbsp;if(n1&gt;n2){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(n2&gt;n3)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(n2);&nbsp;&nbsp;&nbsp;&nbsp;// 
n1&gt;n2,n2&gt;n3&nbsp;&nbsp;&nbsp;&nbsp;n1&gt;n2&gt;n3<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(n1&gt;n3)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(n3);&nbsp;&nbsp;&nbsp;&nbsp;// 
n1&gt;n2,n3&gt;n2,n1&gt;n3 
n1&gt;n3&gt;n2<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(n1);&nbsp;&nbsp;&nbsp;&nbsp;// 
n1&gt;n2,n3&gt;n2,n3&gt;n1 
n3&gt;n1&gt;n2<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;else{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(n3&gt;n2)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(n2);&nbsp;&nbsp;&nbsp;&nbsp;// 
n2&gt;n1,n3&gt;n2 
&nbsp;&nbsp;&nbsp;&nbsp;n3&gt;n2&gt;n1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(n1&gt;n3)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(n3);&nbsp;&nbsp;// 
n2&gt;n1,n2&gt;n3,n1&gt;n3 
n2&gt;n1&gt;n3<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(n1);&nbsp;&nbsp;// 
n2&gt;n1,n2&gt;n3,n3&gt;n1 
n2&gt;n3&gt;n1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}</CODE></P></DIR>
<P><I>Listing 1-9: Example of nested compound statements.</I></P>
<P>Although C is a free-field language, notice how the indenting has been added 
to the above example. The purpose of this indenting is to make the program 
easier to read. On the other hand since C is a free-field language, the 
following two statements are quite different</P>
<DIR>
<P><CODE>if(n1&gt;100) n2=100; n3=0;<BR>if(n1&gt;100) {n2=100; 
n3=0;}</CODE></P></DIR>
<P>In both cases <CODE>n2=100; </CODE>is executed if <CODE>n1&gt;100</CODE>. In 
the first case the statement <CODE>n3=0;</CODE> is always executed, while in the 
second case <CODE>n3=0;</CODE> is executed only if <CODE>n1&gt;100</CODE>.</P>
<P><B><I><FONT face=Helvetica,Arial><A name=GVARIABLES></A>Global 
Variables</FONT></I></B></P>
<P>Variables declared outside of a function, like <CODE>Count</CODE> in the 
following example, are properly called <I>external</I> variables because they 
are defined outside of any function. While this is the standard term for these 
variables, it is confusing because there is another class of external variable, 
one that exists in a separately compiled source file. In this document we will 
refer to variables in the present source file as <I>globals</I>, and we will 
refer to variables defined in another file as externals. </P>
<P>There are two reasons to employ global variables. The first reason is data 
permanence. The other reason is information sharing. Normally we pass 
information from one module to another explicitly using input and output 
parameters, but there are applications like interrupt programming where this 
method is unavailable. For these situations, one module can store data into a 
global while another module can view it. For more information on accessing 
shared globals see chapters 4 and 5 of <U>Embedded Microcomputer Systems: Real 
Time Interfacing</U> by Jonathan W. Valvano, Brooks/Cole Publishing Co., 
1999.</P>
<P>In the following example, we wish to maintain a counter of the number of 
times <CODE>OutSCI</CODE> is called. This data must exist for the entire life of 
the program. This example also illustrates that with an embedded system it is 
important to initialize RAM-based globals at run time. Some C compilers like 
ICC11 and ICC12 will automatically initialize globals to zero at startup. </P>
<DIR>
<P><CODE>unsigned short Count;&nbsp;&nbsp;/* number of characters 
transmitted*/<BR>void OpenSCI(void) { 
<BR>&nbsp;&nbsp;&nbsp;Count=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* initialize global 
counter */<BR>&nbsp;&nbsp;&nbsp;BAUD=0x30;&nbsp;&nbsp;&nbsp;/* 9600 baud 
*/<BR>&nbsp;&nbsp;&nbsp;SCCR2=0x0C;} /* enable SCI, no interrupts */<BR>#define 
TDRE 0x80<BR>void OutSCI(unsigned char 
Data){<BR>&nbsp;&nbsp;Count=Count+1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* 
incremented each time */ <BR>&nbsp;&nbsp;while ((SCSR &amp; TDRE) == 0); /* Wait 
for TDRE to be set */ <BR>&nbsp;&nbsp;SCDR=Data; } 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* 
then output */</CODE></P></DIR>
<P><I>Listing 1-10: A global variable contains permanent information</I></P>
<P>&nbsp;</P>
<P>Although the following two examples are equivalent, I like the second case 
because its operation is more self-evident. In both cases the global is 
allocated in RAM, and initialized at the start of the program to 1.</P>
<DIR>
<P><CODE>short Flag=1;<BR>void main(void) { <BR>/* main body goes here */<BR>} 
</CODE></P></DIR>
<P><I>Listing 1-11: A global variable initialized at run time by the 
compiler</I></P>
<DIR>
<P><CODE>short Flag;<BR>void main(void) { Flag=1;<BR>/* main body goes here 
*/<BR>} </CODE></P></DIR>
<P><I>Listing 1-12: A global variable initialized at run time by the 
compiler</I></P>
<P>From a programmer's point of view, we usually treat the I/O ports in the same 
category as global variables because they exist permanently and support shared 
access.</P>
<P><B><I><FONT face=Helvetica,Arial><A name=LVARIABLES></A>Local 
Variables</FONT></I></B></P>
<P>Local variables are very important in C programming. They contain temporary 
information that is accessible only within a narrow scope. We can define local 
variables at the start of a compound statement. We call these <I>local 
variables</I> since they are known only to the block in which they appear, and 
to subordinate blocks. The following statement adjusts<CODE> x </CODE>and 
<CODE>y </CODE>such that <CODE>x </CODE>contains the smaller number and <CODE>y 
</CODE>contains the larger one. If a swap is required then the local variable 
<CODE>z </CODE>is used.</P>
<DIR>
<P><CODE>if(x&gt;y){ short z;&nbsp;&nbsp;&nbsp;&nbsp;/* create a temporary 
variable */ <BR>&nbsp;&nbsp;z=x; x=y; y=z;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* swap 
x and y 
*/<BR>}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* 
then destroy z */</CODE></P></DIR>
<P>Notice that the local variable z is declared within the compound statement. 
Unlike globals, which are said to be <I>static</I>, locals are created 
dynamically when their block is entered, and they cease to exist when control 
leaves the block. Furthermore, local names supersede the names of globals and 
other locals declared at higher levels of nesting. Therefore, locals may be used 
freely without regard to the names of other variables. Although two global 
variables can not use the same name, a local variable of one block can use the 
same name as a local variable in another block. Programming errors and confusion 
can be avoided by understanding these conventions.</P>
<P><B><I><FONT face=Helvetica,Arial><A name=SOURCE></A>Source 
Files</FONT></I></B></P>
<P>Our programs may consist of source code located in more than one file. The 
simplest method of combining the parts together is to use the #include 
preprocessor directive. Another method is to compile the source files 
separately, then combine the separate object files as the program is being 
linked with library modules. The linker/library method should be used when the 
programs are large, and only small pieces are changed at a time. On the other 
hand, most embedded system applications are small enough to use the simple 
method. In this way we will compile the entire system whenever changes are made. 
Remember that a function or variable must be defined or declared before it can 
be used. The following example is one method of dividing our simple example into 
multiple files.</P>
<DIR>
<P><CODE>/* ****file HC11.H ************ */<BR>#define PORTC *(unsigned char 
volatile *)(0x1003)<BR>#define DDRC *(unsigned char volatile 
*)(0x1007)<BR>#define BAUD *(unsigned char volatile *)(0x102B)<BR>#define SCCR2 
*(unsigned char volatile *)(0x102D)<BR>#define SCSR *(unsigned char volatile 
*)(0x102E)<BR>#define SCDR *(unsigned char volatile *)(0x102F)</CODE></P></DIR>
<P><I>Listing 1-13: Header file for 6811 I/O ports</I></P>
<DIR>
<P><CODE>/* ****file SCI11.H ************ */<BR>void OpenSCI(void);<BR>void 
OutSCI(unsigned char);</CODE></P></DIR>
<P><I>Listing 1-14: Header file for the SCI interface</I></P>
<DIR>
<P><CODE>/* ****file SCI11.C ************ */<BR>void OpenSCI(void) { 
<BR>&nbsp;&nbsp;&nbsp;BAUD=0x30; /* 9600 baud 
*/<BR>&nbsp;&nbsp;&nbsp;SCCR2=0x0C;} /* enable SCI, no interrupts */<BR>/* Data 
is 8 bit value to send out serial port */<BR>#define TDRE 0x80<BR>void 
OutSCI(unsigned char Data){<BR>&nbsp;&nbsp;while ((SCSR &amp; TDRE) == 0); /* 
Wait for TDRE to be set */ <BR>&nbsp;&nbsp;SCDR=Data; } /* then output 
*/</CODE></P></DIR>
<P><I>Listing 1-15: Implementation file for the SCI interface</I></P>
<DIR>
<P><CODE>/* ****file VECTOR.C ************ */<BR></CODE><FONT 
face="Courier,Courier New" size=2>extern void _start(); /* entry point in 
crt11.s */</FONT><CODE><BR></CODE><FONT face="Courier,Courier New" 
size=2>#pragma abs_address:0xfffe</FONT><CODE><BR></CODE><FONT 
face="Courier,Courier New" size=2>void (*reset_vector[])() 
={_start};</FONT><CODE><BR></CODE><FONT face="Courier,Courier New" 
size=2>#pragma end_abs_address</FONT></P></DIR>
<P><I>Listing 1-16: Reset vector</I></P>
<DIR>
<P><CODE>/* ****file MY.C ************ */<BR>/* Translates parallel input data 
to serial outputs */<BR>#include "HC11.H"<BR>#include "SCI11.H"<BR>void 
main(void){ unsigned char Info;<BR>&nbsp;&nbsp;&nbsp;OpenSCI(); /* turn on SCI 
serial port */<BR>&nbsp;&nbsp;&nbsp;DDRC=0x00; /* specify Port C as input 
*/<BR>&nbsp;&nbsp;&nbsp;while(1){<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Info=PORTC; 
/* input 8 bits from parallel port C 
*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OutSCI(Info);}} /* output 8 bits to serial 
port */<BR>#include "SCI11.C"<BR>#include "VECTOR.C"</CODE></P></DIR>
<P><I>Listing 1-17: Main program file for this system</I></P>
<P>With Hiware, we do not need the VECTOR.C file or the line <CODE>#include 
"VECTOR.C"</CODE>. This division is a clearly a matter of style. I make the 
following general statement about good programming style. </P>
<ADDRESS>"If the software is easy to understand, debug, and change, then it is 
written with good style"</ADDRESS>
<P>While the main focus of this document is on C syntax, it would be improper to 
neglect all style issues. This system was divided using the following 
principles:</P>
<DIR>
<P>Define the I/O ports in a HC11.H or HC12.H header file<FONT 
face=Monaco><BR></FONT>For each module place the user-callable prototypes in a 
*.H header file<FONT face=Monaco><BR></FONT>For each module place the 
implementations in a *.C program file<FONT face=Monaco><BR></FONT>In the main 
program file, include the header files first<FONT face=Monaco><BR></FONT>In the 
main program file, include the implementation files last</P></DIR>
<P>Breaking a software system into files has a lot of advantages. The first 
reason is code reuse. Consider the code in this example. If a SCI output 
function is needed in another application, then it would be a simple matter to 
reuse the SCI11.H and SCI11.C files. The next advantage is c

⌨️ 快捷键说明

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