📄 c51pickfrankasm.htm
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0046)http://mcu21cn.topcool.net/c51pickfrankasm.htm -->
<HTML><HEAD><TITLE>Franklin C51和A51函数的相互调用</TITLE>
<META content="text/html; charset=gb2312" http-equiv=Content-Type>
<META content="MSHTML 5.00.2614.3500" name=GENERATOR>
<META content=none name="Microsoft Border"></HEAD>
<BODY bgProperties=fixed leftMargin=0 topMargin=0>
<TABLE bgColor=#ffffff border=0 borderColor=#000000 cellPadding=0 cellSpacing=0
width="100%">
<TBODY>
<TR>
<TD bgColor=#ffffff borderColor=#000000 width="10%"></TD>
<TD width="80%"><B><FONT face=Arial size=5>
<P align=center></FONT><FONT color=#800080 face=隶书 size=6>Franklin
C51和A51</FONT><FONT face=黑体 size=3></P></FONT></B>
<P align=center><B><FONT color=#800080 face=隶书
size=6>函数的相互调用</FONT></B></P><FONT face=楷体_GB2312 size=3>
<P align=center></FONT><SPAN style="FONT-SIZE: 9pt">开发部 胡 戎
郑玉墙</SPAN></P><B>
<P align=justify><SPAN style="FONT-SIZE: 9pt"> <FONT
color=#800080>摘 要</FONT></B> 本文讨论如何在Franklin
C51和A51的编程过程中,实现C函数和汇编子程序的互相调用。内容涉及C51函数及其相关段的命名规则,调用中两种参数的传递规则,最后,用两个具体的编程实例,说明C函数和汇编子程序相互调用方法。</SPAN><B></P>
<P align=justify><SPAN style="FONT-SIZE: 9pt"> <FONT
color=#800080>关键词</FONT></B> 函数名 段 参数传递</SPAN></P>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="100%">
<HR class=2 color=#800080 noShade width="80%">
</TD></TR></TBODY></TABLE>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD colSpan=3 vAlign=top width="100%"><B>
<P align=justify><SPAN style="FONT-SIZE: 9pt"><FONT color=#800080>1
引言</FONT></SPAN></B></P>
<P><SPAN style="FONT-SIZE: 9pt">
C语言是一种编译型程序设计语言,它兼顾了多种高级语言的特点,并可以调用汇编语言的子程序。用C语言设计开发微控制器程序已成为一种必然的趋势。Franklin
C51是一种专门针对Intel
8051系列微处理器的C开发工具,它提供了丰富的库函数,具有很强的数据处理能力,编程中对8051寄存器和存储器的分配均由编译器自动管理,因而,通常用C51来编写主程序。然而,有时也需要在C程序中调用一些用汇编A51编写的子程序。例如,以前用汇编语</SPAN></P></TD></TR>
<TR>
<TD vAlign=top width="47%"><SPAN
style="FONT-SIZE: 9pt">言编写的子程序、要求较高的处理速度而必须用更简练的汇编语言编写的特殊函数或因时序要求严格而不得不使用灵活性更强的汇编语言编写的某些接口程序。另一方面,在以汇编语言为主体的程序开发过程中,如果涉及到复杂的数学运算,往往需要借助C语言工具所提供的运算库函数和强大的数据处理能力,这就要求在汇编中调用C函数。本文所涉及的内容,正是讨论如何在Franklin
C51和A51的编程过程中,实现C函数和汇编子程序的互相调用。</SPAN><B>
<P align=justify><SPAN style="FONT-SIZE: 9pt"><FONT color=#800080>2
Franklin C51和A51接口所涉及的几个主要问题</FONT></SPAN></P>
<P align=justify><SPAN style="FONT-SIZE: 9pt"><FONT
color=#800080>2.1 C51函数名的转换及其命名规则</FONT></SPAN></B></P>
<P align=justify><SPAN style="FONT-SIZE: 9pt">
C51程序模块编译成目标文件后,其中的函数名依据其定义的性质不同会转换为不同的函数名,因此,在C和汇编程序的相互调用中,要求汇编程序必须服从这种函数名的转换规则,否则,将无法调用到所需的函数或出现错误。C51中函数名的转换规则如表1所列。</SPAN></P><B>
<P align=justify><SPAN style="FONT-SIZE: 9pt"><FONT
color=#800080>2.2 C51函数及其相关段的命名规则</FONT></SPAN></B></P>
<P><SPAN style="FONT-SIZE: 9pt">
一个C51源程序模块被编译后,其中的每一个函数以“?PR?函数名?模块名”为名的命名规则被分配到一个独立的CODE段。例如,如果模块“FUNC51”内包含一个名为“func”的函数,则其CODE段的名字是“?PR?FUNC?FUNC51”。如果一个函数包含有data和bit对象的局部变量,编译器将按“?函数名?BYTE和?函数名?BIT”命令规则建立一个data和bit段,它们代表所要传递参数的起始位置,其偏移值为零。这些段是公开的,因而它们的地址可被其它模块访问。另外,这些段被编译器赋予“OVERLAYABLE”标志,故可被L51连接/定位器作覆盖分析。依赖于所使用的存储器模式,这些段的段名按表2所列规则命名,在相互调用时,汇编语言必须服从C51有关段名的命名规则。</SPAN></P><B>
<P align=justify><SPAN style="FONT-SIZE: 9pt"><FONT
color=#800080>2.3 C51函数的参数传递规则</FONT></SPAN></B></P>
<P><SPAN style="FONT-SIZE: 9pt">
C和汇编接口的关键在于要弄清C函数的参数传递规则。Franklin
C51具有特定的参数传递规则,这就为二者的接口提供了条件。Franklin
C51函数最多可通过CPU寄存器传递三个参数,这种传递技术的优点是可产生与汇编语言相比的高效代码。表3是利用寄存器传递参数的规则。如果参数较多而使得寄存器不够用时,部分参数将在固定的存储区域内传送,这种混合的情况有时会令程序员在弄清每一个参数的传递方式时发生困难。如果在源程序中选择了编译控制命令“#pragma
NOREGPARMS”,则所有参数传递都发生在固定的存储区域,所使用的地址空间依赖于所选择的存储器模式。这种参数传递技术的优点是传递途径非常清晰,缺点是代码效率不高,速度较慢。当函数具有返回值时,也需传递参数,这种返回值参数的传递均是通过CPU内部寄存器完成,其传递规则如表4所示。</SPAN></P>
<P align=center><SPAN style="FONT-SIZE: 9pt">表3 寄存器参数传递规则</SPAN></P>
<P align=center><IMG alt="hr3.gif (2098 bytes)" height=114
src="c51pickfrankasm.files/hr3.gif" width=287></P>
<P><SPAN style="FONT-SIZE: 9pt"> 下面是几个说明参数传递规则的例子:</SPAN></P>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="100%"><SPAN style="FONT-SIZE: 9pt">func1(int a)
“a”在R6/R7中传递</SPAN></TD></TR></TBODY></TABLE>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="100%"><SPAN style="FONT-SIZE: 9pt">func2(int b,int
c,int *d)</SPAN></TD></TR>
<TR>
<TD width="100%"><SPAN
style="FONT-SIZE: 9pt">“b”和“c”分别在R6/R7和R4/R5中传递,</SPAN></TD></TR>
<TR>
<TD width="100%"><SPAN
style="FONT-SIZE: 9pt">“d”在R1/R2/R3中传递</SPAN></TD></TR>
<TR>
<TD width="100%"><SPAN style="FONT-SIZE: 9pt">func3(long
e,long f)</SPAN></TD></TR></TBODY></TABLE></TD>
<TD width="4%"></TD>
<TD vAlign=top width="49%">
<P align=center><SPAN style="FONT-SIZE: 9pt">表1
C51中函数名的转换</SPAN></P>
<P align=center><IMG alt="hr1.gif (4846 bytes)" height=311
src="c51pickfrankasm.files/hr1.gif" width=296></P>
<P align=center><SPAN style="FONT-SIZE: 9pt">表2
各种存储器模式下函数相关段<BR>名的命名规则</SPAN></P>
<P align=center><IMG alt="hr2.gif (3323 bytes)" height=203
src="c51pickfrankasm.files/hr2.gif" width=292></P>
<P align=center><SPAN style="FONT-SIZE: 9pt">表4 函数返回值传递规则</SPAN></P>
<P align=center><IMG alt="hr4.gif (4009 bytes)" height=290
src="c51pickfrankasm.files/hr4.gif"
width=289></P></TD></TR></TBODY></TABLE></TD>
<TD width="10%"></TD></TR></TBODY></TABLE>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="10%"></TD>
<TD width="80%"><SPAN style="FONT-SIZE: 9pt">
“e”在R4/R5/R6/R7中传递,“f”在参数段中传递SRC是一个十分有用的编译控制命令,它可令C51编译器将一个C源文件编译成一个相应的汇编源文件,而不是目标文件,在这个汇编文件中,我们可清楚地看到每一个参数的传递方法。例如,对于下面的C源文件(文件名ASM.C):</SPAN>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">#include
<reg51.h></SPAN></TD>
<TD width="67%"></TD></TR>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">#define uchar unsigned
char</SPAN></TD>
<TD width="67%"></TD></TR>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">uchar func(uchar
x,uchar y);</SPAN></TD>
<TD width="67%"><SPAN style="FONT-SIZE: 9pt">/*函数func
原型声明*/</SPAN></TD></TR>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">void
main(void)</SPAN></TD>
<TD width="67%"><SPAN style="FONT-SIZE: 9pt">/* 主函数 */</SPAN></TD></TR>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">{</SPAN></TD>
<TD width="67%"></TD></TR>
<TR>
<TD width="33%"><SPAN
style="FONT-SIZE: 9pt">func(0x12,0x34);</SPAN></TD>
<TD width="67%"><SPAN style="FONT-SIZE: 9pt">/* 调用函数func
*/</SPAN></TD></TR>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">}</SPAN></TD>
<TD width="67%"></TD></TR>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">uchar func(uchar
x,uchar y)</SPAN></TD>
<TD width="67%"><SPAN style="FONT-SIZE: 9pt">/* 函数func
*/</SPAN></TD></TR>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">{</SPAN></TD>
<TD width="67%"></TD></TR>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">return (x/y);</SPAN></TD>
<TD width="67%"><SPAN style="FONT-SIZE: 9pt">/* 计算x/y并返回结果
*/</SPAN></TD></TR>
<TR>
<TD width="33%"><SPAN style="FONT-SIZE: 9pt">}</SPAN></TD>
<TD width="67%"></TD></TR></TBODY></TABLE></TD>
<TD width="10%"></TD></TR></TBODY></TABLE>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="10%"></TD>
<TD width="80%">
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="100%"><SPAN style="FONT-SIZE: 9pt">
编译后将产生如下的汇编输出文件(限于篇幅有所省略):</SPAN></TD></TR></TBODY></TABLE>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="100%">
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="100%">
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="42%"><SPAN style="FONT-SIZE: 9pt">;ASM.SRC
generated from: ASM.C</SPAN></TD>
<TD
width="58%"></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD width="100%">
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="26%"><SPAN
style="FONT-SIZE: 9pt">?PR?main?ASM</SPAN></TD>
<TD width="23%"><SPAN style="FONT-SIZE: 9pt">SEGMENT CODE;
</SPAN></TD>
<TD width="51%"><SPAN
style="FONT-SIZE: 9pt">;主函数main代码段声明</SPAN></TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD width="100%">
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="26%"><SPAN
style="FONT-SIZE: 9pt">?PR?_func?ASM</SPAN></TD>
<TD width="23%"><SPAN style="FONT-SIZE: 9pt">SEGMENT CODE
</SPAN></TD>
<TD width="51%"><SPAN
style="FONT-SIZE: 9pt">;函数func代码段声明</SPAN></TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD width="100%">
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="26%"><SPAN style="FONT-SIZE: 9pt">PUBLIC
_func</SPAN></TD>
<TD width="74%"><SPAN
style="FONT-SIZE: 9pt">;公开函数名以便可被</SPAN></TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD width="100%">
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="26%"></TD>
<TD width="74%"><SPAN
style="FONT-SIZE: 9pt">;其它模块调用</SPAN></TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD width="100%"><SPAN style="FONT-SIZE: 9pt">PUBLIC
main</SPAN></TD></TR>
<TR>
<TD width="100%">
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD width="6%"></TD>
<TD width="94%"><SPAN style="FONT-SIZE: 9pt">RSEG
?PR?main?ASM</SPAN></TD></TR></TBODY></TABLE></TD></TR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -