C51编译器-语言扩展(4)-函数
扫描二维码
随时随地手机看文章
Function Declarations函数声明
Cx51对标准C进行了一定的扩展,使用这些扩展可以:
(1)把一个函数声明为一个中断过程
(2)选择使用的寄存器组
(3)选择存储器模式
(4)声时可重入
(5)声明外部函数
在函数声中包含这些扩展或属性,使用下面的方法声明Cx51函数
[return_type]funcname([args]) [{small | compact | large}][reentrant][interruptn][usingn]
这里
return_type 返回值类型
funcname 函数名称
args参数
small, compact, or large 存储器模式
reentrant 是否可重入
interrupt 是否是中断函数
using 使用哪个寄存器组
Function Parameters and the Stack函数参和堆栈
经典的8051堆栈指针只访问内部的数据存储器。Cx51紧接着在所有的数据之后放堆栈区。堆栈指针间接地访问内部数据存储器,可以访问所有的00-FFH的空间
在经典的8051中堆栈的空间是受限制的,最大只有256字节。除了函数参数消耗堆栈空间,Cx51为每个函数指定了一些固定的内存空间。当函数被调用时,调用者必须在进入函数之前把参数拷贝到这个固定的空间中。然后函数从这个固定的空间中读取并使用这些参数。在这个过程中只有返回地址存放在堆栈中。中断函数会需要更多的堆栈空间,因为程序必须切换寄存器组并且保存一些寄存器的值到堆栈中。
注:Cx51允许使用在某些8051的增强型变种中可用的扩展的堆栈区。通过这种方式,堆栈区域的大小可以增加到几K字节。
在缺省的情况下,Cx51使用三个寄存器传递函数的参数,这样可以提高代码的执行速度。
注:有些8051变种仅提供64字节的片上数据存储器,大多数器件有256字节。在使用存储器模式时应该把这些都考虑进去,毕竟片上的data和idata数据存储器直接影响到堆栈空间的大小。
Passing Parameters in Registers通过寄存器传递参数
Cx51允许使用CPU寄存器传递三个参数,由于这种方式不需将参数写入存储器和从存储器中读出,所以明显地提高了系统的性能。参数的传递受上一章讲到的REGPARMS 和NOREGPARMS指令控制。
下表列出了用于不同位置参数和数据类型的寄存器。
参数个数
Char, 1-yte ptr
Int, 2-byte ptr
Long, float
Generic ptr
1
R7
R6&R7
R4-R7
R1-R3
2
R5
R4&R5
R4-R7
R1-R3
3
R3
R2&R3
R1-R3
没有可用的寄存器来传递参数,则用一个固定的存储器区域来传递函数参数。
Function Return Values函数返回值
函数返回值总是使用CPU寄存器。下表列出了返回值的类型和所用的寄存器。
返回值
寄存器
描述
Bit
进位标志
Char, unsigned char, 1-byte ptr
R7
Int, unsigned int, 2-byte ptr
R6&R7
高位字节为R6,低位字节为R7
Long, unsigned long
R4-R7
高位字节为R4,低位字节为R7
Float
R4-R7
32位IEEE格式
Generic ptr
R1-R3
存储器类型在R3,高位R2,低位R1
注:如果函数的第一个参数是bit类型的,其他的参数据是不通过寄存器传递的。这是因为能在寄存器中传递的参数与前述的编号方案都不相同。因此,bit类型的参数应该在参数列表中末尾声明。
Specifying the Memory Model for a Function
声明函数的存储器模式
Cx51函数通常采用缺省的存储器模式来决定哪个存储器空间用于函数的参数和局部变量。
可以通过包含small, compact,或large在函数的属性中来指定函数的存储器类型。
如:
int large_func (int i, int k) large /* Large model */
{
return (mtest (i, k) + 2);
}
函数使用small存储器模式的好处是函数的参数和局部变量都放在8051的RAM中。因此,数据访问效率非常高。然而,内部的数存储器有限。有时候有限的内部数据存储器的大小不能满足需要,就必须使用其他的存储器模式。在这种情况下,可以使用上面的方法定义一个函数使不同的存储器模式。
通过指定函数的存储器模式,可以从三种可能的可重入堆栈和结构指针中择优使用。堆访问SMALL模式要比访问LARGE模式快得多。
Specifying the Register Bank for a Function
指定函数使用的寄存器组
8051系列器件的低32字节被分成了4个组,每个组8个寄存器。程序可以通过R0-R7访问这些寄存器。寄存器组可以通过程序状态字(PSW)的两个位选择。寄存器组对中断处理或者是使用实时操作系统非常有用。在中断服务程序中CPU切换寄存器组而不把不当前的寄存器都保存起来。
关键字using用来指定函数使用的寄存器组:
void rb_function (void) using 3
{
。。。。。。。
}
关键字using的参数是一个0-3的整型常量,而且表达式中不允许有操作符出现。在函数的原型中不允许出现using关键字。这个关键词对函数代码有如下影响:
(1)当前选择的寄存器组在函数的入口处被保存在堆栈中
(2)指定的寄存器组被设定
(3)前面使用的寄存器组被保存下来直到当前的函数退出
不能关键字using来声明一个返回值在寄存器中的函数。在使用的时候必须非常小心,确保寄存器组切换只出现在谨慎地控制地区域。稍不小心会得到错误的返回值。即使用同一个寄存器组,使用了using关键字声明了属性的函数也不能返回一个bit类型的值。
典型地,using属性对于声明了interrupt属的函数是非常有用的。为每一个级别的中断都声明一个不同寄存器组是比较常见的。因此,你可以在所有非中断程序中使用一个寄存器组,在高优先级中断中使用一个寄存器组,在低优先级中断中使用一个寄存器组。
Register Bank Access寄存器访问
Cx51允许在一函数中定义缺省的寄存器组。控制指令REGISTERBANK允许程序员在源文件中指定在所有函数另使用哪一个寄存器组。然而这个指令并不产生切换寄存器的代码。
复位后,8051在PSW中装入00h从而选择寄存器组0。所以缺省地所有非中断程序代码都使寄存器组0。要想改变,必须:
(1)修改startup代码以选择其他的寄存器组
(2)使用REGISTERBANK指令进行声明
缺省地,Cx51编译器生成用绝对地址访问R0-R7的代码。这是为了最高的执行效率。绝对地址的使用通过指令AREGS和NOAREGS控制。使用绝对址进行寄存器访问的函数不能被使用其他寄存器组的函数调用。由于调用者使用了不同的寄存器组,这样做会引起不可预料的后果。要使用函数对当前的寄存器组不敏感,函数必须在编译前使用控制指令NOAREGS。这对于那种可能在主函数中调用,也可能被使用不同寄存器组的中断程序调用的函数很有用。注:Cx51编译器并不检查函数间的寄存器组是否一致。因此,必须确保使用不寄存器组的函数只调用那些不指定缺省寄存器组的函数。