1. 程式人生 > >STM32的中斷系統

STM32的中斷系統

inter 向量 結構 方式 struct block 文件 觸發 分時

STM32的中斷系統

STM32具有十分強大的中斷系統,將中斷分為了兩個類型:內核異常和外部中斷。並將所有中斷通過一個表編排起來,下面是stm32中斷向量表的部分內容:

技術分享圖片

技術分享圖片

上圖-3到6這個區域被標黑了,這個區域就是內核異常。內核異常不能夠被打斷,不能被設置優先級(也就是說優先級是淩駕於外部中斷之上的)。常見的內核異常有以下幾種:復位(reset),不可屏蔽中斷(NMI),硬錯誤(Hardfault),其他的也可以在表上找到。

從第7個開始,後面所有的中斷都是外部中斷。外部中斷是我們必須學習掌握的知識,包含線中斷,定時器中斷,IIC,SPI等所有的外設中斷,可配置優先級。外部中斷的優先級分為兩種:搶占優先級和響應優先級。

什麽是搶占優先級?

搶占優先級比較霸道,一言不和就插隊。搶占優先級高的,能夠打斷優先級低的任務,等優先級較高的任務執行完畢後,再回來繼續執行之前的任務。所以當存在多個搶占優先級不同的任務時,很有可能會產生任務的嵌套。

什麽是響應優先級?

響應優先級則稍微謙遜些,比較有禮貌。響應優先級又被稱為次優先級,若兩個任務的搶占式優先級一樣,那麽響應優先級較高的任務則先執行,且在執行的同時不能被下一個響應優先級更高的任務打斷,所以我說它比較有有禮貌。。

中斷控制器(NVIC)

因為stm32的中斷系統比較復雜,所以在內核中有一個專門管理中斷的控制器:NVIC.

NVIC負責除了SYSTICK之外的所有中斷的控制,十分重要!

在標準庫中,提供了一套通過NVIC來控制中斷的API,我們首先來看NVIC_Init()函數,這套函數首先要定義並填充一個結構體:NVIC_InitTypeDef 該結構體的定義如下:

NVIC_IRQChannel 需要配置的中斷向量

NVIC_IRQChannelCmd 使能或者關閉相應中斷向量的中斷響應

NVIC_IRQChannelPreemptionPriority 配置相應中斷向量的搶占優先級

NVIC_IRQChannelSubPriority 配置相應中斷的響應優先級

結構體的四個成員都比較好理解,這裏就不再累述了。

不過要註意一點的是,NVIC只可以配置16種中斷向量的優先級,其搶占優先級和響應優先級都用一個4位的數字來決定。在庫函數中,將其分為了5中不同的分配方式:

第0組:所有的4位都有來表示響應優先級,能夠配置16種不同的響應優先級。中斷優先級則都相同。

第1組:最高一位用來配置搶占優先級,剩余三位用來表示響應優先級。那麽就有兩種不同的搶占優先級(0和1)和8種不同的響應優先級(0~7)。

第2組:高兩位用來配置搶占優先級,低位用來配置響應優先級。那麽兩種優先級就各有4種。

第3組:高三位用來配置搶占優先級,低位用來配置響應優先級。有8種搶占優先級和2種相應優先級。

第4組:所有位都用來配置搶占優先級,即有16種搶占優先級,沒有響應屬性。

這5種不同的分配方式,根據項目的實際需求來配置。

配置的API如下:

NVIC_PriorityGroupConfig();

其中括號內可以輸入以下一個參數,代表不同的分配方式:

NVIC_PriorityGroup_0

NVIC_PriorityGroup_1

NVIC_PriorityGroup_2

NVIC_PriorityGroup_3

NVIC_PriorityGroup_4

EXTI外部中斷

STM32的所有GPIO都引入到了EXTI外部中斷線上,也就是說,所有的IO口經過配置後都能夠觸發中斷。下圖就是GPIO和EXTI的連接方式:

技術分享圖片

從上圖我們可以看出,一共有16個中斷線: EXTI0到EXTI15.

每個中斷線都對應了從PAx到PGx一共7個GPIO。也就是說,在同一時刻每個中斷線只能相應一個GPIO端口的中斷,不能夠同時相應所有端口的中斷事件,但是可以分時復用,在程序執行過程中,這個不需要我們太多的去關心。我們關心最多的是中斷觸發的方式

在EXTI中,有三種觸發中斷的方式:上升沿觸發,下降沿觸發,雙邊沿觸發。根據不同的電路,我們選擇不同的觸發方式,以確保中斷能夠被正常觸發。

實例

為了便於理解,這裏我們將中斷配置代碼貼上來。

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 配置NVIC為優先級組1 */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  /* 配置中斷源:按鍵1 */
  NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;  //配置為EXTI0通道
  /* 配置搶占優先級 */
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 配置子優先級 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中斷通道 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure); //將上述配置參數傳入中斷初始化函數
}

除了中斷線的配置,我們還要配置對應引腳

void EXTI_Key_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure; 
    EXTI_InitTypeDef EXTI_InitStructure;

    /*開啟按鍵GPIO口的時鐘*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);
                                                
    /* 配置 NVIC 中斷*/
    NVIC_Configuration();
/*--------------------------KEY1配置-----------------------------*/
    /* 選擇按鍵用到的GPIO */   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  /* 配置為浮空輸入 */ 
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);

    /* 選擇EXTI的信號源 */
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); 
  EXTI_InitStructure.EXTI_Line = EXTI_Line0;
    
    /* EXTI為中斷模式 */
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    /* 上升沿中斷 */
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  /* 使能中斷 */    
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure);
}

至此,中斷的配置完畢。相信你已經看出來,上述代碼是將PA0配置為上升沿中斷。不過,現在只能夠說該中斷已經配置完畢,但我們還不能使用它。我們還缺少一個中斷的執行函數。

當中斷被觸發後,程序要馬上跳轉到中斷函數去執行中斷操作,這個函數在工程創建時默認時沒有的。需要你自己去添加。而且需要註意的是,中斷函數的名稱必須是由標準庫提供的,否則無法識別。

我們打開startup_stm32f10x_hd.s這個文件,在裏面能找到這麽一段代碼:

                ; External Interrupts
                DCD     WWDG_IRQHandler            ; Window Watchdog
                DCD     PVD_IRQHandler             ; PVD through EXTI Line detect
                DCD     TAMPER_IRQHandler          ; Tamper
                DCD     RTC_IRQHandler             ; RTC
                DCD     FLASH_IRQHandler           ; Flash
                DCD     RCC_IRQHandler             ; RCC
                DCD     EXTI0_IRQHandler           ; EXTI Line 0
                DCD     EXTI1_IRQHandler           ; EXTI Line 1
                DCD     EXTI2_IRQHandler           ; EXTI Line 2
                DCD     EXTI3_IRQHandler           ; EXTI Line 3
                ...
                ...
                ...

不難看出,EXTI0_IRQHandler 就是中斷線0的中斷函數,所以,我們把這個函數添加到工程中即可。最好添加到stm32f10x_it.c 這個文件中,方便管理。

可以在這個函數中添加你想要的功能,代碼如下:

void EXTI0_IRQHandler(void)
{
  //確保是否產生了EXTI Line中斷
    if(EXTI_GetITStatus(EXTI_Line0) != RESET) 
    {
        /******/
         //LED閃爍相關代碼
        /******/
    //清除中斷標誌位
        EXTI_ClearITPendingBit(EXTI_Line0);     
    }  
}

至此,整個中斷的流程梳理完畢,如果有什麽紕漏的話,歡迎探討!

STM32的中斷系統