【原创】NVIC中断

(1)NVIC
    全称为Next Vector Interrupt Controoler,嵌套中断向量控制器,是ARM Cortex M3的内部设备之一,任何一款基于ARM Cortex M3的内核都带有NVIC。
(2)中断响应
    当某个中断来临,会将相应的中断标志位置位。当CPU查询到这个置位的标志位时,会响应此中断,并执行相应的中断服务函数,中断标志位要手动清除,否则会不断产生中断。
(3)中断优先级——抢占式优先级和响应优先级
    在ARM Cortex M3中,每个中断源都要指定两种优先级,分别为抢占式优先级和响应优先级。
    所谓抢占式优先级和响应优先级,他们之间的关系是:
1. 具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套。
2. 当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理,即后到的中断进入挂起状态(中断挂起),等待执行
3. 如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;
4. 如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。每一个中断源都必须定义2个优先级。
注意:
1. 如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;
2. 抢占式优先级别相同的中断源之间没有嵌套关系;
3. 如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。
4. 中断嵌套完全由抢占式优先级决定的。
(5)中断优先级分组
    ARM Cortex M3的每个中断通道都具备自己的中断优先级控制字节PRI_n(8位,但是STM32中只使用4位,高4位有效),每4个通道的8位中断优先级控制字构成一个32位的优先级寄存器。68个通道的优先级控制字至少构成17个32位的优先级寄存器。4bit的中断优先级可以分成2组,从高位看,前面定义的是抢占式优先级,后面是响应优先级。按照这种分组,4bit一共可以分成5组
第0组:所有4bit用于指定响应优先级;
第1组:最高1位用于指定抢占式优先级,后面3位用于指定响应优先级;
第2组:最高2位用于指定抢占式优先级,后面2位用于指定响应优先级;
第3组:最高3位用于指定抢占式优先级,后面1位用于指定响应优先级;
第4组:所有4位用于指定抢占式优先级。
    从上面可以看出,第几组,抢占优先级则最高为几位。
(6)GPIO外部中断EXTI
    STM32中,每一个GPIO都可以触发一个外部中断,每个输入通道都可以独立配置输入类型(脉冲或挂起?)和对应的触发事件(上升沿或下降沿或双边沿都触发),每个输入通道都可以独立被屏蔽,挂起寄存器会保持着某个通道的中断请求。
    STM32一共为GPIO配置了19个中断通道,其中16个由用户自由支配,分别EXTI0-15,而EXTI16-18通道分配给了RTC,PVD,USB使用,可以检测脉冲宽度低于APB2时钟宽度的外部信号。
    但是,GPIO的中断是以组位一个单位的,同组间的外部中断同一时间只能使用一个。比如说,PA0,PB0,PC0,PD0,PE0,PF0,PG0这些为1组,如果我们使用PA0作为外部中断源,那么别的就不能够再使用了,在此情况下,我们只能使用类似于PB1,PC2这种末端序号不同的外部中断源。每一组使用一个中断标志EXTIx。EXTI0 – EXTI4这5个外部中断有着自己的单独的中断响应函数,EXTI5-9共用一个中断响应函数,EXTI10-15共用一个中断响应函数。
    简而言之,就是相同末端序号的GPIO口共用一个中断通道,一个或多个中断通道共用一个中断函数。
(7)STM32中断函数特性
    当中断发生后,ARM处理器会处理当前指令后,跳转到中断函数执行,执行完会回到原来的地方继续执行。发生中断时,寄存器R0-R3,R12,LR,PSR,PC会自动入栈,中断返回时会自动出栈,无需汇编代码支持,由硬件完成。中断函数地址存储于中断向量表里。中断向量表一旦初始化完成,该段内容便不可以修改。
(8)中断向量表及其相关的三个变量
    中断函数地址存储于中断向量表里。中断向量表一旦初始化完成,该段内容便不可以修改。_Vectors_Size、_Vectors_End、_Vectors三个常量分别指定了中断向量表的大小、结束地址、起始地址,在中断向量表重映射是需要使用这三个常量。
(9)外部中断的基本步骤:
1. 设置时钟
2. 设置中断
3. IO口初始化
4. 在设置外部中断前,把相应的IO口设置为中断线路,并初始化
5. 中断函数
 

中断使用步骤及注意事项

1 设置相应GPIO时钟

GPIO时钟的设置涉及到了两个方面:

(1)被控制的GPIO

(2)用于中断的GPIO

上述两种GPIO都要设置时钟,如果该IO口为复用IO口,则要顺便开启RCC_APB2Periph_AFIO时钟,如下:

  /* config the extiline(PC13) clock and AFIO clock */

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO,ENABLE);

1.1 RCC_APB2PeriphClockCmd函数

2 设置中断分组和通道优先级

 /**

  * @brief  配置嵌套向量中断控制器NVIC

  * @param  无

  * @retval 无

  */

static void NVIC_Configuration(void)

{

  NVIC_InitTypeDef NVIC_InitStructure;

  

  /* Configure one bit for preemption priority */

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

  

  /* 配置P[A|B|C|D|E]13为中断源 */

  NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  NVIC_Init(&NVIC_InitStructure);

}

2.1 设置中断优先级分组,共有5个

2.1.1 NVIC_PriorityGroupConfig函数

2.2 设置各个中断通道的抢占式优先级和响应式优先级

2.2.1 NVIC_InitTypeDef结构体

2.2.2 NVIC_Init函数

3 IO口初始化

3.1 GPIO_InitTypeDef结构体

3.2 GPIO_Init函数

4 把相应的IO口设置为中断线路

由于GPIO并不是专用的中断引脚,因此在用GPIO来触发外部中断的时候需要设置将GPIO相应的引脚和中断线连接起来

 /**

  * @brief  配置 PC13 为线中断口,并设置中断优先级

  * @param  无

  * @retval 无

  */

void EXTI_PC13_Config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

  EXTI_InitTypeDef EXTI_InitStructure;

  /* config the extiline(PC13) clock and AFIO clock */

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO,ENABLE);

                              

  /* config the NVIC(PC13) */

  NVIC_Configuration();

  /* EXTI line gpio config(PC13) */  

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;       

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    // 上拉输入

  GPIO_Init(GPIOC, &GPIO_InitStructure);

  /* EXTI line(PC13) mode config */

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource13);

  EXTI_InitStructure.EXTI_Line = EXTI_Line13;

  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿中断

  EXTI_InitStructure.EXTI_LineCmd = ENABLE;

  EXTI_Init(&EXTI_InitStructure);

}

4.1  EXTI_InitTypeDef结构体

4.2 函数

4.2.1 GPIO_EXTILineConfig

4.2.2 EXTI_ClearITPendingBit

4.2.3  EXTI_Init

5 写中断响应函数

相对应的中断函数名一定要和startup_stm32f10x_hd.s相同

 

 
参考资料:
 
原文地址:https://www.cnblogs.com/cposture/p/NVIC.html