分享

C语言在8051单片机上的扩展(interrupt、using关键字的用法)

 七色彩虹ty 2014-07-25


C语言在8051单片机上的扩展(interruptusing关键字的用法)


 


直接访问寄存器和端口


定义


sfr   P0 0x80

       sfr     P1 0x81

       sfr     ADCON; 0xDE

       sbit EA     0x9F




操作


ADCON = 0x08 ;    

     P1
= 0xFF       ;    


     io_status = P0 ;

     EA
= 1         ;    




在使用了interrupt 1 关键字之后,会自动生成中断向量




ISR中不能 与其他 "后台循环代码"(the
background loop code)
共享 局部变量


因为 连接器 会复用 RAM中这些变量的 位置 ,所以 它们会有不同的意义,这取决于当前使用的不同的函数


复用变量对 RAM有限的51来将 很重要。所以,这些函数希望按照一定的顺序执行 而不被中断。




timer0_int() interrupt 1 using 2

{

       unsigned char temp1 ;

       unsigned char temp2 ;

       executable C statements ;

}




"interrupt"
声明 表示 向量生成在 (8*n3),这里,n就是interrupt参数后的那个数字

这里,08H的代码区域 生成 LJMP timer0_int 这样一条指令


"using"
tells the compiler to switch register banks on entry to an interrupt routine.
This "context" switch is the fastest way of providing a fresh
registerbank for an interrupt routine's local data and is to be preferred to
stacking registers for very time-critical routines. Note that interrupts of the
same priority can share a register bank, since there is no risk that they will
interrupt each other.


'using' 告诉编译器 在进入中断处理器 去切换 寄存器的bank。这个"contet"切换是

为中断处理程序的局部变量提供一个新鲜的寄存器bank 最快的方式。 对时序要求严格的程序,是首选的 stack寄存器(保存寄存器到stack)方式。


注意:同样优先级别的中断 可以共享 寄存器bank,因为 他们每次将中断 没有危险




If a USING 1 is added to the timer1 interrupt function prototype, the pushing
of registers is replaced by a simple MOV to PSW to switch registerbanks.
Unfortunately, while the interrupt entry is speeded up, the direct register
addressing used on entry to sys_interp fails. This is because C51 has not yet
been told that the registerbank has been changed. If no working registers are
used and no other function is called, the optimizer eliminiates teh code to
switch register banks.

如果在timer1 的中断函数原型中使用USING 1, 寄存器的pushing将被 MOV to
PSW
切换寄存器bank 所替换。




不幸的是,当一个中断入口被加速时。用在入口的 直接寄存器寻址 将失败。

这是因为 C51没有告诉 寄存器bank已经改变。如果 不工作的寄存器将被使用,如果没有其他函数被调用,优化器.....


Logically, with an
interrupt routine, parameters cannot be passed to it or returned. When the
interrupt occurs, compiler-inserted code is run which pushes the accumulator,
B,DPTR and the PSW (program status word) onto the stack. Finally, on exiting
the interrupt routine, the items previously stored on the stack are restored
and the closing "}" causes a RETI to be used rather than a normal
RET.


逻辑上,一个中断服务程序,不能传递参数进去,也不可返回值。

当中断发生时,编译器插入的代码 被运行,它 累加器 BDPTRPSW(程序状态字)入栈。最后,在退出中断程序时,预先存储在 栈中 被恢复。最后的"}"结束符号

插入 RETI 中断程序的最后,

为了用 Keil‘C’语言创建一个中断服务程序(ISR),利用 interrupt 关键词和正确的中断号声明一个 static
void
函数。Keil‘C’编译器自动生成中断向量,以及中断程序的进口、出口代码。Interrupt 函数属性标志着该函数为 ISR。可用 using 属性指定ISR使用哪一个寄存器区,这是可选的。有效的寄存器区范围为13




中断源的矢量位置


中断源               Keil中断编号           矢量地址

最高优先级             6                     0x0033

外部中断0             0                     0x0003

定时器0溢出           1                     0x000B

外部中断1             2                     0x0013

定时器1溢出           3                     0x001B

串口                   4                     0x0023

定时器2溢出           5                     0x002B

DMA                   7                     0x003B

硬件断点               8                     0x0043

JTAG                   9                     0x004B

软件断点               10                     0x0053

监视定时器             12                     0x0063




1.

函数在调用前定义与在调用后定义产生的代码是有很大差别的(特别是在优化级别大于3级时)。(本人也不太清楚为什么,大概因为在调用前定义则调用函数已经 知道被调用函数对寄存器的使用情况,则可对函数本身进行优化;而在调用后进行定义则函数不知被调用函数对寄存器的使用情况,它默认被调用函数对寄存器 ACC B DPH DPL PSW R0 R1 R2 R3R 4 R5, R6 R7)都已经改变,因此不在这些寄存器中存入有效的数据)


2.

