KEIL C51集成开发环境C和汇编语言的相互调用
[VIP专享]关于在 KEIL C51 中直接嵌入汇编
![[VIP专享]关于在 KEIL C51 中直接嵌入汇编](https://img.taocdn.com/s3/m/55c8b65ecc7931b764ce1505.png)
我找到了一些资料希望对你有用下周就要做实验了,由于听老师说机房位子可能比较少,对我这种蹭课的学生来说也就不敢奢望同选这门课的同学一样能够正常的在机房调试程序了,因此,我决定提前先在自己的工作室里把实验内容给过一遍。
第一个实验是关于嵌入式编程的,这个实验目的一方面是为了让我们熟悉ARM下编程的编译环境ADS和调试器ATX,另一方面是让我们掌握如何将c语言和汇编语言在实际编程中相互调用。
经过这两天靠自己不断的摸索,终于掌握了如何在编译环境中进行ARM编程,另外,还学会了在c中调用汇编程序的方法,以及如何通过linux自带的gcc编译嵌有汇编的c程序,总之,收获还是蛮多的哦,下面就总结一下吧。
1、c嵌汇编首先说一下关于GCC编译嵌有汇编语言的c语言吧,GCC编译的汇编语言不是我们上课时学的Intel x86汇编,而是AT&T汇编,两者的区别可以查看《Gcc使用的内嵌汇编语法格式小教程》。
下面是内嵌汇编的几种格式:语法__asm__(“instruction. ……instruction”); //Linux gcc中支持(注意asm的下划线均为两个否则GCC将会无法编译)__asm{instruction…instruction}; //ADS中支持(注意asm的下划线均为两个否则GCC将会无法编译)asm(“instruction [; instruction]”); //ARM C++中使用例1是我在linux环境下,编的嵌有汇编程序的c语言,并通过了GCC的编译:例1:#includeint plus(int a,int b){__asm__(“add %1,%0\n\t”:”+r”(a):”r”(b));return (c);}int main(){int a,b,c;a=2;b=1;c=plus(a,b);printf(“c=%d\n”,c);}这个程序应该是很简单的,但关键是子函数中嵌入的那段汇编程序,具体的写法可以参看其他文章。
KeilC51使用教程

Keil C语言程序设计示例教程(开发C8051F310)使用汇编语言或C语言要使用编译器,以便把写好的程序编译为机器码,才能把HEX可执行文件写入单片机内。
KEIL uVISION是众多单片机应用开发软件中最优秀的软件之一,它支持众多不同公司的MCS51架构的芯片,甚至ARM,它集编辑,编译,仿真等于一体,它的界面和常用的微软VC++的界面相似,界面友好,易学易用,在调试程序,软件仿真方面也有很强大的功能。
因此很多开发51应用的工程师或普通的单片机爱好者,都对它十分喜欢。
在这里以51单片机并结合C程序为例(汇编操作方法类似,唯一不同的是汇编源程序文件名后缀为“.ASM ”),图文描述工程项目的创建和使用方法。
1.首先我们要养成一个习惯:最好先建立一个空文件夹,把您的工程文件放到里面,以避免和其他文件混合,如下图, 创建了一个名为“PRJ_C8051”文件夹2.点击桌面上的Keil uVision4图标,出现启动画面:3.点击“project --- New uVision Project”新建一个工程:4.在对话框,选择放在刚才建立的“PRJ_C8051”文件夹下,给这个工程取个名为Test_C8051F310, 然后保存,工程的后缀为uvporj。
5.弹出一个框,在CPU类型下我们找到并选中“Silicon Laboratories. Inc.”下的C8051F3106.加入C8051起动码7.建立一个源程序文本8.在下面空白区别写入或复制一个完整的C程序:9.输入源程序文件名名称,示例输入“Test_C8051F310.c”,然后保存:10.把刚创建的源程序文件加入到工程项目文件中。
11.设置---目标(第1步~ 第4步)15.工程项目创建和设置全部完成!点击保持并编译16.在C8051F310中的C语言程序示例//-----------------------------------------------------------------------------// Includes// 在c8051f310.h在头文件中定义了C8051F310的寄存器、输入/输出的端口//-----------------------------------------------------------------------------#include <c8051f310.h> // SFR declarations//-----------------------------------------------------------------------------// 16-bit SFR Definitions for 'F30x//-----------------------------------------------------------------------------sfr16 TMR2RL = 0xca; // Timer2 reload valuesfr16 TMR2 = 0xcc; // Timer2 counter//-----------------------------------------------------------------------------// Global CONSTANTS//-----------------------------------------------------------------------------#define SYSCLK 24500000 / 8 // SYSCLK frequency in Hzsbit LED = P0^0; // LED='1' means ON//-----------------------------------------------------------------------------// Function PROTOTYPES//-----------------------------------------------------------------------------void SYSCLK_Init (void);void PORT_Init (void);void Timer2_Init (int counts);void Timer2_ISR (void);//-----------------------------------------------------------------------------// MAIN Routine//-----------------------------------------------------------------------------void main (void){// disable watchdog timerPCA0MD &= ~0x40; // WDTE = 0 (clear watchdog timer// enable)SYSCLK_Init (); // Initialize system clock to// 24.5MHzPORT_Init (); // Initialize crossbar and GPIOTimer2_Init (SYSCLK / 12 / 10); // Init Timer2 to generate// interrupts at a 10Hz rate.EA = 1; // enable global interruptswhile (1) // spin forever{}}//-----------------------------------------------------------------------------// SYSCLK_Init//-----------------------------------------------------------------------------//// This routine initializes the system clock to use the internal 24.5MHz / 8// oscillator as its clock source. Also enables missing clock detector reset.//void SYSCLK_Init (void){OSCICN = 0x80; // configure internal oscillator for// its lowest frequency RSTSRC = 0x04; // enable missing clock detector }//-----------------------------------------------------------------------------// PORT_Init//-----------------------------------------------------------------------------//// Configure the Crossbar and GPIO ports.// P3.3 - LED (push-pull)//void PORT_Init (void){// assignmentsXBR0 = 0x00; // no digital peripherals selectedXBR1 = 0x40; // Enable crossbar and weak pull-ups//P3MDOUT |= 0x08;P0MDOUT |= 0x03; // enable LED as a push-pull output}//-----------------------------------------------------------------------------// Timer2_Init//-----------------------------------------------------------------------------//// Configure Timer2 to 16-bit auto-reload and generate an interrupt at// interval specified by <counts> using SYSCLK/48 as its time base.//void Timer2_Init (int counts){TMR2CN = 0x00; // Stop Timer2; Clear TF2;// use SYSCLK/12 as timebase CKCON &= ~0x60; // Timer2 clocked based on T2XCLK;TMR2RL = -counts; // Init reload valuesTMR2 = 0xffff; // set to reload immediatelyET2 = 1; // enable Timer2 interruptsTR2 = 1; // start Timer2}//-----------------------------------------------------------------------------// Interrupt Service Routines//-----------------------------------------------------------------------------//-----------------------------------------------------------------------------// Timer2_ISR//-----------------------------------------------------------------------------// This routine changes the state of the LED whenever Timer2 overflows.//void Timer2_ISR (void) interrupt 5{TF2H = 0; // clear Timer2 interrupt flagLED = ~LED; // change state of LED}17.KEIL C语言与汇编语言的混合编程方法C语言中加入汇编语言模块的方法:例子:void func(){C语言代码……#pragma asmMOV R6,#23DELAY2: MOV R7,#191DELAY1: DJNZ R7,DELAY1DJNZ R6,DELAY2RET#pragma endasmC语言代码……}汇编部分需要用#pragma asm和#pragma endasm包起来18.KEIL C混合编程中的错误与解决方法1)Keil提示“asm/endasm”出错的解决方法如果只是像1中那样直接加入汇编代码的话,编译将会报错,错误如下:compiling sendata.c...sendata.c(81): error C272: 'asm/endasm' requires src-control to be active sendata.c(87): error C272: 'asm/endasm' requires src-control to be active Target not created解决方法如下:首先project workspace窗口右键单击包含有汇编部分的c语言文件名,然后在如上图所示的菜单中选择带有红色方框的选项在弹出的对话框中,将上图中红色方框选中的两项打上勾(默认的情况下,前面的勾是灰色的,要让这两项前的勾变为黑色的),点击确定。
51汇编调用C实例

51汇编中嵌入C51程序实战记录一.C文件处理1.调用的C文件开头加入:#pragma code small ;2.调用的C文件中要指定RAM 位置,例如:unsigned char m[4] _at_ 0x35 ;unsigned int n _at_ 0x4A ;unsigned int address _at_ 0x4C ;3. 其它函数文件直接调用,调用不包含参数传递,需要传递函数的需要再深入研究。
4.中断函数的处理,直接在C文件中写中断函数,特别注意寄存器的选用,一般要选择using 2 和 using 3. using 0 和 using 1已经别其它程序占用。
程序范例见下面代码,一个DMX512程序的C文件调用实例:#pragma code small#include "stc15w.h"#include <intrins.h>typedef unsigned char uchar;typedef unsigned int uint;sbit EN_DMX = P1^5;unsigned char m[4] _at_ 0x35 ;unsigned int n _at_ 0x4A ;unsigned int address _at_ 0x4C ;#define S1_S0 0x40 //P_SW1.6#define S1_S1 0x80 //P_SW1.7void dmx512_ini( ){ACC = P_SW1;ACC &= ~(S1_S0 | S1_S1); //S1_S0=0 S1_S1=0P_SW1 = ACC; //(P3.0/RxD, P3.1/TxD)address=500;n=0;EA=1;ES=1;REN=1;EN_DMX =0;PCON=0x00;SCON=0x90;}void Uart() interrupt 4 using 2{RI=0;if(RB8==0){n=0;return;};if((n>=address)&&(n<address+4))m[n-address]=SBUF;n++;}二.汇编文件中的处理:1.调用C文件中的子程序: EXTRN CODE ( dmx512_ini)2.其它按照汇编程序,下面的汇编实例内容:/*EXTRN CODE ( dmx512_ini)ORG 0000HLJMP mainORG 000100HMAIN:LCALL dmx512_iniloop:MOV A,35HLCALL DISPLAY_1LCALL DELAY1MSCPL LEDSJMP loopDELAY1MS:MOV R7,#01HDL1:MOV R6,#8EHDL0:MOV R5,#02HDJNZ R5,$DJNZ R6,DL0DJNZ R7,DL1RET*/3 . 项目文件中加入库文件 C51S.LIB:3.添加编译器选项:4.选择两个选项:5.编译文件Gary 编译2017-09-22。
第4章4.2C程序及汇编程序的相互调用

May 28, 2020
Neusoft Institute of Information
使用ADS的C语言编译器编译的C语言子程序
May 28, 2020
• 寄存器的使用规则:
Neusoft Institute of Information
1. 子程序通过寄存器R0~R3来传递参数。 这时寄存 器可以记作: A1~A3 , 被调用的子程序在返回前无 需恢复寄存器R0~R3的内容。
2. 在子程序中,使用R4~R11来保存局部变量,这时 寄存器R4~R11可以记作: V1~V8 。如果在子程序中 使用到V1~V8的某些寄存器,子程序进入时必须保存 这些寄存器的值,在返回前必须恢复这些寄存器的值, 对于子程序中没有用到的寄存器则不必执行这些操作。 在THUMB程序中,通常只能使用寄存器R4~R7来保存 局部变量。
AREA CALL_C,CODE,READONLY
IMPORTsum
ENTRY
start LDR SP,=0xA000
STR LR,[SP,#-4]! ;LR --> stack
MOV R0,#1
;R0 = 1
MOV R1,#2
;R1 = 2
MOV R2,#3
;R2 = 3
MOV R3,#5
;5 --> R3
各个浮点参数按顺序处理,为每个浮点参 数分配FP寄存器。分配的方法是:满足该浮点 参数需要的且编号最小的一组连续的FP寄存器。
第一个整数参数通过寄存器R0~R3来传递, 其他参数通过数据栈传递。
关于c语言和汇编语言相互嵌套调用的学习总结

关于c语言和汇编语言相互嵌套调用的学习总结在计算机编程中,C语言和汇编语言是两种常用的编程语言。
C语言是一种高级语言,而汇编语言则是一种低级语言。
尽管C语言在编程方面更为简单和人性化,但是汇编语言却更为底层和灵活。
因此,在一些特定的情况下,C语言与汇编语言会相互嵌套调用,以充分发挥各自的优势。
首先,理解C语言和汇编语言的基本特点是学习的关键。
C语言是一种结构化的高级语言,它具有变量和函数的特性。
C语言通过调用函数来完成特定的任务,使用变量来存储和操作数据。
相比之下,汇编语言是一种低级语言,它直接操作计算机硬件,使用寄存器和内存地址来存储和操作数据。
汇编语言的指令直接映射到底层的CPU指令。
其次,学习如何在C语言中嵌入汇编代码。
在C语言中,可以使用内联汇编语句来嵌入汇编代码。
为了实现这一点,需要使用特殊的语法。
在GCC编译器中,可以使用asm关键字来指定内联汇编代码。
内联汇编语句由汇编语句和C语言代码组成,以实现C函数内的底层操作。
通过内联汇编,可以直接访问底层硬件功能,并在C函数中实现特定的优化。
而在汇编语言中嵌入C代码则需要借助外部汇编调用接口。
在C语言中编写函数时,可以使用extern关键字声明函数为外部函数。
对于汇编语言而言,可以使用特定的语法和指令来调用C函数。
在调用C函数时,需要将参数传递给C函数,并处理返回值。
通过外部汇编调用接口,可以在汇编语言中利用C函数的高级功能,如数组操作、内存分配等。
当C语言和汇编语言相互嵌套调用时,需要注意以下几点。
首先,理解数据传递的原理。
C语言和汇编语言使用不同的参数传递方式。
C语言通常使用栈来传递参数,而汇编语言则使用寄存器。
在混合编程中,需要确保参数正确地传递给函数。
其次,需要注意变量的声明和使用。
C语言和汇编语言使用不同的编译规则和约定。
在混合编程中,需要正确地定义和使用变量,以免引起错误。
此外,需要注意寄存器的保存和恢复,以避免影响程序的正确执行。
C和汇编之间的函数调用.

●C 和汇编之间的函数调用ARM 工程中, C 程序调用汇编函数和汇编程序调用 C 函数时经常的事情,遵守ARM-Thumb 过程调用标准 ATPCS (ARM-Thumb Procedure Call Standard 。
ATPCS 标准—— ARM 编译器使用的函数调用规则(详见下面(温故知新 C 语言程序中的调用int main({printf("1234+5678=%d\n",sum(1234,5678;return 0;}请编写 sum 函数,实现两个数的相加。
int sum(int x,int y{int s;s=x+y;return s}C 程序调用汇编程序函数要点:1. 在汇编语言中,用该函数名作为汇编代码段的标识,定义函数代码, 最后用MOV PC,LR返回2. 在汇编语言中用 EXPORT 导出函数名3. 在 C 语言中用 extern 关键词声明函数原型。
4. 函数调用时参数传递规则:寄存器组中的 {R0-R3}作为参数传递和结果返回寄存器,如果参数数目超过 4个,则使用堆栈进行传递。
;工程 exp10_1_2;汇编函数文件 strcopy.s;把 R1指向的数据块复制到 R0指向的存储块。
AREA StrCopy,CODE,READONLYEXPORT strcopystrcopyLDRB R2,[R1],#1STRB R2,[R0],#1CMP R2,#0BNE strcopyMOV PC,LREND; C 文件 main.c;调用 strcopy 函数extern void StrCopy(char *d,const char *s; //声明 strcopy 为外部引用符号int main(void{const char *src=” Source ” ;char dest[12]=” Destination ” ;strcopy(dest,src; //调用汇编函数 strcopyprintf(“ After copying:\n” ;printf(“ %s\n%s\n” ,src,dest;return(0;}根据 ATPCS 的 C 语言程序调用汇编函数规则,参数由左向右依次传递给寄存器 R0~R3,可知汇编函数 strcopy 在 C 程序中的原型应该为:void strcopy(char *d,const char *s;其中,参数 d 对应 R0,参数 s 对应 R1。
C51与汇编语言混合编程之一

C51与汇编语言混合编程之一
1、函数内部混合编程若想在C 语言函数内部使用汇编语言,应使用以下Cx51 编译器控制命令:
#pragma asm
;;;Assembly code
#pragma endasm
功能作用:
asm 和endasm 命令用于将其标记的汇编程序合并到.SRC 文件中。
这个带有asm 和endasm 块标记的源程序可看作是在线嵌入式汇编程序。
从这点来说,此命令有些类似于#define 命令。
具体实现:
(1)编译器设置及SRC 文件的产生
.SRC 文件在命令行编译模式下是使用SRC 编译器控制命令产生的,在IDE 环境中可以为需要产生SRC 文件的C 源文件设置特定选项:
l 右键单击Project Workspace 下的文件标签
l 选择Options for file 项,打开Options – Properties 页。
l 选中Generate Assembler SRC file 项
l 选中Assembler SRC file 项
(2)添加库文件
根据选择的编译模式,把相应的库文件添加到工程下面,如在small 模式下,需将keil\c51\lib\c51s.lib 文件加入工程中。
在Keil 安装目录下的\C51\LIB\ 目录的LIB 文件如下:
C51S.LIB - 没有浮点运算的Small modelC51C.LIB - 没有浮点运算的。
汇编与C语言的相互调用

汇编与C语言的相互调用汇编与C语言的相互调用一、实验目的阅读Embest EduKit-III启动代码,观察处理器启动过程;学会使用Embest IDE辅助信息窗口来分析判断调试过程和结果;学会在Embest IDE环境中编写、编译与调试汇编和C语言相互调用的程序。
二、实验设备硬件:PC机。
软件:Embest IDE Pro2004集成开发环境,Windows98/2000/NT/XP。
三、实验原理1.ARM过程调用ATPCS(ARM)ATPCS是一系列用于规定应用程序之间相互调用的基本规则,这此规则包括:支持数据栈限制检查;支持只读段位置无关(ROPI);支持可读/写段位置无关(RWPI);支持ARM程序和Thumb程序的混合使用;处理浮点运算。
使用以上规定的ATPCS规则时,应用程序必须遵守如下:程序编写遵守ATPCS;变量传递以中间寄存器和数据栈完成;汇编器使用-apcs开关选项。
关于其他ATPCS规则,用户可以参考ARM处理器相关书籍或登录ARM公司网站。
程序只要遵守ATPCS相应规则,就可以使用不同的源代码编写程序。
程序间的相互调用最主要的是解决参数传递问题。
应用程序之间使用中间寄存器及数据栈来传递参数,其中,第一个到第四个参数使用R0-R3,多于四个参数的使用数据栈进行传递。
这样,接收参数的应用程序必须知道参数的个数。
但是,在应用程序被调用时,一般无从知道所传递参数的个数。
不同语言编写的应用程序在调用时可以自定义参数传递的约定,使用具有一定意义的形式来传递,可以很好地解决参数个数的问题。
常用的方法是把第一个或最后一个参数作为参数个数(包括个数本身)传递给应用程序。
ATPCS中寄存器的对应关系如表3-5所列:ARM寄存器ARPCS别名APTCS寄存器说明R0~R3a1~a4参数/结果/scratch寄存器1-4R4v1局部变量寄存器1R5v2局部变量寄存器2R6v3局部变量寄存器3R7v4,wr局部变量寄存器4Thumb状态工作寄存器R8v5ARM状态局部变量寄存器5R9v6,sb ARM状态局部变量寄存器6RWPI的静态基址寄存器R10v7,s1ARM状态局部变量寄存器7数据栈限制指针寄存器R11v8ARM状态局部变量寄存器8R12ip子程序内部调用的临时(scratch)寄存器R13sp数据栈指针寄存器R14lr链接寄存器R15PC程序计数器2.main()函数与__gccmain()当应用程序中包含了main()函数,将会引起对C运行时库的初始化。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第27卷第1期 2008年2月 兰州 交通大学学报
Journal of Lanzhou Jiaotong University V()1.27 No.1
Feh.2008
文章编号:1001—4373(2008)01—013卜O4
KEIL C5 1集成开发环境C和汇编语言的相互调用
严天峰, 王耀琦 (兰州交通大学电子与信息工程学院,甘肃兰州 730070) 摘要:目前C语言已成为开发单片机项目的主要工具,但一些特殊的应用场合仍然需要汇编语言编写程序,如编 写时序要求非常严格的接口协议时,这必然涉及到C与汇编的相互调用,即混合编程的问题.详细介绍了KE1L C51环境下的C和汇编语言相互调用的方法和原则,并具体说明混合编程的细节和应注意的问题. 关键词:KEIL C51汇编调用混合编程 中图分类号:TP311.11 文献标识码:A
目前,C语言已是单片机应用系统的主流编程 工具,它具有代码可靠性高,可移植性好,易于维护 的特点.特别是德国KEII 公司推出功能强大的基 于WINDOWS平台的51系列单片机集成开发工具 /*Vision之后,这一趋势越发明显.采用C语言几乎 可以完成江编语言的所有工作,可以大在提高程序 的开发效率.但在一些特殊应用的场合仍然需要通 过汇编语言编写程序,比如对时序要求非常严格的 接口协议和中断向量的地址处理等等.另外还存在 种情况,即程序员原先已用汇编语言编写了大量 的子程序,现在虽然改用C语言开发设计,但又不 想重写代码;或者想充分发挥C语言在数值计算的 优势,通过汇编语言调用C来实现复杂的数学计 算.这必然要涉及到C与汇编的相互调用,即混合 编程的问题.C与汇编的混合编程,重点是参数的传 递和函数值的返回以及C51对目标代码的段管理, 这是嵌人式系统混合编程过程中实现开发和运行效 率统一的关键环节. 1 C51编译器对程序和数据代码段的管理 C51能否成功调用汇编语言的前提条件之一是 汇编程序的编写应符合C51编译器的编译规则.事 实上,C51对汇编程序的调用就是对函数的调用.因 此,要实现C和汇编的相互调用,首先要清楚的是 个被C51编译后的函数,其程序代码段和数据段 的转换规则.C51对所属模块的各个函数进行编译 收稿日期:2007—09—13 作者简介:严天峰(1970一),男,四川平昌人,副教授 时,每个函数都生成一个以?PR?函数名?模块名 为段名的程序代码段,如果该函数包括无明确存储 器类型声明的局部变量,将生成一个字节类型的局 部数据段;当参数中有位变量时,还将生成一个位类 型的局部位段,用来存放在函数内部已定义的位标 量和位变量参数.在SMAI I 编译模式下,局部段 的命名原则如表1所示_1]. 表1局部段的命名原则 Tab.1 Naming principle of local se ̄ent
每个局部段的段名表示该段的起始地址.假如, 模块example包含一个名为“func”的函数,其程序 代码段的命名为”?PR?func?example,其中func (函数名)即为该段的起始地址.如果func函数包含 有DATA和BIT对象的局部变量,局部数据段和 局部位段的起始地址则定义为?func?BYTE和? func?BIT,它们代表所传递的参数的初始位置. C51编译器将源程序的函数名转换为汇编格式的目 标文件时,转换后的函数名要根据参数传递的性质 不同而改变,当C和汇编程序互相调用时,汇编程 序的编写必须符合这种转换规则,否则编译器将会 出现错误提示.表2为函数名的转换规则l_1].
维普资讯 http://www.cqvip.com 132 兰州 交通 大学学 报 第27卷 void func(void) 函数类型Fune(形参) Fune_(void)reentrant
函数内部无参数在寄存器内部传递,函数名不做改变. 函数内部有参数在寄存器内部传递,函数名前加“一”下划线. 原函数为再入函数时,函数名前加“一?”,表明有参数在数据存储器内部传递. 假设函数rune的C源程序如下所示,现分析经 汇编后产生的代码. //c源程序: void(unsigned char a) {bit c; c=0;} 汇编后的代码(文件ExAMPLE.SRC): NAMEExAMPLE;模块名 PRfune?D MPLE SEGMENT CODE;定义程
序代码段 DT一fune?D LE SE 诬NT DATA;定义 局部数据段
c?041:DBIT 1;a?041标号为该BIT位地址 void rune(unsigned char a) RsEG?PR?fune?D MPLE;程序代码段 rune:;程序代码段起始地址 MOV a?040,R7;R7参数传递到地址a?040 ;{ ;bit c; ;c一0; CLR c?041 ;} RET END
Ⅸunc?ExA LE sEGMENT瑚T.定义局部 2 参数的传递和返回
位段 一………一。。 PUBLICrune;PUBLIC声明,表明该函数可被其它模 块调用 RSDG?DT?fune?D MPLE;局部数据段
一funeBYTE:;局部数据段起始地址 a?040:DS 1;a?040标号为该字节的地址 RSEG?BI?fune?EXAMPI,E;局部位段
一fune?BIT:;局部位段起始地址
C和汇编的另一个关键问题是参数的传递和返 回.函数调用时,默认为通过寄存器进行参数传递. 当采用预处理编译控制指令#pragma NOREG— PARMS时,参数将通过固定的存储区域传递.表3 为参数在寄存器内部传递时的传递规则 .
表3寄存器参数传递规则 Tab.3 Passing rulesof registerparameters
例如在函数func(*P,unsigned char a,un— signed char b)中,指针“P”通过R1,R2,R3寄存器 进行参数传递,其中R1传递低字节,R2传递高字 可从前面介绍的EXAMPI E.SRC例子中清楚的 看到,通过R7寄存器将形参“a”的内容传递到了地 址a?040.当C程序调用的汇编函数有参数返回 节.“a”通过R7传递,“b”则通过R5传递.读者也 时,其返回值的参数传递见表4[引. 表4函数返回值的参数传递 Tab.4 Parameterpassingoffunction returned value
维普资讯 http://www.cqvip.com 第1期 严天峰等:KEIL C51集成开发环境C和汇编语言的相互调用 3 C51和汇编语言相互调用的方法 3.1 C51调用汇编 下面以C51调用一个ADCo8O9模数转换子程 序为例来具体说明C51调用汇编的方法.在C主程 序调用汇编子程序之前,应先用”extern”声明被调 用的汇编程序是一个外部函数;同时在汇编程序中 则要用“PUBI IC”声明该子程序可以被其它模块调 用. C51程序: #include<reg51.h> #include<stdio.h> #define uchar unsigned char extern uchar ad0809(uchar p);//说明被调用的 ad0809汇编子程序是一个外部函数, //采用一般指针传递参数 extern delasm(uchar time)}//被调用delasm延时子程 序是一个外部函数 main() { uchar data adc_data[8]}//ADCo809转换后的8通道 采样值放入adc_data数组 while(1) ad0809(adc_data);//调用的ad0809汇编子程序,通过 数组名进行参数传递 delasm(2)}//调用的delasm延时子程序 } AD0809 A/D转换子程序: EOCEQUP1.4 NAME ADCo809;模块名为 809 7 PR?一 )o8097 ADO0809 SEGMENT C0DE;子程 序代码段声明,一AD0809为函数名,“一“表明有参数在寄存 器内部传递 PUBLIC—AD0809;用“PUBLIC”声明该函数可以被 其它模块调用 RSEG?PR?一AD08097 ADCo809;AD0809子程序代 码段起始位置 AD0809: MOV A,R1;R1传递数组adc_data[8]首址 MOV R0,A MOVR4,#00H MOVR7,#8 MOVDPTR,#0FDF8H SAM:M0V A,R4 M0VX@D rR,A JB EOC,¥ M0VX A,@DPTR MOV@R0,A INC DPTR INC R0 INCR4 DJNZR7,SAM RET END 上面的例程中,在C程序里,首先对汇编子程 序AD0809进行外部函数声明,extern uehar ad0809(uchar*p)表明传递的是一个一般指针变 量.主函数用ad0809(ado—data)调用汇编子程序,在 调用ad0809子程序的过程中,将数组名adc—data (即该数组的首地址)以指针的方式进行参数传递, R1存放该数组的首地址.在AD0809汇编子程序 中,将R1地址内容赋给R0,而以R0寻址的连续8 个地址空间存放的就是ADCo8O9八个通道的采样 值,经过参数传递后,数组ade—data[8]各元素的内 容就是A/D转换后的结果.函数ad0809(uchar* p)中的形参P被定义为一个一般指针。参数传递通 过R1、R2、R3寄存器进行;如果写为uchar data p,形参P则被定义为一个基于data区的指针,按表 3可知,参数传递通过R7进行,读者可自行改动测 试. 3.2汇编调用C 下面的例子是一个汇编调用C程序的过程,汇 编程序A_FUNC.ASM的60H至63H分别存放两 个int类型的整型数值,count.C实际上是一个2字 节乘法的运算函数,同时将一个4字节长整类型的 结果返回给汇编,程序代码如下: //主函数: #include<stdio.h> extem void a_func(void)f说明被调用的a rune子程 序是一个外部函数 voidmain(void) { ̄func();};汇编程序A_FUNC.ASM: NAMEA..FUNC,模块名 PRa_func?A_FUNC SEGMENT CODE;程序代 码段声明 EXTRN CODE(count);声明被调用的eounL c是外 部函数 PUBLICa_func RSEG?PR?a_func?A_FUNC ̄程序代码段起始 a..func; USING0 MOV 60h,#23h}60H至63H存放两个整型数值, 60H存放乘数高字节