STM32外部中断

中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。

中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。

中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回。

NVIC:嵌套向量中断控制器,控制着整个芯片中断相关的功能,是Cortex-M3内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对 Cortex-M3内核里面的 NVIC进行裁剪,把不需要的部分去掉,即 STM32F103系列的 NVIC 是阉割过得。

使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级。
NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级 。

抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队。(STM32中断向量表,值越小优先级越高)

EXTI(Extern Interrupt)外部中断

EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序。

支持的触发方式:上升沿/下降沿/双边沿/软件触发。

支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断 通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒。

触发响应方式:中断响应/事件响应。

外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,但是一个GPIO口就有16个引脚,所以需要使用外部中断配置寄存器AFIO_EXTICR来配置GPIO的外部中断,这是不同的GPIO口相同的引脚不能同时触发中断的原因。

给外部中断使用的硬件外部中断线有16个,但是GPIO端口却远不止16个,所以为了解决这个问题,采用了每一个外部中断线控制一组GPIO端口,即尾号相同的引脚作为一组被一条外部中断线控制。

当使用外部中断的时候,通过配置,我们可以将某一组中的某一个引脚连接到外部中断线上。所以一组引脚只能有一个作为外部中断引脚。例如,PA0、PB0、PC0、PD0、PE0、PF0、PG0和PH0这些引脚作为一组,如果我们使用PA0引脚作为外部中断引脚,那么该组的其余引脚就不能作为外部中断引脚使用。因此,从本质上讲,可供用户同时使用的外部中断引脚最多只有16个。

而且虽然外部中断线有16个,但是NVIC只为EXTI提供了7个中断通道,其中EXTI0_IRQ、EXTI1_IRQ、EXTI2_IRQ、EXTI3_IRQ、EXTI4_IRQ分别控制一条外部中断线,EXTI9_5_IRQ控制EXTI5-EXTI9,并且这几条外部中断线共享一个外部中断服务程序,EXTI5_10_IRQ同理。

外部中断设置方法

中断优先级:
当同时有两个及以上的中断时,就必须设置中断优先级了,在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx, 用来配置外部中断的优先级,其宽度为 8bit,每个外部中断可配置的优先级为 0~255,数值越小,优先级越高。但是绝大多数CM3芯片都会精简设计,以致实际上支持的优先级数减少,在F103中,只使用了高 4bit。
分成抢占优先级(主优先级)和子优先级。而且为了管理这用于表达优先级的这高4bit,于是又封装了一个优先级组,通过选择不同的组可以得到不同的优先级数目的比例,参看库文件misc.h:

  ============================================================================================================================
    NVIC_PriorityGroup   | NVIC_IRQChannelPreemptionPriority | NVIC_IRQChannelSubPriority  | Description
  ============================================================================================================================
   NVIC_PriorityGroup_0  |                0                  |            0-15             |   0 bits for pre-emption priority
                         |                                   |                             |   4 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------
   NVIC_PriorityGroup_1  |                0-1                |            0-7              |   1 bits for pre-emption priority
                         |                                   |                             |   3 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------    
   NVIC_PriorityGroup_2  |                0-3                |            0-3              |   2 bits for pre-emption priority
                         |                                   |                             |   2 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------    
   NVIC_PriorityGroup_3  |                0-7                |            0-1              |   3 bits for pre-emption priority
                         |                                   |                             |   1 bits for subpriority
  ----------------------------------------------------------------------------------------------------------------------------    
   NVIC_PriorityGroup_4  |                0-15               |            0                |   4 bits for pre-emption priority
                         |                                   |                             |   0 bits for subpriority                       
  ============================================================================================================================

显然,大多数时候,
人们都喜欢选择折中的,即 NVIC_PriorityGroup_2。
当有多个中断同时请求(注意是还没执行中断服务函数)时,抢占优先级(主优先级)高的就会先得到执行,如果抢占优先级(主优先级)相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,就越先响应。

中断嵌套:
假定在选定了优先级组后,在组里添加了两个中断,当单片机正在执行中断1的服务函数过程中,突然,又来一个中断2的请求,那么:
若中断2的主优先级比中断1的主优先级高,那么单片机暂停中断1的服务函数,进入中断2的服务函数,执行完之后,才返回中断1的服务函数。形成了所谓的嵌套。
若中断2的主优先级比中断1的主优先级低,那么就必须等待中断1的服务函数执行完毕才能响应中断2。不能形成嵌套。
在配置每个中断的时候一般有3个步骤:

