null*4。8 汇编语言和C语言的混合编程*4。8 汇编语言和C语言的混合编程 本节介绍不同的模块,不同的语言相结合的编程方法。
通常情况下以高级语言编写主程序,用汇编语言编写与硬件有关的子程序。不同的编译程序 高级语言对汇编的调用方法不同,在Franklin C51中,是将不同的模块(包括不同语言的模 块)分别汇编或编译,再通过连接生成一个可执行文件。
C语言程序调用汇编语言程序要注意以下几点:
1. 被调函数要在主函数中说明,在汇编程序中,要使用伪指令使CODE选项有效并声明为可再 定位段类型,并且根据不同情况对函数名作转换,见
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
4.6。
nullnull2.对为其他模块使用的符号进行PUBLIC声明,对外来符号进行EXTRN声明。
3.参数的传递。
在混合语言编程中,关键是入口参数和出口参数的传递,Franklin C编译器可使用寄存器传递参数,也可以使用固定存贮器或使用堆栈,由于8XX51的堆栈深度有限,因此多用寄存器 或存贮器传递。用寄存器传递最多只能传递三个参数,选择固定的寄存器,见表4.7 。 表4.7
例如 func1(int a) “a”是第一个参数,在R6,R7传递,例如 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。
null下面通过两个实例说明混合编程的方法及参数传递过程.
例4_10 用P1.0产生周期为4ms的方波,同时用P1.1产生周期为8ms的方波。
说明:
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
三个模块
模块一 C语言编主程序,使 P1.1产生周期为8ms的方波;
模块二 用C语言编程,使P1.0产生周期为4ms的方波;
模块三 用汇编语言编写延时1ms 程序。
模块一调用模块二获得8ms方波, 模块二调模块三
,向汇编程序传递字符型参数(x=2),延时2ms。
各模块程序如下:
null模块一: P1.1产生周期为8ms的方波
#include
#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*/
}
}
null模块二(delay4ms) :使P1.0产生周期为4ms的方波
#include
#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);/* 调汇编函数(模块三)*
}
null 模块三:
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) 。
例2.在汇编程序中比较两数大小,将大数放到指定的存储区,由C程序的主调函数取出。
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存放模块二传递过来的参数 */
}
null模块二:汇编语言程序
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到汇编语言程序,汇编语言程序将返回值 放在固定存贮单元,主调函数通过指针取出返回值。
null C语言程序调用汇编程序最多只能传递三个参数,如果多于三个参数,就需要通过存贮qu区传递,这就需要在汇编程序中建立数据段,在下例中C语言程序向汇编传递六个参数,汇编程序
************C_CALL.C****************
#pragma code small
extern 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;
null 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); }
null**********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
nullv_e: DS 1
v_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,进位存R6
MOV A,#0 ;以便返回
RLC A
null MOV R6,A
RET
END
编译连接方法
以上各模块可以先分别汇编(A51)和编译(C51)(选择DEBUG编译控制项),生成的.OBJ文件,然后运 行L51将各OBJ文件连接,生成一个新的文件。
在集成环境下的连接调试可以连续进行,比上面方法更为方便,现使用wave(伟福)的仿真软 件ICExplorerW(ICE For Windows)的编译连接步骤如下:
1.编辑好各个模块,保存。
2.点击文件/新建项目,弹出项目窗口。null3.点击项目菜单,选加入模块,此时弹出有文件
目录
工贸企业有限空间作业目录特种设备作业人员作业种类与目录特种设备作业人员目录1类医疗器械目录高值医用耗材参考目录
的对话框,选中要加入刚才编辑好的文 件(模块),并打开。此时在项目窗口中可以看到加入的模块文件。
4.点击项目菜单中的全部编辑,并取名保存项目。于是系统对加入各模块进行编译,并进行 连
5.编译连接完成会弹出信息窗口,如编译连接有错,信息窗口将出现错误信息。
6.模块连接成功,生成二进制文件(.BIN)和十六进制文件(.HEX)。
7.点击跟踪或单步按钮,就可对程序进行跟踪调试,程序运行到不同模块时,wave就会弹 出相应的模块源程序窗口,显示程序运行情况。
null 4。9 小 结
本章介绍了C51的基本数据类型、存贮类型及对C51对单片机内部部件的定义,并介绍了C语 言 基础知识,最后通过编程实例介绍了各种结构的程序设计,以上是利用C语言编单片机程序 的基础,都应该掌握并灵活应用,只有多编程,多上机才能不断提高编程的能力。
如何编写高效的C语言程序,通常应注意以下问题:null 1. 定位变量
经常访问的数据对象放入在片内数据RAM中,这可在任一种模式(COMPACT/LARGE)下用输入存贮器类型的方法实现。访问片内RAM要比访问片外RAM快得多。在片内RAM由寄存器组、位 数据区、栈和其它由用户用“data”类型定义的变量共享。由于片内RAM容量的限制(128 ~256)字节,由使用的处理器决定),必须权衡利弊以解决访问效率和这些对象的数量之间的 矛盾。
2 .尽可能使用最小数据类型
MCS-51系列单片机是8位机,因此对具有“char”类型的对象的操作比“int”或“long”类型null 的对象方便得多。建议编程者只要能满足要求,应尽量使用最小数据类型。
C51编译器直接支持所有的字节操作,因而如果不是运算符要求,就不作“int”类型的转 换,这可用一个乘积运算来说明,两“char”类型对象的乘积与8XX51操作码“MUL AB”刚 好相符。如果用整型完成同样的运算,则需调用库函数。
只要有可能,使用“unsigned”数据类型
8XX51单片机的CPU不直接支持有符号数的运算。因而C51编译必须产生与之相关的更多的 代码以解决这个问题。如果使用无符号类型,产生的代码要少得多。null 只要有可能,使用局部函数变量
编译器总是尝试在寄存器里保持局部变量。 这样,将索引变量(如FOR和WHILE循环中计数变 量)声明为局部变量是最好的,这个优化步骤只为局部变量执行。使用“unsigned char/int ”的对象通常能获得最好的结果。