CC2530的中断系统是为了让CPU对内部或外部的突发事件及时地做出响应,并执行相应的终端程序。中断由中断源引起,中断源由相应的寄存器来控制。当需要使用中断时,需配置相应的中断寄存器来开启中断,当终端发生时将跳入中断服务函数中来执行此中断所需处理的事件。
1.终端源和中断向量
CC2530有18个中断源,每个中断源都可以产生中断请求,中断请求可以通过设置中断使能SFR寄存器的中断使能位IEN0、IEN1或IEN2使能或禁止中断。
中断号码 | 描述 | 中断名称 | 中断向量 | 中断屏蔽 | 中断标志 |
0 |
RF TX RFIO下溢 或
RX FIFO溢出
| RFERR | 03H | IEN0.RFERRIE | TCON.RFERRIF |
1 | ADC转换结束 | ADC | 0BH | IEN0.ADCIE | TCON.ADCIF |
2 | USART0 RX完成 | URX0 | 13H | IEN0.URX0IE | TCON.URX0IF |
3 | USART1 RX 完成 | URX1 | 1BH | IEN0.URX1IE | TCON.URX1IF |
4 | AES加密解密完成 | ENC | 23H | IEN0.ENCIE | S0CON.ENCIF |
5 | 睡眠定时器完成 | ST | 2BH | IEN0.STIE | IRCON.STIF |
6 | 端口2中断 | P2INT | 33H | IEN2.P2IE | IRCON2.P2IF |
7 | USART0 TX完成 | UTX0 | 3BH | IEN2.UTX0IE | IRCON2.UTX0IF |
8 | DMA传输完成 | DMA | 43H | IEN1.DMAIE | IRCON.DMAIF |
9 | Timer1(16位)捕获/比较/溢出 | T1 | 4BH | IEN1.T1IE | IRCON.T1IF |
10 | Timer2(MAC Timer) | T2 | 53H | IEN1.T2IE | IRCON.T2IF |
11 | Timer3(8位)捕获/比较/溢出 | T3 | 5BH | IEN1.T3IE | IRCON.T3IF |
12 | Timer4(8位)捕获/比较/溢出 | T4 | 63H | IEN1.T4IE | IRCON.T4IF |
13 | 端口0中断 | P0INT | 6BH | IEN1.P0IE | IRCON.P0IF |
14 | USART1 TX 完成 | UTX1 | 73H | IEN2.UTXIE | IRCON2.UTX1IF |
15 | 端口1中断 | P1INT | 7BH | IEN2.P1IE | IRCON2.P1IF |
16 | RF通用中断 | RF | 83H | IEN2.RFIE | S1CON.RFIF |
17 | 看门狗计时溢出 | WDT | 8BH | IEN2.WDTIE | IRCON.WDTIF |
中断服务程序的入口地址即中断向量,CC2530的18个中断源对应了18个中断向量,中断向量定义在头文件"ioCC2530.h"中,定义如下:
/* ------------------------------------------------------------------------------------------------
* Interrupt Vectors
* ------------------------------------------------------------------------------------------------
*/
//RF内核错误中断(RF TX RFIO下溢或RF FIFO溢出)
#define RFERR_VECTOR VECT( 0, 0x03 ) /* RF TX FIFO Underflow and RX FIFO Overflow */
//ADC转换结束
#define ADC_VECTOR VECT( 1, 0x0B ) /* ADC End of Conversion */
//USART0 RX完成
#define URX0_VECTOR VECT( 2, 0x13 ) /* USART0 RX Complete */
//USART1 RX 完成
#define URX1_VECTOR VECT( 3, 0x1B ) /* USART1 RX Complete */
//AES加密解密完成
#define ENC_VECTOR VECT( 4, 0x23 ) /* AES Encryption/Decryption Complete */
//睡眠定时器完成
#define ST_VECTOR VECT( 5, 0x2B ) /* Sleep Timer Compare */
//端口2中断
#define P2INT_VECTOR VECT( 6, 0x33 ) /* Port 2 Inputs */
//USART0 TX完成
#define UTX0_VECTOR VECT( 7, 0x3B ) /* USART0 TX Complete */
//DMA传输完成
#define DMA_VECTOR VECT( 8, 0x43 ) /* DMA Transfer Complete */
//Timer1(16位)捕获/比较/溢出
#define T1_VECTOR VECT( 9, 0x4B ) /* Timer 1 (16-bit) Capture/Compare/Overflow */
//Timer2(MAC Timer)
#define T2_VECTOR VECT( 10, 0x53 ) /* Timer 2 (MAC Timer) */
//Timer3(8位)捕获/比较/溢出
#define T3_VECTOR VECT( 11, 0x5B ) /* Timer 3 (8-bit) Capture/Compare/Overflow */
//Timer4(8位)捕获/比较/溢出
#define T4_VECTOR VECT( 12, 0x63 ) /* Timer 4 (8-bit) Capture/Compare/Overflow */
//端口0中断
#define P0INT_VECTOR VECT( 13, 0x6B ) /* Port 0 Inputs */
//USART1 TX 完成
#define UTX1_VECTOR VECT( 14, 0x73 ) /* USART1 TX Complete */
//端口1中断
#define P1INT_VECTOR VECT( 15, 0x7B ) /* Port 1 Inputs */
//RF通用中断
#define RF_VECTOR VECT( 16, 0x83 ) /* RF General Interrupts */
//看门狗计时溢出
#define WDT_VECTOR VECT( 17, 0x8B ) /* Watchdog Overflow in Timer Mode */
2.中断优先级
中断优先级将决定中断响应的先后顺序,在CC2530中分为6个中断优先组,即IPG0~IPG5,每一组中断优先组中有三个中断源:
组 | 中断 | 中断 | 中断 |
IPG0 | RFERR | RF | DMA |
IPG1 | ADC | T1 | P2INT |
IPG2 | URX0 | T2 | UTX0 |
IPG3 | URX1 | T3 | UTX1 |
IPG4 | ENC | T4 | P1INT |
IPG5 | ST | P0INT | WDT |
中断优先组的优先级设定由寄存器 IP0和 IP1来设置。CC2530的优先级有4级,即0~3级,其中0级的优先级最低,3级的优先级最高。
IP1_X | IP0-X | 优先级 |
0 | 0 | 0(优先级别最低) |
0 | 1 | 1 |
1 | 0 | 2 |
1 | 1 | 3(优先级别最高) |
//设置IPG0优先级组为最高优先级别
IP1_IPG0 = 1;
IP0_IPG0 = 1;
如果同时收到相同优先级或同一优先级组中的中断请求时,将采用轮流检测顺序来判断中断优先级别的响应。
中断向量编号 | 中断名称 | 优先级排序 |
0 | RFERR | 高 |
16 | RF | |
8 | DMA | |
1 | ADC | |
9 | T1 | |
2 | URX0 | |
10 | T2 | |
3 | URX1 | |
11 | T3 | |
4 | ENC | |
12 | T4 | |
5 | ST | |
13 | P0INT | |
6 | P2INT | |
7 | UTX0 | |
14 | UTX1 | |
15 | P1INT | |
17 | WDT | 低 |
3.中断处理过程
中断发生时,CC2530硬件自动完成以下处理:
- 中断申请:中断源向CPU发出中断请求信号(中断申请一般需要在程序初始化中配置相应的终端寄存器开启中断);
- 中断响应:CPU检测中断申请,把中断的地址保存到堆栈,转入中断向量入口地址;
- 中断处理:按照中断向量中设定好的地址,转入相应的中断服务程序;
- 中断返回:中断服务程序执行完毕后,CPU执行中断返回指令,把堆栈中保存的数据从堆栈中弹出,返回原来程序。
4.中断编程
中断编程的一般过程如下:
- 中断设置:根据外设的不同,具体的设置是不同的,一般至少包含启用中断。
- 中断函数编写:这是中断编程的主要工作,需要注意的是,中断函数应尽可能地减少耗时或不进行耗时操作。
CC2530所使用的编译器为IAR,在IAR编译器中用关键词_interrupt来定义一个中断函数。使用#progma vector来提供中断函数的入口地址,并且中断函数没有返回值,没有函数参数。中断函数的一般格式如下:
#progma vector = 中断向量
_interrupt void 函数名(void)
{
//中断函数代码
}
在中断函数的编写中,当程序进入中断服务程序之后,需要执行以下四个步骤:
- 将对应的中断关掉(不是必须的,需要根据具体情况来处理);
- 其次如果需要判断具体的中断源,则根据中断标志位进行判断(所有I/O中断共用1个中断向量,需要通过中断标志区分是哪个引脚引起的中断);
- 清中断标志(不是必须的,CC2530中中断发生后由硬件自动清中断标志位);
- 处理中断事件,此过程要尽可能地减少耗时;
- 最后,如果在第一步中关闭了相应的中断源,则需要在退出中断服务程序之前打开相应的中断。
一般情况下,中断函数的编写是根据实际项目中的需求来定的。以CC2530端口0的P0_4、P0_5外部中断为例,中断程序编写如下所示:
//中断函数入口地址
#pragma vector = POINT_VECTOR
//定义一个终端函数
_interrupt void P0_ISR(void)
{
//关端口P0_4、P0_5中断
P0IEN &= ~0x30;
//判断中断发生
if(P0IFG > 0)
{
//清中断标志
P0IFG = 0;
/***中断事件的处理***/
}
}