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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM