




已阅读5页,还剩43页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1,2,第6章C51与汇编语言混合编程,6.1、C51与汇编语言混合编程概述6.2、C51和A51程序接口基础6.3、混合编程的实现,3,6.1C51与汇编语言混合编程概述,在一个应用程序中,根据每个任务的具体特点和要求,用不同的编程语言编写源程序,最后通过编译/连接器生成一个可执行的完整程序,这种编程方式称为混合编程。,汇编语言特点:优点:执行速度快、效率高、实时性强、与硬件结合紧密。缺点:编程难度大、可读性差,不便于移植、开发时间长。C语言特点:优点:编程容易、可移植性强、支持多种数据类型,能直接对硬件进行操作,效率高。缺点:实时处理弱于汇编语言,无法准确定时。混合编程特点:效率高、速度快、易于编程、可读性、可移植性好,使用范围广,4,单片机程序的编译过程:,无论是C语言还是汇编语言,源程序都要被转换成目标代码(机器语言),单片机才能识别。在Keil中程序的编译过程如图61所示。,图61程序编译连接过程,在单片机混合编程中,C模块与汇编模块的接口简单,分别用C51和A51对源文件进行编译,然后经连接定位器L51产生可下载到程序存储器的十六进制可执行文件。,5,6.2C51和A51程序接口基础,C语言与汇编语言程序的连接,在技术上有两个问题:一个是C语言程序与汇编语言程序如何相互调用;另一个是C语言程序和汇编语言程序如何实现相互之间的数据传递。混合编程中,必须约定两个规则,即命名规则和参数传递规则。6.2.1C51函数名的转换及其命名规则C51程序模块编译成目标文件后,其中的函数名要依据其定义的性质转换为相应不同的函数名。因此,在C和汇编程序的相互调用中,要求汇编程序必须服从这种函数名的转换规则,否则将无法调用到所需的函数甚至出现错误。C51中函数名的转换规则如表61所示,其汇编符号名全部转换为大写。,6,表61C51中函数名的转换规则,7,6.2.2C51函数及其相关段的命名规则,一个C51源程序模块被编译后,其中的每个函数以“?PR?函数名?模块名”为命名规则被分配到一个独立的CODE段。例如,如果模块“FUNC51”内包含一个名为“func”的函数,则其CODE段的名字是“?PR?FUNC?FUNC51”。如果一个函数包含有data或bit类型的局部变量,编译器将按“?函数名?BYTE”或“?函数名?BIT”命名规则建立一个data或bit段,它们代表所要传递参数的起始位置,其偏移量为0。这些段是公开的,因而它们的地址可以被其它模块访问。这些段被编译器赋予“OVERLAYABLE”标志,可被L51连接/定位器作覆盖分析。依据所使用的存储器模式,这些段按表62所列规则命名,在相互调用时,汇编语言必须服从C51有关段名的命名规则。,8,表62各种存储模式下C51函数段名的命名规则,9,6.2.3C51函数的参数传递规则,C51中调用汇编程序时参数传递有两种方式,一种是通过寄存器传递,一种是通过固定存储区传递。1通过寄存器传递参数KeilC51规定,调用函数时,通过寄存器最多可传递3个参数,余下的通过固定存储区传递。如果在源程序中采用了编译控制命令“#pragmaNOREGPARMS”,则所有参数传递都发生在固定的存储区域,所使用的地址空间依赖于所选择的存储模式。用寄存器传递参数的函数在编译时被C51编译器在函数名前加了一个“_”的前缀,用固定存储区传递参数的函数转换成的函数名没有下划线,如表61所示。不同的参数用到的寄存器不一样,不同的数据类型用到的寄存器也不同。表63是利用寄存器传递参数的规则。,10,表63C51利用寄存器传递参数规则,其中,int型和long型数据传递时,低地址寄存器中放数据的高位字节,高地址寄存器中放数据的低位字节;float型数据满足IEEE格式,R4中存放阶码和符号位,尾数按从高位到低位的顺序依次存放在寄存器R5、R6和R7中;通用指针的存储类型存放在R3中,高位在R2,低位在R1。如果某一函数的形式参数有两个或更多,当发生寄存器冲突时,后者改为通过固定存储区传递。,11,【例61】函数参数传递举例。,func1(inta)a是第一个参数,在R6,R7中传递。func2(intb,intc,int*d)“b”是第一个参数,在R6,R7中传递;“c”是第二个参数,在R4,R5中传递;“d”是第三个参数,在R1,R2和R3中传递。func3(longe,longf)“e”是第一个参数,在R4R7中传递;“f”是第二个参数,不能在寄存器中传递,只能在固定存储区中传递。func4(floatg,charh)“g”是第一个参数,在R4R7中传递;“h”是第二个参数,必须在固定存储区中传递。,12,2通过固定存储区传递,通过固定存储区传递参数的优点是传递途径非常清晰,缺点是代码效率不高,速度较慢。用固定存储区传递参数给汇编程序,参数段首地址通过名为“?函数名?BYTE”的符号确定。当传递位值时,使用名为“?函数名?BIT”的符号保存位参数段首地址。所有传递的参数存放在以首地址开始递增的存储区内,即使通过寄存器传递参数,参数也将在这些段中分配空间,参数按声明的先后在每个段中顺序保存。用作参数传递的固定存储区可能在内部数据区或外部数据区,由存储模式决定。SMALL模式的参数段用内部数据区,COMPACT和LARGE模式用外部数据区。,13,3函数返回值,当函数具有返回值时,也需传递参数,这种返回值的传递是通过51内核单片机内部寄存器完成的,其传递规则如表64所示。,14,表64函数返回值所用寄存器分配,15,【例62】C51的函数名转换规则、段命名规则及参数传递规则举例。,/*文件名:DIV.c功能:计算x/y*/#include#defineucharunsignedcharucharfunc(ucharx,uchary);/函数func原型声明voidmain(void)/主函数func(0 x12,0 x34);/调用函数funcwhile(1);ucharfunc(ucharx,uchary)return(x/y);/计算x/y并返回结果,16,/*文件名:DIV.SRC说明:此文件是DIV.c编译后的汇编输出文件(限于篇幅,有所省略)*/?PR?main?DIVSEGMENTCODE;主函数main代码段声明?PR?_func?DIVSEGMENTCODE;函数func代码段声明EXTRNCODE(?C_STARTUP);使用其它模块中的符号?C_STARTUPPUBLIC_func;公开函数名,以便可以被其它模块调用PUBLICmain;#include;#defineucharunsignedchar;ucharfunc(ucharx,uchary);voidmain(void)RSEG?PR?main?DIV,17,main:;主函数代码段起始USING0;SOURCELINE#4;SOURCELINE#5;func(0 x12,0 x34);SOURCELINE#6MOVR5,#034H;R5传递第二个char参数MOVR7,#012H;R7传递第一个char参数LCALL_func;调用函数func?C0001:;while(1);SOURCELINE#7SJMP?C0001;ENDOFmain;,18,;ucharfunc(ucharx,uchary)RSEG?PR?_func?DIV_func:;函数func代码段起始USING0;SOURCELINE#9;Variabley?141assignedtoRegisterR5;Variablex?140assignedtoRegisterR7;SOURCELINE#10;return(x/y);SOURCELINE#11MOVA,R7;计算x/yMOVB,R5DIVABMOVR7,A;结果经R7返回,19,;SOURCELINE#12?C0004:RET;返回;ENDOF_funcEND;结束上面给出了一个C51程序及其编译后的程序清单,可以看出,函数func有2个char型参数,通过R7,R5传递,所以转换成汇编函数名_func,返回值通过R7传递回主函数。如果在前述的DIV.C源文件中使用“#pragmaNOREGPARMS”控制命令,禁止寄存器内参数传递,则所有参数均通过固定的存储区传递。其编译后的汇编输出文件如下:,20,?PR?main?DIVSEGMENTCODE;主函数main代码段声明?PR?func?DIVSEGMENTCODE;函数func代码段声明?DT?func?DIVSEGMENTDATAOVERLAYABLE;局部变量内部数据段声明EXTRNCODE(?C_STARTUP);使用外部模块?C_STARTUPPUBLIC?func?BYTE;公开函数func中的data区的局部变量PUBLICfunc;公开函数名,以便可以被其它模块调用PUBLICmainRSEG?DT?func?DIV?func?BYTE:;局部变量内部存储区首地址x?140:DS1ORG1y?141:DS1,21,;#include;#defineucharunsignedchar;#pragmaNOREGPARMS;ucharfunc(ucharx,uchary);voidmain(void)RSEG?PR?main?DIVmain:;主函数代码段起始USING0;SOURCELINE#5;SOURCELINE#6;func(0 x12,0 x34);SOURCELINE#7MOV?func?BYTE,#012H;固定存储区首地址单元传递第一个参数MOV?func?BYTE+01H,#034H;固定存储区首地址加1单元传递第二个参数LCALLfunc;调用函数func,22,?C0001:;while(1);SOURCELINE#8SJMP?C0001;ENDOFmain;ucharfunc(ucharx,uchary)RSEG?PR?func?DIVfunc:;函数func代码段起始USING0;SOURCELINE#10;SOURCELINE#11;return(x/y);SOURCELINE#12,23,MOVA,x?140;计算x/yMOVB,y?141DIVABMOVR7,A;结果经R7返回;SOURCELINE#13?C0004:RET;返回;ENDOFfuncEND;结束,24,6.3混合编程的实现,KeilC51编译器支持在C51程序中直接插入汇编语言,也可以调用以汇编语言编写的子程序。6.3.1C51程序中嵌入汇编程序有时需要在C51程序中嵌入用汇编语言编写的一个小程序段,来对硬件进行操作,提高程序的可靠性和灵活性。下面是C51文件中嵌入汇编语言的一般步骤。第一步:通过预编译命令“#pragmaasm”和“#pragmaendasm”在C语言代码中插入汇编语言代码。,25,#includesbitP1_1=P11;voidmain()while(1)P1_1=1;#pragmaasmMOVR7,#12;2TDEL:MOVR6,#250;2TDJNZR6,$;4TDJNZR7,DEL;4T#pragmaendasmP1_1=0;,【例63】用C语言程序中插入汇编语言延时程序的方法,编程实现从P1.1引脚输出周期为2ms的方波(设STC12C5A60S2单片机系统时钟频率为12MHz)。,#pragmaasmMOVR7,#12DEL:MOVR6,#250DJNZR6,$DJNZR7,DEL#pragmaendasm,26,第二步:在KeilC51环境下,在Project窗口中包含汇编代码的C文件上单击右键,在弹出的快捷菜单中选择“Optionsfor”命令,再点击选中右边的“GenerateAssemblerSRCFile”和“AssemblerSRCFile”复选框,使检查框由灰色(无效)变成黑色(有效)状态。第三步:根据选择的编译模式,把相应的库文件(如Small模式时,是KeilC51LibC51S.Lib)加入到工程中,该文件必须作为工程的最后文件。如果没有做这一步编译,则会出现如下警告“UNRESOLVEDEXTERNALSYMBOL”。,27,库文件与编译模式的关系如下:C51S.LIB_没有浮点运算的Small模式C51C.LIB_没有浮点运算的Compact模式C51L.LIB_没有浮点运算的Large模式C51FPS.LIB_带浮点运算的Small模式C51FPC.LIB_带浮点运算的Compact模式C51FPL.LIB_带浮点运算的Large模式第四步:编译,生成目标代码。,28,6.3.2C51与汇编函数的相互调用,在汇编代码比较短的场合,可以使用在C51程序中直接嵌入汇编语言的方法。如果需要汇编语言实现的功能比较复杂,就需要用汇编语言编写函数,此时就要用到C51程序调用汇编函数的方法。当然,有时候也需要用汇编调用C51函数。无论是C51调用汇编函数,还是汇编调用C51函数,其操作是完全一致的。当我们需要利用函数进行混合编程时,只需分别用C语言和汇编语言把函数写好,然后在C语言程序(汇编程序)中调用汇编函数(C函数)。也可以先用C语言编写所有的代码,包括需要汇编语言实现的部分,然后采用编译控制指令SRC对需要汇编语言实现的函数进行编译,编译后将产生一个与C文件同名的汇编语言源文件,该文件的扩展名为.SRC,根据需要再对该文件进行精炼、修改。下面分别介绍这两种方法。,29,1.混合项目文件编程,混合项目文件编程就是把用C语言编写的程序保存为扩展名为.C的C语言文件,把用汇编语言编写的程序保存为扩展名为.asm、.SRC或者.A51的汇编语言文件,然后把这些文件导入到同一个工程下进行编译连接的方法。在C语言中调用汇编程序时,对被调用函数(汇编语言函数)要在主调函数(C语言函数)所在文件中作出声明,并且对汇编语言程序有以下要求:要使用SEGMENT伪指令定义可再定位的CODE段。要根据不同情况对函数名进行转换,见表61。要使用PUBLIC伪指令将被调用函数说明为外部可用函数。若有参数传递,按照表63所列的规则使用参数。若有返回值,按照表64所列规则存入寄存器。,30,【例64】编程实现从单片机P1.0引脚输出周期为4ms的方波,同时从P1.1引脚输出周期为8ms的方波(设单片机系统时钟频率为12MHz)。,分析:分别用汇编语言和C语言设计3个模块程序如下:模块1:用C语言编写主程序,使P1.1引脚输出周期为8ms的方波;模块2:用C语言编程,使P1.0引脚输出周期为4ms的方波;模块3:用汇编语言编写延时1ms的程序。程序执行时用模块1调用模块2获得8ms方波,模块2调用模块3,并向汇编程序传递字符型参数(x=2),实现2ms延时。程序如下:,31,模块1(文件名pulse1.c):#include#defineucharunsignedcharsbitP1_1=P11;externvoiddelay4ms(void);/外部函数delay4ms()声明voidmain()while(1)P1_1=0;delay4ms();/调用模块2延时4msP1_1=1;delay4ms();/调用模块2延时4ms,32,模块2(文件名pulse2.c):#include#defineucharunsignedcharsbitP1_0=P10;externdelay1ms(ucharx);voiddelay4ms(void)P1_0=0;delay1ms(2P1_0=1;delay1ms(2);,33,模块3(文件名pulse3.asm):PUBLIC_DELAY1MS;用PUBLIC声明_DELAY1MS为其它函数调用,以“_”为前缀的函数名,表示该函数通过寄存器传递参数DELAYSEGMENTCODE;定义DELAY段为再定位程序段,DELAY是用户任意起的段名RSEGDELAY;选择DELAY为当前段_DELAY1MS:DELA:MOVR6,#12;2TLOP1:MOVR5,#250;2TDJNZR5,$;4TDJNZR6,LOP1;4TDJNZR7,DELA;R7中数值为C;程序传递过来的参数,参数为2则延时2msEXIT:RETEND,34,本例用Keil软件对程序进行编译、调试时,先新建一个项目,再建立3个文件,在文件中编辑好各个模块代码并保存,然后将这3个文件加入项目中,进行编译和调试。本例只有1个传递参数,用寄存器传递即可。如果参数个数多于3个,则需通过固定存储区传递。通过固定存储区传递参数,可以在C程序中建立数组,将数组首地址(数组名)作为参数传递给被调用的汇编函数,汇编函数即可使用从该首地址开始的存储区;也可以在汇编程序中建立C程序变量所需数据段以供参数传递。现举例说明。,35,【例65】C程序提供5个参数,汇编完成该5个数的求和运算,并将和保存在片内RAM30H单元并供C程序使用。,方法一:通过数组传递参数模块1:C语言程序(文件名sum1.c)#include#defineucharunsignedcharexternucharasmadd1(uchar*);/定义外部汇编函数asmadd1voidmain()ucharidatabuf5=1,2,3,4,5;/数组中存放待计算的数据uchar*pp,sum;pp=0 x30;/pp指针变量指向片内RAM30H单元asmadd1(buf);/调用汇编函数,传递参数为数组首地址sum=*pp;/sum存放模块2传递过来的参数while(1);,36,模块2:汇编语言程序(文件名asmadd1.asm)PUBLIC_ASMADD1;_ASMADD1为其它模块调用DTESEGMENTCODE;定义DTE段为再定位程序段RSEGDTE;选择DTE为当前段_ASMADD1:PUSHACC;保护现场MOVA,R0PUSHACCMOVA,R2PUSHACCMOVA,R7;取BUF地址MOVR0,A;R0指向存放地址MOVA,#0MOVR2,#5,37,LOOP:ADDA,R0INCR0DJNZR2,LOOPMOV30H,A;和存片内RAM30H单元POPACC;恢复现场MOVR2,APOPACCMOVR0,APOPACCRETEND,38,方法二:在汇编程序中建立数据段传递参数,模块1:C语言程序(文件名sum2.c)#include#defineucharunsignedcharexternucharasmadd2(ucharx1,ucharx2,ucharx3,ucharx4,ucharx5);/外部函数说明voidmain()ucharx1=0 x01;/传递参数赋值ucharx2=0 x02;ucharx3=0 x03;ucharx4=0 x04;ucharx5=0 x05;uchar*pp,sum;pp=0 x30;/pp指针变量指向片内RAM30H单元asmadd2(x1,x2,x3,x4,x5);/调用汇编函数sum=*pp;/sum存放模块2传递过来的参数while(1);,39,模块2:汇编语言程序(文件名asmadd2.asm)PR_ASMADD2SEGMENTCODE;名为ASMADD2段为代码;段(PR)在CODE区可再定位DT_ASMADD2SEGMENTDATAOVERLAYABLE;名为;ASMADD2段为数据段(DT)在DATA区可再定位,可以覆盖PUBLIC?_ASMADD2?BYTE;公共符号定义PUBLIC_ASMADD2RSEGDT_ASMADD2?_ASMADD2?BYTE:;数据段保留参数传递区x1:DS1x2:DS1x3:DS1x4:DS1x5:DS1,40,RSEGPR_ASMADD2_ASMADD2:;程序段开始MOVA,R7;取R7中的x1ADDA,R5;取R5中的x2ADDA,R3;取R3中的x3ADDA,x4ADDA,x5MOV30H,A;和存进片内RAM30H单元RETEND使用方法二,3个以内的参数还是通过R7R5R3传送,多于3个的参数才通过定义的数据区传送。,41,2.借助SRC文件实现混合编程,(1)先用C语言编写所有的代码,包括需要汇编语言实现的部分。下面所举的例子中,延时子程序用汇编语言编写,其余程序用C语言编写。程序如下:/*文件名:main.c功能:亮灯控制程序*/#includesbitL1=P13;voidmain(void)L1=0;/点亮灯delay02s();/延时0.2s,42,L1=1;/熄灭灯delay02s();/延时0.2s/*文件名:delay02s.c功能:延时0.2s*/delay02s(void)chari,j,k;for(i=151;i0;i)for(j=24;j0;j)for(k=244;k0;k);,43,(2)建立项目文件,将main.c和delay02s.c都包含进项目。(3)在KeilC51环境下,在Project窗口右击.c文件,在弹出的快捷菜单中选择“Optionsfor”命令,选中右边的“GenerateAssemblerSRCFile”和“AssemblerSRCFile”复选框,使复选框由灰色变成黑色(有效)状态。本例是在delay02s.c文件上进行此操作。(4)根据选择的编译模式,把相应的库文件(如Small模式时,是KeilC51LibC51S.Lib)加入到工程中,该文件必须作为工程的最后文件。(5)编译这个项目后将会产生一个delay02s.SRC文件,将这个文件名改为delay02s.asm。为了让读者更直观地认识C程序经编译器汇编之后的情况,下面给出了由编译器产生的delay02s.asm文件。,44,;.delay02s.SRCgeneratedfrom:D:delay02s.c;COMPILERINVOKEDBY:;C:KeilC51BINC51.EXED:delay02s.cBROWSEDEBUGOBJECTEXTENDPRINT(.delay02s.lst)SRC(.delay02s.SR
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 热敷与低频电刺激协同作用-洞察及研究
- 手指画树叶课件
- 公司管理者遵守公司既定制度
- 视听行为分析-洞察及研究
- 公司复印机买卖合同5篇
- 2025-2026学年九年级上册期中模拟试卷(一)(含答案)
- 2024-2025学年四川省成都市龙泉驿区八年级(下)期中数学试卷(含部分答案)
- 橡胶厂考勤管理规范制度
- 自然冷却技术优化-洞察及研究
- 采购成本管理技术与谈判技巧培训(采购培训)
- 2025-2030中国成品润滑剂行业市场发展趋势与前景展望战略研究报告
- 保密警示教育典型泄密案例教育学习
- 道路货物运输经营申请表
- 乡村积分超市协议书
- 小学一年级上册体育全册教案
- 电焊工理论知识培训课件
- DB42-T 2051-2023 文物保护单位保护标志及保护界桩设置规范
- 高压配电抢修方案范本
- 2025高考英语全国II卷试题分析及备考策略指导课件
- 人口老龄化带来的公共卫生挑战-深度研究
- 医院外出进修、培训及参加学术会议的管理规定
评论
0/150
提交评论