STM32F1迷你板外部中断

开始学习外部中断的基本知识

中断优先级分组管理

CortexM3内部支持256个中断,其中包含了 16 个内核中断和 240 个外部中断,并且具有 256
级的可编程中断设置。STM32F1系列有 84 个中断,包括 16 个内核中断和 68 个可屏蔽中断,具有 16 级可编程的中断优先级。而我们常用的就是这 68 个可屏蔽中断, 但是 STM32 的 68 个可屏蔽中断,在 STM32F103 系列
上面,可屏蔽中断又只有 60 个(在 107 系列才有 68 个)。

中断管理办法:
首先,对STM32中断进行分组,分成5个组:组0~4,该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。 同时,对每个中断设置一个抢占优先级和一个响应优先级。
有4个位来分配抢占优先级和响应优先级。
下面是AIRCR 中断分组设置表

AIRCR[10: 8] bit[7: 4]分配情况 分配结果
0 111 0: 4 0 位抢占优先级, 4 位响应优先级
1 110 1: 3 1 位抢占优先级, 3 位响应优先级
2 101 2: 2 2 位抢占优先级, 2 位响应优先级
3 100 3: 1 3 位抢占优先级, 1 位响应优先级
4 011 4: 0 4 位抢占优先级, 0 位响应优先级

每个中断,可以设置抢占优先级为 0~7,响应优先级为 1 或 0。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。抢占优先级相同的中断,当两个中断同时发生,哪个响应优先级高,哪个先执行。

这里需要注意两点:第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。

中断优先级分组设置函数NVIC_PriorityGroupConfig

void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
	assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
	SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}

分组可以在下面选

(((GROUP) == NVIC_PriorityGroup_0) ||
((GROUP) == NVIC_PriorityGroup_1) || \
((GROUP) == NVIC_PriorityGroup_2) || \
((GROUP) == NVIC_PriorityGroup_3) || \
((GROUP) == NVIC_PriorityGroup_4))

设置好了系统中断分组,那么对于每个中断我们又怎么确定他的抢占优先级和响应优先级呢?通过中断初始化函数void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

解析一下上式用到的结构体NVIC_InitTypeDef

typedef struct
{
uint8_t NVIC_IRQChannel;
uint8_t NVIC_IRQChannelPreemptionPriority;
uint8_t NVIC_IRQChannelSubPriority;
FunctionalState NVIC_IRQChannelCmd;
} NVIC_InitTypeDef;

成员变量的含义
NVIC_InitTypeDef 结构体中间有三个成员变量,这三个成员变量的作用是:
NVIC_IRQChannel:定义初始化的是哪个中断,这个我们可以在 stm32f10x.h 中找到每个中断对应的名字。例如 USART1_IRQn。
NVIC_IRQChannelPreemptionPriority:定义这个中断的抢占优先级别。
NVIC_IRQChannelSubPriority:定义这个中断的子优先级别。
NVIC_IRQChannelCmd:该中断是否使能。

比如我们要使能串口 1 的中断,同时设置抢占优先级为 1,子优先级位 2,初始化的方法是

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口 1 中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为 1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位 2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据上面指定的参数初始化 NVIC 寄存器

NVIC 寄存器结构体NVIC_Type

typedef struct
{
	__IO uint32_t ISER[8]; /*!< Interrupt Set Enable Register */
	uint32_t RESERVED0[24];
	__IO uint32_t ICER[8]; /*!< Interrupt Clear Enable Register */
	uint32_t RSERVED1[24];
	__IO uint32_t ISPR[8]; /*!< Interrupt Set Pending Register */
	uint32_t RESERVED2[24];
	__IO uint32_t ICPR[8]; /*!< Interrupt Clear Pending Register */
	uint32_t RESERVED3[24];
	__IO uint32_t IABR[8]; /*!< Interrupt Active bit Register */
	uint32_t RESERVED4[56];
	__IO uint8_t IP[240]; /*!< Interrupt Priority Register, 8Bit wide */
	uint32_t RESERVED5[644];
	__O uint32_t STIR; /*!< Software Trigger Interrupt Register */
} NVIC_Type;

外部中断

STM32每一个IO口都可以作为外部中断输入。
STM32的中断控制器支持19个外部中断/事件请求。
线0~15:对应外部IO口的输入中断

每个外部中断线可以独立配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位。
GPIO的管脚和中断线有一个对应关系,每个中断线最多对应7个IO口。以线0为例,它对应了GPIOA.0,GPIOB.0,GPIOC.0,GPIOD.0,GPIOE.0,GPIOF.0,GPIOG.0。中断线每次只能连接到一个IO口,所以需要在7个IO口中进行选择。

映射关系
在这里插入图片描述
图片来源:正点原子

外部中断的一般配置步骤
初始化IO口为输入GPIO_Init()
开启IO口复用时钟RCC_APB2PeriphClockCmd(RCC_APB2Perith_AFIO,ENABLE);
设置IO口与中断线的映射关系void GPIO_EXTILineConfig()
初始化线上中断,设置触发条件等EXTI_Init()
配置中断分组(NVIC),并使能中断NVIC_Init()
编写中断服务程序EXTIx_IRQHandler()
清除中断标志位EXTI_ClearTPendingBit()

IO口和中断线的映射
在库函数中,配置 GPIO 与中断线的映射关系的函数 GPIO_EXTILineConfig()来实现的:
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
该函数将 GPIO 端口与中断线映射起来,使用范例是:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);
将中断线 2 与 GPIOE 映射起来,即GPIOE.2 与 EXTI2 中断线连接了。我们要是用的是PE4(对应的是KEY0),所以这里是

GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);

然后我们对中断进行初始化

	 //初始化中断
	 EXTI_InitStructure.EXTI_Line=EXTI_Line4;//线号
	 EXTI_InitStructure.EXTI_LineCmd=ENABLE;//使能
	 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断还是事件
	 EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
	 EXTI_Init(&EXTI_InitStructure);

这里笔者有个问题?这里为什么选择下降沿触发呢?原来是因为KEY0接的是低电平,所以让它有效的话,必须是到低电平。

配置中断分组NVIC

 //NVIC中断分组的设置
	 NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQn;
	 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE:
	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	 NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
	 NVIC_Init(&NVIC_InitStructure);

前五步的初始化函数如下

 
 void EXITX_Init(){
 
	 
		EXTI_InitTypeDef EXTI_InitStructure;//结构体变量
	 NVIC_InitTypeDef NVIC_InitStructure;
	 KEY_Init();//初始化GPIO
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	 //key0对应PE4
	 //PE4映射到中断线4
	 GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4 );
	 
	 //初始化中断
	 EXTI_InitStructure.EXTI_Line=EXTI_Line4;//线号
	 EXTI_InitStructure.EXTI_LineCmd=ENABLE;
	 EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断
	 EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿触发
	 EXTI_Init(&EXTI_InitStructure);
	 
	 //NVIC中断分组的设置
	 NVIC_InitStructure.NVIC_IRQChannel=EXTI4_IRQn;
	 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE:
	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	 NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
	 NVIC_Init(&NVIC_InitStructure);
 }
 

猜你喜欢

转载自blog.csdn.net/shizheng_Li/article/details/106500282