C51的中断函数的格式为:void (void) x [using y]

以下是梦游的一些分析:

一、中断函数是一个特殊的函数,没有参数,也没有返回值;但是程序中允不允许使用呢?答案是允许的,不过只能用”;”,不能用”(z);”;用在一些需要快速返回的地方,对应的汇编会有多个ret语句,相对效率会高一些。

二、using的用法,using可以修饰任何函数,不过个人建议只用来修饰中断函数;简单的说,“using”会指定工作寄存器组,由于中断函数一般都是比较紧急的事情,有时一条语句都会斤斤计较,所以使用using切换寄存器组可以省去一些压栈的动作,由于51只有两级中断,同级中断不能被打断,因此,我们可以同级中断设成同样的寄存器组,从某种意义上来说,有一组寄存器是多余的。同时个人建议中断函数应该使用using这个关键字。

三、中断中调用函数,首先要讨论中断函数中调用函数的必要性,前天在论坛上我和别人争论过这个问题,现在我还是这个观点:有些情况中断中调用函数还是必要的,这个时候是不是该调用函数,其实和普通函数差不多,首先是这个函数如果调用多次,或者要带一些参数什么的就更加必要的;前天有人跟我叫劲,说假如只调用一次且无参数无返回的函数要直接写,因为如果用函数,至少会增加CALL和RET两条语句,我不敢苟同,我是实际调试发现的,当你程序比较复杂时,你将那部单独拉出来做成函数,可能代码和时间都会更好。

四、中断中调用的函数最好不要被中断外的其它函数调用,因为会出现“重复调用”的警告,有时这种调用是很致命的,有人说这个函数可以用来修饰,是的,的确可以这样解决,不过个人不建议这么做,也许这样会跟你减少很多堆栈空间,并且整个程序的优化要差很多,个人建议出现这种情况就把这个函数写两遍,分成两个函数分别调用。

五、中断调用了函数,会出现一些莫名其妙的问题,一些数据不对(我现在遇到这个问题)其实一般是因为汇编中使用了绝对寄存器引起的,有人说中断函数使用那个寄存器组,被中断调用的函数就使用哪个寄存器组(我认为好参考C51.PDF: from an must with the same bank as the . When the is not , the may using the bank (by the using or by the ) for that . may occur when a a bank other than the one . Refer to “ Bank ” on page 124 for more .),我认为这样不好:

这样会增加额外的消耗,使用using会增加一下语句:

PUSH PSW

MOV PSW, #XX

….

POP PSW

更重要的是,使用using的函数不能有返回值(这个地方有问题,应该可以有返回值,下文说是不能不能返回bit类型的值),这是致命伤(所以这不是致命伤,可以使用using解决这个问题)

个人推荐的方法有两种:

1、使用“# ”禁止使用绝对寄存器

2、使用“# RB(x)”来指定本文件的工作寄存器组

六、一般说来,要求中断函数尽可能的短,但也有特殊情况,有些前/后台的系统中,就会把很多相对重要的事情放到定时中断(这个定时中断类似实时操作系统中的时钟节拍)去做,而且程序很长。我单独提出来这点是想告诉大家,中断函数也是一个函数而已,只要系统有必要,可以做一些看似不合理的事情,该出手时就出手,就像goto语句一样。

本文引用地址:

转自,请大家去他的博客中支持他,里面有不错的文章。括号中是我的理解

关于using:

举个例子来说:

定义一个函数

