一、中断基础
1、概念:
计算机在执行现行程序的过程中,出现某些急需处理的异常情况和特殊请求(满足中断条件),cpu自动停止正在运行的程序并转入处理新情况的程序(中断函数),处理完毕后又返回原被暂停的程序继续运行。(zigbee根据中断触发条件,有外部中断、定时中断等)
2、CC2530的中断资源:
CPU 有 18 个中断源。每个中断源都有它自己的位于一系列 SFR 寄存器中的中断请求标志。相应标志位请求的每个中断可以分别使能或禁用。
3、中断使能/屏蔽逐级管理
笔者根据开发经验,将中断的使能概括为三级使能管理模式,从总使能(第一级)——>资源使能/组中断使能(第二级)——>功能使能(第三级),注意:有些中断资源没有第三级使能。资源使能/组中断使能、功能使能都会有一个对应的中断标志位,其中资源使能/组中断使能的标志位被置1,会引起CPU跳转中断函数。
一个具体的中断功能的开启过程必须完整,具体分析如下:
二、使能中断开发步骤
1、中断开启步骤
为了使能任一中断功能(以外部中断为例),应当采取下列步骤:
(1)、设置 IEN0 中的 EA 位为 1 使能全局中断(总使能)
寄存器IEN0的第7位是系统所有的总开关,可以直接操作EA=1,开启中断总开关。
(2)设置寄存器 IEN0、IEN1 和 IEN2 中对应中断使能(资源使能/组中断使能)
寄存器 IEN0、IEN1 和 IEN2的位值对应着各个中断资源的开启/屏蔽,如下图所示,通过设置对应的值,可以使能对应资源的中断。
例如寄存器IEN1 的第5位,对应P0口外部中断的组使能,若是要用P0口的某一位作为外部中断信号接收口,则必须使能该位;
寄存器IEN1 的第5位,对应着T3定时器这个资源所引发的中断的使能,若要使用T3定时器的中断资源(捕获/比较/溢出中断),则需要使能该位。
(3)组中断/资源中断 中断标志
步骤(2)中资源使能/组中断使能开启后,当中断条件满足时产生中断,会有相应的中断标志位被自动设置(置1),笔者这里不严谨地取名——资源中断标志位,如下图所示,然后CPU回跳转执行中断函数。中断函数编写见下一小节。资源中断标志需要我们在中断函数中清除(置0)。
组中断/资源中断 中断标志为对应的寄存器如下图
(4)设置中断资源对应寄存器的各中断使能位为 1(功能使能)有些中断没有这一级使能
在步骤(2)中,开启了某一个资源的资源中断/组中断后,我还要开启相应的功能中断使能。功能中断使能相当于三级使能,随着不同的资源有着不的寄存器控制,并没有由集中几个寄存器统一管理,只能具体使用具体去查,笔者这里就举两个例子
例如,我们在开启P0口的组中断后,还要选择具体哪一位作为外部中断的信号入口,需要使能功能中断,如下图
当然。外部中断还涉及是否设置上升沿或下降沿中断,IO口的上下拉配置等,这里主要讲中断使能过程的梳理,其他细节不过多赘述。
又例如,T3定时器的资源中断使能后,具体使用哪种功能的中断(捕获/比较/溢出中断),需要配置相应的功能中断使能,如下图
(5)功能中断 中断标志
同资源中断标志位类似,当相应的功能中断使能后,中断发生时,也会产生相应的中断标志位,在这里笔者不严谨地取名——功能中断标志。同样的,中断标志需要我们在中断函数清除(置0)。
例如外部中断功能中断标志
T4定时器的功能中断标志
几点注意总结:
(1)资源中断标志位和功能中断标志位都应在中断函数中进行清除置0,为下一次中断准备;但在清除顺序上,最好遵循先清除功能中断标志位再资源中断标志位。
(2)不开启资源使能/组中断使能,无法不会引发程序跳转中断函数执行;
(3)可以不严谨地认为,资源使能/组中断使能与资源中断标志位相对应, 功能使能与功能中断标志位相对应。
2、中断函数
系统中断的意义就是中断函数的执行,这是中断的目的。中断函数的格式如下:
三、案例
案例,通过P0_1口作为引起下降沿触发外部中断,使得P0_1控制的LED灯进行亮暗翻转。
#include<iocc2530.h>
//初始化一个按键中断
void initInterrupt()
{
P0SEL &= 0xfd; //中断口是P0_1,相关设置
P0DIR &= 0xfd;
P0INP &= 0xfd;
P2INP &= 0xdf;
EA = 1; //使能总中断(一级使能)
P0IE = 1; //使能P0组中断(二级使能)
P0IEN |= 0x02; //功能中断使能(三级使能)
PICTL |= 0x01;//下降沿触发
}
// 初始化一个LED P1_0
void initLED()
{
P1SEL &= 0xfe;
P1DIR |= 0x01;
P1_0 = 1;
}
void main()
{
initInterrupt(); //初始化一个按键中断
initLED(); // 初始化一个LED
while(1);
}
#pragma vector=P0INT_VECTOR
__interrupt void P0_INT(void)
{
if(P0IFG & 0x02) //判断是否是相应的PO的哪一位位引起的中断
{
delayms( 10 ) ;
if(P0_1 == 0)
{
P1_0 = ~P1_0;
}
}
P0IFG = 0; //清除中断标志
P0IF = 0; //清除中断标志
}