zoukankan      html  css  js  c++  java
  • STM32的NVIC和外部中断

    1.NVIC是什么

    NVIC 是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。但是各个芯片厂商在设计芯片的时候会对 Cortex-M3 内核里面的NVIC 进行裁剪,把不需要的部分去掉,所以说 STM32 NVIC Cortex-M3 NVIC 的一个子集。普通外设都在标准库中以stmf10x_xxx.c中。NVIC属于内核中的外设,相关的函数存放在misc.c中。

    void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
    void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
    void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
    void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
    void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
    

    说一下NVIC的设置中断分组和设置优先级问题。

    NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx, 用来配置外部中断的优先级, IPR 宽度为 8bit,原则上每个外部中断可配置的优先级为 0~255,数值越小,优先级越高。但是绝大多数 CM3 芯片都会精简设计,以致实际上支持的优先级数减少,在F103 中,只使用了高 4bit,如下所示: 

     图 1 中断优先级寄存器NVIC_IPRx

     用于表达优先级的这 4bit(bit4-bit7),又被分组成抢占优先级和子优先级。总共可以分成5个分组:在用到NVIC时,需要先设置分组,再对某个中断设置抢占优先级和子优先级。

    主优先级占4位,子优先级占0位      //这种情况,如果有2个中断,他们的的主优先级可以设置2^4种,0-15,而子优先级只能设置成一样的
    
    主优先级占3位,子优先级占1位    //这种情况,如果有2个中断,他们的的主优先级可以设置2^3种,0-8,而子优先级可以设置成2^1种,0-1
    主优先级占2位,子优先级占2位   //这种情况,如果有2个中断,他们的的主优先级可以设置2^2种,0-3,而子优先级可以设置成2^2种,0-3
    主优先级占1位,子优先级占3位     //这种情况,如果有2个中断,他们的的主优先级可以设置2^1种,0-1,而子优先级可以设置成2^3种,0-7
    主优先级占0位,子优先级占4位     //这种情况,如果有2个中断,他们的的主优先级可以设置2^0种,0,而子优先级可以设置2^4种。0-15

     图2 主优先级和子优先级的分配

     ----------------------------------------------------------------分割线------------------------------------------------------------------------------------------------------------------------------------

    1     NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;            //使能按键WK_UP所在的外部中断通道
    2       NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;    //抢占优先级2, 
    3       NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;           //子优先级3
    4       NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                 //使能外部中断通道

    上面这4句代码是配置某个中断的NVIC初始化。第一行中 NVIC_IRQChannel 必须选定一个中断源,既然用到了NVIC肯定用到了中断,那中断源从哪里来,必须指定出来。那中断源从哪里找,比如,我要是设置定时器中断的优先级,NVIC_IRQChannel怎么赋值?

    从stm32f10x.h中找即可。(该文件中170行开始)

      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        */

     中断的处理函数在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

    2.如何比较中断的优先级?

    如果有多个中断同时响应,抢占优先级高的就会 抢占 抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。 

     

     3.EXTI是什么?

    普通的GPIO作为输入输出,EXTI则是把普通的GPIO复用作为检测口,根据EXTI寄存器配置是中断模式还是事件模式。来控制引脚的输入信号是到NVIC中去,还是到脉冲发生器中去。如果配置为中断,则引脚的输入信号会通过下降沿触发选择寄存器、上升沿触发选择寄存器、软件中断事件寄存器、请求挂起寄存器、中断屏蔽寄存器共同设置最后达到NVIC中。CPU则会响应这个中断,去处理它的中断服务函数。事件的话,最后到达脉冲发生器,不需要CPU响应。

     

    图3 EXTI 框图

     每个GPIO引脚都可以配置外部中断。每个端口有16个引脚,EXTI0-EXTI15总共16个外部中断线。分配方法是,把每个端口的0号引脚连接到EXTI0上,一次类推,可以看下面的图。

     

    图4 EXTI中断线的连接方式

    具体配置方法和疑问

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟
    
        //GPIOE.2 中断线以及中断初始化配置  
      	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);
    
      	EXTI_InitStructure.EXTI_Line=EXTI_Line2;	//KEY2
      	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
      	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
            EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存

     EXTI使用方法是。对照上面的代码

    1.把引脚连接到外部中断线上

    2.关闭中断屏蔽

    3.触发模式(中断还是事件)

    4.触发方式(上升还是下降还是全部)

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);
    
     EXTI_InitStructure.EXTI_Line=EXTI_Line2;	//KEY2

    通过代码中发现这两行代码好像是重复了,都是配置中断线的,通过查看这两个函数的实现,发现GPIO_EXTILineConfig内部操作的是8.4.3 外部中断配置寄存器(AFIO_EXTICRx),就是把具体引脚连接到对应的中断线上,(总共有4个寄存器,共同配置EXTI0-EXTI15)

     

    图5 外部中断配置寄存器AFIO_EXTICRx

     而 EXTI_InitStructure.EXTI_Line=EXTI_Line2; 这句代码,通过EXTI_Init函数内部查找发现,这个是操作的9.3.1 中断屏蔽寄存器(EXTI_IMR),是用来屏蔽还是开放这个线上的中断的。主要作用是是否开发中断。对应图3中的中断屏蔽寄存器。

    图6 中断屏蔽寄存器(EXTI_IMR)

    问题0:EXTI->IMR &= ~EXTI_InitStruct->EXTI_Line;的疑惑,解答地址https://bbs.21ic.com/icview-245974-1-1.html

    问题1:外部中断5-9 外部中断10-15共用同一个中断处理函数,怎么设置5-9的中断优先级?

    问题2:如果PA0,PB0,PC0同时连接到了EXTI0,如何判断是哪个引脚的外部中断?

    https://bbs.21ic.com/icview-561604-1-1.html

     

  • 相关阅读:
    [levelDB] Version Manager
    [levelDB] Compaction
    <Effective Modern C++> 读书笔记
    <Effective Modern C++> 笔记-1-Deducing Type
    水塘抽样(Reservoir Sampling)问题
    【C++工程实践】条件变量
    【c++工程实践】内存模型
    【c++工程实践】智能指针
    【c++工程实践】值语义与右值引用
    分布式系统原理-CAP/2PC/3PC
  • 原文地址:https://www.cnblogs.com/1024E/p/13208056.html
Copyright © 2011-2022 走看看