void func( char i) {

有如下一个中断函数

void int_0(void) 0 using 1 {

….

在默认状态下,func使用寄存器组0(BANK0),那么当int_0调用func时是否存在当传递参数时会造成参数传递错误?

如果在中断服务函数ISR中使用寄存器,那么必须处理好using的使用问题:

1、中断服务函数使用using指定与主函数不同的寄存器组(主函数一般使用 bank 0)。

2、中断优先级相同的ISR可用using指定相同的寄存器组,但优先级不同的ISR必须使用不同的寄存器组,在ISR中被调用的函数也要使用using指定与中断函数相同的寄存器组。(应该是这样的)

3、如果不用using指定,在ISR的入口,C51默认选择寄存器组0,这相当于中断服务程序的入口首先执行指令:

MOV PSW #0

这点保证了,没使用using指定的高优先级中断。可以中断使用不同的寄存器组的低优先级中断。

4、使用using关键字给中断指定寄存器组,这样直接切换寄存器组而不必进行大量的PUSH和POP操作,可以节省RAM空间,加速MCU执行时间。寄存器组的切换,总的来说比较容易出错,要对内存的使用情况有比较清晰的认识,其正确性要由你自己来保证。特别在程序中有直接地址访问的时候,一定要小心谨慎!至于“什么时候要用到寄存器组切换”,一种情况是:当你试图让两个(或以上)作业同时运行,而且它们的现场需要一些隔离的时候,就会用上了。在ISR或使用实时操作系统RTOS中,寄存器非常有用。

寄存器组使用的原则:

1、8051的最低32个字节分成4组8寄存器。分别为寄存器R0到R7。寄存器组由PSW的低两位选择。在ISR中,MCU可以切换到一个不同的寄存器组。对寄存器组的访问不可位寻址,C51编译器规定使用using或禁止中断的函数(# )均不能返回bit类型的值。

2、主程序(main函数)使用一组,如bank 0;低中断优先级的所有中断均使用第二组,如bank 1;高中断优先级的所有中断均使用再另外一组,如bank 2。显然,同级别的中断使用同一组寄存器不会有问题,因为不会发生中断嵌套;而高优先级的中断则要使用与低优先级中断不同的一组,因为有可能出现在低优先级中断中发生高优先级中断的情况。编译器会自动判断何时可使用绝对寄存器存取。

3、在ISR中调用其它函数,必须和中断使用相同的寄存器组。当没用命令做明确的声明,编译器将使用绝对寄存器寻址方式访问函数选定(即用using或指定)的寄存器组,当函数假定的和实际所选的寄存器组不同时,将产生不可预知的结果,从而可能出现参数传递错误,返回值可能会在错误的寄存器组中。

举一例子:当需要在中断内和中断外调用同一个函数,假定按照程序的流程控制,不会出现函数的递归调用现象,这样的调用会不会出现问题?若确定不会发生重入情况,则有以下两种情况:

1、如果ISR和主程序使用同一寄存器组(主程序缺省使用BANK 0,若ISR没有使用using为其指定寄存器区,则缺省也使用BANK 0),则不需其他设置。

2、如果ISR和主程序使用不同的寄存器组(主程序缺省使用BANK 0,ISR使用using指定了其他BANK),则被调用函数必须放在:

#

# AREGS

控制参数对中,指定编译器不要对该函数使用绝对寄存器寻址方式;或者也可在->C51,选中“Dont use ”,使所有代码均不使用绝对寄存器寻址方式(这样,执行效率将稍有降低)。不论以上的哪一种情况,编译器均会给出重入警告,需手工更改参数,做重入说明。

3、还有一种办法:如果被调用函数的代码不是很长,还是将该函数复制一份,用不同的函数名代替,这种情况适合ROM有足够多余的空间。

因此,对using关键字的使用,如果没把握,宁可不用,交给编译系统自己去处理好了。

例子

用上using可以精简代码,节省堆栈,不过有时会出现一个问题:

用上using ,在中断服务程序里调用函数要小心一点,因为keil C有时会产生依赖绝对地址的代码,例如如下函数,功能是从片外的存储设备中读取一个字节:

uchar (uchar )

PBYTE[];

会被编译成如下代码:

MOVR0,0x07

MOVXA,@R0

MOVR7,A

这时,如果在中断服务程序里调用 (0xAA); 就会发现读出的数据根本不对,因为using 1使得中断服务程序在调用函数时使用第一组寄存器传递参数,编译器生成的代码如下:

MOVR7,#0xAA

而这个函数的代码是使用绝对地址为0x07的第0组寄存器的R7来传递参数的,所以会出问题。

解决方法是在定义这个函数的前面加上”# “,这样编译器就会生成不依赖于绝对地址的代码了,函数被编译生成的代码如下:

XCHA,R0

MOVA,R7

XCHA,R0

MOVXA,@R0

MOVR7,A

这样就可以大胆的使用using了,使用using才是充分利用51架构的使用方法。

Usingcomputer_c#using_usingclothbags

———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,永久会员只需109元,全站资源免费下载 点击查看详情
站 长 微 信: nanadh666