STM32——EXTI外部中斷:中斷方式翻轉LED燈

任務目的

使用EXTI(External Interrupt)外部中斷方式, 通過中斷服務函數對GPIO口進行控制, 使得LED燈可以進行亮滅翻轉.

原理圖分析

問題分析結束之後還是先來看原理圖的分析.
首先是LED燈部分:

LED燈原理圖

由圖中可知, 若要控制紅燈(PB5), 則只需輸出引腳輸出爲0(低電平)即可.
然後再看下按鍵部分:

按鍵原理圖

從圖中可知, 按鍵未按時爲低電平, 按下按鍵時爲高電平. 符合下拉輸入的邏輯.

EXTI外部中斷

簡介

外部中斷指的是通過GPIO檢測輸入的脈衝變化,從而引起中斷. 觸發方式爲邊沿觸發.

中斷

筆者使用的STM32(F103VET6)單片機使用的是Cortex-M3內核,中斷資源豐富.
外部中斷/事件控制器包含19個邊沿檢測器,用於產生中斷/事件請求。每個中斷線都可以獨立地配置它的觸發事件(上升沿或下降沿或雙邊沿),並能夠單獨地被屏蔽;有一個掛起寄存器維持所有中斷請求的狀態。 EXTI可以檢測到脈衝寬度小於內部APB2的時鐘週期。多達112個通用I/O口連接到16個外部中斷線.
具體中斷向量表不再列出, 詳情請參照STM32中文參考手冊(132/754).
這裏我們需要注意一下, 中斷線有EXTI_Line0~EXTI_Line15共16條(其實還有四條,不再詳細闡述,詳情參照參考手冊), 但是中斷向量只有EXTI0~EXTI4以及EXTI9_5, EXTI15_10共7箇中斷向量.使用時需注意這一點。

中斷線

由上圖可以發現,按鍵所在的PA0引腳處於EXTI_Line0中斷線上,中斷向量爲EXTI0.

NVIC設置

說到中斷,就不得不說到NVIC(Nested Vectored Interrupt Controller)嵌套向量中斷控制器。因爲STM32的中斷十分豐富,所以NVIC的出現幾乎是必然的。那麼談到NVIC,利用庫函數開發的思想,就不難想到結構體的應用。NVIC的結構體定義如下:

typedef struct {
  uint8_t NVIC_IRQChannel;                    /*!< Specifies the IRQ channel to be enabled or disabled.
                                                   This parameter can be a value of @ref IRQn_Type 
                                                   (For the complete STM32 Devices IRQ Channels list, please
                                                    refer to stm32f10x.h file) */

  uint8_t NVIC_IRQChannelPreemptionPriority;  /*!< Specifies the pre-emption priority for the IRQ channel
                                                   specified in NVIC_IRQChannel. This parameter can be a value
                                                   between 0 and 15 as described in the table @ref NVIC_Priority_Table */

  uint8_t NVIC_IRQChannelSubPriority;         /*!< Specifies the subpriority level for the IRQ channel specified
                                                   in NVIC_IRQChannel. This parameter can be a value
                                                   between 0 and 15 as described in the table @ref NVIC_Priority_Table */

  FunctionalState NVIC_IRQChannelCmd;         /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
                                                   will be enabled or disabled. 
                                                   This parameter can be set either to ENABLE or DISABLE */   
} NVIC_InitTypeDef;

NVIC的結構體共有三個成員,描述如下:

結構體成員名 介紹
NVIC_IRQChannel 需要配置的中斷向量名
NVIC_IRQChannelCmd 使能/關閉中斷向量
NVIC_IRQChannelPreemptionPriority 中斷搶佔優先級
NVIC_IRQChannelSubPriority 響應優先級

Tip:什麼是搶佔優先級和響應優先級

中斷向量有兩個屬性:搶佔屬性和響應屬性,屬性編號越小,中斷優先級級別越高。
搶佔優先級運用在中斷嵌套之中,而響應優先級運用在中斷響應處理方面。下面給出一個例子(參考自Fire的《STM32庫開發實戰指南》):
以下是三個中斷向量:

中斷向量 搶佔優先級 響應優先級
A 0 0
B 1 0
C 1 1

當內核正在執行C的中斷服務函數時,則它可以被搶佔優先級更高的A打斷,但不能被B打斷。當B和C同時發生中斷,則優先處理響應優先級較高的B中斷的中斷服務函數。

