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

     

  • 相关阅读:
    LeetCode 258 Add Digits
    LeetCode 231 Power of Two
    LeetCode 28 Implement strStr()
    LeetCode 26 Remove Duplicates from Sorted Array
    LeetCode 21 Merge Two Sorted Lists
    LeetCode 20 Valid Parentheses
    图形处理函数库 ImageTTFBBox
    php一些函数
    func_get_arg(),func_get_args()和func_num_args()的用法
    人生不是故事,人生是世故,摸爬滚打才不会辜负功名尘土
  • 原文地址:https://www.cnblogs.com/1024E/p/13208056.html
Copyright © 2011-2022 走看看