汇编语言混合编程对Keil的设置.docx

上传人:b****5 文档编号:2833333 上传时间:2022-11-15 格式:DOCX 页数:8 大小:107.25KB
下载 相关 举报
汇编语言混合编程对Keil的设置.docx_第1页
第1页 / 共8页
汇编语言混合编程对Keil的设置.docx_第2页
第2页 / 共8页
汇编语言混合编程对Keil的设置.docx_第3页
第3页 / 共8页
汇编语言混合编程对Keil的设置.docx_第4页
第4页 / 共8页
汇编语言混合编程对Keil的设置.docx_第5页
第5页 / 共8页
点击查看更多>>
下载资源
资源描述

汇编语言混合编程对Keil的设置.docx

《汇编语言混合编程对Keil的设置.docx》由会员分享,可在线阅读,更多相关《汇编语言混合编程对Keil的设置.docx(8页珍藏版)》请在冰豆网上搜索。

汇编语言混合编程对Keil的设置.docx

汇编语言混合编程对Keil的设置

在keilC语言与汇编语言的混合编程中曾经遇到过的一些问题,写下来留作以后参考。

(本文写于11.04.10,在8.18日加入了第4点的内容)

1、C语言中加入汇编语言模块的方法:

例子:

voidfunc()

{

C语言代码……

#pragmaasm

MOVR6,#23

DELAY2:

MOVR7,#191

DELAY1:

DJNZR7,DELAY1

DJNZR6,DELAY2

RET

#pragmaendasm

C语言代码……

}

其中红色为C语言部分,绿色为嵌入的汇编语言部分。

汇编部分需要用#pragmaasm和#pragmaendasm包起来

2、Keil提示“asm/endasm”出错的解决方法

如果只是像1中那样直接加入汇编代码的话,编译将会报错,错误如下:

compilingsendata.c...

sendata.c(81):

errorC272:

'asm/endasm'requiressrc-controltobeactive

sendata.c(87):

errorC272:

'asm/endasm'requiressrc-controltobeactive

Targetnotcreated

解决方法如下:

首先右键单击包含有汇编部分的c语言文件名,然后在如上图所示的菜单中选择带有红色方框的选项

在弹出的对话框中,将上图中红色方框选中的两项打上勾(默认的情况下,前面的勾是灰色的,要让这两项前的勾变为黑色的),点击确定。

3、?

C_START等相关警告的处理

按照2中的方法处理完之后,再编译不会出现错误信息了,但是会出现如下的警告信息:

linking...

***WARNINGL1:

UNRESOLVEDEXTERNALSYMBOL

SYMBOL:

?

C_START

MODULE:

STARTUP.obj(?

C_STARTUP)

***WARNINGL2:

REFERENCEMADETOUNRESOLVEDEXTERNAL

SYMBOL:

?

C_START

MODULE:

STARTUP.obj(?

C_STARTUP)

ADDRESS:

000DH

处理方法如下:

在如上图所示的“SourceGroup1”上点右键,在菜单中选择“AddFilestoGroup'SourceGroup1'”

找到你的KEIL安装目录,选择其中的“C51”目录下的“LIB”目录下的“C51S.LIB”文件,点击Add,然后Close即可。

注意,上图所示的文件选择框进入LIB目录下后,默认只显示.c文件,需要在“文件类型”中选择“Libraryfile(*.lib)”,即可显示LIB文件了。

添加C51S.LIB到工程后,再次编译,警告信息消失。

linking...

ProgramSize:

data=9.0xdata=0code=28

creatinghexfilefrom"sendata"...

"sendata"-0Error(s),0Warning(s).

4、寄存器冲突问题的解决

汇编程序块中常常会使用到51的通用寄存器,比如R0-R7。

这种情况下可能会和C语言程序中已经使用到的R0-R7产生冲突,以至于产生一些非常隐蔽和古怪的错误。

虽然有人说KEIL可以自动分配寄存器组使之不产生冲突。

但是在我这里具体测试时还是有冲突的(或者是我的KEIL设置有问题?

),下面是测试小程序:

/*************************************************************

*测试程序

*************************************************************/

#include

#include

typedefunsignedcharuint8;

uint8buf[16]=

{

0x55

};

uint8i=0;

/************************************************************

*初始化单片机相关寄存器

***********************************************************/

voidUartInit()

