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

📄 chapter 10 functions -- valvano.htm

📁 介绍了在嵌入式系统中如何用c来设计嵌入式软件
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<B>GetFifo</B> will store the return parameter into a local variable of 
<B>InChar</B>. Normally <B>GetFifo</B> does not have the scope to access local 
variables of <B>InChar</B>, but in this case <B>InChar</B> explicitly granted 
that right by passing a pointer to <B>GetFifo</B>.</FONT></P>
<DIR>
<P><CODE>int&nbsp;GetFifo&nbsp;(char&nbsp;*datapt)&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;if&nbsp;(Size&nbsp;==&nbsp;0&nbsp;)&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(0);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;Empty&nbsp;if&nbsp;Size=0&nbsp;*/<BR>&nbsp;&nbsp;&nbsp;else{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;asm("&nbsp;sei");&nbsp;&nbsp;&nbsp;/*&nbsp;make&nbsp;atomic,&nbsp;entering&nbsp;critical&nbsp;section&nbsp;*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*datapt=Fifo[GetI++];&nbsp;Size--;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(GetI&nbsp;==&nbsp;FifoSize)&nbsp;GetI&nbsp;=&nbsp;0;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;asm("&nbsp;cli");&nbsp;&nbsp;&nbsp;/*&nbsp;end&nbsp;critical&nbsp;section&nbsp;*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(-1);&nbsp;}<BR>}<BR>char 
InChar(void){ char 
data;&nbsp;<BR>&nbsp;&nbsp;&nbsp;while(GetFifo(&amp;data)){};<BR>&nbsp;&nbsp;&nbsp;return 
(data);}</CODE></P></DIR>
<ADDRESS>Listing 10-5: Mulitple output parameters can be implemented using call 
by reference</ADDRESS>
<P><FONT face="Times New Roman,Times">When we use the <I>call by value</I> 
scheme, the values, not references, are passed to functions. With call by value 
copies are made of the parameters. Within a called function, references to 
formal arguments see copied values on the stack, instead of the original objects 
from which they were taken. At the time when the computer is executing within 
PutFifo() of the example below, there will be three separate and distinct copies 
of the 0x41 data (main, OutChar and PutFifo).</FONT></P>
<DIR>
<P><CODE>int&nbsp;PutFifo&nbsp;(char&nbsp;data)&nbsp;{&nbsp;<BR>&nbsp;&nbsp;&nbsp;if 
(Size == FifoSize ) {<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(0);} 
/* Failed, fifo was full 
*/<BR>&nbsp;&nbsp;&nbsp;else{<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Size++;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*(PutPt++)=data; 
/* put data into fifo */<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (PutPt == 
&amp;Fifo[FifoSize]) PutPt = &amp;Fifo[0]; /* Wrap 
*/<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(-1); /* Successful */ 
<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR>}<BR>void OutChar(char data){ 
&nbsp;<BR>&nbsp;&nbsp;&nbsp;while(PutFifo(data)){};<BR>&nbsp;&nbsp;&nbsp;SC0CR2=0xAC;}<BR>void 
main(void){ char data=0x41; 
&nbsp;<BR>&nbsp;&nbsp;&nbsp;OutChar(data);}</CODE></P></DIR>
<ADDRESS>Listing 10-6: Call by value passes a copy of the data.</ADDRESS>
<P><FONT face="Times New Roman,Times">The most important point to remember about 
passing arguments by value in C is that there is no connection between an actual 
argument and its source. Changes to the arguments made within a function, have 
no affect what so ever on the objects that might have supplied their values. 
They can be changed with abandon and their sources will not be affected in any 
way. This removes a burden of concern from the programmer since he may use 
arguments as local variables without side effects. It also avoids the need to 
define temporary variables just to prevent side effects.</FONT></P>
<P><FONT face="Times New Roman,Times">It is precisely because C uses call by 
value that we can pass expressions, not just variables, as arguments. The value 
of an expression can be copied, but it cannot be referenced since it has no 
existence in global memory. Therefore, call by value adds important generality 
to the language.</FONT></P>
<P><FONT face="Times New Roman,Times">Although the C language uses the call by 
value technique, it is still possible to write functions that have side effects; 
but it must be done deliberately. This is possible because of C's ability to 
handle expressions that yield addresses. And, since any expression is a valid 
argument, addresses can be passed to functions.</FONT></P>
<P><FONT face="Times New Roman,Times">Since expressions may include assignment, 
increment, and decrement operators (<A 
href="http://www.ece.utexas.edu/~valvano/embed/chap9/chap9.htm">Chapter 9</A>), 
it is possible for argument expressions to affect the values of arguments lying 
to their right. (Recall that C evaluates argument expressions from left to 
right.) Consider, for example,</FONT></P>
<DIR>
<P><CODE>func (y=x+1, 2*y);</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">where the first argument has the value 
<B>x+1</B> and the second argument has the value <B>2*(x+1)</B>. What would be 
the value of the second argument if arguments were evaluated from right to left? 
This kind of situation should be avoided, since the C language does not 
guarantee the order of argument evaluation. The safe way to write this 
is</FONT></P>
<DIR>
<P><CODE>y=x+1;<BR>func (y, 2*y);</CODE></P></DIR>
<P><FONT face="Times New Roman,Times">It is the programmer's responsibility to 
ensure that the parameters passed match the formal arguments in the function's 
definition. Some mistakes will be caught as syntax errors by the compiler, but 
this mistake is a common and troublesome problem for all C 
programmers.</FONT></P>
<P><FONT face="Times New Roman,Times">Occasionally, the need arises to write 
functions that work with a variable number of arguments. An example is 
<B>printf()</B> in the library. ICC11 and ICC12 implement this feature using 
macros defined in the library file STDARG.C. To use these features you include 
STDARG.H in your file. For examples see the STDIO.C source file in your LIBSRC 
directory. </FONT></P>
<P>&nbsp;</P>
<P><B><I><FONT face=Helvetica,Arial><A name=PRIVATE></A>Private versus Public 
Functions</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">For every function definition, ICC11 and 
ICC12 generates an assembler directive declaring the function's name to be 
<I>public</I>. This means that every C function is a potential entry point and 
so can be accessed externally. One way to create private/public functions is to 
control which functions have declarations. Consider again the main program in 
Listing 10-2 shown earlier. Now lets look inside the Timer.H and Timer.C files. 
To implement Private and Public functions we place the function declarations of 
the Public functions in the Timer.H file. </FONT></P>
<DIR>
<P><CODE>void TimerInit(void);<BR>void TimerMsWait(unsigned int 
time);</CODE></P></DIR>
<ADDRESS>Listing 10-7: Timer.H header file has public functions</ADDRESS>
<P><FONT face="Times New Roman,Times">The implementations of all functions are 
included in the Timer.C file. The function, <B>TimerWait</B>, is private and can 
only be called by software inside the Timer.C file. We can apply this same 
approach to private and public global variables. Notice that in this case the 
global variable, <B>TimerClock</B>, is private and can not be accessed by 
software outside the Timer.C file.</FONT>&nbsp;</P>
<DIR>
<P><CODE>unsigned int TimerClock; // private global<BR>void TimerInit(void){ // 
public function<BR>&nbsp;&nbsp;TSCR |=0x80; // 
TEN(enable)<BR>&nbsp;&nbsp;TMSK2=0xA2;&nbsp;&nbsp;// TOI arm, TPU(pullup) 
timer/4 (500ns)<BR>&nbsp;&nbsp;TimerClock=2000; // 2000 counts per 
ms<BR>}<BR>void TimerWait(unsigned int time){ // private 
function<BR>&nbsp;&nbsp;TC5=TCNT+TimerClock;&nbsp;&nbsp;// 1.00ms 
wait<BR>&nbsp;&nbsp;TFLG1 = 0x20; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// clear 
C5F<BR>&nbsp;&nbsp;while((TFLG1&amp;0x20)==0){};}<BR>void TimerMsWait(unsigned 
int time){ // public 
function<BR>&nbsp;&nbsp;for(;time&gt;0;time--)<BR>&nbsp;&nbsp;&nbsp;&nbsp;TimerWait(TimerClock); 
// 1.00ms wait<BR>}</CODE></P></DIR>
<ADDRESS>Listing 10-8: Timer.C implementation file defines all 
functions</ADDRESS>
<P><FONT face="Times New Roman,Times">For more information about software 
development see Chapter 2 of the book <U>Embedded Microcomputer Systems: Real 
Time Interfacing</U> by Jonathan Valvano published by Brooks Cole.</FONT></P>
<ADDRESS>&nbsp;</ADDRESS>
<P><B><I><FONT face=Helvetica,Arial><A name=STACK></A>The Stack 
Frame</FONT></I></B></P>
<P><FONT face="Times New Roman,Times">Figure 10-2 illustrates the structure of a 
C stack frame. The stack frame generated by the ICC11 compiler places the 
explicit local variables (and other temporary data) at the top of the stack. 
Input parameters to the function and the subroutine return address are also on 
the stack. Recall that the 6811 stack pointer points to an empty place just 
above the top element of the stack. Within a 6811 function, <B>RegX</B> is not 
saved, but rather whenever stack access is required, the SP is copied into 
<B>RegX</B> using the <B>tsx</B> instruction and the stack is accessed using 
X-index address. The 6811 stack picture in Figure 10-2 illustrates the condition 
after executing <B>tsx</B>. The stack frame generated by the ICC12 compiler is 
similar, but not identical. Just like the 6811, the 6812 stack includes local 
variables, temporaries, subroutine return address and the input parameters. Just 
like the 6811, the first input parameter is above the return address and the 
remaining input parameters are below the return addressing. In actuality, this 
first input parameter is passed into the function in <B>RegD</B>, and the 
function itself pushes it on the stack. Different from the 6811, the 6812 stack 
pointer points to the top element of the stack. Within the 6812 function, 
<B>RegX</B> is saved, and then <B>RegX</B> is using within the function as a 
stack frame pointer. Because the value of <B>RegX</B> is maintained throughout 
the function and the 6812 stack is accessed simply using X-index addressing 
without having to execute <B>tsx</B> or (<B>tfr s,x</B>) each time. In 
particular notice <B>tsx</B> is executed twice in the 6811 main program in 
Listing 10-10, but <B>tfr s,x</B> is executed only once in the 6812 main program 
in Listing 10-11.</FONT></P>
<P><FONT face="Times New Roman,Times"><IMG height=211 
src="Chapter 10 Functions -- Valvano.files/stacks.gif" width=350></FONT></P>
<ADDRESS>Figure 10-2: Stack frame for a function with one local variable and 
three input parameters.</ADDRESS>
<P><FONT face="Times New Roman,Times">In order to understand both the machine 
architecture and the C compiler, we can look at the assembly code generated. 
This example shows a simple C program with three global variables 
</FONT><B><FONT face=Courier>x1,x2,x3</FONT></B><FONT 
face="Times New Roman,Times">, two local variables both called </FONT><B><FONT 
face=Courier>y </FONT></B><FONT face="Times New Roman,Times">and three function 
parameters </FONT><B><FONT face=Courier>z1,z2,z3</FONT></B><FONT 
face="Times New Roman,Times">.</FONT></P>
<DIR>
<P><CODE>int x1;<BR>static int x2;<BR>const int x3=1000;<BR>int add3(int z1, int 
z2, int z3){ int 
y;<BR>&nbsp;&nbsp;&nbsp;&nbsp;y=z1+z2+z3;<BR>&nbsp;&nbsp;&nbsp;&nbsp;return(y);}<BR>void 
main(void){ int 
y;<BR>&nbsp;&nbsp;&nbsp;&nbsp;x1=1000;<BR>&nbsp;&nbsp;&nbsp;&nbsp;x2=1000;<BR>&nbsp;&nbsp;&nbsp;&nbsp;y=add3(x1,x2,x3);</CODE></P></DIR>
<ADDRESS>Listing 10-9: Example function call with local variables</ADDRESS>
<P>The first compiler we will study is the ImageCraft ICC11 version 4.0 for the 
Motorola 6811. The disassembled output has been edited to clarify its operation. 
The linker/loader allocates 3 segmented memory areas: code pointed to by the PC; 
global accessed with absolute addressing; and locals pointed to by the stack 
pointer SP. The global symbols, <B><FONT face=Courier>_x1 _x2_x3</FONT></B>, 
will be assigned or bound by the linker/loader. The <B><FONT 
face=Courier>pshx</FONT></B><FONT face=Courier> </FONT>instruction allocates the 
local variable, and the <B><FONT face=Courier>tsx</FONT></B><FONT face=Courier> 
</FONT>instruction establishes a stack frame pointer, X. This compiler passes 
the first input parameter (<B><FONT face=Courier>z1</FONT></B>) into the 
subroutine by placing it in register D. The remaining parameters (<B><FONT 
face=Courier>z2</FONT></B>, <B><FONT face=Courier>z3</FONT></B> in this example) 
are pushed on the stack by the main program before the subroutine is called. The 
first operation the subroutine performs is to push the remaining parameter on 
the stack (<B><FONT face=Courier>pshb psha</FONT></B>) so that all three 
parameters,<B><FONT face=Courier> z1 z2 z3</FONT></B>, are on the stack. </P>
<DIR>
<P><CODE>&nbsp;&nbsp;&nbsp;&nbsp;.area text&nbsp;&nbsp;&nbsp;&nbsp;;text area is 
ROM<BR>&nbsp;&nbsp;&nbsp;&nbsp;.globl _x3<BR>_x3: .word 
1000<BR>&nbsp;&nbsp;&nbsp;&nbsp;.area text<BR>&nbsp;&nbsp;&nbsp;&nbsp;.globl 
_add3<BR>;&nbsp;&nbsp;&nbsp;&nbsp; y -&gt; 0,x<BR>;&nbsp;&nbsp;&nbsp;&nbsp;z3 
-&gt; 8,x<BR>;&nbsp;&nbsp;&nbsp;&nbsp;z2 -&gt; 6,x<BR>;&nbsp;&nbsp;&nbsp;&nbsp; 
z1 -&gt; 2,x<BR>_add3:&nbsp;pshb&nbsp;&nbsp;&nbsp;&nbsp;;push z1 on 
stack<BR>&nbsp;&nbsp;&nbsp;&nbsp;psha<BR>&nbsp;&nbsp;&nbsp;&nbsp;pshx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;allocate 
y<BR>&nbsp;&nbsp;&nbsp;&nbsp;tsx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;create 
local stack 
frame<BR>&nbsp;&nbsp;&nbsp;&nbsp;ldd&nbsp;&nbsp;2,x&nbsp;&nbsp;;RegD=z1<BR>&nbsp;&nbsp;&nbsp;&nbsp;addd&nbsp;6,x&nbsp;&nbsp;;RegD=z1+z2<BR>&nbsp;&nbsp;&nbsp;&nbsp;addd&nbsp;8,x&nbsp;&nbsp;;RegD=z1+z2+z3<BR>&nbsp;&nbsp;&nbsp;&nbsp;std&nbsp;&nbsp;0,x&nbsp;&nbsp;;y=z1+z2+z3<BR>&nbsp;&nbsp;&nbsp;&nbsp;pulx&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;deallocate 

⌨️ 快捷键说明

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