STM32个人笔记-中断

笔记来源于STM32F103VET6,野火指南者,中文参考手册,HAL库开发手册和b站的野火指南者中级篇视频。观看过好多次中级篇了,但往往理解得不够全面,现记下小笔记,用来回顾。属于个人笔记,不用于商业。​​​​​

EXTI:外部中断/事件控制器,管理了控制器的 20 个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。

STM32个人笔记-中断_第1张图片

中断分为:系统异常(内核水平)、外部中断(内核之外)。

系统异常保存在core_m3.h、misc.h。

外部中断保存在stm32f10x.h。

 

STM32个人笔记-中断_第2张图片

对于第一点,输入线,EXTI控制器有19个中断/事件输入线,这些输入线可以通过寄存器设置为任意一个GPIO,也可以是一些外设的事件。输入线一般是存在电平变化的信号。

STM32个人笔记-中断_第3张图片 STM32个人笔记-中断_第4张图片

对于第二点,边沿检测电路可以选择上升沿触发选择寄存器(EXTI_RTSR)或下降沿触发选择寄存器(EXTI_FTSR)。边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号1给第三点电路,否则输出无效信号0。而EXTI_RTSR和EXTI_FTSR两个寄存器可以控制需要检测哪些类型的电平跳变过程,可以是只有上身沿触发、只有下降沿触发或者上身沿和下降沿都触发。

例如按键中断,上升沿触发选择寄存器记录的是按键按下时,下降沿触发选择寄存器记录的是按键按下后反弹回时。

对于第三点,或门电路,输入来自第二点和软件中断事件寄存器(EXTI_SWIER),任意一路输入给1就放行。EXTI_SWIER允许我们通过程序控制就可以启动中断/事件线。

STM32个人笔记-中断_第5张图片

STM32个人笔记-中断_第6张图片

对于第四点,与门电路,输入来自第三点和中断屏蔽寄存器(EXTI_IMR),所有输入都给1才放行。

如果EXTI_IMR设置为0时,那不管第三点电路的输出信号是1还是0,最终第四点的电路输出信号都为0。

如果EXTI_IMR设置为1时,最终第四点的电路输出信号才由第三点电路的输出信号决定。

这样我们可以简单的控制EXTI_IMR来实现是否产生中断的目的。第四点的电路输出信号会被保存到挂起寄存器(EXTI_PR)内,如果确定第四点的电路输出信号为1,就会把EXTI_PR对应位置1。

对于第五点,将EXTI_PR寄存器内容输出到NVIC中断控制器内,NVIC属于内核cm3的,内核就会在cm3文件中找中断服务函数ESR,实现ESR的功能。

对于第六点,与门电路,输入来自第三点和事件屏蔽寄存器(EXTI_EMR),所有输入都给1才放行。

如果EXTI_EMR设置为0时,那不管第三点电路的输出信号是1还是0,最终第六点的电路输出信号都为0。

如果EXTI_EMR设置为1时,最终第六点的电路输出信号才由第三点电路的输出信号决定。

这样我们可以简单的控制EXTI_EMR来实现是否产生事件的目的。

对于第七点,脉冲发生器电路,输出来自第六点。若第六点输出为1,则会产生1个脉冲。

对于第八点,产生脉冲信号。这个脉冲信号可以给其他外设电路使用,比如定时器TIM、模拟数字转换器ADC等等。

产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。 另外,EXTI 是在 APB2 总线上的。

中断编程的顺序:

1)使能中断请求

2)配置中断优先级分组

3)配置NVIC寄存器,初始化NVIC_InitTypeDef

4)编写中断服务函数

对于第一步,使能中断请求。先使能NVIC,在使能外设相应配置寄存器的中断使能位。

对于第二步,根据misc.h,有void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

现附上简单的按键中断例子程序:

static void EXTI_NVIC_Config(void)	
{
	NVIC_InitTypeDef NVIC_InitStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;
	NVIC_Init(&NVIC_InitStruct);
}