{

SCON=0x50;

TMOD|=0x21;

PCON|=0x80;

TH1=0xE8;

TL1=0xE8;

IE|=0x90;

TR1=1;

}

/**************************************************

*延时

***************************************************/

voiddelay()

{

#pragmaasm

MOVR6,#19

DELAY2:

MOVR7,#18

DELAY1:

DJNZR7,DELAY1

DJNZR6,DELAY2

RET

#pragmaendasm

}

/**********************************************

*向COM1发送一个字符

**********************************************/

voidSendChar(uint8byteToSend)

{

SBUF=byteToSend;

while(!

TI);

TI=0;

}

/************************************************************

*读取一个字节

***********************************************************/

uint8read_byte()

{

uint8recvdata=8;

delay();//延时

returnrecvdata;

}

/**************************************************

*主程序

***************************************************/

intmain()

{

UartInit();//串口初始化

while

(1)

{

buf[i++]=read_byte();

}

}

/**************************************************

*串口中断处理

***************************************************/

voidchuankou()interrupt4

{

if(RI)

for(i=0;i

{

SendChar(buf[i]);

}

RI=0;

}

程序本身非常简单,一目了然。

main函数的作用就是不断把read_byte()的返回值读入buf中,再待有串口中断时,将buf中的内容输出到串口。

read_byte()函数也已经做了简化,返回值固定为8。

将这个程序在KEIL中编译,下载运行。

奇怪的情况出现了,buf中的内容输出到串口总是0(输出理所当然应该是8)。

把delay();这一句注释掉后,程序就输出正常了。

delay();不过起到了一个延时作用而已,怎么可能改变到函数返回值呢?

看看read_byte()函数生成的汇编程序

USING0

MOVR7,#08H

ACALLdelay

RET

才晓得,原来read_byte()函数将返回值放到R7中,然后调用delay函数,再返回。

后面的程序调用read_byte()返回值时,直接从R7中取数。

但是“ACALLdelay”时,已经存放了#08H的R7,在延时中被递减到了0,这也是为什么buf中存放的内容都是0的缘故。

知道了原因就好办一些了,由于本人是菜鸟,单片机水平很有限,目前只想到了如下4种解决方法:

(1)避开C语言部分已经使用了的Rn

编汇编模块时,看看C语言部分生成的汇编程序,把那些C语言已经使用到的,且可能对汇编部分构成冲突的Rn避开就好了。

比如上面的延时程序中,把R6、R7换成R3、R4,程序就正常了。

(2)用USINGX+ARX的方式调用其他组Rn寄存器

51单片机有4组R0-R7的寄存器,据说main中一般使用的都是第0组。

那么在汇编部分中使用其他的组就可以了,delay函数的内容可以改成如下这样:

voiddelay()

{

#pragmaasm

USING2

MOVAR6,#19

DELAY2:

MOVAR7,#18

DELAY1:

DJNZAR7,DELAY1

DJNZAR6,DELAY2

RET

#pragmaendasm

}

但是注意,如果这样用的话,delay延时的长度可能需要重新计算。

因为AR6和R6有所不同,以下是在网上找到的两段英文描述:

R0–R7Theeight8bitgeneralpurpose8051registersinthecurrentlyactiveregisterbank.

AMaximumoffourregisterbanksareavailable.

AR0–AR7RepresenttheabsolutedataaddressesofR0throughR7inthecurrentregisterbank.

Theabsoluteaddressfortheseregisterschangesdependingontheregisterbankthatiscurrentlyselected.

ThesesymbolsareonlyavailablewhentheUSINGassemblerstatementisgiven.

RefertotheUSINGassemblerstatementformoreinformationonselectingtheregisterbank.

TheserepresentationsaresuppressedbytheNOAREGSdirectiveofftheCx51compiler.

看这意思,似乎R0–R7是寄存器,而AR0–AR7是地址,所以“MOVAR6,#19”和“MOVR6,#19”所花的时钟周期数是不同的。

我调一个采集数据的程序时,刚开始没有注意到这个问题,因此很奇怪为什么用AR6和R6,采集到的数据是不一样的,后来才反应过来它们延时不同。

(关于51单片机的各条指令的时钟周期数可以在XX上搜到很多,这里就不列出了)

(3)对汇编部分中使用到的寄存器采用入栈保护

简单的说就是在汇编部分使用Rn之前,将它们的内容塞进栈中存起来,延时循环结束之后再从栈中取出来

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > PPT模板 > 其它模板

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1