Keil 内联汇编的设置问题

上传人:ji****72 文档编号:37533404 上传时间:2018-04-18 格式:DOC 页数:9 大小:148.50KB
返回 下载 相关 举报
Keil 内联汇编的设置问题_第1页
第1页 / 共9页
Keil 内联汇编的设置问题_第2页
第2页 / 共9页
Keil 内联汇编的设置问题_第3页
第3页 / 共9页
Keil 内联汇编的设置问题_第4页
第4页 / 共9页
Keil 内联汇编的设置问题_第5页
第5页 / 共9页
点击查看更多>>
资源描述

《Keil 内联汇编的设置问题》由会员分享,可在线阅读,更多相关《Keil 内联汇编的设置问题(9页珍藏版)》请在金锄头文库上搜索。

1、在 keil C 语言与汇编语言的混合编程中曾经遇到过的一些问题,写下来留作以 后参考。(本文写于 09.08.15,在 8.18 日加入了第 4 点的内容) 1、C 语言中加入汇编语言模块的方法:例子: void func() C 语言代码 #pragma asmMOV R6,#23 DELAY2: MOV R7,#191 DELAY1: DJNZ R7,DELAY1 DJNZ R6,DELAY2 RET #pragma endasmC 语言代码 其中红色为 C 语言部分,绿色为嵌入的汇编语言部分。汇编部分需要用#pragma asm 和#pragma endasm 包起来2、Keil 提示

2、“asm/endasm”出错的解决方法如果只是像 1 中那样直接加入汇编代码的话,编译将会报错,错误如下: compiling sendata.c. sendata.c(81): error C272: asm/endasm requires src-control to be active sendata.c(87): error C272: asm/endasm requires src-control to be active Target not created解决方法如下:首先左键单击包含有汇编部分的 c 语言文件名,然后在菜单栏中选择 Project- Option for Fil

3、e中选择带有红色方框的选项在弹出的对话框中,将上图中红色方框选中的两项打上勾(默认的情况下,前 面的勾是灰色的,要让这两项前的勾变为黑色的),点击确定。3、?C_START 等相关警告的处理按照 2 中的方法处理完之后,再编译不会出现错误信息了,但是会出现如下的 警告信息: linking. * WARNING L1: UNRESOLVED EXTERNAL SYMBOL SYMBOL: ?C_START MODULE: STARTUP.obj (?C_STARTUP) * WARNING L2: REFERENCE MADE TO UNRESOLVED EXTERNAL SYMBOL: ?C

4、_START MODULE: STARTUP.obj (?C_STARTUP) ADDRESS: 000DH处理方法如下:在如上图所示的“Source Group 1”上点右键,在菜单中选择 “Add Files to Group Source Group 1 ”找到你的 KEIL 安装目录,选择其中的“C51”目录下的“LIB”目录下的 “C51S.LIB”文件,点击 Add,然后 Close 即可。注意,上图所示的文件选择框进入 LIB 目录下后,默认只显示.c 文件,需要在 “文件类型”中选择“Library file (*.lib)”,即可显示 LIB 文件了。添加 C51S.LIB

5、到工程后,再次编译,警告信息消失。 linking. Program Size: data=9.0 xdata=0 code=28 creating hex file from “sendata“. “sendata“ - 0 Error(s), 0 Warning(s).4、寄存器冲突问题的解决汇编程序块中常常会使用到 51 的通用寄存器,比如 R0-R7。这种情况下可能会 和 C 语言程序中已经使用到的 R0-R7 产生冲突,以至于产生一些非常隐蔽和古 怪的错误。虽然有人说 KEIL 可以自动分配寄存器组使之不产生冲突。但是在我 这里具体测试时还是有冲突的(或者是我的 KEIL 设置有问题

6、?),下面是测试 小程序:/* 测试程序*/#include #includetypedef unsigned char uint8 ;uint8 buf16= 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 DJN

7、Z 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) bufi+=read_byte(); /* 串口中断处理*/void chuankou()interrupt 4 i

8、f(RI) for(i=0;isizeof(buf);i+) SendChar(bufi); RI=0 ; 程序本身非常简单,一目了然。main 函数的作用就是不断把 read_byte()的 返回值读入 buf 中,再待有串口中断时,将 buf 中的内容输出到串口。 read_byte()函数也已经做了简化,返回值固定为 8。将这个程序在 KEIL 中编译,下载运行。奇怪的情况出现了,buf 中的内容输 出到串口总是 0(输出理所当然应该是 8)。把 delay();这一句注释掉后,程序就输出正常了。delay();不过起到了一个延时作用而已,怎么可能改变到函数返回值呢?看看 read_by

9、te()函数生成的汇编程序USING 0 MOV R7,#08H ACALL delay RET 才晓得,原来 read_byte()函数将返回值放到 R7 中,然后调用 delay 函数,再返回。后面的程序调用 read_byte()返回值时,直接从 R7 中取数。但是“ACALL delay”时,已经存放了#08H 的 R7,在延时中被递减到了 0, 这也是为什么 buf 中存放的内容都是 0 的缘故。知道了原因就好办一些了,由于本人是菜鸟,单片机水平很有限,目前只想到 了如下 4 种解决方法:(1)避开 C 语言部分已经使用了的 Rn编汇编模块时,看看 C 语言部分生成的汇编程序,把那些

10、 C 语言已经使用到的, 且可能对汇编部分构成冲突的 Rn 避开就好了。比如上面的延时程序中,把 R6、R7 换成 R3、R4,程序就正常了。(2)用 USING X + ARX 的方式调用其他组 Rn 寄存器51 单片机有 4 组 R0-R7 的寄存器,据说 main 中一般使用的都是第 0 组。那 么在汇编部分中使用其他的组就可以了,delay 函数的内容可以改成如下这样:void delay() #pragma asm USING 2 MOV AR6,#19 DELAY2: MOV AR7,#18 DELAY1: DJNZ AR7,DELAY1 DJNZ AR6,DELAY2 RET #

11、pragma endasm 但是注意,如果这样用的话,delay 延时的长度可能需要重新计算。因为 AR6 和 R6 有所不同,以下是在网上找到的两段英文描述: R0 R7 The eight 8 bit general purpose 8051 registers in the currently a ctive register bank. A Maximum of four register banks are available. AR0 AR7 Represent the absolute data addresses of R0 through R7 in the cu rrent

12、 register bank. The absolute address for these registers changes depending on the reg ister bank that is currently selected. These symbols are only available when the USING assembler statement i s given. Refer to the USING assembler statement for more information on select ing the register bank. The

13、se representations are suppressed by the NOAREGS directive off theCx51 compiler. 看这意思,似乎 R0 R7 是寄存器,而 AR0 AR7 是地址,所以“MOV AR6,#19”和“MOV R6,#19”所花的时钟周期数是不同的。我调一个采集数据 的程序时,刚开始没有注意到这个问题,因此很奇怪为什么用 AR6 和 R6,采 集到的数据是不一样的,后来才反应过来它们延时不同。(关于 51 单片机的 各条指令的时钟周期数可以在百度上搜到很多,这里就不列出了)(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,

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号