目前多数开发人员都在用C51开发单片机程序,但在一些速度和时序敏感的场合下,C51略显不足,而有些特殊的要求必须通过汇编语言程序来实现,但是用汇编语言编写的程序远不如用C51语言编写的程序可读性好和效率高。因此采用C51与汇编语言混合编程是解决这类问题的最好方案。
混合编程多采用如下的编程思想,程序的框架或主体部分以及数据处理及运算用C51编写,而时序要求严格的部分用汇编语言编写。这种混合编程的方法将C语言和汇编语言的优点结合起来,已经成为目前单片机程序开发的最流行的编程方法。
C51与汇编语言混合编程的方法为:在把汇编语言程序加入到C语言程序前,须使汇编语言和C51程序一样具有明确的边界、参数、返回值和局部变量;必须为汇编语言编写的程序段指定段名并进行定义;如果要在它们之间传递参数,则必须保证汇编程序用来传递参数的存储区和C51函数使用的存储区是一样的。
在C51中使用汇编语言有以下3种方法:
1.C51代码中直接嵌入汇编代码
在C51代码中直接嵌入汇编指令有两种方法。其中:
第1种方法使用asm功能。当在某一行写入_asm “字符串”时,可以把双引号中的字符串按汇编语言看待,通常用于直接改变标志和寄存器的值或做一些高速处理,双引号中只能包含一条指令。
第2种方法使用#pragma asm功能。如果嵌入的汇编语言包含许多行,可以使用#pragma asm识别程序段,并直接插入编译通过的汇编程序到C51源程序中。此法的具体格式为:
#pragma asm
汇编指令行
#pragma endasm
这种方法是通过asm和endasm告诉C51编译器,中间的行不用编译为汇编行。
【例4-10】 编写程序从P1.0接口输出方波。要求Keil C环境下C51程序中嵌入汇编程序段。
注意,KeilμVision4的默认设置不支持asm和endasm,采用本法进行混合编程,需要在Keil C环境下,内嵌汇编时将SRC CONTROL激活。激活的方法是:在Project窗口中包含汇编代码的C文件上单击鼠标右键,选择“Options for”单击左边的“Gerate Assembler SRC File”和“Assemble SRC File”,使复选框由灰色变成黑色(有效)状态,这样才允许用伪指令asm和endasm选项。
直接嵌入汇编代码的方法:
(1)在C文件中要嵌入汇编代码片的方式为:
#pragma ASM
;Assembler Code Here
#pragma ENDASM
(2)在Project窗口中包含汇编代码的C文件上右键,选择“Options for...”,点击右边的“Generate Assembler SRC File”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;
(3)根据选择的编译模式,把相应的库文件(如Small模式时,是Keil\C51\Lib\C51S.Lib)加入工程中,该文件必须作为工程的最后文件;
(4)编译,即可生成目标代码。
2.控制命令SRC控制
本方式最为灵活简单,先用C51编写代码,然后用SRC控制命令将C51文件编译生成汇编文件(.SRC),在该汇编文件中对要求严格的部分进行修改,保存为汇编文件.ASM,再用ASM51进行编译生成机器代码。(www.xing528.com)
下面的例子阐述了编写C51程序调用汇编函数的一种方法,这个外部函数的入口参数是一个字符型变量和一个位变量,返回值是一个整型变量。本例中,先用C51写出这个函数的主体,然后用SRC控制指令编译产生asm文件,进一步修改这个asm文件就得到我们所要的汇编函数。该方法让编译器自动完成各种段的安排,提高了汇编程序的编写效率。
(1)按写普通C51程序方法,建立工程,在里面导入main.c文件和CFUNC.c文件。相关文件如下:
(2)在Project窗口中包含汇编代码的C文件上右键,选择“Options for...”,点击右边的“Generate Assembler SRC File”和“Assemble SRC File”,使检查框由灰色变成黑色(有效)状态;
(3)根据选择的编译模式,把相应的库文件(如Small模式时,是Keil\C51\Lib\C51S.Lib)加入工程中,该文件必须作为工程的最后文件;
(4)build这个工程后将会产生一个CFUNC.SRC的文件,将这个文件改名为CFUNC.A51(也可以通过编译选项直接产生CFUNC.A51文件),然后在工程里去掉库文件(如C51S.Lib)和CFUNC.c,而将CFUNC.A51添加到工程里。CFUNC.SRC文件如下:
(5)检查main.c的“Generate Assembler SRC File”和“Assemble SRC File”是否有效,若是有效则点击使检查框变成无效状态;再次build这个工程,到此你已经得到汇编函数的主体,修改函数里面的汇编代码就得到你所需的汇编函数了。
3.模块间接口
在此方式,汇编语言程序部分和C51程序部分位于不同的模块,或不同的文件,通常由C51程序模块调用汇编语言程序模块的变量和函数,例如调用汇编语言编写的中断服务程序。此法的C51模块和汇编模块的接口比较简单,分别用C51和A51对源文件进行编译,然后用L51连接obj文件即可。模块接口间的关键问题是C51函数与汇编语言函数之间的参数传递。C51中可借助寄存器、固定存储区两种参数传递方法。
由于C51语言对函数的参数、返回值传送规则、段的选用和命名都做了严格规定。因而,在混合编程时汇编语言要按照C51语言的规定来编写。这也是一般高级语言与低级语言混合编程的通用规则。当采用C51与汇编语言混合编程时,在技术上有两个问题:一个是在C51中如何调用汇编语言程序;另一个是C51程序如何与汇编语言程序之间实现数据的交换。当采用混合编程时,必须约定这两方面的规则,即命名规则和参数传递规则。
(1)命名规则。关于C51中如何调用汇编语言程序,是这样来解决的。在C51中被调用函数要在主函数中说明,在汇编语言程序中,要使用伪指令使CODE选项有效并申明为可再定位段类型,并且根据不同情况对函数名作转换,函数名的转换原则如表4-12所示。
表4-12 函数名的转换
在汇编语言中,变量、子程序或标号与其它模块共享时,必须在定义它们的模块开头说明为PUBLIC(公用),使用它们的模块必须在模块的开头包含EXTERN(外部的)。
例如,用汇编语言编写函数“toupper”,参数传递发生在寄存器R7中,以供C51函数调用。
(2)参数传递规则。关于参数传递问题,见前续章节。而当采用混合语言编程时,关键是入口参数和出口参数的传递,两种语言必须使用同一规则,否则传递的参数在程序中得不到。典型的规则是所有参数在内部RAM固定单元中传递,若是传递位变量,也必须位于内部可位寻址空间的顺序位中。当然参数在内部RAM中的顺序和长度必须让调用和被调用程序一致。事实上,内部RAM相同的数据块可共享。调用程序在进行汇编程序调用之前,在数据块中填入要传递的参数,调用程序在调用时,假定所需的值已在块中。
C51编译器可使用寄存器传递参数,也可以使用固定存储器或使用堆栈,由于MCS-51系列单片机的堆栈深度有限,因此多用寄存器或存储器来传递。利用寄存器最多只能传递3个参数,选择固定的寄存器,这种参数传递方法能产生高效率代码,参数传递的寄存器选择如表4-13所示。
表4-13 参数传递的寄存器选择
下面提供了几个说明参数传递方法的例子。
1)func1(int a),整型变量a是第1个参数,在R6,R7中传递。
2)func2(int b,int c,int*d),整型变量b是第1个参数,在R6,R7中传递,整型变量c是第2个参数,在R4,R5中传递,指针变量d是第3个参数,在R1,R2,R3中传递。
3)func3(long e,long f),长整型变量e是第1个参数,在R4~R7中传递,长整型变量f是第2个参数,只能在参数段中传递(第2个参数的传递寄存器R4~R7已被占用)。
4)func4(float g,char h),单精度浮点变量g是第1个参数,在R4~R7中传递,字符变量h是第2个参数,只能在参数段中传递(第2个参数的传递寄存器R5已被占用)。
注意:在汇编程序中,当前选择的寄存器组及寄存器ACC、B、DPTR和PSW都可能改变。当汇编程序被C51调用时,必须无条件地假设这些寄存器的内容已被破坏。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。