20
*4 8 汇汇汇汇汇 C 汇汇汇汇汇汇汇 汇汇汇汇汇汇汇汇汇 汇汇汇汇汇汇汇汇汇汇汇汇汇汇 汇 ,。 汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇 汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇 ,。 汇汇汇汇汇汇汇 汇汇汇汇汇汇汇汇汇汇汇汇汇汇 Franklin C51 汇 汇汇汇 汇汇汇汇 ( 汇汇汇汇汇汇汇汇 汇 ) 汇汇汇汇汇汇汇 汇汇汇汇汇汇汇汇 汇汇汇汇汇汇汇 汇 ,一。 C 汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇 1. 汇汇汇汇汇汇汇汇汇汇汇汇 汇汇汇汇汇汇汇 汇汇汇汇汇汇汇 ,, C ODE 汇汇汇汇汇汇汇汇汇汇 汇汇汇汇汇 汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇汇 汇汇 ,, 4.6

*4 。 8 汇编语言和 C 语言的混合编程

Embed Size (px)

DESCRIPTION

*4 。 8 汇编语言和 C 语言的混合编程. 本节介绍不同的模块,不同的语言相结合的编程方法。 通常情况下以高级语言编写主程序,用汇编语言编写与硬件有关的子程序。不同的编译程序 高级语言对汇编的调用方法不同,在 Franklin C51 中,是将不同的模块 ( 包括不同语言的模 块 ) 分别汇编或编译,再通过连接生成一个可执行文件。 C 语言程序调用汇编语言程序要注意以下几点: 1. 被调函数要在主函数中说明,在汇编程序中,要使用伪指令使 CODE 选项有效并声明为可再 定位段类型,并且根据不同情况对函数名作转换,见表 4.6 。 - PowerPoint PPT Presentation

Citation preview

Page 1: *4 。 8  汇编语言和 C 语言的混合编程

*4 。 8 汇编语言和 C 语言的混合编程

本节介绍不同的模块,不同的语言相结合的编程方法。

通常情况下以高级语言编写主程序,用汇编语言编写与硬件有关的子程序。不同的编译程序 高级语言对汇编的调用方法不同,在 Franklin C51 中,是将不同的模块 ( 包括不同语言的模 块 ) 分别汇编或编译,再通过连接生成一个可执行文件。

C 语言程序调用汇编语言程序要注意以下几点:

1. 被调函数要在主函数中说明,在汇编程序中,要使用伪指令使 CODE 选项有效并声明为可再 定位段类型,并且根据不同情况对函数名作转换,见表 4.6 。

Page 2: *4 。 8  汇编语言和 C 语言的混合编程

说 明 符 号 名 解 释

void func(void) FUNC无参数传递或不含寄存器参数的函数名不作改变转入目标文件中,名字只是简单的转为大写形式。

void func(char) _FUNC含寄存器参数的函数名加入“ _”字符前缀以示区别,它表明这类函数包含寄存器内的参数传递。

void func(void)

reentrant_? FUNC

对于重入函数加上“ _?” 字符前缀以示区别,它表明这类函数包含栈内的参数传递。

Page 3: *4 。 8  汇编语言和 C 语言的混合编程

2. 对为其他模块使用的符号进行 PUBLIC 声明,对外来符号进行 EXTRN 声明。

3. 参数的传递。

在混合语言编程中,关键是入口参数和出口参数的传递,Franklin C 编译器可使用寄存器传递参数,也可以使用固定存贮器或使用堆栈,由于 8XX51 的堆栈深度有限,因此多用寄存器 或存贮器传递。用寄存器传递最多只能传递三个参数,选择固定的寄存器,见表 4.7 。 表 4.7

参数类型 char int long ,float 一般指针

第一个参数第二个参数第三个参数

R7

R5

R3

R6,R7

R4,R5

R2,R3

R4~R7

R4~R7

R1,R2,R3

R1,R2,R3

R1,R2,R3

Page 4: *4 。 8  汇编语言和 C 语言的混合编程

例如 func1(int a) “a”是第一个参数,在 R6,R7 传递 ,

func2(int b,int c,int *d)“b”在 R6 , R7 中传递,“ c”在 R4 , R5 中传递,“ d”在 R1 , R2 , R3 中传递。

如果传递参数寄存器不够用,可以使用存贮器传送 ,

通过指针取得参数。

汇编语言通过寄存器或存贮器传递参数给 C 语言程序,汇编语言通过寄存器传递给 C 语言的返回值见表 4.8 。

返回值 寄存器 说明bit

(unsigned)char

(unsigned)int

(unsigned)long

Float

指针

C

R7

R6,R7

R4~R7

R4~R7

R1,R2,R3

进位标志

高位在 R6 ,低位在 R7

高位在 R4 ,低位在 R7

32 位 IEEE 格式,指数和符号位 R7

R3 放存储器类型,高位在 R2 ,低位 R1

Page 5: *4 。 8  汇编语言和 C 语言的混合编程

下面通过两个实例说明混合编程的方法及参数传递过程 .