void EXTI_Key_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	
	//配置中断优先级
	EXTI_NVIC_Config();
	/*--------------------------------KEY1配置--------------------------------*/
	//配置初始化GPIO-PA0
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA,&GPIO_InitStruct);	
	//初始化EXTI
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
	EXTI_InitStruct.EXTI_Line = EXTI_Line0;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;	//上升沿
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
	/*------------------------------------------------------------------------*/
	
	/*--------------------------------KEY2配置--------------------------------*/
	//配置初始化GPIO-PC13
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOC,&GPIO_InitStruct);	
	//初始化EXTI
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);
	EXTI_InitStruct.EXTI_Line = EXTI_Line13;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
	/*------------------------------------------------------------------------*/
}
void EXTI0_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line0) != RESET)
	{
		LED_G_TOGGLE;    //LED状态翻转
	}
	EXTI_ClearITPendingBit(EXTI_Line0);		//pemding是挂起。这个函数是将中断标志位清除掉

}

void EXTI15_10_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line13) != RESET)
	{
		LED_R_TOGGLE;    //LED状态翻转
	}
	EXTI_ClearITPendingBit(EXTI_Line13);		//pemding是挂起。这个函数是将中断标志位清除掉

}

对NVIC_InitTypeDef 进行分析

typedef struct
{
  uint8_t NVIC_IRQChannel;                    //IRQ通道。这个参数可以是IRQn_Type的值。(完整的STM32设备IRQ通道列表,请参阅stm32f10x.h文件)                                                   

  uint8_t NVIC_IRQChannelPreemptionPriority;  //抢占优先级。该参数可以是一个值,在0到15之间,如表NVIC_Priority_Table所述  

  uint8_t NVIC_IRQChannelSubPriority;         //子优先级。 该参数可以是一个值,在0到15之间,如表NVIC_Priority_Table所述  

  FunctionalState NVIC_IRQChannelCmd;         //IRQ通道使能,可选ENABLE或DISABLE
} NVIC_InitTypeDef;

IRQ通道如下