函数调用函数时除在堆栈中存入返回地址之外,不在堆栈中保存其它任何寄存器(ACC B DPH DPL PSW R0 R1 R2 R3R 4 R5, R6 R7)的内容。(除非被调用函数使用了using特性)




3.

中断函数是一个例外,它会计算自身及它所调用的函数对寄存器(ACC B DPH DPL PSW R0 R1 R2 R3R 4 R5, R6 R7)的改变,并保存相应它认为被改变了的寄存器。




4.

使用C写程序时,尽量少使用using n
(n=0,1,2,3)
特性。(这个特性在本人使用的过程中存在一些问题,不知算不算是一个小bug




默认keil c51中的函数使用的是0寄存器组,当中断函数使用using n时,n = 1,2,3或许是对的,但n=0时,程序就已经存在了bug(只有中断函数及其所调用的函数并没有改变R0 ---- R7的值时,这个bug不会表现出来))


一个结论是,在中断函数中如果使用了using n,则中断不再保存R0----R7的值。




由此可以推论出,一个高优先级的中断函数及一个低优先级的中断函数同时使用了using n,(n = 0,1,2,3)当n相同时,这个存在的bug 是多么的隐蔽。(这恰是使人想象不到的)




使用不同寄存器组的函数(特殊情况外)不能相互调用

using"
关键字告诉 编译器 切换 register bank




如果中断程序不重要,using关键字 能忽略。

如果一个函数被从中断程序调用,而此中断强制使用using

当编译一个被调用的函数时,编译器必须告诉它


1)

在函数前 必须用伪 指令

#pragma NOAREGS


在进入 函数

#pragma RESTORE

或者

#pragmas AREGS




这样就不会使用 "绝对地址定位"




2


#pragma REGISTERBANK(n)


用这个指定告诉当前使用的 bank




NOAREGS指令 移除 MOV R7,AR7




中断服务例程




  

timer0_int() interrupt 1 USING 1 {  

unsigned char temp1 ;  

unsigned char temp2 ;  



}


被调用的函数


#pragma SAVE //
Rember current registerbank

#pragma REGISTERBANK(1)     // Tel C51 base address of
current registerbank.

void func(char x) {     // Called from interrupt routine      

// with "using1"  

  

}

#pragma RESTORE // Put back to original registerbank




如果中断服务例程使用了 USING,被中断服务例程 调用的函数一定要

REGISTERBANK(n)

一个被ISR调用的 函数 也可能被 后台程序 调用


为了函数
"reentrant"
(可重入)

8051
系列 MCU 的基本结构包括:32 I/O 口(4 8 bit 端口);两个16 位定时计数器;全双工串行通信;6 个中断源(2 个外部中断、2 个定时/计数器中断、1 个串口输入/输出中断),两级中断优先级;128 字节内置RAM;独立的 64K 字节可寻址数据和代码区。中断发生后,MCU 转到 5 个中断入口处之一,然后执行相应的中断服务

处理程序。中断程序的入口地址被编译器放在中断向量中,中断向量位于程序代码段的最低地址处,注意这里的串口输入/输出中断共用一个中断向量。8051的中断向量表如下:

中断源 中断向量

---------------------------

上电复位 0000H

外部中断0 0003H

定时器0 溢出 000BH

外部中断1 0013H

定时器1 溢出 001BH

串行口中断 0023H

定时器2 溢出 002BH


interrupt using 都是 C51 的关键字。C51 中断过程通过使用 interrupt
关键字和中断号(0 31)来实现。中断号指明编译器中断程序的入口地址中断序号对应着 8051中断使能寄存器IE 中的使能位,对应关系如下:

IE
寄存器 C51中的 8051

的使能位 中断号 中断源

--------------------------------

IE.0 0
外部中断0

IE.1 1
定时器0 溢出

IE.2 2
外部中断1

IE.3 3
定时器1 溢出

IE.4 4
串口中断

IE.5 5
定时器2 溢出


有了这一声明,编译器不需理会寄存器组参数的使用和对累加器A、状态寄存器、寄存器B、数据指针和默认的寄存器的保护。只要在中断程序中用到,编译 器会把它们压栈,在中断程序结束时将他们出栈。C51 支持所有 5 8051 标准中断从 0 4 和在 8051 系列(增强型)中多达 27 个中断源。

using
关键字用来指定中断服务程序使用的寄存器组。用法是:using 后跟一个0 3 的数,对应着 4 组工作寄存器。一旦指定工作寄存器组,默认的工作寄存器组就不会被压栈,这将节省 32 个处理周期,因为入栈和出栈都需要 2 个处理周期。这一做法的缺点是所有调用中断的过程都必须使用指定的同一个寄存器组,否则参数传递会发生错误。因此对于using,在使用中需灵活取舍。


 



出自:http://blog.sina.com.cn/s/blog_46c081e101009tr4.html


(2008-06-26 14:12:36)


 




    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多