在我们学习STM32时中断是一个必不可少的部分,中断能够帮助我们解决很多问题,下面就让小编给大家展示STM32中断相关知识吧。

一、中断的定义

    中断就是CUP暂时中断正在执行的程序,转而去执行中断请求的外设或者事件的服务程序,待处理完毕中断服务程序后再执行原程序。例如,小明正在看书(CUP的主程序),这时有人打电话给小明,小明就去接这个电话(中断服务函数),接完电话后小明接着去看书(CPU主函数)。

二、中断的作用

1、提高CPU的利用率;
2、具有实时功能;
3、具有故障处理功能;
4、能够实现分时操作;

三、中断处理的过程

esp32 中断打印_stm32


第一步,中断响应。这时需要保护现场,并且找到中断对应的中断服务程序的地址,即中断向量表。(一般由硬件自动实现)

第二步,执行中断服务函数。中断服务函数既没有参数,也没有返回值,更不需要用户调用;中断服务函数是中断产生后,才执行的一个函数。(由用户编程)

第三步,中断返回。恢复现场。(由硬件自动实现)

四、STM32F103的中断系统

1、嵌套向量中断控制器NVIC

    向量中断控制器,简称NVIC,访问地址是OxE000_E000,共支持1至240个外部中断输入(通常外部中断写作 IRQs),具体的数值由芯片厂商在设计芯片时决定。此外,NVIC还支持一个“永垂不朽”的不可屏蔽中断(NMI〉输入。所有NVIC的中断控制/状态寄存器都只能在特权级下访问。不过有一个例外——软件触发中断寄存器可以在用户级下访问以产生软件中断。所有的中断控制/状态寄存器均可按字/半字/字节的方式访问。由于NVIC集成在ARM Cortex-M3内核中,与中央处理器核心CM3Core紧密耦合,从而实现低延迟的中断处理和高效地处理晚到的较高优先级的中断。
NVIC中断控制器

  • (1)支持84个异常,包括16个内部异常和68个非内核异常中断;
  • (2)使用4位优先级设置,具有16级可编程异常优先级;
  • (3)中断响应时处理器状态的自动保存,无须额外指令;
  • (4)中断返回时处理器状态的自动恢复,无须额外指令;
  • (5)支持嵌套和向量中断;
  • (6)支持中断尾链技术。

2、STM32F103中断优先级

  • (1)抢占式优先级
        高抢占式优先级的中断事件会打断当前的主程序/中断程序运行,俗称中断嵌套。
  • (2) 响应优先级
        在抢占式优先级相同的情况下,高响应优先级的中断优先被响应。
  • (3)中断响应依据
        首先,比较抢占式优先级;其次,比较响应优先级。是否含有中断嵌套取决于抢占优先级。
  • (4)优先级冲突的处理
        具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断的嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。

    STM32F013对优先级的设定

五、函数解析

1、NVIC_DeInit函数

esp32 中断打印_esp32 中断打印_02

2、NVIC_Init函数

esp32 中断打印_单片机_03

3、NVIC_PriorityGroupConfig函数

esp32 中断打印_优先级_04

4、EXTI_Init函数

esp32 中断打印_stm32_05

5、EXTI_DeInit函数

esp32 中断打印_优先级_06

6、EXTI_GetITStatus函数

esp32 中断打印_arm_07

7、EXTI_ClearFlag函数

esp32 中断打印_单片机_08

8、GPIO引脚中断映射函数

esp32 中断打印_esp32 中断打印_09

六、示例功能

    在STM32F103ZET6开发板上,有五个按键与八个LED灯,现在我们需要按下KEY1点亮LED1、按下KEY2点亮LED2……按下KEY5点亮LED5。

1、中断初始化函数

    在中断初始化函数中,我们需要注意的是GPIO引脚与中断的映射关系。GPIO引脚、外部线路EXTI_Line的值、指定中断通道NVIC_IRQChannel的值都需要一样,不然定义中断就没有效果。例如我们需要使用外部中断6,那么我们就需要选择GPIO_Pin6、EXTI_Line6与EXTI9_5_IRQn。(外部中断的Pin5-Pin9所用的是同一个中断通道。)

void exit_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; 
	EXTI_InitTypeDef EXTI_InitStructure; 
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/* 选择GPIOC时钟与时钟复用  */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE|RCC_APB2Periph_AFIO , ENABLE);
	
	/* 	GPIO管脚初始化 上拉输入模式  */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 
	GPIO_Init(GPIOE, &GPIO_InitStructure); 
	
	/*中断映射 选择GPIO引脚作为外部中断线路 这里一定要给端口引脚加上外部中断线路*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource0); 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource1); 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2); 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3); 
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource6); 
	
	 /* 设置外部中断的模式 PE0 PE1 PE2 PE3 PE6中断初始化*/ 
	EXTI_InitStructure.EXTI_Line = EXTI_Line0|EXTI_Line1|EXTI_Line2|EXTI_Line3|EXTI_Line6;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; 
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; 
	EXTI_InitStructure.EXTI_LineCmd = ENABLE; 
	EXTI_Init(&EXTI_InitStructure); 
	
	//NVIC优先级分组 抢占式优先2位四级 响应式优先级2位四级
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	/* 设置 外部中断0 的NVIC参数*/
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //指定中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//配置抢占式优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//配置响应式优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
	NVIC_Init(&NVIC_InitStructure); 	
	
	/* 设置 外部中断1 的NVIC参数*/	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //指定中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//配置抢占式优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//配置响应式优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
	NVIC_Init(&NVIC_InitStructure); 	
	
	/* 设置 外部中断2 的NVIC参数*/
	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //指定中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//配置抢占式优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//配置响应式优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
	NVIC_Init(&NVIC_InitStructure); 	
	
	/* 设置 外部中断3 的NVIC参数*/
	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //指定中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//配置抢占式优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//配置响应式优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
	NVIC_Init(&NVIC_InitStructure); 	
	
	
	/* 设置 外部中断6 的NVIC参数*/
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //指定中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;//配置抢占式优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//配置响应式优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //中断使能
	NVIC_Init(&NVIC_InitStructure); 	
}

