基于koilc的8051单片机嵌入式开发_第1页
基于koilc的8051单片机嵌入式开发_第2页
基于koilc的8051单片机嵌入式开发_第3页
基于koilc的8051单片机嵌入式开发_第4页
基于koilc的8051单片机嵌入式开发_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

基于koilc的8051单片机嵌入式开发

1c语言生成模块8151纳米针系列是八本最著名的机系列之一。近几年,随着8051系列单片机版权的开放,在8051系列上的应用开发不断增加,而且应用规模比以往大,可执行代码往往上几百KB。这对于现在32位的PC平台来说只是小菜一碟,而对于8位的单片机来说,已经算是大规模的开发了。这种大型的嵌入式开发不可能完全用汇编语言或C语言来完成。C语言便于模块化的编程风格、优良的可读性、良好的可移植性和调试方便性更是这种大型程序开发的项目维护管理所需要的。另外,C51经过多年的发展,已经具有很多优秀的集成开发工具,KeilC就是其中之一,这些集成开发工具为程序开发调试提供了良好的人机接口。因此,C语言广泛应用在这类大型的嵌入式程序中,通常占95%以上的代码量。由于C51是8051单片机的C语言编译器,与ANSI-C编译器有不同的地方,具有很多8051单片机的特点。280c语言代码设计8051系列单片机有多种存储器类型:外部程序存储器、内部程序存储器、外部数据存储器、内部数据存储器。在开发较大型程序的时候,因为内部程序存储器和内部数据存储器容量都比较小,通常会被分配给实现底层功能的汇编语言使用。C语言的代码一般使用外部程序存储器和外部数据存储器。由于51系列单片机16位地址寄存器的限制,外部程序存储器和外部数据存储器的寻址范围都是64KB。分组连接定位器BL51允许生成代码长度大于64KB的8051目标程序,它可以管理一个公共区域(COMMONAREA)和最多32个代码组区域(BANKAREA),每个代码组最大为64KB。8051单片机本身不支持代码组切换,切换要通过额外的地址线(片选信号)来完成。代码组切换的软件功能由文件L51_BANK.A51完成。每次组切换要花费50个机器周期和2个字节的堆栈空间,所以如果发生频繁的组切换,会消耗CPU大量的时间。外部数据存储器和外部程序存储器包括公共区域和组区域就是我们最关心的部分。3存储模式分类C51有三种存储器模式,分别是SMALL、COMPACT和LARGE。存储器模式决定默认情况下给变量分配的存储器的类型。本文所讨论的问题都设定在LARGE存储器模式下,在这种模式下,变量缺省被定义在外部存储器中。3.1外部程序存储的静态分配图我们可以通过查看BL51连接器产生的m51文件来了解程序所使用的存储器的情况。在m51文件中的LINKMAPOFMODULE部分,可以看到其中XDATAMEMORY段是外部数据存储器的静态分配图,CODEMEMORY段是外部程序存储器公共区域的连接分配图,紧跟在后面的是CODEBANKx段就是各个组代码的连接分配图。在这些段里,我们可以看到类型、开始地址、长度和段名等的信息。段名的前缀?PR?、CO?和?XD?是最常见的,分别代表程序执行代码、程序代码中的常量和放在外部存储器的数据变量。而段的后缀一般就是大写的C文件名的前缀。3.2堆栈方式管理通常硬件设计时外部数据存储器要比外部程序存储器少得多,一般限制在64KB内,这是在一般的PC平台开发中很少遇到的。根据应用的不同,我们可以采用包括算法、程序设计方法和技巧等方面的各种内存受限的开发方法,不能一一尽述。这里将讲述C51在存储管理方式上不同于ANSI-C的特殊的地方。首先以下面的例子来了解C51是如何给不同类型的变量分配存储器的。为了产生短小和快速的代码,C51缺省把函数看作不可重入的,不使用堆栈来管理函数。对上面例子中的所有变量,包括函数fun1里面的a,b和函数fun2里面的a,b,C51都在外部数据存储器里分配不同的空间。这是C51与ANSI-C不同的地方,也是相同的代码在C51编译器和ANSI-C编译器上有不同行为的原因。C1这种缺省的不可重入函数处理方式一方面令那些利用堆栈的程序设计方法如递归函数出错;另一方面它为函数中的自动变量分配不同的空间也浪费了大量宝贵的外部数据存储器空间。对于大型的应用来说,我们更趋向使用与ANSI-C一致的堆栈方式。这时候,我们可以使用C51的特殊保留字reentrance把函数声明为可再入函数,C51编译器使用堆栈方式来管理可再入函数的变量。在上面例子中应用reentrance后代码的如下:现在,编译器只为全局变量g、fun1里面的静态变量sa和fun1里面的静态变量sa在XDATA分配不同的空间。而对于fun1和fun2的参数变量b和自动变量a,则使用在XDATA中的模拟堆栈空间,在程序运行时才自动分配。这样,我们就节省了大量的自动变量的空间。要注意的是,中断函数不可以使用reentrance。另外,上面例子不直接使用保留字reentrance是为了方便在非C51下试调代码,在非C51的编译环境下,我们只要把例子中的首行改为#defineCOMPILER_REENTRANCE就可以避免非C51编译器不认识C51的特殊保留字reentrance的错误了。3.3公共区域ct的生成外部程序存储器放置连接器产生的公共区域代码和组代码。公共区域中的代码可以在任何时候由所有代码组使用。这些代码包括:复位和中断向量、常数、C51中断函数、组切换跳转表和库函数。其实,公共区域与每个组的代码共享64KB的寻址空间,连接器缺省把公共区域放在64KB空间的低端,如图1所示。而且公共区域在每个64KB中的起始地址和内容完全一样,所以叫做公共区域。这样,实际上,程序代码可用的最大空间=组数目×64KB-(组数目-1)×公共区域大小。可见,为了获取更多的代码空间,就要尽可能减少公共区域的大小。分析公共区域的代码后,可以从三个方面减少代码。1用一个中断函数C51编写的中断函数必需放在公共区域里,但是在中断函数里面可以调用任何组的函数。我们可以利用中断函数的这个特性,把中断函数写成只有一个函数调用的外壳函数的形式,把实际工作交给组代码里的函数完成。这个方法可以减少中断函数的大小,但是必须考虑组切换的时间(50个机器周期)是否满足中断函数处理时间的要求。2减少库函数的大小因为库函数的调用有时需要采用一些特殊的调用方式,这些方式有时会受到组间切换的影响,所以连接程序BL51总是库函数段放置在公共区域,程序员也无法重新定位库函数段到其他地方。要减少库函数段的大小,就要减少使用的库函数的数目。我们需要了解某个库函数在哪些组里被调用,还有被调用的次数。我们应该尽量把被多个组调用,而且被调用频率最高的库函数保留在公共区域;考虑重写那些只是在单个组里被调用或使用频率很低的库函数。通过重写这些库函数,我们可以根据自己要求去裁剪原来库函数的功能,使得执行代码更小。另外,我们还可以自由摆放重写后函数的位置,一般是放在发生调用的那一组里,以减少公共区域的大小。3调整传输字符缺省情况下,程序中的所有字符串常量会被安排在公共区域里。这种安排的好处是程序员可以像ANSI-C的习惯一样放心地传递字符串常量的指针来调用函数,不需要担心C51特殊的跨组调用问题。因为每个64KB的代码组都有公共区域的代码,而且定位地址是一致的。但是在大型开发,特别是涉及人机用户界面相关的开发中,程序中会存在大量的字符串常量,如果按照以上的缺省配置方式来存放,这些字符串将占用大量的公共区域空间。为了减少公共区域中字符串常量的大小,我们可以调整的BL51设定,把常量放在指定的组,而不放在公共区域里面。例如,我们要把文件file1.c中的常量放在组1,在KeilC集成开发环境下,选择Project菜单下Optionsfortarget,然后在BL51Misc页下的Misccontrols中,把file1.c的常量段?CO?FILE1加到BANK1()的括号中。在把常量放在独立的组以后,我们就必须考虑跨组调用的问题。3.4组切换时的pstC51的指针不带有代码组的信息,不能辨识是指向哪个代码组的,在发生代码组切换的时候,这些指针就会出现问题。如以下的例子:如图2所示,假设函数fun1(void)在组1,display(char*pstr)函数在组0,并根据上面所述的方法把字符串常量放置在组1,连接器分配给常量“中文”的起始地址是1000H。在程序运行的时候,程序把常量“中文”的起始地址1000H压入堆栈,调用display,因为display在组0,所以程序发生组切换,由当前组1切换到组0,在display函数里面,程序读出刚刚压入的地址信息1000H并赋予pstr,这时候pstr指向的地址是组0的1000H地址,而不是组1的1000H,所以display显示的结果是不正确的。为了解决常量字符串指针的跨组调用的问题,我们先把常量字符串拷贝到外部数据存储器,然后传递指向外部数据存储器字符串的指针给需要切换组调用的函数。如图2所示。使用这个方法后上例的代码修改如下:另外,其他指向代码组的指针,如指向函数的指针都存在同样的问题。不过函数指针使用得比较少,一般可以通过调整函数所在的代码组来解决。此外,出于提高性能和减少错误的考虑,我们通常希望组切换尽量少发生,这就涉及到如何把组代码分配到64KB-公共区域代码大小的若干个组里去了。这时候我们采用软件工程的方法,把软件按功能划分为模块,较大的模块划分为更小的子模块。然后分析各个模块、子模块间的耦合度,把耦合最大的模块尽量放在同一个组里。这属于静态分析的方法。另外,我们还可以对程序进行动态分析,把软件运行时经常执行的代码放在同一个组里面。经过这样划分和整理以后,一方面使得软件架构条理清晰,一方面减少了跨组调用的情况。3.5动态内存池的自适应内容分配对于大型应用来说,在很多情况下都会用到C语言的动态内存分配库函数。因为C51是为资源相对宝贵的单片机而设的,所以C51动态内存分配函数的使用也与一般的C语言有所不同。首先,考虑到单片机硬件和应用的独特性,C51的动态内存分配函数不单以函数库的形式提供的,同时还提供源程序。源代码分别在KeilC安装路径下的\C51\Lib目录下的init_mem.c、malloc.c、alloc.c、realloc.c和free.c文件里。用户可以根据自己的需要编写自己的内存分配函数来替换这些库函数。当然,用户也可以把这些文件拷贝出来加入自己的工程中,以减少公共区域的大小。其次,在使用C51的所有动态内存管理函数(malloc,alloc,realloc,free,)前,必须先初始化动态内存池,其函数原型是:voidinit_mempool(voidxdata*p,unsignedintsize);其中p是动态内存池的开始地址,size是动态内存池的大小。函数的功能是从外部数据存储器里面划出一块内存建立动态内存池,并交由动态内存分配函数管理,程序员必须保证动态内存池不会与其他的内存区域相互覆盖,相互改写内容。实际应用中的问题是如何确定动态内存池的位置。我们提供以下两个方法方法一:把动态内存池建立在变量分配堆栈的上部,与堆栈共用同一空间,如图3所示。先任意填写init_mempool()函数调用中的内存池开始地址或填写地址0X0000,在编译连接通过后,利用连接器生成的m51文件分析外部数据存储器的使用情况,确定C51变量分配堆栈的顶端地址,也就是外部数据存储器的最后空闲区域的开始地址。然后把init_mempool()的开始地址改为堆栈的顶端地址。最后再重新编译连接一次。这个方法的一个弊端是,随着程序的修改增减,变量分配堆栈的顶端会发生改变,所以每次程序的更改,都要重复以上的步骤。方法二:如果只是模块A需要使用动态内存分配,那么动态内存池可以与其他不和模块A同时运作的模块来共享一部分内存。例如,模块A需要5KB的内存池用作动态分配,而模块B要用到3个2KB的缓冲区。我们可以依照如下代码来定义模块B缓冲区和初始化内存池。其示意图如图4所示:4参数返回值和贮存前阀值的传递关系在单片机开发中,底层的硬件中断和驱动等的例程往往用汇编语言来实现。在大型的嵌入式开发中,C语言代码调用底层的汇编语言代码。要解决C语言与汇编语言之间的调用,最重要的是了解它们之间的函数名的命名规则和函数参数传递规则和返回值传递规则。C51程序模块编译成目标文件后,其中的函数名依据其定义的性质不同会转换为不同的函数名。对于不传递参数或参数不通过寄存器传递的函数,其函数名不改变。voidfunc(void)转变后函数名为FUNC。对于参数通过寄存器传递的函数,转变后函数名在原来的名字前加′_′。voidfunc(intt)转变后函数名为_FUNC。函数参数传递和寄存器的对应关系,一般按参数从左到右的顺序填写寄存器R7到R0。char类型占1byte,先填R7,第二个char类型填R5。int类型占2bytes,按高低位先填R6、R7,第二个int类型填R4、R5。float和double类型占4bytes,按高低位填R4、R5、R6、R7。一般指针占3bytes,存储器类型在R3,高位在R2,低位在R1。函数返回值和寄存器之间的对应关系与参数传递的对应关系差不多。以函数charVoiceOperation(charmode,intid,char*str)为例,R7存放char类型参数mode,R4、R5存放int类型参数id,R1、R2、R3存放char*类型参数str,函数的返回值存放在R7。根据上面的参数和返回值传递规则,用汇编编写函数_VoiceOperation。在C语言中声明函数VoiceOperation为外部函数,然后就可以在C语言中调用汇编语言实现的VoiceOperation。5调试模块的实现调试是软件开

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论