STM32学习100步之第七十二-七十六步——外部中断、其驱动函数以及嵌套中断

中断

所谓的中断是对于CPU而言,简单说起来就是当没有中断触发时,CPU处理main()中或其他不是中断函数,一旦中断触发(相应的中断标志位变化),CPU会立即退出现在正在执行的main()函数,转而执行中断函数内部的内容(名称不可修改)。
在这里插入图片描述
其中事件不需要CPU的参与,需要特定的硬件电路连接。

外部中断

外部中断/事件控制器(EXTI)
外部中断/事件控制器包含19个边沿检测器,用于产生中断/事件请求。每个中断线都可以独立地配置它的触发事件(上升沿或下降沿或双边沿),并能够单独地被屏蔽:有一一个挂起寄存器维持所有中断请求的状态。EXTI可以检测到脉冲宽度小于内部APB2的时钟周期。多达80个通用I/O口连接到16个外部中断线。

STM32F1支持将所有GPIO设置为中断输入。
外部I0可由上升沿、下降沿、高低电平的三种方式触发。
可选择中断或事件触发。
上升沿、下降沿的意义如下图:
在这里插入图片描述

各个IO端口对应的中断标志位及中断函数如下表:

在这里插入图片描述

嵌套的向量式中断控制器(NVIC)

STM32F103xx增强型产品内置嵌套的向量式中断控制器,能够处理多达43个可屏蔽中断通道(不包括16个Cortex TM-M3的中断线)和16个优先级。
1、紧耦合的NVIC能够达到低延迟的中断响应处理
2、中断向量入口地址直接进入内核
3、紧耦合的NVIC接口
4、允许中断的早期处理
5、处理晚到的较高优先级中断
6、支持中断尾部链接功能
7、自动保存处理器状态
8、中断返回时自动恢复,无需额外指令开销

该模块以最小的中断延迟提供灵活的中断管理功能。

cortex-m3支持256个中断,其中包含了16个内核中断,240个外部中断
stm32只有84个中断,包括1 6个内核中断和68个可屏蔽中断
stm32f103上只有60个可屏蔽中断

具体中断和相应的控制器连接以及和CPU的连接关系图如下:
在这里插入图片描述

关于抢占优先级和响应优先级

抢占优先级和响应优先级,其实是一个中断所包含的两个优先级,其中前者是对抢占优先级的级别划分,后者是相同抢占优先级的优先级别的划分。比如:中断A抢占优先级比B高,那么A的中断可以在B里面触发,忽略响应优先级;A和B抢占优先级相同,则A、B的响应优先级决定谁先响应;

注意两点:第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看 哪个中断先发生就先执行;第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级 中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。抢占式优先级别相同的中断源之间没有嵌套关系;
优先级的设置:
NVIC_ InitStruct.NVIC IRQChannelPreemptionPriority=2; //抢 占优先级
NVIC_ .InitStruct.NVIC .IRQChannelSubPriority=2; // 子优先级

设置值越小,优先级越高

通过下面函数设置优先级

void NVIC_Configuration(void){ //嵌套中断向量控制器 的设置
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    	//设置NVIC中断分组2:2位抢占优先级,2位响应优先级
}

具体意义如下图:
在这里插入图片描述

具体中断初始化函数如下:

u8 INT_MARK;//中断标志位

void KEYPAD4x4_INT_INIT (void){	 //按键中断初始化
	NVIC_InitTypeDef  NVIC_InitStruct;	//定义结构体变量
	EXTI_InitTypeDef  EXTI_InitStruct;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //启动GPIO时钟 (需要与复用时钟一同启动)     
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);//配置端口中断需要启用复用时钟