2、中断响应函数

/**
	* @brief function of exti0(中断0响应函数)
	* @param none
	* @retval none
	*
*/
void EXTI0_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line0)==SET) 
	{
		EXTI_ClearFlag(EXTI_Line0);//清楚中断EXTI 线路挂起标志位
		//dealy_ms(10);//按键消抖
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_0)==Bit_RESET)
		{			
			exit_flag = 1;
		}	
	}
}

/**
	* @brief function of exti1(中断1响应函数)
	* @param none
	* @retval none
	*
*/
void EXTI1_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line1)==SET) 
	{
		
		EXTI_ClearFlag(EXTI_Line1);	//清楚中断EXTI 线路挂起标志位	
		//dealy_ms(10);
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_1)==Bit_RESET)
		{			
			exit_flag = 2;
		}		
	}
}

/**
	* @brief function of exti2(中断2响应函数)
	* @param none
	* @retval none
	*
*/
void EXTI2_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line2)==SET) 
	{
		EXTI_ClearFlag(EXTI_Line2);//清楚中断EXTI 线路挂起标志位
		//dealy_ms(10);
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)==Bit_RESET)
		{				
			exit_flag = 3;
		}	
	}
}

/**
	* @brief function of exti3(中断3响应函数)
	* @param none
	* @retval none
	*
*/
void EXTI3_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line3)==SET) 
	{
		EXTI_ClearFlag(EXTI_Line3);//清楚中断EXTI 线路挂起标志位
		//dealy_ms(10);
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_3)==Bit_RESET)
		{			
			exit_flag = 4;
		}	
	}
}

/**
	* @brief function of exti6(中断6响应函数 这里我们只用到了Pin6)
	* @param none
	* @retval none
	*
*/
void EXTI9_5_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line6)==SET) 
	{
		EXTI_ClearFlag(EXTI_Line6);//清楚中断EXTI 线路挂起标志位
		//dealy_ms(10);
		if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_6)==Bit_RESET)
		{				
			exit_flag = 5;
		}	
	}
}

3、中断服务函数

extern unsigned char exit_flag;

/**
	* @brief work of exti(中断执行函数)
	* @param none
	* @retval none
	*
*/
void exti_pro(void)
{
	LED_all_off();
	if(exit_flag == 1){//按键1按下 点亮LED1
		LED_ctrl(LED1,LED_ON);
	}else	if(exit_flag == 2){//按键2按下 点亮LED2
		LED_ctrl(LED2,LED_ON);
	}else if(exit_flag == 3){//按键3按下 点亮LED3
		LED_ctrl(LED3,LED_ON);
	}else if(exit_flag == 4){//按键4按下 点亮LED4
		LED_ctrl(LED4,LED_ON);
	}else if(exit_flag == 5){//按键5按下 点亮LED5
		LED_ctrl(LED5,LED_ON);
	}else{//外部中断未响应关闭所有的LED灯
		LED_all_off();
	}
}

4、主函数

int main(void)
{
	LED_GPIO_init();//LED初始化
	key_GPIO_init();//按键初始换化
	exit_Init();//中断初始化
	while(1){
		exti_pro();//中断服务函数
	}
}