例 4_10 用 P1.0 产生周期为 4ms 的方波 , 同时用 P1.1 产生周期为 8ms 的方波。

说明:设计三个模块模块一 C 语言编主程序,使 P1.1 产生周期为 8ms 的方波;模块二 用 C 语言编程,使 P1.0 产生周期为 4ms 的方波;模块三 用汇编语言编写延时 1ms 程序。 模块一调用模块二获得 8ms 方波, 模块二调模块三,向汇编程序传递字符型参数 (x=2) ,延时 2ms 。各模块程序如下:

Page 6: *4 。 8  汇编语言和 C 语言的混合编程

模块一: P1.1 产生周期为 8ms 的方波#include<reg51.h>#define uchar unsigned char sbit P1-1=P1^1; void delay4ms(void); /* 定义延时 4ms 函数 ( 模块二 ) */ main( ) { uchar i; for(;;) { P1-1=0; delay4ms();/* 调模块二延时 4ms */ P1-1=1; delay4ms();/* 调模块二延时 4ms*/} }

Page 7: *4 。 8  汇编语言和 C 语言的混合编程

模块二( delay4ms ) :使 P1.0 产生周期为 4ms 的方波 #include<reg51.h>

#define uchar unsigned char

sbit P1-0=P1^0;

delaylms(uchar x); /* 定义延时 1ms 函数 ( 模块三 ) */

void delay4ms(void){

P1-0=0;

delaylms(2);/* 调汇编函数 ( 模块三 ) */

P1-0=1;

delaylms(2);/* 调汇编函数 ( 模块三 )*

Page 8: *4 。 8  汇编语言和 C 语言的混合编程

模块三: PUBLIC -DELAY1MS ; DE LAY1MS 为其他 模块调用 DE SEGMENT CODE ;定义 DE 段为再定位程序段 RSEG DE ;选择 DE 为当前段- DELAY1MS : NOP DELA : MOV R1 , #0F8H ;延时 LOP1 : NOP

NOP DJNZ R1 , LOP1 DJNZ R7 , DELA ; R7 为 C 程序传递 过来的参数 (x=2)

EXIT : RET END上例可见汇编语言程序从 R7 中获取 C 程序传递参数 (x=2) 。

Page 9: *4 。 8  汇编语言和 C 语言的混合编程

例 2. 在汇编程序中比较两数大小,将大数放到指定的存储区,由 C 程序的主调函数取出。C 语言程序

模块一: #define uchar unsigned char

void max(uchar a, uchar b); /* 定义汇编函数 */

main(){

uchar a=5,b=35,*c,d;

c=0x30; /* c 指针变量指向内部 RAM 30H 单元 */

max(a,b); /* 调汇编函数, a,b 为传递的参数 */

d=*c; /* d 存放模块二传递过来的参数 */

}

Page 10: *4 。 8  汇编语言和 C 语言的混合编程

模块二:汇编语言程序 PUBLIC -MAX MAX 为其 他模块调 DE SEGMENT CODE ;定义 DE 段为再定位程序段

RSEG DE ;选择 DE 为当前段 MAX : MOV A , R7 ;取模块一的参数 a MOV 30H , R5 ;取模块一的参数 b CJNE A , 30H , TAG1 ;比较 a,b 的大小

TAG1 : JC EXIT MOV 30H , R7 ;大数存于 30H 单元EXIT : RET END

可见, C 语言程序通过 R7 和 R5 传递字符型参数a 和 b 到汇编语言程序,汇编语言程序将返回值 放在固定存贮单元,主调函数通过指针取出返回值。

Page 11: *4 。 8  汇编语言和 C 语言的混合编程

C语言程序调用汇编程序最多只能传递三个参数,如果多于三个参数,就需要通过存贮qu区传递,这就需要在汇编程序中建立数据段,在下例中C语言程序向汇编传递六个参数,汇编程序************C_CALL.C****************#pragma code smallextern int afunc(char v_a,char v_b, char v_c, char v_d,char v_e,char v_f); /*外来函数说明void C_call(void){ char v_a=0x11; /*传递参数赋值*/

char v_b=0x18;char v_c=0x33;char v_d=0x44;char v_e=0x55;char v_f=0x98;

Page 12: *4 。 8  汇编语言和 C 语言的混合编程

int data *aa; /* 指针变量指向 int 型 data 区 */int A_ret; /* 存汇编返回结果的变量 */

aa=0x30; /* 置指针 */A_ret=afunc(v_a,v_b,v_c,v_d,v_e,v_f); /* 调汇编函数 */

*aa=A_ret; /* 取汇编返回结果 */ *aa=(int)0; /* 为方便观察改值,强制 0 为 int 型 */ *aa=A_ret;} /* 再次观察汇编返回结果 */void main(void) { /* 主函数 */ char a1,a2,a3; /* 为方便观察设 a1 a2 a3*/ a1=0; a2=2; a3=3;

C_call(); a1=1; a2=3; while(1); }

