《KEIL编程_C语言嵌入汇编.pdf》由会员分享,可在线阅读,更多相关《KEIL编程_C语言嵌入汇编.pdf(8页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、keil C 语言与汇编语言混合编程1、在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码:#pragma ASM;Assembler Code Here#pragma ENDASM2、在 Project 窗口中包含汇编代码的 C 文件上右键,选择“Options for.”,点击右边的“Generate Assembler SRC File”和“Assemble SRC File”使检查框由灰色变成黑色(有效)状态3、根 据 选 择 的 编 译 模 式,把 相 应 的 库 文 件(如Small 模 式 时,是KeilC51LibC51S.Lib)加入工程中,该文件必须作为工程的最后文件,在
2、默认安装盘 KEIL/C51/LIB/C51S.Lib4、编译,即可生成目标代码来个实例吧:#include#define uchar unsigned charsbit LED1=P10;/*C 嵌入汇编例程*/void delay_ms(void)#pragma asmMOVR0,#0FFHMOVR1,#0FFHD_LOOP1:DJNZR0,D_LOOP1MOVR0,#0FFHDJNZR1,D_LOOP1#pragma endasmvoid main(void)uchar i;P1=0 xFF;while(1)i+;delay_ms();if(i=7)LED1=LED1;i=0;2.无参数
3、传递的函数调用C51调用汇编函数1.无参数传递的函数调用先来个例子:其中 C_ASM.c 和 DELAY.a 为项目中的两个文件/*C_ASM.c*/#include#define uchar unsigned charextern void delay100();sbit LED1=P11;/*C 嵌入汇编例程*/void main(void)uchar i;P1=0 xFF;while(1)i+;delay100();if(i=7)LED1=LED1;i=0;*DELAY100.a*?PR?DELAY100 SEGMENT CODE;/在程序存储区中定义段PUBLIC DELAY100;/
4、声明函数RSEG?PR?DELAY100;/函数可被连接器放置在任何地方DELAY100:MOVR0,#0FFHMOVR1,#0FFHD_LOOP1:DJNZR0,D_LOOP1MOVR0,#0FFHDJNZR1,D_LOOP1RETEND在 C_ASM.c 文件中,先声明外部函数,然后直接在 main 中调用即可。在 DELAY100.a 中,?PR?DELAY100 SEGMENT CODE;作用是在程序存储区中定义段,DELAY100为段名,?PR?表示段位于程序存储区内PUBLIC DELAY100;作用是声明函数为公共函数RSEG?PR?DELAY100;表示函数可被连接器放置在任何
5、地方,RSEG 是段名的属性段名的开头为 PR,是为了和 C51内部命名转换兼容,命名转换规律如下:CODE?PR?XDATA?XDDATA?DTBIT?BIPDATA?PD3.有参数传递的函数调用记住哦,c 文件和 A51文件不能使用同一个文件名,不过我还不知道为什么会这样,有高手知道得话请告知。今天说说带参数传递的函数调用,在 C51和汇编之间传递参数的方式有两种,一种是通过寄存器传递参数,C51中不同类型的实参会存入相应的寄存器,在汇编中只需对相应寄存器进行操作,即达到传递参数的目的。不同类型的数据及其传递参数的寄存器如下表所示:在 C 和汇编混合编程的时候,存在 C 语言和汇编语言的变
6、量以及函数的接口问题。在 C 程序中定义的变量,编译为.asm 文件后,都被放进了.bss 区,而且变量名的前面都带了一个下划线。在 C 程序中定义的函数,编译后在函数名前也带了一个下划线。例如:extern int num 就会变成.bss _num,1extern float nums5就会变成.bss _nums,5extern void func()就会变成 _func,一汇编和 C 的相互调用可以分以下几种情况:(1)汇编程序中访问 c 程序中的变量和函数。在汇编程序中,用_XX 就可以访问 C 中的变量 XX 了。访问数组时,可以用_XX+偏移量来访问,如_XX+3访问了数组中的
7、XX3。在汇编程序调用 C 函数时,如果没有参数传递,直接用_funcname 就可以了。如果有参数传递,则函数中最左边的一个参数由寄存器 A 给出,其他的参数按顺序由堆栈给出。返回值是返回到 A 寄存器或者由 A 寄存器给出的地址。同时注意,为了能够让汇编语言 能访问到 C 语言中定义的变量和函数,他们必须声明为外部变量,即加 extern 前缀。(2)c 程序中访问汇编程序中的变量如果需要在 c 程序中访问汇编程序中的变量,则汇编程序中的变量名必须以下划线为首字符,并用 global 使之成为全局变量。如果需要在 c 程序中调用汇编程序中的过程,则过程名必须以下划线为首字符,并且,要根据
8、c 程序编译时使用的模式是 stack-based model 还是 registerargument model 来正确地编写该过程,使之能正确地取得调用参数。(3)在线汇编在 C 程序中直接插入 asm(“*”),内嵌汇编语句,需要注意的是这种用法要慎用,在线汇编提供了能直接读写硬件的能力,如读写中断控制允许寄存器等,但编译器并不检查和分析在线汇编语言,插入在线汇编语言改变汇编环境或可能改变 C 变量的值可能导致严重的错误。二 汇编和 C 接口中寻址方式的改变:需 要注意的是,在 C 语言中,对于局部变量的建立和访问,是通过堆栈实现的,它的寻址是通过堆栈寄存器 SP 实现的。而在汇编语言中
9、,为了使程序代码变得更为精 简,TI 在直接寻址方式中,地址的低7位直接包含在指令中,这低7位所能寻址的具体位置可由 DP 寄存器或 SP 寄存器决定。具体实现可通过设置 ST1寄存器 的 CPL 位实现,CPL=0,DP 寻址,CPL=1,SP 寻址。在 DP 寻址的时候,由DP 提供高9位地址,与低7位组成16位地址;在 SP 寻址的时候,16位地址是由SP(16位)与低7位直接相加得来。由于在 C 语言的环境下,局部变量的寻址必须通过 SP 寄存器实现,在混合编程的时候,为了使汇编语言不影响堆栈寄存器 SP,通常的方式是在汇编环境中使用 DP 方式寻址,这样可以使二者互不干扰。编程中只要
10、注意对 CPL 位正确设置即可1.word 的意思就相当与 C 语言里的 int,char 等定义一个变两的宽度2.编译错误原因有2:a.如果在汇编里面定义.global(全局符号),那么在 C 语言里面应该用 extern声明,以引用该符号。b.在汇编里面声明的时候,符号前应加下划线,如 FIQ_Addr:.word EXTint_FIQ应为:FIQ_Addr:.word _EXTint_FIQ 在 C 语言里面应用 extern 声明。另外,一中方法是,用.ref 代替.global 来声明符号,这样就不用在 C 源程序里面用extern 声明了。两种方法结果相同。我讲的是用 C 和汇编混
11、编程用法,至于C+变量如何翻译成汇编符号可以用仿真器,自己去看,原则类似.汇编与 C 语言混合编程的关键问题1 C 程序变量与汇编程序变量的共用为了使程序更易于接口和维护,可以在汇编程序中引用与 C 程序共享的变量:.ref_to_dce_num,_to-dte_num,_to_dce_buff,_to_dte_buff在汇编程序中引用而在 C 程序可直接定义的变量:unsigned char to_dte_buffBUFF_SIZE;/DSP 发向 PC 机的数据int to_dte_num;/缓冲区中存放的有效字节数int to_dte_store;/缓冲区的存放指针int to_dte_
12、read;/缓冲区的读取指针这样经过链接就可以完成对应。2 程序入口问题在 C 程序中,程序的入口是 main()函数。而在汇编程序中其入口由*.cmd 文件中的命令决定,如:-e main_start;程序入口地址为 main _start。这样,混合汇编出来的程序得不到正确结果。因为 C 到 ASM 的汇编有默认的入口 c-int00,从这开始的一段程序为 C 程序的运行做准备工作。这些工作包括初始化变量、设置栈指针等,相当于系统壳不能跨越。这时可在*.cmd 文件中去掉语句:-emain_start。如仍想执行某些汇编程序,可以 C 函数的形式执行,如:main_start();/其中含
13、有其他汇编程序但前提是在汇编程序中把_main_start 作为首地址,程序以 rete 结尾(作为可调用的函数)的程序段,并在汇编程序中引用_main_start,即.ref _main_start。3 移位问题在 C 语言中把变量设为 char 型时,它是8位的,但在 DSP 汇编中此变量仍被作为16位处理。所以会出现在 C 程序中的移位结果与汇编程序移位结果不同的问题。解决的办法是在 C 程序中,把移位结果再用0X00FF 去“与”一下即可。4 堆栈问题在汇编程序中对堆栈的依赖很小,但在 C 程序中分配局部变量、变量初始化、传递函数变量、保存函数返回地址、保护临时结果功能都是靠堆栈完成。而 C编译器无法检查程序运行时堆栈能否溢出。5 程序跑飞问题编译后的 C 程序跑飞一般是对不存在的存储区访问造成的。首先要查.MAP 文件与 memory map 图对比,看是否超出范围。如果在有中断的程序中跑飞,应重点查在中断程序中是否对所用到的寄存器进行了压栈保护。如果在中断程序中调用了 C 程序,则要查汇编后的 C 程序中是否用到了没有被保护的寄存器并提供保护(在 C 程序的编译中是不对 A、B 等寄存器进行保护的)。
限制150内