首页 理论教育 C51函数与中断函数的原理及应用

C51函数与中断函数的原理及应用

时间:2023-10-23 理论教育 版权反馈
【摘要】:表4-8寄存器传递函数参数表4-9函数返回值4.中断函数C51提供以调用中断函数的方法处理中断,编译器在中断入口产生中断向量,当中断发生时,跳转到中断函数,中断函数以RETI指令返回。C51编译器支持直接编写中断服务函数程序,从而减轻了采用汇编语言编写中断服务程序的繁琐程度。3)圆括号为函数标志,interrupt为中断函数的关键字。

C51函数与中断函数的原理及应用

C语言是函数式语言,C源程序中有一个主函数main(),由主函数调用其他函数,程序的功能是由函数完成的。C51提供丰富的库函数,只要在源文件开头包含相应的头文件,就可以调用库函数,也允许用户自己定义函数。

1.函数的定义

定义一个函数的一般形式如下:

(1)类型说明符。类型说明符指定函数执行结果返回值的数据类型,若没有返回值可用void表示或缺省。

(2)函数名。函数名为一个标识符,主函数用main,其他函数按函数的功能取名。

(3)形参表列。函数名后括号内的形参表列相当于子程序的入口参数,是主调函数传送给被调用子函数的参数及类型,形参可以是整型字符型或数组元素等变量,也可以是地址指针,形参可以有一个或几个(用‘,’号分开),也可以没有,但函数名后的函数标志括号()不可省略。

(4)函数体。花括号内的声明部分和语句称为函数体,函数的功能是由函数体完成的,有返回值的函数必须有一个或几个return语句。花括号内的声明和语句也可以没有,此时称为空函数,什么也不执行。

【例4-8】 求两个整型变量中的大数

2.函数的调用

(1)函数调用的一般形式。函数调用的一般形式为:

函数名(实参表列)

实参的个数、顺序、数据类型必须和函数定义中的形参一一对应,参数之间用“,”号分开。若没有参数传递可省略()内的实参表列,但函数标志括号不能省略。

(2)函数调用方式。

1)函数调用语句:这种方式适用于无参数传递的函数。

例如:

inil_sys();/*调用无参数的初始化程序*/

2)函数表达式:例如:c=2*max(a,b);

3)函数参数:例如:m=max(a,max(b,c));

(3)对被调用函数的声明。如果调用自定义函数,应该在主调函数的源文件开头对被调函数作声明(函数原型),使编译系统对调用函数的合法性进行检查,如果主调函数和被调函数不在同一个文件中,在声明中加extern(表示调用外部函数)。函数声明的一般形式为:

[extern]类型说明符 函数名(形参表列);

例如: int max(int x,int y); /*在同一文件中*/

extern int max(int x,int y);/*不在同一文件中*/

如被调函数位于调用函数之前,可以省去该函数声明。

3.C51函数的参数传递

C51支持用工作寄存器传递参数,最多可以传3个参数,也可以通过固定存储区来传速参数。表4-8和表4-9列出了参数传递中寄存器使用情况。

表4-8 寄存器传递函数参数

表4-9 函数返回值

4.中断函数

C51提供以调用中断函数的方法处理中断,编译器在中断入口产生中断向量,当中断发生时,跳转到中断函数,中断函数以RETI指令返回。

(1)中断函数的定义。C51编译器支持直接编写中断服务函数程序,从而减轻了采用汇编语言编写中断服务程序的繁琐程度。为了在C语言源程序中直接编写中断服务函数的需要,C51编译器对函数的定义进行了扩展,增加了一个扩展关键字interrupt,使用关键字interrupt可以将一个函数定义成中断服务函数。由于C51编译器在编译时对申明为中断服务程序的函数自动添加了相应的现场保护、阻断其他中断、返回时恢复现场等处理的程序段,因而在编写C51中断服务函数时可以不必考虑这些问题,而把精力集中在如何处理引发中断的事件上。C51用关键字interrupt和中断号定义中断函数,定义中断服务函数的一般形式为:

中断函数注意事项:(www.xing528.com)

1)中断函数无返回值,数据类型以void表示,也可以缺省。

2)中断函数名为标识符,一般以中断名称表示,如timer()。

3)圆括号为函数标志,interrupt为中断函数的关键字。

4)中断号为该中断在IE寄存器的使能位位置,比如外部中断0的中断号为0;而串行口的中断号为4。应根据所选单片机的器件手册正确编写中断号。

5)选项[using n],指定中断函数使用的工作寄存器组号,n=0~3。如果使用[using n]选项,编译器不产生保护和恢复R0~R7的代码,执行速度会快一些。这时中断函数及其所调用的函数必须使用同一组工作寄存器,否则会破坏主程序的现场。如果不使用[using n]选项,中断函数和主程序使用同一组寄存器,在中断函数中编译器自动产生保护和恢复R0~R7现场,执行速度慢一些。一般情况下,主程序和低优先级中断使用同一组寄存器,而高优先中断可使用选项[using n]指定工作寄存器组。

关键字interrupt后面的n是中断号,n的取值范围为0~31。编译器从8*n+3处产生中断向量,具体的中断号n和中断向量取决于不同的MCS-51系列单片机芯片,基本中断源和中断向量如表4-10所示。