Page 13: *4 。 8  汇编语言和 C 语言的混合编程

**********AFANC.ASM**********PR_AFUNC SEGMENT CODE ; 名为 AFUNC 段为代码段 ( PR) 在 CODE 区可再定位,DT_AFUNC SEGMENT DATA OVERLAYABLE ; 名为 AFUNC 段为数据段 (DT) 在 DATA 区 , 可再定位,可以覆盖

PUBLIC ?_afunc?BYTE ;公共符号定义PUBLIC _afunc

RSEG DT_AFUNC?_afunc?BYTE: ;数据段保留参数传递区 v_a: DS 1 v_b: DS 1 v_c: DS 1 v_d: DS 1

Page 14: *4 。 8  汇编语言和 C 语言的混合编程

v_e: DS 1v_f: DS 1 RSEG PR_AFUNC_afunc: USING 0 ;程序段

MOV A,R7 ; 取 R7 中的 v_a ADD A,R5 ; 取 R5 中的 v_b ADD A,R3 ; 取 R3 中的 v_c ADD A,v_d ADD A,v_e ADD A,v_f MOV R7,A ; 和存 R7, 进位存 R6MOV A,#0 ; 以便返回RLC A

Page 15: *4 。 8  汇编语言和 C 语言的混合编程

MOV R6,A RETEND

编译连接方法 以上各模块可以先分别汇编 (A51) 和编译 (C51)( 选

择 DEBUG 编译控制项 ) ,生成的 .OBJ 文件,然后运 行 L51 将各 OBJ 文件连接,生成一个新的文件。

在集成环境下的连接调试可以连续进行,比上面方法更为方便,现使用 wave( 伟福 ) 的仿真软 件 ICExplorerW(ICE For Windows) 的编译连接步骤如下:

1. 编辑好各个模块,保存。

2. 点击文件 / 新建项目,弹出项目窗口。

Page 16: *4 。 8  汇编语言和 C 语言的混合编程

3. 点击项目菜单,选加入模块,此时弹出有文件目录的对话框,选中要加入刚才编辑好的文 件 ( 模块 ) ,并打开。此时在项目窗口中可以看到加入的模块文件。

4. 点击项目菜单中的全部编辑,并取名保存项目。于是系统对加入各模块进行编译,并进行 连

5. 编译连接完成会弹出信息窗口,如编译连接有错,信息窗口将出现错误信息。

6. 模块连接成功,生成二进制文件 (.BIN) 和十六进制文件(.HEX) 。

7. 点击跟踪或单步按钮,就可对程序进行跟踪调试,程序运行到不同模块时, wave 就会弹 出相应的模块源程序窗口,显示程序运行情况。

Page 17: *4 。 8  汇编语言和 C 语言的混合编程

4 。 9 小 结 本章介绍了 C51 的基本数据类型、存

贮类型及对 C51 对单片机内部部件的定义,并介绍了 C 语 言 基础知识,最后通过编程实例介绍了各种结构的程序设计,以上是利用 C 语言编单片机程序 的基础,都应该掌握并灵活应用,只有多编程,多上机才能不断提高编程的能力。

如何编写高效的 C 语言程序,通常应注意以下问题 :

Page 18: *4 。 8  汇编语言和 C 语言的混合编程

1. 定位变量

经常访问的数据对象放入在片内数据 RAM 中,这可在任一种模式 (COMPACT/LARGE) 下用输入存贮器类型的方法实现。访问片内 RAM 要比访问片外 RA

M快得多。在片内 RAM 由寄存器组、位 数据区、栈和其它由用户用“ data”类型定义的变量共享。由于片内 RAM容量的限制 (128 ~ 256) 字节,由使用的处理器决定 ) ,必须权衡利弊以解决访问效率和这些对象的数量之间的 矛盾。

2 .尽可能使用最小数据类型 MCS-51系列单片机是 8 位机,因此对具

有“ char”类型的对象的操作比“ int”或“ long”类型

Page 19: *4 。 8  汇编语言和 C 语言的混合编程

的对象方便得多。建议编程者只要能满足要求,应尽量使用最小数据类型。

C51 编译器直接支持所有的字节操作,因而如果不是运算符要求,就不作“ int”类型的转 换,这可用一个乘积运算来说明,两“ char”类型对象的乘积与 8XX51

操作码“MUL AB”刚 好相符。如果用整型完成同样的运算,则需调用库函数。

只要有可能,使用“ unsigned”数据类型

8XX51 单片机的 CPU 不直接支持有符号数的运算。因而 C51 编译必须产生与之相关的更多的 代码以解决这个问题。如果使用无符号类型,产生的代码要少得多。

Page 20: *4 。 8  汇编语言和 C 语言的混合编程

只要有可能,使用局部函数变量

编译器总是尝试在寄存器里保持局部变量。 这样,将索引变量 ( 如 FOR 和 WHILE循环中计数变 量 ) 声明为局部变量是最好的,这个优化步骤只为局部变量执行。使用“ unsigned char/int ”的对象通常能获得最好的结果。