1、结合当前使用的外设,确定自己需要的中断源(单片机外设)。比如单片机用于通信的固件外设(I2C,SPI,USART等)和GPIO等。

以GPIOB的14引脚外部中断为例

配置AFIO

/*AFIO选择中断引脚*/
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
//将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚

2、配置EXTI

	/*EXTI初始化*/
	EXTI_InitTypeDef EXTI_InitStructure;						//定义结构体变量
	EXTI_InitStructure.EXTI_Line = EXTI_Line14;					//选择配置外部中断的14号线
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;					//指定外部中断线使能
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//指定外部中断线为中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//指定外部中断线为下降沿触发
	EXTI_Init(&EXTI_InitStructure);								//将结构体变量交给EXTI_Init,配置EXTI外设

3、配置NVIC

1). NVIC中断分组

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	 //配置NVIC为分组2
						//即抢占优先级范围:0~3,响应优先级范围:0~3
						//此分组配置在整个工程中仅需调用一次
						//若有多个中断,可以把此代码放在main函数内,while循环之前
						//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置

2). 初始化NVIC

NVIC_InitTypeDef NVIC_InitStructure;					//定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;	//选择通道(要中断的对象)
                                                        //选择配置NVIC的EXTI15_10线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;		//指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure);							//将结构体变量交给NVIC_Init,配置 
                                                        //NVIC外设

4、 编写中断服务函数,在固件库启动文件 startup_stm32f10x_Hd.s 中预先为每个中断都写了一个中断服务函数,只是这些中断函数都是为空,为的只是初始化中断向量表:

WWDG_IRQHandler
PVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
DMA1_Channel5_IRQHandler
DMA1_Channel6_IRQHandler
DMA1_Channel7_IRQHandler
ADC1_2_IRQHandler
USB_HP_CAN1_TX_IRQHandler
USB_LP_CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_SCE_IRQHandler
EXTI9_5_IRQHandler
TIM1_BRK_IRQHandler
TIM1_UP_IRQHandler
TIM1_TRG_COM_IRQHandler
TIM1_CC_IRQHandler
TIM2_IRQHandler
TIM3_IRQHandler
TIM4_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
SPI1_IRQHandler
SPI2_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
USART3_IRQHandler
EXTI15_10_IRQHandler
RTCAlarm_IRQHandler
USBWakeUp_IRQHandler
TIM8_BRK_IRQHandler
TIM8_UP_IRQHandler
TIM8_TRG_COM_IRQHandler
TIM8_CC_IRQHandler
ADC3_IRQHandler
FSMC_IRQHandler
SDIO_IRQHandler
TIM5_IRQHandler
SPI3_IRQHandler
UART4_IRQHandler
UART5_IRQHandler
TIM6_IRQHandler
TIM7_IRQHandler
DMA2_Channel1_IRQHandler
DMA2_Channel2_IRQHandler
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler

实际的中断服务函数都需要我们重新编写, 放在 stm32f10x_it.c 这个库文件中,可以看到那里面已经有了一些写好的系统中断的服务函数,我们只需跟着在文件末尾继续写就行了。中断服务函数的函数名必须跟启动文件里面预先设置的一样,如果写错,系统就在中断向量表中找不到中断服务函数的入口,直接跳转到启动文件里面预先写好的空函数,实现不了中断。 注意:中断服务函数里不应该处理耗时的操作!
接下来这个中断服务函数需要放在stm32f10x_it.c里

/**
  * @brief  中断服务函数
  * @param  无
  * @retval 无
  */
void EXTI0_IRQHandler(void)
{
  //确保是否产生了中断
	if(EXTI_GetITStatus(EXTI_Line14) != RESET)   //判断是否是外部中断14号线触发的中断
	{
		//TODO:
		/*别放置耗时间的操作!!!!!!!!*/
   
		EXTI_ClearITPendingBit(EXTI_Line14);  //清除中断标志位   
	}  

   
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值