关于NVIC和EXTI详解

本人使用的GD207,不过GD和ST的关系,你懂的。

先说EXTI吧, 

EXTI 控制器的主要特性如下: 

● 每个中断/事件线上都具有独立的触发和屏蔽 

● 每个中断线都具有专用的状态位 

● 支持多达 23 个软件事件/中断请求 

● 检测脉冲宽度低于 APB2 时钟宽度的外部信号

下图是ST207的框架图

下图为翻译版

从图中看出和外部中断有关的寄存器有:上升沿触发选择、下降沿触发选择、软件中断事件寄存器、中断屏蔽寄存器、挂起请求寄存器、事件屏蔽寄存器和NVIC中断控制寄存器等。此外就是对输入线的理解了。

也就是说对于一个外部中断线可以和多个GPIO相连,当你要使用哪一个IO的时候只要对SYSCFG_EXTICR对应的位设置就好了,在中断屏蔽寄存器或事件屏蔽寄存器对应位可以设置使用哪一个中断线

注:ST的使用SYSCFG_EXTICR来配置,GD的采用AFIO寄存器(在GPIO寄存器中)

EXTI是外部中断吧,上面的主要是针对的这22条中断线的说明,我们还知道还是有很多中断的,比如定时器中断,串口中断等等,他们不属于这22条中断线。

我们可以在中断向量表中看到

其他的中断配置都在各个模块的寄存器中了

在上面的EXTI寄存器都设置好后就可以设置NVIC了,关于NVIC的芯片编程手册上描述较少,但是说了

所以我们就参考一下M3手册吧

找到AIRCR寄存器,其中8到10位为优先级分组

我们在代码中使用的库函数是

void NVIC_PRIGroup_Enable(uint32_t NVIC_PRIGroup)

{

/* Set the priority grouping value */

SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PRIGroup;

}

其中我们查到

1、SCB->AIRCR在库函数的地址是0XE000 ED0C,不懂的如何查询的,请自行百度

2、查到SCB的结构体定义

我们看到SCB是System Control Block的简写

下面我们说一下分组的取值

抢占优先级 & 响应优先级区别:

1、高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。

2、抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。

3、抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。

4、如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;

例子:

假定设置中断优先级组为2,然后设置

中断3(RTC中断)的抢占优先级为2,响应优先级为1。  中断6(外部中断0)的抢占优先级为3,响应优先级为0。中断7(外部中断1)的抢占优先级为2,响应优先级为0。

那么这3个中断的优先级顺序为:中断7>中断3>中断6

表现在代码中

NVIC_InitPara NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQ = IRQn;

NVIC_InitStructure.NVIC_IRQPreemptPriority =pri;

NVIC_InitStructure.NVIC_IRQSubPriority = pri1;

NVIC_InitStructure.NVIC_IRQEnable = ENABLE;

NVIC_Init(&NVIC_InitStructure);

如果我们是分组0,那么pri的取值范围0~16,pri1的取值范围0~0

类推下去:分组2,那么pri的取值范围0~4,pri1的取值范围0~4

分组4,那么pri的取值范围0~0,pri1的取值范围0~16

 修正(2018.3.7)

如果我们是分组0,那么pri的取值范围0~0,pri1的取值范围0~16

类推下去:分组2,那么pri的取值范围0~4,pri1的取值范围0~4

分组4,那么pri的取值范围0~16,pri1的取值范围0~0

原因:

其中,pri是抢占优先级,pri1是响应优先级,具体取值范围请看上面关于SCB-AIRCR寄存器的讲解

此次修正由Wu13735796979用户发现,在评论区提出。对此表示感谢


下面我们讲解一下NVIC寄存器

__IO uint8_t  IP[240]; //中断优先级控制的寄存器组

__IO uint32_t ISER[8]; //中断使能寄存器组

__IO uint32_t ICER[8]; //中断失能寄存器组

__IO uint32_t ISPR[8]; //中断挂起寄存器组

__IO uint32_t ICPR[8]; //中断解挂寄存器组

__IO uint32_t IABR[8]; //中断激活标志位寄存器组

中断优先级控制的寄存器组:IP[240]

全称是:Interrupt Priority Registers

240个8位寄存器,每个中断使用一个寄存器来确定优先级。

比如:STM32F10x系列一共60个可屏蔽中断,使用IP[59]~IP[0]。

每个IP寄存器的高4位用来设置抢占和响应优先级(根据分组),低4位没有用到。

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

中断使能寄存器组:ISER[8]

作用:用来使能中断

32位寄存器,每个位控制一个中断的使能。STM32F10x只有60个可屏蔽中断,所以只使用了其中的ISER[0]和ISER[1]。

ISER[0]的bit0~bit31分别对应中断0~31。ISER[1]的bit0~27对应中断32~59;

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

中断失能寄存器组:ICER[8]

作用:用来失能中断

32位寄存器,每个位控制一个中断的失能。STM32F10x只有60个可屏蔽中断,所以只使用了其中的ICER[0]和ICER[1]。

ICER[0]的bit0~bit31分别对应中断0~31。ICER[1]的bit0~27对应中断32~59;

配置方法跟ISER一样。

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

中断挂起控制寄存器组:ISPR[8]

作用:用来挂起中断

中断解挂控制寄存器组:ICPR[8]

作用:用来解挂中断

static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn);

static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn);

static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)

中断激活标志位寄存器组:IABR [8]

作用:只读,通过它可以知道当前在执行的中断是哪一个

如果对应位为1,说明该中断正在执行。

static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)

猜你喜欢

转载自blog.csdn.net/Firefly_cjd/article/details/77964671