51中断using的用法

1 参考

官方文档里关于using的说明可参阅2个地方,(1)keil软件菜单栏->Help->uVision Heip,打开帮助文件,然后依次展开Ax51 Assembler User Guide -> Control Statement -> Reference -> USING,(2)帮助文件依次展开CX51 Compiler User‘s Guide-> Language Extensions -> Function Declarations -> Register Banks

2 中断用法

void 函数名(void) interrupt n using m
{
    函数体语句
}

n是中断号    

  • 0   是外部中断0

  • 1   是定时中断T0

  • 2   是外部中断1

  • 3   是定时中断T1

  • 4   是串行中断

  • 5   是定时器T2

 m是寄存器组

BANK0~BANK3,这4个组(BANK)在RAM中的位置分别是[00H, 07H]、[08H, 0FH]、[10H, 17H]、[18H, 1FH],换句话说,RAM中的00H地址、08H地址、10H地址、18H地址,这四个地址的名字都叫R0

3 BANK0~BANK3共4组3 函数的局部变量可能会使用相同的地址

51不可重入函数:keil编译51程序时,使用了覆盖技术(不同函数的形参和局部变量可分时共享同一个绝对内存单元)。的局部变量分时共享同一RAM空间。因为51的RAM空间极其有限,keil在编译51的C程序时,C语言函数中的局部变量、形参、返回值、返回地址会优先使用工作寄存器R0~R7(因为工作寄存器读写速度最快),如果这8个字节不够用,keil会为其余的局部变量分配RAM空间,这个空间在编译完成后就固定下来了,假如某个函数中的局部变量a编译后位于RAM的0x5d位置,但是keil也有可能为另一个函数的中的局部变量b分配空间时,把b也分配到RAM的0x5d位置,相当于a和b分时复用同一个RAM空间,这种编译手段也就导致了函数的不可重入特性。

51可重入函数:由仿真栈来实现,即使main调用链和中断同时调用它也不会出现上述被破坏的情形,因为add5_re的形参和局部变量全部都被定义到了仿真栈中,main调用链中使用add5_re函数会申请栈空间中断时add5_re又会申请新的栈空间

对于STM32等RAM较为充足的单片机来说,keil分配局部变量就不采用这种分时复用RAM的方法了,而是通过栈,具体地说就是,在调用函数前,先把实参添加到工作寄存器(工作寄存器并不是全部用来传参,还有一些用来传递函数的返回值、函数的返回地址等),若工作寄存器满足不了传参需求,那么其余实参将被压栈,这样,在进入函数之后,通过读取工作寄存器出栈,即可令形参获得实参的值;另外函数中的局部变量一般也先从工作寄存器开始分配空间,若空间不足,会从栈中申请空间。这种编译方法是最常见的,而上一段keil针对51的编译手段比较另类

对于51的中断服务函数,它没有形参,也不用返回值,但是一般肯定有局部变量,这时就需要用到R0~R7。

单片机有四组寄存器组,任何时候,单片机只能用到四组寄存器中的一组。普通函数的执行过程中,传参、局部变量、返回值默认使用BANK0的R0~R7;如果发生了中断,中断服务函数虽然没有形参,也不用返回值,但是一般如果有局部变量也想使用R0~R7,要么通过入栈来保护R0~R7,要么通过修改PSW的RS0和RS1两个比特位切换BANK来保护R0~R7。

但是这8个Rn不能直接入栈,PUSH R0这样的语句是不允许的,要想R0入栈只能用两句
 

MOV A R0;

PUSH A;

这样的后果是,每次工作寄存器入栈都需要2*8=16条汇编语句才能完成,再加上A、B、PSW等寄存器入栈等,相当于每次中断都要消耗大量的时间来出栈入栈,影响程序速度。

KEIL C51使用using n编写的C语言中断服务函数,就编译成PSW切换BANK的方式。如切换到1组,然后退出中断时,再切换到0组。同时,在你另外一个中断里如果不想保存寄存器,你可切换到2组,返回时再切换到0组。也就是说程序采用0组寄存器,中断可采用其它3组,如果不想保存寄存器,一个中断只能用一组,否则得保存寄存器。

对于同一优先级的中断,可以using同一个寄存器组,因为同一优先级的中断不会互相打断,他们只会分时复用同一个BANK。但是对于不同优先级的中断函数,必须手动设定为让他们使用不同的BANK,因为高优先级的中断会打断低优先级的中断,如果使用相同的BANK,一旦发生中断嵌套,低优先级服务函数正在使用的R0~R7将会被覆盖。这些东西都是说的在用C编程时的情况,如果用的是汇编编程,那我们可以自由的任意压栈出栈CPU寄存器,任意的压栈出栈BANKn,只要程序员自己心里清楚地知道哪些Rn正在被使用,那他就能写出安全的程序。用C编程的话,程序员比较省心,只要使用了using指令,就能轻易地保护R0~R7。当然,在汇编中使用USING也是可以的,也不用压栈出栈BANK,也很省心。

如果我们使用了keil为51构造的仿真栈,以大编译模式为例,keil会给仿真栈指针?C_XBP分配一个RAM空间(2个字节),这个空间在哪呢?通过查看map文件(后缀名为.m51)我们发现,若我们的中断函数只使用了BANK 1(普通函数默认已把BANK 0给用了,除非程序员为所有的普通函数都用using 1或2或3来修饰,如果不是闲的蛋疼没人会这么做),这时仿真栈指针?C_XBP将会被分配到BANK 2的R0和R1所在的位置上,也即RAM的10H、11H地址。如果普通函数使用了BANK0,中断函数只使用了using 2,那么?C_XBP将会被分配到BANK 1的R0和R1所在的位置上;如果普通函数使用了BANK0,中断函数使用了BANK1和BANK2,那么?C_XBP将会被分配到BANK 3的R0和R1所在的位置上。

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值