表4-10 常用中断号和中断向量

MCS-51系列单片机可以在内部RAM中使用4个不同的工作寄存器组,每个寄存器组中包含8个工作寄存器(R0~R7)。C51编译器扩展了一个关键字using,专门用来选择MCS-51系列单片机中不同的工作寄存器组。using后面的n是一个0~3的整型常数,分别选中4个不同的工作寄存器组。在定义一个函数时using是一个选项,如果不用该选项,则由编译器选择一个寄存器组作绝对寄存器组访问。需要注意的是,关键字using和interrupt的后面都不允许跟一个带运算符的表达式。关键字using对函数目标代码的影响如下:在函数的入口处将当前工作寄存器组保护到堆栈中,指定的工作寄存器内容不会改变,函数返回之前将被保护的工作寄存器组从堆栈中恢复。使用关键字using在函数中确定一个工作寄存器组时必须十分小心,要保证任何寄存器组的切换都只在控制的区域内发生,如果不做到这一点将产生不正确的函数结果。另外还要注意,带using属性的函数原则上不能返回bit类型的值,并且关键字using不允许用于外部函数,关键字interrupt也不允许用于外部函数。

编写MCS-51系列单片机中断程序时应遵循的规则:

1)中断函数不能进行参数传递,如果中断函数中包含任何参数声明都将导致编译出错。

2)中断函数没有返回值,如果企图定义一个返回值将得到不正确的结果。因此建议在定义中断函数时将其定义为void类型,以明确说明没有返回值。

3)在任何情况下都不能直接调用中断函数,否则会产生编译错误。因为中断函数的返回是由MCS-51系列单片机指令RETI完成的,RETI指令影响MCS-51系列单片机的硬件中断系统。如果在没有实际中断请求的情况下直接调用中断函数,RETI指令的操作结果会产生一个致命的错误。

4)如果中断函数中用到浮点运算,必须保存浮点寄存器的状态,当没有其他程序执行浮点运算时可以不保存。C51编译器的数学函数库math.h中,提供了保存浮点寄存器状态的库函数fpsave和恢复浮点寄存器状态的库函数fprestore。

5)如果在中断函数中调用了其他函数,则被调用函数所使用的寄存器组必须与中断函数相同。用户必须保证按要求使用相同的寄存器组,否则会产生不正确的结果,这一点必须引起足够的注意。如果定义中断函数时没有使用using选项,则由编译器选择一个寄存器组作绝对寄存器组访问。另外,由于中断的产生不可预测,中断函数对其他函数的调用可能形成递归调用,需要时可将被中断函数所调用的其他函数定义成重入函数。

(2)中断函数举例。主程序和中断函数之间的信息交换一般通过全局变量(见后介绍)实现。例如,定时器中断函数修改变量Tick_count,主程序可查询Tick_count之值作相应的处理。如是否进行A/D采样,是否进行键盘或显示器的定时扫描等。

【例4-9】 T0定时器中断函数

(3)无用中断的处理。为了提高系统的可靠性,对于不使用的中断,编写一个空的中断函数,使之能通过指令RETI返回主程序。例如外部中断0若不用,可以编写如下空中断函数。

extern0_ISR()interrupt 0{}

5.局部变量和全局变量

(1)局部变量。在一个函数(即使是主函数)内部定义的变量在本函数内有效,在函数外无效。在复合语句内定义的变量也只能在本复合语句内有效,复合语句外无效。这类变量称为局部变量。因此,不同函数内使用的变量可以使用相同的名称。局部变量名是用小写字母表示的标识符。

(2)全局变量。一个源文件包含若干个函数,在函数外部定义的变量可以为多个函数所共用,有效范围从定义变量处到文件结束,一般在文件开头定义,使之对整个文件有效。这类变量称之为全局变量。全局变量名称一般以大写字母开头。

设置全局变量增加了函数之间的联系渠道(特别适用于主程序和中断程序之间信息交换),但不宜使用过多,全局变量使函数的移植性变差。

6.变量的存储种类

变量定义中的存储种类指出变量的存储方式和作用域

(1)auto动态变量。在函数或复合语句内部定义的变量,在定义中若缺省存储种类则默认为动态变量,动态变量只在函数被调用时,系统才给动态变量分配存储单元,函数执行结束时释放存储空间。动态变量只能在函数或复合语句的内部使用。

(2)static静态变量。在函数内或复合语句内的变量定义中,用static指定存储种类,这种变量称为静态局部变量,静态局部变量在程序运行时始终存在(占用存储单元),但只能在函数内部使用,其作用是本次调用函数时能使用上次调用后的变量值。例如中断函数中定义的一些特殊变量可以用静态变量。全局变量也是静态变量,始终占有存储单元,但可以为多个函数共用。

(3)用extern声明外部变量。在函数外部定义的变量称为外部变量(即全局变量),如果在变量定义处之前使用该变量,必须用extern声明,从声明处开始可使用该变量,如果一个文件中使用另一个文件中的全局变量,在使用之前也应用extern声明。

(4)用extern声明外部函数。一个文件使用另一个文件中的函数,也用extern声明是外部函数。如

extern int max(int x,int y)

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