Keil C使用经验小结.doc
《Keil C使用经验小结.doc》由会员分享,可在线阅读,更多相关《Keil C使用经验小结.doc(19页珍藏版)》请在三一办公上搜索。
1、Keil C使用经验小结秦建勋2005/7/29目录引言1语言扩展1数据存储器区域1存储器模型2指针3函数3参数传递3自动变量分配8C51的陷阱9运算溢出9编译与链接控制10编译时控制10定制文件10Startup.A5110INIT.A5110L51_BANK.A5111链接时控制11代码或常数的绝对定位11和_at_关键字的比较11Overlay12如何控制overlay15overlay相关的其它问题15可重入函数16Vision IDE使用简介16简单的代码习惯17头文件(.h文件)习惯17C模块的习惯18CVS的使用18引言2004年6月以来开始接触Keil C,原因是MUSE项目控
2、制器采用了目前8位微控制器领域最经典、使用最广泛的8051 MCU。从一年多来的使用实践看,我们的8051 IP还是比较可靠的,那么以后可能有更多的产品需要用到该IP,因此看起来还是需要在相当长一段时间需要与Keil C打交道。本文就简单小结我对Keil C的一些理解以及使用过程中的一些经验、教训,试图起到抛砖引玉的作用,为大家总结Keil C使用经验提供一个讨论的起点。语言扩展所谓语言扩展是指相对标准C(如ANSI C严格说来,主要是针对ANSI C,因为Keil C显然不支持C+,一些语言特性,如“/”注释是C 99标准引入的)进行的针对8051硬件平台进行的扩展,这样的C编译器才是真正为
3、8051量身订做的:资源的使用是紧凑的、编译出来的代码是高效的,另外,Keil 公司好象也出了针对ARM的C编译器,所以,从命名来说,看起来C51更准确些,实际上Vision也是这么做的。数据存储器区域8051的数据存储器分为片内和片外存储器两大类,片内RAM分为直接访问和间接访问两部分,片外RAM由可有页寻址和普通区域两部分,总是让人混淆,下面我结合C51的数据存储器区域给一个图示解释FF007F80FF只能间接访问,idata直接访问:data间接访问:idataSFRs,只能直接访问,sfrFFFF00FF0000pdata, movx Rnxdatamovx DPTR片内数据存储器片外
4、数据存储器,DMbdataRegister banks1F2F图1 8051数据存储器对应的C51存储器模型我们可以看到,data作为可存放数据的空间只有128字节,还要排除掉32字节的寄存器组和16字节的可位寻址空间,实际只有80字节的变量可分配空间,所以有时候会出现链接时报告片内数据只使用100字节却数据空间溢出的情况(使用small存储器编译模型),原因就在于程序引入的附加data型的数据量已经超过了80字节,此时,把data型变量改为idata就可以通过链接,只要变量总量不超过片内的256字节(还应该考虑运行时堆栈大小 J)。存储器模型C51的存储器模型用于确定:函数参数、自动变量以及
5、不带显式存储器类型说明变量声明的缺省存储器类型,有如下几种模型:小模型(small model),在该模型下,所有变量缺省都驻留在8051片内存储器中(如同声明为data类型),变量的访问效率非常高。然而,所有对象,包括堆栈(运行时的最大堆栈容量)必须都放在片内RAM中,一般来说在程序规模小且使用overlay技术(后面会讲到)、没有声明可重入函数并多次嵌套调用情况下是最佳的。紧凑模型(compact model),该模型下,所有变量,缺省驻留在外部DM的一个page之内,(通过MOVX Ri指令访问,见图说明),紧凑模型的效率逊于小模型、优于打模型。这里自然产生一个问题问题,当紧凑模型下使用
6、的变量超过一个页大小(256字节)怎么办?多余的部分,Keil C手册说,使用P2的设置以使用另外的page,但实际情况是我们的8051只支持0页,我向徐国柱核实过,这体现在MOVX Ri的时候,16为DM地址总线的高8位(我们的8051与经典的不一样,经典的由于考虑到封装的要求,使用P0和P2,P0还是地址、数据复用,我们的8051和DM都是集成在片内的,没有封装带来的限制)始终为0,可否搞一个sfr来产生MOVX Ri指令执行时候的高8位地址,复位地址为0。我们现在的程序规模就采用了这种模式。大模型(large model),该模型下,所有变量缺省情况下都驻留在DM中,就象使用xdata存
7、储器类型修饰符声明一样(通过MOVX DPTR指令访问,寻址采用DPTR),这种方式速度慢,产生的代码也最多,而且对于需要频繁运算的变量,效率更低。指针通用指针以标准C指针的方式声明,如:char *s; /* string ptr */int*numptr; /* int ptr */long*state; /* Texas */ 通用指针总是以三字节进行存储,第一个字节是存储器类型,第二字节是指针代表的地址的高字节,第三字节是地址的低字节。通用指针的好处就是可以访问8051存储器空间中任何存储器区域中的变量,因为这个原因,很多Cx51库例程使用这种指针类型。存储器专用指针就是在指针声明的时
8、候,指定对应存储器类型,如:char data*str; /* ptr to string in data */int xdata*numtab; /* ptr to int(s) in xdata */long code*powtab; /* ptr to long(s) in code */由于存储器类型在编译期指定了,通用指针需要的存储器类型字节就不再需要了,而且,通用指针的指针地址部分必须取所有指针类型中最长的,2个字节,而存储器专用指针则根据实际的指针类型确定指针大小,对于idata, data, bdata, 和 pdata是一个字节,对于code和xdata是两字节,这样可以加快
9、速度和减少代码,用于函数参数的传递时候效果更佳。这里需要澄清两个概念:存储器专用指针,和位于特定存储区中的指针变量,前着是指指针的值(地址)指向的特定存储区的,后者是指指针本身(指针本身也是一个变量,只不过其值是个地址)存放在特定的存储区域,看下面的例子char data *str; /* 指向位于data空间的字符类型,指针本身的位置没说明,依据编译采用的存储器模型 */char data * xdata str; /* 指向位于data空间的字符类型,指针本身位于xdata中 */函数参数传递经典8051的堆栈指针只是以间接方式访问片内数据存储器,因此可以使用整个片内256字节的存储器。8
10、051的堆栈指针是向上增长的(即PUSH指令执行时是先增加栈指针SP,与x86相反),C51编译器把堆栈指针初始化到紧邻片内存储器所有变量之后的位置。由于堆栈空间最多为256字节,实际上还远小于这个值,因此C51编译器并不使用堆栈传递参数,而是为函数参数分配一个固定的存储器位置,函数调用发生时,调用者先把参数拷贝到该位置,然后被调用需要参数时就从该固定位置抽取参数,只有返回值是存储在堆栈上的(位返回值放在CF中)。这个固定存储器位置是怎么确定的呢?第一种情况,当参数满足下列条件的时候,采用寄存器传递参数这里特别需要注意的是,如果函数第一参数是bit类型,则后面的其它参数不能通过寄存器传递,因为
11、这种情况下破坏了上面的编号方案,因此,bit型的变量应尽量作为参数列表的末尾。那么,当2字节大小参数多于3个,或包含4字节大小的参数多于一个时,C51怎么传递参数呢?对于需要接收寄存器方式以外传递参数的函数,C51会自动产生一个参数传递数据段,命名方式是 “?函数名?BYTE”和“?函数名?BIT”,位参数在调用参数前先拷贝到?函数名?BIT段,所有其它参数拷贝到?函数名?BYTE段,在这些段中所有参数都分配空间,即使有些参数通过寄存器传递(是否效率低?),参数传递以它们声明的顺序存储在这些参数传递段中。需要说明的是,这些用于参数传递的固定存储器可能位于内部数据存储器或外部数据存储器,具体情况
12、依赖于使用的编译存储器模型:SMALL使用片内RAM,COMPACT使用DM的pdata,LARGE使用普通DM。特别需要注意的是,对于4字节(32位)大小、非寄存器、位于xdata(compact和large模型编译)参数的传递,C51是调用一个内部例程?C?LSTKXDATA来实现参数的拷贝(到对应参数数据段)的,效率相当低,所以我要建议诸如32位的运算都传地址,地址最多16位。#include bastype.hINT32 testF(INT16 arg1, INT16 arg2, INT16 arg3, INT16 arg4, INT32 arg5)return (arg1 + arg
13、2 + arg3 + arg4 + arg5);void main()testF(11, 22, 33, 44, 55);搞清楚参数是怎么传递后,我们就可以消除一个警告,因为以秦氏理解,C语言的参数永远是传值的(即使对于传指针,从指针作为变量这个意义上仍旧就传递的是值,C+由于引用的引入,从形式上改变了这一情况,尽管编译器实现仍旧使用指针),而且这个值还是在固定的存储位置,所以我们不能对实参(值)本身指定存储区位置INT16 testF(INT16 xdata arg, INT16 xdata * arg1, INT16 * data arg2);在上例中,第一个形参声明指定arg放在xdat
14、a空间,这违背了编译器选择固定存储器位置传递参数的原则;第二个形参声明是正确的,因为它只是说指针arg1指向的地址(即把指针视为一个变量的话,变量的值是一个指向xdata的地址);第三个形参对指针本身的位置进行限定,本质上犯了形参1声明的错误。?PR?_testF?TEST SEGMENT CODE ?XD?_testF?TEST SEGMENT XDATA OVERLAYABLE ?PR?main?TEST SEGMENT CODE EXTRNCODE (?C_STARTUP)EXTRNCODE (?C?LSTKXDATA)PUBLICmainPUBLIC?_testF?BYTEPUBLIC
15、_testFRSEG ?XD?_testF?TEST?_testF?BYTE: arg1?040: DS 2 arg2?041: DS 2 arg3?042: DS 2 arg4?043: DS 2 arg5?044: DS 4; #include bastype.h; ; INT32 testF(INT16 arg1, INT16 arg2, INT16 arg3, INT16 arg4, INT32 arg5)RSEG ?PR?_testF?TEST_testF:USING0; SOURCE LINE # 3;- Variable arg1?040 assigned to Register
16、 R6/R7 -;- Variable arg3?042 assigned to Register R2/R3 -;- Variable arg2?041 assigned to Register R4/R5 -; ; SOURCE LINE # 4; return (arg1 + arg2 + arg3 + arg4 + arg5); SOURCE LINE # 5MOV A,R7ADD A,R5MOV R7,AMOV R7,AMOV A,R6ADDC A,R2MOV R6,AMOV DPTR,#arg4?043+01HMOVX A,DPTRADDC A,R4MOV R4,A; ; SOUR
17、CE LINE # 6?C0001:RET ; END OF _testF; ; void main()RSEG ?PR?main?TESTmain:USING0; SOURCE LINE # 8; ; SOURCE LINE # 9; testF(11, 22, 33, 44, 55); SOURCE LINE # 10MOV DPTR,#?_testF?BYTE+06HCLR AMOVX DPTR,AINC DPTRMOV A,#02CH;44MOVX DPTR,AINC DPTRLCALL?C?LSTKXDATADB 00HDB 00HDB 00HDB 037H;55MOV R3,#02
18、1H;33MOV R2,#00HMOV R5,#016H;22MOV R4,#00HMOV R7,#0BH;11MOV R6,#00HLJMP _testF; END OF main自动变量 自动变量在标准C里是自动分配和释放的变量,一般对应函数栈帧上分配的、函数调用期间存在返回后消失的变量,从这个意义上说C51几乎没有自动变量(可重入函数除外),这里的自动变量可理解为函数内部的非静态存储局部变量。分配前面已经提到“C51 把函数的自动变量放在固定的存储器位置”,那么这个固定存储器位置是哪里呢?首先,速度最快、访问最简单的当推当前的寄存器组了,INT8 test(INT16 arg)/ lin
19、e 18INT8 temp = 0;/ line 20temp = 2;/ line 22if ( arg = 0 )return temp;elsereturn 0; FUNCTION _test (BEGIN) ; SOURCE LINE # 18;- Variable arg assigned to Register R6/R7 - ; SOURCE LINE # 19 ; SOURCE LINE # 20;- Variable temp assigned to Register R5 -0000 E4 CLR A ; SOURCE LINE # 220001 25E0 ADD A,AC
20、C0003 25E0 ADD A,ACC0005 FD MOV R5,A自动变量采用寄存器进行分配的原则是什么?视是否能容纳。超过的自动变量会在前面讨论参数传递超过寄存器部分一样,在固定存储器位置创建一个数据段来容纳这些自动变量,而不是放在栈上,这些数据段属性具有OVERLAYABLE的,所以进行overlay,怎么overlay,请参阅文档后部分。创建的数据段视当前的编译采用的存储器模型来确定,small是data,compact是pdata,large是普通xdataC51的陷阱运算溢出看下面例子UINT32 testF(UINT16 a, UINT16 b)return a * b; ;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Keil C使用经验小结 使用 经验 小结
![提示](https://www.31ppt.com/images/bang_tan.gif)
链接地址:https://www.31ppt.com/p-2385049.html