您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > C-51语言程序设计基础
c51设计基础1.7寄存器组定义8051系列的器件包含4个相同的寄存器组,每个寄存器组包括8个寄存器(R0~R7),C51编译器可使在一函数中决定用哪一寄存器组成为可能。绝对寄存器的访问可用AREGS/NOAREGS和REGISTERBANK来控制。定义一个带扩展性的函数语法如下:返回类型函数名([参数])[模式][再入][中断n]usingn再入和中断将在后两节讨论。例:voidrb_function(void)using3;“using”不允许用于外部函数,它对函数的目标代码影响如下:l函数入口处将当前寄存器保存入栈;l指它的寄存器还会改变;l函数退出前寄存器组被恢复。“using”定义对于返回一个寄存器内的值的函数是无用的。编程者必须十分小心以保证任何寄存器切换都只在仔细控制的区域发生。如果不做到这一点将会产生不正确的函数结果。即使当编程者使用同一寄存器组时,带“using”属性的函数原则上也不能返回一个位值。实际产生的代码决定于编译器及不同开关条件,有时用命令产生绝对的寄存器地址,当需要进行这样的地址计算时,使用REGISTERBANK指令的影响只是计算Arn寄存器使用的地址,而必进行实际切换。1.8中断服务程序C51编译器及其对C语言的扩充允许编程者对中断的所有方面进行控制。这种支持能使系统编程者创建高效的中断服务程序,用户只需在普通和高级方式下关心中断及必要的寄存器组切换操作,C51编译器将产生最合适的代码。1.8.1中断服务程序的定义使用中断服务函数的完整语法如下:返回值函数名([参数])[模式][再入]interruptn[usingn]“interrupt”后接一个0~31的常数,不允许使用表达式。中断不允许用于外部函数,它对函数目标代码的影响如下:l当使用函数时,SFR中的ACC、B、DPH、DPL和PSW(当需要时)入栈;l如不使用寄存器组切换,甚至中断函数所需的所有工作寄存器(Rn)都入栈;l函数退出前,所有的寄存器内容出栈;l函数由8051控制命令“RETI”终止。1.8.2开发中断过程时的规则l不能进行参数传递,如果中断过程包括任何参数声明,编译器将产生一个错误信息;l无返回值,如果想定义一个返回值将产生错误,然而,如果返回整型值编译器将不产生错误信息,因为整型值是默认值,因而编译器不能清楚识别。l编译器会识别对中断过程的直接调用并拒绝它们,在任何情况下不能直接调用中断过程,因为退出该过程是由操作码RETI完成的。RETI影响8051芯片的硬件中断系统,由于硬件上没有中断请求存在,因而这个操作码的结果是不定的并且通常是致命的。由于疏忽,可能用指针来间接调用它,这是值得注意的。l编译器从绝对地址8n+3处产生一个中断向量,其中n为中断号,该向量包括一个到中断过程的跳转,向量的产生可由指令NOINTVECTOR压缩。因而用户有能力从独立的汇编模块中提供中断向量。lC51编译器允许0~31个中断,究竟允许哪些中断依赖于使用的8051系列芯片,编译器不能检查。l如果中断程序中有浮点运算,必须保持浮点寄存器状态,当没有其它程序执行浮点运算时,可能不保存,函数“fsave”和“fprestore”用来保存浮点状态。l中断过程调用的函数所使用的寄存器必须与中断过程相同,当没有使用“using”指令时,编译器会选择一个寄存器组作绝对寄存器访问,当子程序使用另一个寄存器组时会发生错误,用户必须保证按要求使用相应寄存器组,C编译器不会对此检查。例:unsignedintinterruptent;unsignedcharsecond;time()interrupt1using2/*定时器0中断服务程序,工作寄存器使用2区*/{if(++interruptcnt==4000){second++;/*秒计数加一*/interruptcnt=0;/*清中断计数*/}}1.9再入函数再入函数可被递归调用,调用可发生在任何时候,即使是在中断过程中。在实时处理的应用问题中常常需要再入函数。使用关键字“reentrant”可有选择地定义函数有再入能力。在存贮器模式的基础上为再入函数在内部或外部存贮器中模拟了一个栈区域。由于MCS-51缺乏合适的寻址方法,使用栈结构是相当必要的。因而应尽量少用再入函数。定义一再入函数的语法如下:返回值函数名([参数])[模式]reetrant[interruptn][usingn]例:intcalc(chari,intb)reentrant{intx;x=table[i];return(x*b);}使用再入函数有如下规定:l不能传递类型为“bit”的参数。也不能声明一个局部标量,再入功能不能包括位操作及MCS-51可位寻址区域。l不能在“alien”函数调用再入函数。l再入函数可同时有其它属性,如“using”函数模式和“interrupt”。l再入函数不能同时有“alien”属性,从而遵守PL/M规则。l返回地址及可能的PUSH/POP操作存入MCS-51的栈中或被执行(不在再入栈中)。l在同一模块中,任意模块的再入函数(smallreentrant,lagereentrant,compactreentrant)不能与具有不同模式的再入函数混合。再入函数举例:/*这个再入函数可以从“main”及中断程序中调用*/intcalc(chari,intb)reentrant{intx;x=table[i];return(x*b);}1.10参数传递通过CPU的寄存器可传递至多三个参数。这样产生与汇编子程序相当的有效参数机制。如果寄存器被占用,或说明了“#pragmaNOREGPARMS”,参数变量将使用固定的存贮器位置,存贮器模式决定了8051存贮器为参数提供的位置。表:候选的参数寄存器参数类型CHAR,1字节指针INT,2字节指针LONG,FLOAT一般指针一个参数R7R6,R7R4~R7R1,R2,R3二个参数R5R4,R5R4~R7R1,R2,R3三个参数R3R2,R3…R1,R2,R3函数的返回值放在CPU固定的寄存器中,列表如下。这样,与汇编子程序的接口变得非常容易。表:函数返回值的寄存器用法返回值寄存器意义bit进位标志C(unsigned)charR7(unsigned)intR6,R7高位在R6,低位在R7(unsigned)longR4~R7高位在R4,低位在R7floatR4~R732位IEEE格式指针R1,R2,R3类型选择在R3,高位在R2,低位在R11.11PL/M51接口FranklinC51利用关键字“alien”提供了一个与IntelPL/M-51直接和简单和接口,关键字“alien”在所有存贮器模式下可用于“extern”和“public”函数。现有的PL/M-51程序利用C语言的强大功能可与FranklinC-51连接起来。使用关键字“alien”,C51可用PL/M-51规定的参数传递方式工作。“alien”可用于外部或公共函数,并可用于任一模式,这样,已有的PL/M-51程序可加入到C-51中。Alien函数始终包含一个标准的参数数量,因此,C中定义的三点(…)记号不被接受,且会产生一个错误信息。例:externaliencharplm_function(unsignedchar,unsignedint);externcharc_function(unsignedcharx,unsignedchary){return(x*y);}PL/M-51兼容函数必须定义以关键字“alien”。这样,PL/M函数的参数传递及参数返回规定在C编译器中才被考虑。1.12汇编接口参数是通过固定的CPU寄存器传给汇编程序的,当使用“#pragmaNOREGPARMS”时,则通过固定的存贮器位置传递参数。这样就给汇编与FranklinC-51之间提供了一个非常简洁的接口。返回值在CPU寄存器中。下例为在汇编中用来编码的“toupper”函数,参数传递发生在寄存器中。UPPERSEGMENTCODE;程序代码段PUBLIC_toupper;入口地址RESGUPPER;选择程序代码段toupper:MOVA,R7;char参数在寄存器R7中CJNEA,#’a’,UPP1UPP1:JCUPPERTCJNEA,#’z’+1,UPP2UPP2:JNEUPPRETCLRACC.5UPPRET:MOVR7,A;char返回值在寄存器R7中RET;返回C1.13内部函数FranklinC-51支持下列内部函数。内部函数既是再入的又是有效的。表:C51的内部函数函数描述memcpy,memsset,memchr,memmove,memcmpANSI的内存操作功能strcmp,strcpyANSI字符串处理功能_crol_,_irol_,lrol_左移字符、整数、长整数_crolr_,_irolr_,lrolr_右移字符、整数、长整数_nop_空操作_testbit_测试并清位(JBC指令)1.14代码优化FranklinC51可将即使有经验的程序员编制的代码进行优化。用户可选6个优化级,另外,用OPTIMIZE(SIZE),NOREGPARMS和NOAREGS时会影响生成代码的类型。C51的所有优化如下:(1)一般优化:l常数折迭:发生在一个表达式或地址计算中的几个常数值组合为一个常数。l跳转优化:跳转转到最终的目标地址,以提高程序效率。l死码消除:不可执行代码(死码)可从程序中去掉。l寄存器变量:只要有可能,自动变量和参量放入寄存器中,为这些变量保留的数据存贮器将去除。l通过寄存器传递参数:寄存器中可传递最多三个参数。l全局公共子式消除:相同的子表达式或地址计算(多次发生在同一函数中)将被识别出来,并且只要有可能,将只计算一次。(2)基于8051的优化:l窥孔(PEEPHOLE)优化:只要能节省存贮空间或执行时间,复杂的运算都将化简。l访问优化:常数和变量直接包含在操作中。l数据覆盖:函数的数据和位移被标记为OVERLAYABLE,被L51用其它数据和位覆盖。lCASE/SWITCH优化:SWITCH/CASE语句优化为一个跳转或一串跳转。(3)代码生成选项:lOPTMIZE(SIZE):共同的“C”操作被子程序代替:程序码长被压缩。lNOAREGS:不使用绝对寄存器访问,程序代码在这种方式下独立于寄存器组。lNOREGPARMS:参数传递总是在本数据段完成,程序代码与早期C-51版本兼容。1.15C库C-51编译器包含6个不同的编译库,可根据不同函数的需要进行优化,这些库几乎支持所有的ANSI函数调用。因此,用此标准的C程序可在编译和连接后立即运行。库描述C51S.LIBSMALL模式,无浮点运算C51FPS.LIB浮点数学运算库(SMALL模式)C51C.LIBCOMPACT模式,无浮点运算C51FPC.LIB浮点运算库(COMPACT模式)C51L.LIBLARGE模式,无浮点运算C51FPL.LIB浮点运算库(LARGE模式)C51编译器包含的库模块,都有源代码,对它们可作与硬件相关的修改。用户改变对于现有硬件输入和输出结构的两个模块,就可修改所有库函数,同样也可以重新很快地构造如“printf”和“puts”函数用LCD显示。L51连接器的检查从而保证所有模块都用一种模式编译并自动选择编译库,从而使用户完全可以不用不同库的细节。1.16配置文件C51编译器可根据不同的硬件环境由4个文件作出修改。下列配置文件包括在C-51软件包中:STARTUP51.51:C51编译器的启动程序,所有的栈指针和存贮器,只要需要,将被初始化。INIT.A51:在文件中已明确初始化了变量作初始化。如果系统装入“看门狗”,该文件可包含附加的“看门狗”刷新。PUBCHAR.C:函数“printf”、“puts”等的字符输出核心程序,该程序可根据用户硬件加以修改(如LCD显示)。GETKEY.C:函数“getchar”、“scanf”等的字符输入核心程序,该程序可根据硬件加以修改(如矩阵键盘)。所有的文件
本文标题:C-51语言程序设计基础
链接地址:https://www.777doc.com/doc-4011631 .html