任何微控制器的主要目的都是接受来自输入设备的输入,并相应地驱动输出。因此,一次将有几个设备连接到一个微控制器。此外,在微控制器中有许多内部组件,如定时器、计数器等,需要处理器的注意。
由于所有的设备不能在任何时候都获得处理器的注意,“中断”的概念就出现了。一个中断,顾名思义,中断微控制器正在做的任何事情,并吸引它的注意力来执行一个特殊的任务。下图描述了中断所涉及的过程。
在中断事件中,中断源(如定时器、计数器等)向处理器发送一个特殊的请求,称为中断请求(IRQ),以运行一段特殊的代码。这种特殊代码或函数被称为中断服务例程(ISR)。
从上图中可以看出,CPU执行它的正常代码集,直到发生IRQ。当接收到IRQ信号时,CPU停止执行常规代码,开始执行ISR。一旦ISR的执行被CPU完成,它就会返回到正常代码的执行。
矢量中断控制器(VIC)处理LPC214x系列单片机中的中断。它可以采取多达32中断请求。LPC2148微控制器中的中断可分为快速中断请求(FIQ)、矢量中断请求(IRQ)和非矢量中断请求。LPC214x中的所有中断都有一个可编程设置,即中断的优先级可以动态设置。
在这三类请求中,FIQ请求的优先级最高,矢量IRQ请求的优先级中等,非矢量IRQ请求的优先级最低。
当我们讨论“矢量”和“非矢量”IRQ请求时,我们实际上是在讨论ISR的地址。对于矢量IRQ请求,CPU知道ISR。一个叫做中断矢量表(IVT)的特殊表包含了所有关于矢量IRQ的信息。这些信息可以是关于中断的来源,IRQ请求的ISR地址等。
因此,每个矢量IRQ都有自己唯一的ISR地址。在32个可能的中断请求中,有16个中断请求可以定义为矢量IRQ。在这16个插槽中,可以分配LPC2148中可用的22个中断中的任何一个。在16个vector IRQ槽位中,槽位0的优先级最高,槽位16的优先级最低。
在非矢量IRQ的情况下,正如它的名字所表明的那样,CPU不知道中断的来源或中断的ISR地址。在这种情况下,必须为CPU提供一个默认的ISR地址。对于处理非矢量IRQ请求,在LPC2148中有一个叫做“VICDefVectAddr”的特殊寄存器。默认ISR的地址必须由用户在这个寄存器中给出,以便处理非矢量IRQ请求。
请注意所有的非矢量IRQ请求都有相同的ISR地址,ISR地址在VICDefVectAddr寄存器中定义。
LPC2148中的中断相关寄存器
有许多寄存器与矢量中断控制器(VIC)相对应。这些寄存器要么用于配置中断,要么用于读取中断状态。关于所有与VIC相关的寄存器,要记住的重要一点是,在所有VIC寄存器中,每个比特都与一个特定的中断源相关联。位0与与看门狗定时器相对应的中断相关联,在所有VIC相关寄存器中都是相同的。
下表显示了LPC2148中22个中断源的列表以及它们在VIC寄存器中对应的位位置。
位# | 22 | 21 | 20. | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 |
硬中断请求优先级别 | USB | AD1 | 生化需氧量 | I2C1 | AD0 | EINT3 | EINT2 | EINT1 | EINT0 | 清债信托公司 | 锁相环 | SPI1 / SSP |
位# | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3. | 2 | 1 | 0 | |
硬中断请求优先级别 | SPI0 | I2C0 | 脉宽调制 | UART1 | UART0 | TIMER1 | TIMER0 | ARMCore1 | ARMCore0 | N/A | WDT |
下面是LPC214x系列mcu中与中断相关联的寄存器列表和描述。在所有可用的维也纳国际中心登记册中,这里提到的登记册只是少数几个重要的登记册,也是开始了解维也纳国际中心的最佳登记册。
- 软件中断寄存器(VICSoftInt):软件中断寄存器(Software Interrupt Register)用于在外部源屏蔽之前,用软件即代码手动生成中断。当VICSoftInt寄存器中的一个位设置为1时,即使没有任何外部源,也会触发相应的中断。
- 软件中断清除寄存器(VICSoftIntClear):软件中断清除寄存器用于清除软件中断寄存器设置的位。当一个位在这个寄存器中被设置为1时,相应的位在软件中断寄存器中被清除,因此释放强制中断。
- 中断使能寄存器(VICIntEnable)中断启用寄存器是用来启用中断的,这些中断之后可能会导致FIQ或IRQ。当位设置为1时,相应的中断被启用。由于这是一个读/写寄存器,当这个寄存器被读时,“1”表示外部中断请求或软件中断被启用。
- Interrupt Enable Clear Register (VICIntEnClear)功能:中断使能清除寄存器用于清除中断使能清除寄存器设置的位,即用于禁用中断。当一个位设置为“1”时,寄存器允许软件清除中断使能寄存器中相应的位,从而禁用该特定请求的中断。
- 中断选择寄存器(VICIntSelect)中断选择寄存器(Interrupt Select Register)用于将32个中断分类为FIQ或IRQ。当这个寄存器中的一个位被设置为“0”时,相应的中断(如上表所示)将作为一个IRQ。类似地,当某位设置为“1”时,相应的中断作为FIQ。
- IRQ状态寄存器(VICIRQStatus)中断状态寄存器(Interrupt Status Register)用于读取启用并声明为IRQ的中断的状态。矢量和非矢量的IRQ都被读出。当一个比特被读为“1”时,相应的中断被启用,并被定义为IRQ。
- FIQ状态寄存器(VICFIQStatus):这个寄存器类似于IRQ状态寄存器(VICIRQStatus),除了它读取被启用并定义为FIQ的中断的状态。
- 病媒控制登记册(VICVectCntl0 - VICVectCntl15)矢量控制寄存器用于分配插槽给不同的中断源,这些中断源被分类为IRQ。有16个矢量控制寄存器,每个寄存器控制16个矢量IRQ插槽中的一个。优先级最高的是VICVectCntl0 (Slot 0),优先级最低的是VICVectCntl15 (Slot 15)。矢量控制寄存器(位0 -位4)的前5位包含中断请求的数字。5th位(第5位)用于启用矢量IRQ插槽。下面的表格是用来显示中断源和它们对应的十进制格式的源号。
中断源 | 源数 在十进制 |
WDT | 0 |
N/A | 1 |
ARMCore0 | 2 |
ARMCore1 | 3. |
TIMER0 | 4 |
TIMER1 | 5 |
UART0 | 6 |
UART1 | 7 |
脉宽调制 | 8 |
I2C0 | 9 |
SPI0 | 10 |
SPI1 | 11 |
中断源 | 源数 在十进制 |
锁相环 | 12 |
清债信托公司 | 13 |
EINT0 | 14 |
EINT1 | 15 |
EINT2 | 16 |
EINT3 | 17 |
ADC0 | 18 |
I2C1 | 19 |
生化需氧量 | 20. |
ADC1 | 21 |
USB | 22 |
例如,如果我们想将Slot 0分配给Timer0 IRQ,那么矢量控制寄存器必须声明如下:
VICVectCntl0 = 0x20 | 4;
请注意:当一个矢量IRQ在任何VICVectCntl0 - 15寄存器中被禁用时,它将不会禁用实际的中断,但矢量IRQ被更改为非矢量IRQ。
- 矢量地址寄存器(VICVectAddr0 - VICVectAddr15):矢量地址寄存器用于保存16个矢量IRQ插槽的ISR地址。如果Slot 0 (VICVectCntl0)被分配给TIMER0 IRQ,那么中断功能的地址必须分配给VICVectAddr0。
- 默认矢量地址寄存器(vicdefvecaddr):默认向量地址寄存器保存非向量irq的ISR地址。当非矢量IRQ发生时,这个地址充当默认的或通用的ISR地址。
- 矢量地址寄存器:这是一个不同的单一寄存器,不能与矢量地址寄存器(VICVectAddr0 - VICVectAddr15)混淆。它是一个读/写寄存器,当从这个寄存器读取数据时,它返回ISR地址。向寄存器写入一个值向VIC表明当前中断的执行已经结束。因此,这个寄存器在ISR的末尾用一个哑值来表示执行的结束。
在LPC2148中配置中断
现在我们已经看到了与VIC相关联的不同寄存器的列表和功能,我们将看到如何配置中断和定义各自的isr。首先,我们将看到如何正确地定义ISR函数,以便编译器理解它是一个ISR,但不是一个常规函数。
在Keil IDE中,我们可以用两种方式定义ISR,在这两种情况下,我们都需要使用关键字" __irq "。
//定义ISR的第一种方法
__irq void userISR (void)
{
/////////
}
//或以下方式定义ISR
userISR (Void) __irq
{
///////
}
定义ISR之后,现在我们将设置中断。例如,考虑我们想要分配TIMER0 IRQ和对应的ISR到Slot 0。为此,我们需要遵循三个步骤。
- 启用TIMER0 IRQ(使用VICIntEnable寄存器)
- 分配Slot 0到TIMER0 IRQ(使用一个VICVectCntl0 - 15寄存器)
- 分配ISR地址(使用一个VICVectAddr0 - 15寄存器)
基于以上步骤,必须进行以下分配来设置中断。
VICIntEnable | = (1<<4);
VICVectCntl0 = 0x20 | 4;
VICVectAddr0 =(无符号)userISR;
LPC2148中使用中断的示例程序
现在,我们将看到一个在LPC2148单片机中使用中断的示例程序。我们将使用定时器来产生延迟和定时器中断来闪烁led。
# include < lpc214x.h >
#定义了0 xffffffff;
int z = 0;
/*定时器函数的函数定义
无效计时器(空白)
{
T0CTCR = 0 x00;
T0PR = 60000 - 1;
T0TCR = 0 x02;
T0MR0 = 1000 - 1;
T0mcr = (1<<0) | (1<<1);
}
/*延迟函数的函数定义
Void delay (int d)
{
T0TCR = 0 x02;
T0TCR = 0 x01;
while (T0TC < d);
T0TCR = 0 x00;
}
/*中断的ISR
__irq void timerISR
{
长int val;
val = T0IR;
如果(z = = 0)
{
IOSET1 =领导;
}
其他的
{
IOCLR1 =领导;
}
z = ~ z;
T0IR = val;
VICVectAddr = 0 x00;
}
/*中断函数的函数定义
无效中断(空白)
{
VICIntSelect = 0 x00;
VICIntEnable | = (1 < < 4);
VICVectCntl0 = 0x20 | 4;
VICVectAddr0 =(无符号)timerISR;// ISR指针
}
int main ()
{
PINSEL2 = 0 x00;
IODIR1 =领导;
/*使能PLL块并设置CCLK和PCLK到60 MHz */
PLL0CON = 0 x01;
PLL0CFG = 0 x24;
PLL0FEED = 0 xaa;
PLL0FEED = 0 x55;
而(!(PLL0STAT & 0 x00000400));
PLL0CON = 0 x03;
PLL0FEED = 0 xaa;
PLL0FEED = 0 x55;
VPBDIV = 0 x01;
/*调用Timer函数*/
计时器();
/*调用中断函数*/
中断();
/*开启定时器*/
T0TCR = 0 x01;
(1);
}
2反应
容易理解。谢谢你!
不需要Hi延迟功能。