NVIC的優先級組

在配置中斷優先級時,由於搶佔優先級和響應優先級共同分配一個4位的二進制數,則一共可以有24=16 種中斷優先級。但是其有5種不同的分配方式:

  • 第 0 組: 所有 4 位用來配置響應優先級。即 16 種中斷向量具有都不相同的響應優先級。
  • 第 1 組:最高 1 位用來配置搶佔優先級,低 3 位用來配置響應優先級。表示有 21=2 種級別的搶佔優先級(0 級,1 級),有 23=8 種響應優先級,即在 16 種中斷向量之中,有8 種中斷,其搶佔優先級都爲 0 級,而它們的響應優先級分別爲 0~7,其餘 8 種中斷向量的搶佔優先級則都爲 1 級,響應優先級別分別爲 0~7。
  • 第 2 組:2 位用來配置搶佔優先級,2 位用來配置響應優先級。即 22=4 種搶佔優先級,22=4 種響應優先級。
  • 第 3 組:高 3 位用來配置搶佔優先級,最低 1 位用來配置響應優先級。即有 8 種搶佔優先級,2 種響應 2 優先級。
  • 第 4 組:所有 4 位用來配置搶佔優先級,即 NVIC 配置的24=16 種中斷向量都是隻有搶佔屬性,沒有響應屬性。要配置這些優先級組,可以採用庫函數 NVIC_PriorityGroupConfig(),可輸入的參數爲NVIC_PriorityGroup_0 ~ NVIC_PriorityGroup_4,分別爲以上介紹的 5 種分配組。

更直觀的圖像版描述如下(其中的佔先式優先級即搶佔式優先級,副優先級即爲響應優先級):

中斷優先級組

NVIC結構體程序設置

static void NVIC_Configuration(void) {
    NVIC_InitTypeDef key_nvic;

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

    key_nvic.NVIC_IRQChannel = EXTI0_IRQn;
    key_nvic.NVIC_IRQChannelCmd = ENABLE;
    key_nvic.NVIC_IRQChannelPreemptionPriority = 0;
    key_nvic.NVIC_IRQChannelSubPriority = 0;
    NVIC_Init(&key_nvic);
}

EXTI設置

前面說了好多NVIC的內容,終於寫到了EXTI的處理內容。EXTI的設置核心也是結構體的設置。但是別忘了,由於外部中斷依託於GPIO,所以也要同時設置GPIO的結構體成員。
注意:外部中斷在同一時間內只能響應一個中斷.

結構體說明

EXTI的結構體定義如下:

typedef struct {
  uint32_t EXTI_Line;               /*!< Specifies the EXTI lines to be enabled or disabled.
                                         This parameter can be any combination of @ref EXTI_Lines */

  EXTIMode_TypeDef EXTI_Mode;       /*!< Specifies the mode for the EXTI lines.
                                         This parameter can be a value of @ref EXTIMode_TypeDef */

  EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines.
                                         This parameter can be a value of @ref EXTIMode_TypeDef */

  FunctionalState EXTI_LineCmd;     /*!< Specifies the new state of the selected EXTI lines.
                                         This parameter can be set either to ENABLE or DISABLE */ 
}EXTI_InitTypeDef;

從中可以看出其共有4個結構體成員,描述如下表:

結構體成員名 作用
EXTI_Line 明確外部中斷線
EXTI_LineCmd 外部中斷線使能
EXTI_Mode 外部中斷線的模式選擇,共有EXTI_Mode_InterruptEXTI_Mode_Event兩種模式,前者爲中斷觸發,後者不會立刻觸發中斷,而只是在 寄存器上把相應的事件標誌位置1,應用這個模式需要不停地查詢相應的寄存器
EXTI_Trigger EXTI_Trigger_Rising:上升沿觸發; EXTI_Trigger_Falling:下降沿觸發;EXTI_Trigger_Rising_Falling:上升/下降沿觸發

結構體編程

void key_exti(void) {
    GPIO_InitTypeDef key_struct;
    EXTI_InitTypeDef key_exti_struct;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    NVIC_Configuration();

    key_struct.GPIO_Mode = GPIO_Mode_IPD;   // pull down input
    key_struct.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOA, &key_struct);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
    key_exti_struct.EXTI_Line = EXTI_Line0;
    key_exti_struct.EXTI_Mode = EXTI_Mode_Interrupt;
    key_exti_struct.EXTI_Trigger = EXTI_Trigger_Falling;
    key_exti_struct.EXTI_LineCmd = ENABLE;
    EXTI_Init(&key_exti_struct);

}