typedef enum IRQn
{
/******  Cortex-M3 Processor Exceptions Numbers ***************************************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                             */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M3 Memory Management Interrupt              */
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M3 Bus Fault Interrupt                      */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M3 Usage Fault Interrupt                    */
  SVCall_IRQn                 = -5,     /*!< 11 Cortex-M3 SV Call Interrupt                       */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M3 Debug Monitor Interrupt                 */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M3 Pend SV Interrupt                       */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M3 System Tick Interrupt                   */

/******  STM32 specific Interrupt Numbers *********************************************************/
  WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                            */
  PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt            */
  TAMPER_IRQn                 = 2,      /*!< Tamper Interrupt                                     */
  RTC_IRQn                    = 3,      /*!< RTC global Interrupt                                 */
  FLASH_IRQn                  = 4,      /*!< FLASH global Interrupt                               */
  RCC_IRQn                    = 5,      /*!< RCC global Interrupt                                 */
  EXTI0_IRQn                  = 6,      /*!< EXTI Line0 Interrupt                                 */
  EXTI1_IRQn                  = 7,      /*!< EXTI Line1 Interrupt                                 */
  EXTI2_IRQn                  = 8,      /*!< EXTI Line2 Interrupt                                 */
  EXTI3_IRQn                  = 9,      /*!< EXTI Line3 Interrupt                                 */
  EXTI4_IRQn                  = 10,     /*!< EXTI Line4 Interrupt                                 */
  DMA1_Channel1_IRQn          = 11,     /*!< DMA1 Channel 1 global Interrupt                      */
  DMA1_Channel2_IRQn          = 12,     /*!< DMA1 Channel 2 global Interrupt                      */
  DMA1_Channel3_IRQn          = 13,     /*!< DMA1 Channel 3 global Interrupt                      */
  DMA1_Channel4_IRQn          = 14,     /*!< DMA1 Channel 4 global Interrupt                      */
  DMA1_Channel5_IRQn          = 15,     /*!< DMA1 Channel 5 global Interrupt                      */
  DMA1_Channel6_IRQn          = 16,     /*!< DMA1 Channel 6 global Interrupt                      */
  DMA1_Channel7_IRQn          = 17,     /*!< DMA1 Channel 7 global Interrupt                      */

  ADC1_2_IRQn                 = 18,     /*!< ADC1 and ADC2 global Interrupt                       */
  USB_HP_CAN1_TX_IRQn         = 19,     /*!< USB Device High Priority or CAN1 TX Interrupts       */
  USB_LP_CAN1_RX0_IRQn        = 20,     /*!< USB Device Low Priority or CAN1 RX0 Interrupts       */
  CAN1_RX1_IRQn               = 21,     /*!< CAN1 RX1 Interrupt                                   */
  CAN1_SCE_IRQn               = 22,     /*!< CAN1 SCE Interrupt                                   */
  EXTI9_5_IRQn                = 23,     /*!< External Line[9:5] Interrupts                        */
  TIM1_BRK_IRQn               = 24,     /*!< TIM1 Break Interrupt                                 */
  TIM1_UP_IRQn                = 25,     /*!< TIM1 Update Interrupt                                */
  TIM1_TRG_COM_IRQn           = 26,     /*!< TIM1 Trigger and Commutation Interrupt               */
  TIM1_CC_IRQn                = 27,     /*!< TIM1 Capture Compare Interrupt                       */
  TIM2_IRQn                   = 28,     /*!< TIM2 global Interrupt                                */
  TIM3_IRQn                   = 29,     /*!< TIM3 global Interrupt                                */
  TIM4_IRQn                   = 30,     /*!< TIM4 global Interrupt                                */
  I2C1_EV_IRQn                = 31,     /*!< I2C1 Event Interrupt                                 */
  I2C1_ER_IRQn                = 32,     /*!< I2C1 Error Interrupt                                 */
  I2C2_EV_IRQn                = 33,     /*!< I2C2 Event Interrupt                                 */
  I2C2_ER_IRQn                = 34,     /*!< I2C2 Error Interrupt                                 */
  SPI1_IRQn                   = 35,     /*!< SPI1 global Interrupt                                */
  SPI2_IRQn                   = 36,     /*!< SPI2 global Interrupt                                */
  USART1_IRQn                 = 37,     /*!< USART1 global Interrupt                              */
  USART2_IRQn                 = 38,     /*!< USART2 global Interrupt                              */
  USART3_IRQn                 = 39,     /*!< USART3 global Interrupt                              */
  EXTI15_10_IRQn              = 40,     /*!< External Line[15:10] Interrupts                      */
  RTCAlarm_IRQn               = 41,     /*!< RTC Alarm through EXTI Line Interrupt                */
  USBWakeUp_IRQn              = 42,     /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */
  TIM8_BRK_IRQn               = 43,     /*!< TIM8 Break Interrupt                                 */
  TIM8_UP_IRQn                = 44,     /*!< TIM8 Update Interrupt                                */
  TIM8_TRG_COM_IRQn           = 45,     /*!< TIM8 Trigger and Commutation Interrupt               */
  TIM8_CC_IRQn                = 46,     /*!< TIM8 Capture Compare Interrupt                       */
  ADC3_IRQn                   = 47,     /*!< ADC3 global Interrupt                                */
  FSMC_IRQn                   = 48,     /*!< FSMC global Interrupt                                */
  SDIO_IRQn                   = 49,     /*!< SDIO global Interrupt                                */
  TIM5_IRQn                   = 50,     /*!< TIM5 global Interrupt                                */
  SPI3_IRQn                   = 51,     /*!< SPI3 global Interrupt                                */
  UART4_IRQn                  = 52,     /*!< UART4 global Interrupt                               */
  UART5_IRQn                  = 53,     /*!< UART5 global Interrupt                               */
  TIM6_IRQn                   = 54,     /*!< TIM6 global Interrupt                                */
  TIM7_IRQn                   = 55,     /*!< TIM7 global Interrupt                                */
  DMA2_Channel1_IRQn          = 56,     /*!< DMA2 Channel 1 global Interrupt                      */
  DMA2_Channel2_IRQn          = 57,     /*!< DMA2 Channel 2 global Interrupt                      */
  DMA2_Channel3_IRQn          = 58,     /*!< DMA2 Channel 3 global Interrupt                      */
  DMA2_Channel4_5_IRQn        = 59      /*!< DMA2 Channel 4 and Channel 5 global Interrupt        */
} IRQn_Type;

抢占优先级和子优先级可以参考如下表

NVIC_PriorityGroup NVIC_IRQChannelPreemptionPriority NVIC_IRQChannelSubPriority Description
NVIC_PriorityGroup_0        0        0-15 主优先级占0位,子优先级占4位
NVIC_PriorityGroup_1 0-1 0-7 主优先级占1位,子优先级占3位
NVIC_PriorityGroup_2 0-3 0-3 主优先级占2位,子优先级占2位
NVIC_PriorityGroup_3 0-7 0-1 主优先级占3位,子优先级占1位
NVIC_PriorityGroup_4 0-15 0 主优先级占4位,子优先级占0位

举个例子,NVIC的初始化

static void EXTI_NVIC_Config(void)	
{
	NVIC_InitTypeDef NVIC_InitStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
}

