Bootstrap

STM32F407-外部中断

一.基本概念

 

STM32F4的每个IO都可以作为外部中断输入。  

STM32F4的中断控制器支持22个外部中断/事件请求:

EXTI线0~15:对应外部IO口的输入中断。

EXTI线16:连接到PVD输出。

EXTI线17:连接到RTC闹钟事件。

EXTI线18:连接到USB OTG FS唤醒事件。

EXTI线19:连接到以太网唤醒事件。

EXTI线20:连接到USB OTG HS(在FS中配置)唤醒事件。

EXTI线21:连接到RTC入侵和时间戳事件。

EXTI线22:连接到RTC唤醒事件。 每个外部中断线可以独立的配置触发方式(上升沿,下降沿或者双边沿触发),触发/屏蔽,专用的状态位。

 

2.中断线与IO口的对应关系

中断线只有16根,因此

将PIOx.0映射到EXTI0

GPIOx.1映射到EXTI1

.......

GPIOx.15映射到EXTI15 

每一根中断线接收多个端口的映射,就解决了中断线不够用的情况

3.对于每个中断线,可以设置相应的触发方式(上升沿触发,下降沿触发,边沿触发)以及使能。

IO口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数

从表中可以看出,外部中断线5~9分配一个中断向量,共用一个服务函数外部中断线10~15分配一个中断向量,共用一个中断服务函数。 

4.中断服务函数列表:

EXTI0_IRQHandler        

EXTI1_IRQHandler

EXTI2_IRQHandler          

EXTI3_IRQHandler          

EXTI4_IRQHandler          

EXTI9_5_IRQHandler        

EXTI15_10_IRQHandler      

外部中断常用库函数:

①void SYSCFG_EXTILineConfig(uint8_t EXTI_PortSourceGPIOx, uint8_t EXTI_PinSourcex);    //设置IO口与中断线的映射关系    exp: SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);     //将PE2映射到2号中断线

②void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);  //初始化中断线:触发方式等

③ITStatus EXTI_GetITStatus(uint32_t EXTI_Line); //判断中断线中断状态,是否发生

④void EXTI_ClearITPendingBit(uint32_t EXTI_Line); //清除中断线上的中断标志位

⑤RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟 //这个函数非常重要,在使用外部中断的时候一定要先使能SYSCFG时钟

 

二、中断编写

1.中断配置一般过程

①使能SYSCFG时钟:          RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

②   初始化IO口为输入。        GPIO_Init();

③设置IO口与中断线的映射关系。         void SYSCFG_EXTILineConfig();

④初始化线上中断,设置触发条件等。        EXTI_Init();

⑤配置中断分组(NVIC),并使能中断。        NVIC_Init();

⑥编写中断服务函数。       EXTIx_IRQHandler();

⑦清除中断标志位       EXTI_ClearITPendingBit();

 

2.硬件连接

3.

中断服务函数:delay_ms(10)用于判断按键按下若超过10ms,就说明是真的按下了,也就是消除抖动的作用。

void EXTIx_IRQHandler(void)
{
	delay_ms(10);	
	if(WK_UP==1)	 
	{
		BEEP=!BEEP; 
	}		 
	 EXTI_ClearITPendingBit(EXTI_Linex); 
}	

 4.初始化线上中断,映射到2号中断线,设置模式为中断,下降沿触发,初始使能。

 EXTI_InitStructure.EXTI_Line=EXTI_Line2;	 
 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
 EXTI_InitStructure.EXTI_LineCmd = ENABLE;
 EXTI_Init(&EXTI_InitStructure);

5.配置中断分组(NVIC),并使能中断。设置中断通道,抢占优先级,子优先级,使能外部中断通道。

  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

 

 

6.完整exti代码:

其中

key0对应蜂鸣器响停,抢占优先级:0,响应优先级:2,中断线0,中断处理函数EXTI0_IRQn

key1对应LED0翻转,抢占优先级:3,响应优先级:2,中断线2,中断处理函数EXTI2_IRQn

key2对应LED1翻转,抢占优先级:2,响应优先级:2,中断线3,中断处理函数EXTI3_IRQn

key3对应LED0,LED1同时翻转,抢占优先级:1,响应优先级:2,中断线4,中断处理函数EXTI4_IRQn

 




void EXTI0_IRQHandler(void)
{
	delay_ms(10);	
	if(WK_UP==1)	 
	{
		BEEP=!BEEP; 
	}		 
	 EXTI_ClearITPendingBit(EXTI_Line0); 
}	

void EXTI2_IRQHandler(void)
{
	delay_ms(10);	
	if(KEY2==0)	  
	{				 
   LED0=!LED0; 
	}		 
	 EXTI_ClearITPendingBit(EXTI_Line2);

void EXTI3_IRQHandler(void)
{
	delay_ms(10);	
	if(KEY1==0)	 
	{
		LED1=!LED1;
	}		 
	 EXTI_ClearITPendingBit(EXTI_Line3);   
}

void EXTI4_IRQHandler(void)
{
	delay_ms(10);	
	if(KEY0==0)	 
	{				 
		LED0=!LED0;	
		LED1=!LED1;	
	}		 
	 EXTI_ClearITPendingBit(EXTI_Line4); 
}
	   

void EXTIX_Init(void)
{
	NVIC_InitTypeDef   NVIC_InitStructure;
	EXTI_InitTypeDef   EXTI_InitStructure;
	
	KEY_Init();
 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
	
 
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource2);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4);
	SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
	

  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; 
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
	
  EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3 | EXTI_Line4;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; 
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
 
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x03;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//×ÓÓÅÏȼ¶2
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	   
}












7.总结

在进行STM32F407外部中断按键实验时,通过key0绑定蜂鸣器,key1绑定led0(亮灭),key2绑定led1(亮灭),key3绑定led0和led1(同时反转),样例给定时延为10ms,在进行按键检测时,发现并未体现函数中的抢占优先级,思考过后可能是由于时延太短,无法在10ms内看出其中的差别,因此我首先将时延设置为1000ms,给予充分的观察时间,设立优先级:

首先保持子优先级(响应优先级)相同,全部设为2,对于抢占优先级:

0级:key0(蜂鸣器)

1级:key1(LED0)

2级:key2(LED1)

3级:key3(LED0和LED1)

在进行试验时,按下key0与key1,在按下的时候有意的略微早一点按下key1,然后再按下key0,按照优先级抢占原则,key1的优先级为1,key0的优先级为0,虽然先按下key1,先进入key1的中断处理,但是由于key0的抢占优先级高于key1,于是将会先响应key0的中断,再响应key1的中断,最后实验发现确实如此,蜂鸣器先响,然后led0才亮,此后尝试了key2,key3均符合该原理。

 

另设优先级:

key0,key1抢占优先级设为0,子优先级(响应优先级)设为1,3

key2,key3抢占优先级设为1,子优先级(响应优先级)设为2,2

实验发现:

抢占优先级等级高于子优先级(响应优先级),子优先级低的抢占优先级高的会先响应,在抢占优先级相同的情况下,子优先级(响应优先级)高的将会先响应,两个优先级均相同的情况下,先来的会先响应。

;