中斷服務函數

中斷服務函數的定義與51系列單片機不同。必須與規定的中斷服務函數名相同。我們可以從啓動文件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
                DCD     EXTI4_IRQHandler           ; EXTI Line 4
                DCD     DMA1_Channel1_IRQHandler   ; DMA1 Channel 1
                DCD     DMA1_Channel2_IRQHandler   ; DMA1 Channel 2
                DCD     DMA1_Channel3_IRQHandler   ; DMA1 Channel 3
                DCD     DMA1_Channel4_IRQHandler   ; DMA1 Channel 4
                DCD     DMA1_Channel5_IRQHandler   ; DMA1 Channel 5
                DCD     DMA1_Channel6_IRQHandler   ; DMA1 Channel 6
                DCD     DMA1_Channel7_IRQHandler   ; DMA1 Channel 7
                DCD     ADC1_2_IRQHandler          ; ADC1 & ADC2
                DCD     USB_HP_CAN1_TX_IRQHandler  ; USB High Priority or CAN1 TX
                DCD     USB_LP_CAN1_RX0_IRQHandler ; USB Low  Priority or CAN1 RX0
                DCD     CAN1_RX1_IRQHandler        ; CAN1 RX1
                DCD     CAN1_SCE_IRQHandler        ; CAN1 SCE
                DCD     EXTI9_5_IRQHandler         ; EXTI Line 9..5
                DCD     TIM1_BRK_IRQHandler        ; TIM1 Break
                DCD     TIM1_UP_IRQHandler         ; TIM1 Update
                DCD     TIM1_TRG_COM_IRQHandler    ; TIM1 Trigger and Commutation
                DCD     TIM1_CC_IRQHandler         ; TIM1 Capture Compare
                DCD     TIM2_IRQHandler            ; TIM2
                DCD     TIM3_IRQHandler            ; TIM3
                DCD     TIM4_IRQHandler            ; TIM4
                DCD     I2C1_EV_IRQHandler         ; I2C1 Event
                DCD     I2C1_ER_IRQHandler         ; I2C1 Error
                DCD     I2C2_EV_IRQHandler         ; I2C2 Event
                DCD     I2C2_ER_IRQHandler         ; I2C2 Error
                DCD     SPI1_IRQHandler            ; SPI1
                DCD     SPI2_IRQHandler            ; SPI2
                DCD     USART1_IRQHandler          ; USART1
                DCD     USART2_IRQHandler          ; USART2
                DCD     USART3_IRQHandler          ; USART3
                DCD     EXTI15_10_IRQHandler       ; EXTI Line 15..10
                DCD     RTCAlarm_IRQHandler        ; RTC Alarm through EXTI Line
                DCD     USBWakeUp_IRQHandler       ; USB Wakeup from suspend
                DCD     TIM8_BRK_IRQHandler        ; TIM8 Break
                DCD     TIM8_UP_IRQHandler         ; TIM8 Update
                DCD     TIM8_TRG_COM_IRQHandler    ; TIM8 Trigger and Commutation
                DCD     TIM8_CC_IRQHandler         ; TIM8 Capture Compare
                DCD     ADC3_IRQHandler            ; ADC3
                DCD     FSMC_IRQHandler            ; FSMC
                DCD     SDIO_IRQHandler            ; SDIO
                DCD     TIM5_IRQHandler            ; TIM5
                DCD     SPI3_IRQHandler            ; SPI3
                DCD     UART4_IRQHandler           ; UART4
                DCD     UART5_IRQHandler           ; UART5
                DCD     TIM6_IRQHandler            ; TIM6
                DCD     TIM7_IRQHandler            ; TIM7
                DCD     DMA2_Channel1_IRQHandler   ; DMA2 Channel1
                DCD     DMA2_Channel2_IRQHandler   ; DMA2 Channel2
                DCD     DMA2_Channel3_IRQHandler   ; DMA2 Channel3
                DCD     DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5

查得本次中斷服務函數的函數名爲:EXTI0_IRQHandler
編寫的中斷服務函數爲:

void EXTI0_IRQHandler(void) {
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
        led_toggle();    // LED狀態翻轉
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}

主函數

int main()
{
    led_config();
    key_exti();
    while (1);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章