再对EXTI_InitTypeDef进行分析

typedef struct
{
  uint32_t EXTI_Line;                   //中断/事件线,这个参数可以在EXTI_Lines中查看
   
  EXTIMode_TypeDef EXTI_Mode;           //中断/事件线模式,这个参数可以在EXTIMode_TypeDef中查看

  EXTITrigger_TypeDef EXTI_Trigger;     //触发状态,这个参数可以在EXTIMode_TypeDef中查看

  FunctionalState EXTI_LineCmd;         //中断/事件线使能,可以是ENABLE或DISABLE
}EXTI_InitTypeDef;

中断/事件线如下

#define EXTI_Line0       ((uint32_t)0x00001)  /*!< External interrupt line 0 */
#define EXTI_Line1       ((uint32_t)0x00002)  /*!< External interrupt line 1 */
#define EXTI_Line2       ((uint32_t)0x00004)  /*!< External interrupt line 2 */
#define EXTI_Line3       ((uint32_t)0x00008)  /*!< External interrupt line 3 */
#define EXTI_Line4       ((uint32_t)0x00010)  /*!< External interrupt line 4 */
#define EXTI_Line5       ((uint32_t)0x00020)  /*!< External interrupt line 5 */
#define EXTI_Line6       ((uint32_t)0x00040)  /*!< External interrupt line 6 */
#define EXTI_Line7       ((uint32_t)0x00080)  /*!< External interrupt line 7 */
#define EXTI_Line8       ((uint32_t)0x00100)  /*!< External interrupt line 8 */
#define EXTI_Line9       ((uint32_t)0x00200)  /*!< External interrupt line 9 */
#define EXTI_Line10      ((uint32_t)0x00400)  /*!< External interrupt line 10 */
#define EXTI_Line11      ((uint32_t)0x00800)  /*!< External interrupt line 11 */
#define EXTI_Line12      ((uint32_t)0x01000)  /*!< External interrupt line 12 */
#define EXTI_Line13      ((uint32_t)0x02000)  /*!< External interrupt line 13 */
#define EXTI_Line14      ((uint32_t)0x04000)  /*!< External interrupt line 14 */
#define EXTI_Line15      ((uint32_t)0x08000)  /*!< External interrupt line 15 */
#define EXTI_Line16      ((uint32_t)0x10000)  /*!< External interrupt line 16 Connected to the PVD Output */
#define EXTI_Line17      ((uint32_t)0x20000)  /*!< External interrupt line 17 Connected to the RTC Alarm event */
#define EXTI_Line18      ((uint32_t)0x40000)  /*!< External interrupt line 18 Connected to the USB Device/USB OTG FS
                                                   Wakeup from suspend event */                                    
#define EXTI_Line19      ((uint32_t)0x80000)  /*!< External interrupt line 19 Connected to the Ethernet Wakeup event */

中断/事件线模式如下

typedef enum
{
  EXTI_Mode_Interrupt = 0x00,    //中断--针对外设
  EXTI_Mode_Event = 0x04         //事件--针对内核
}EXTIMode_TypeDef;

触发状态如下

typedef enum
{
  EXTI_Trigger_Rising = 0x08,            //上升沿触发
  EXTI_Trigger_Falling = 0x0C,           //下降沿触发
  EXTI_Trigger_Rising_Falling = 0x10     //上升沿和下降沿都触发
}EXTITrigger_TypeDef;

举个例子,EXTI的初始化

void EXTI_Config(void)
{
	EXTI_InitTypeDef EXTI_InitStruct;
	
	//配置中断优先级
	EXTI_NVIC_Config();

	//初始化EXTI-PA0
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
	EXTI_InitStruct.EXTI_Line = EXTI_Line0;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;	//上升沿
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStruct);
}

外部中断的一般配置步骤:

1.使能SYSCFG时钟

RCC_APB2PeriphClockCmd(Rcc_APB2Periph_SYSCFG,ENABLE);

2.初始化IO口为输入

GPIO_Init();

3.设置IO口与中断线的映射关系

viod SYSCFG_EXTILineConfig();

4.初始化线上中断,设置触发条件等

EXTI_Init();

5.配置中断分组(NVIC),并使能中断

NVIC_Init();

6.编写中断服务函数

EXTIx_IRQHandle();

7.清除中断标志位

EXTI_ClearITPendingBit();

你可能感兴趣的:(STM32个人笔记,stm32)