//第1个中断	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);  //定义 GPIO  中断
	
	EXTI_InitStruct.EXTI_Line=EXTI_Line4;  //定义中断线
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;              //中断使能
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;     //中断模式为 中断
	EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;   //下降沿触发
	
	EXTI_Init(& EXTI_InitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel=EXTI4_IRQn;   //中断线     
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;  //使能中断
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;  //抢占优先级 2
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;     //子优先级  2
	NVIC_Init(& NVIC_InitStruct);
	
//第2个中断	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5);  //定义  GPIO 中断
	
	EXTI_InitStruct.EXTI_Line=EXTI_Line5;  //定义中断线
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;              //中断使能
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;     //中断模式为 中断
	EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;   //下降沿触发
	
	EXTI_Init(& EXTI_InitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn;   //中断线
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;  //使能中断
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;  //抢占优先级 2
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;     //子优先级  2
	NVIC_Init(& NVIC_InitStruct);
//第3个中断	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);  //定义  GPIO 中断
	
	EXTI_InitStruct.EXTI_Line=EXTI_Line6;  //定义中断线
	EXTI_InitStruct.EXTI_LineCmd=ENABLE;              //中断使能
	EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;     //中断模式为 中断
	EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;   //下降沿触发
	
	EXTI_Init(& EXTI_InitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn;   //中断线
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;  //使能中断
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=2;  //抢占优先级 2
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;     //子优先级  2
	NVIC_Init(& NVIC_InitStruct);
       第4个中断与前面类似。
}

void  EXTI4_IRQHandler(void){
	if(EXTI_GetITStatus(EXTI_Line4)!=RESET){//判断某个线上的中断是否发生 
		INT_MARK=1;//标志位置1,表示有按键中断
		EXTI_ClearITPendingBit(EXTI_Line4);   //清除 LINE 上的中断标志位
	}     
}
void  EXTI9_5_IRQHandler(void){
	if(EXTI_GetITStatus(EXTI_Line5)!=RESET){//判断某个线上的中断是否发生 
		INT_MARK=2;//标志位置1,表示有按键中断
		EXTI_ClearITPendingBit(EXTI_Line5);   //清除 LINE 上的中断标志位
	}     
	if(EXTI_GetITStatus(EXTI_Line6)!=RESET){//判断某个线上的中断是否发生 
		INT_MARK=3;//标志位置1,表示有按键中断
		EXTI_ClearITPendingBit(EXTI_Line6);   //清除 LINE 上的中断标志位
	}     
	if(EXTI_GetITStatus(EXTI_Line7)!=RESET){//判断某个线上的中断是否发生 
		INT_MARK=4;//标志位置1,表示有按键中断
		EXTI_ClearITPendingBit(EXTI_Line7);   //清除 LINE 上的中断标志位
	}     
}

对于两条中断线的解释,其中第一条中断线EXTI_Line_n是外部中断的中断线即相应的GPIO、串口等的中断线,并不共用,而是每一个中断有一根中断线。第二个中断线NVIC控制器直接接至CPU的中断线,CPU中断通过此中断线进入中断函数。需要简单区分一下。比如上面程序CPU通过中断控制器的中断线EXTI9_5_IRQn进入中断函数EXTI9_5_IRQHandler()之后,还需要进一步根据第一条中断线判断到底是哪个中断源引起的中断,因为它们通过中断控制器,和CPU中断的通信共用中断线和中断函数。

主函数的调用如下:

	while(1){

		//其他程序内容

		if(INT_MARK){ //中断标志位为1表示有按键中断
			INT_MARK=0;//标志位清0
			s=KEYPAD4x4_Read();//读出按键值
			if(s!=0){ //如按键值不是0,也就是说有按键操作,则判断为真
				//-------------------------"----------------"
				OLED_DISPLAY_8x16_BUFFER(6," KEY NO.        "); //显示字符串
				OLED_DISPLAY_8x16(6,8*8,s/10+0x30);//
				OLED_DISPLAY_8x16(6,9*8,s%10+0x30);//
			}
		}
	}
}

通过设置全局变量INT_MARK记录哪个中断源的中断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值