Keil 内联汇编的设置问题.docx

上传人:b****5 文档编号:3525514 上传时间:2022-11-23 格式:DOCX 页数:8 大小:107.41KB
下载 相关 举报
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语言与汇编语言的混合编程中曾经遇到过的一些问题,写下来留作以后参考。

(本文写于09.08.15,在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语言文件名,然后在菜单栏中选择Project->OptionforFile‘……’中选择带有红色方框的选项

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

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

typedef unsigned char uint8 ;

uint8 buf[16]=

{

0x55 

};

uint8 i=0 ;

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

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

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

void UartInit()

{

SCON=0x50 ;

TMOD|=0x21 ;

PCON|=0x80 ;

TH1=0xE8 ;

TL1=0xE8 ;

IE|=0x90 ;

TR1=1 ;

}

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

*    延时

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

void delay()

{

#pragma asm 

MOV R6,#19 

DELAY2 :

   MOV R7,#18 

DELAY1 :

   DJNZ R7,DELAY1 

DJNZ R6,DELAY2 

RET 

#pragma endasm 

}

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

*    向COM1发送一个字符

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

void SendChar(uint8 byteToSend)

{

SBUF=byteToSend ;

while(!

TI);

TI=0 ;

}

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

*    读取一个字节

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

uint8 read_byte()

{

uint8 recvdata=8 ;

delay();            //延时

    

return recvdata ;

}

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

*        主   程   序

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

int main()

{

UartInit();//串口初始化

    while

(1)

{

buf[i++]=read_byte();

}

}

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

*        串口中断处理

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

void chuankou()interrupt 4 

{

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()函数生成的汇编程序

USING   0

MOV    R7,#08H

ACALL   delay

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函数的内容可以改成如下这样:

void delay()

{

#pragma asm 

USING2

MOVAR6,#19

DELAY2:

   MOVAR7,#18

DELAY1:

   DJNZAR7,DELAY1

DJNZAR6,DELAY2

RET 

#pragma endasm 

}

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

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

R0 – R7 The eight 8 bit general purpose 8051 registers in the currently active register bank.

A Maximum of four register banks are available. 

AR0 – AR7 Represent the absolute data addresses of R0 through R7 in the current register bank.

The absolute address for these registers changes depending on the register bank that is currently selected.

These symbols are only available when the USING assembler statement is given.

Refer to the USING assembler statement for more information on selecting the register bank.

These representations are suppressed by the NOAREGS directive off the Cx51 compiler. 

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

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

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

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

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

比如上面的delay程序,可以改成这样:

void delay()

{

#pragma asm

MOV A,R6

PUSH ACC

MOV A,R7

PUSH ACC

MOV R6,#19

DELAY2:

MOV R7,#18

DELAY1:

DJNZ R7,DELAY1

DJNZ R6,DELAY2

POP ACC

MOV R7,A

POP ACC

MOV R6,A

RET

#pragma endasm

}

(4)使用RS0和RS1切换使用的寄存器组

51单片机中使用RS0和RS1来选择使用哪一组Rn,因此在汇编程序通过修改这两位的值,即可实现切换寄存器组。

上面的delay函数可修改为如下形式:

void delay()

{

#pragma asm

SETB RS1

SETB RS0

MOV R6,#19

DELAY2:

MOV R7,#18

DELAY1:

DJNZ R7,DELAY1

DJNZ R6,DELAY2

CLR RS1

CLR RS0

RET

#pragma endasm

}

进入汇编部分后选择采用第3组寄存器,退出汇编部分前更换回之前使用的第x组寄存器(在本程序中是第0组寄存器)

不过对于比较精细的延时的话,方法(3)和方法(4)这样或许会稍有些影响,毕竟增加了一些入栈出栈或者置位清零的语句。

因此如果对延时精度要求较高,且采用方法(3)或(4)的话,计算延时的循环次数时,需要把入栈出栈或置位清零语句花费的时间也考虑进去。

另外,除上面四种方法之外,我还曾经尝试过以下方法,但是失败:

一种是在voiddelay()的函数定义后面加上using2,使之变成

voiddelay()using2

{

................................

}

或者是在汇编中加上USING2,使之变成

voiddelay()

{

#pragmaasm

USING2   

................................

#pragmaendasm

}

但是似乎都不行。

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

当前位置:首页 > 初中教育 > 数学

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

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