welcom ! Handel home

2014年6月17日 星期二

STM32 EXTI GPIO 外部中斷源參數範例說明

STM32  EXTI
1、 PA0 ... PF0 共用一個中斷標誌 EXT0
      PA1 ... PF1
共用一個中斷標誌 EXT1
       .        .
       .        .
       PA15... PF15
共用一個中斷標誌 EXT15
       ps: 中斷源 EXT0 .. 15 對應各個 PORT(A .. F) 的相對應Pin 指定單一pin 不能共用中斷向量

2
EXT5-9   共用一個中斷源  (Px5 .. Px9) 
     EXT10-15
共用一個中斷源 (Px10..Px15) 
     ps: 中斷源發生後 因為多pin 共用 得使用 EXTI_Line(5 ..9) or (10..15)  近一步判定 發生的中斷源

3
、啟用中斷前,需ENABLE IO口的複用功能(AFIO) 

4、設置中斷IO

5、將IO口註冊到中斷線(IO口映射到中斷線N)
例:GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource3); GPIOD.3註冊至
中斷線EXTILine3
       GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource4); GPIOD.4註冊至中斷線EXTILine4

6、配置中斷
   EXTI_InitStructure.EXTI_Line       =   EXTI_Line3;

   EXTI_InitStructure.EXTI_Mode     =   EXTI_Mode_Interrupt;            // 中斷
                                                   =   EXTI_Mode_Event                  // 
事件(觸發其它模組)

   EXTI_InitStructure.EXTI_Trigger =   EXTI_Trigger_Rising               //上升沿觸發
                                                  =    EXTI_Trigger_Falling             //
下降沿觸發
                                                  =   EXTI_Trigger_Rising_Falling    //
脈衝觸發(上升 ,下降均會觸發)

7、配置NVIC

8、如果使用庫函數寫中斷,要開放stm32f10x_conf.h中的相應中斷
----------------------------------------------------------------------------------------------------    
Ext:
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOD|RCC_APB2Periph_AFIO, ENABLE);                                        
/* PD3,4,5,6按鍵輸入*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   //上拉輸入
GPIO_Init(GPIOD, &GPIO_InitStructure);

/* 連接IO口到中斷線 */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource3);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource4);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource5);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource6);

/*
配置中斷線3為邊降沿觸發*/
EXTI_InitStructure.EXTI_Line = EXTI_Line3;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);

/*
其他為下降沿觸發*/
EXTI_InitStructure.EXTI_Line = EXTI_Line4|EXTI_Line5|EXTI_Line6;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);


==================================================================================
範例2:


1
、系統初始化,如系統時鐘初始化,使之進入 72MHZ 主頻;
2GPIO 配置,務必注意打開 GPIO 時鐘時,一定打開 AFIO 時鐘。
3EXTI 配置,在這裡配置需要選擇哪個引腳作為中斷引腳。
4NVIC 配置,這也是比單片機多出來的部分,我們必須把 NVIC 中對應
的通道使能,並且設置優先順序別。
5、使用 while(1)進行閉環,並在中斷程式中寫入中斷發生時應如何處理。

步驟一 系統初始化,使用固件範本中自帶的 SystemInit();函數即可。通過
分析這個函數,我們會發現此函數把主頻預設調整到 72MHZ

步驟二 GPIO 配置,這以後均是需要自己編寫的函數,常式中採用
GPIO_Config();函數,如下所示:

void GPIO_Config(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE| RCC_APB2Periph_AFIO, ENABLE);
/**
* LED1 -> PB8 , LED2 -> PB9 , LED3 -> PE0 , LED4 -> PE1
* Key1 -> PE2 , Key2 -> PE3
*/
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 |GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  
  GPIO_Init(GPIOE, &GPIO_InitStructure);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 |GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOE, &GPIO_InitStructure);
}

在這裡函數裡,我們首先使能了 GPIOBGPIOE 的時鐘,因為我們使用
PB8\PB9\PE0\PE1 作為用戶指示燈來驗證外部中斷,使用 PE2\PE3 作為中斷觸發
引腳。注意它們的配置中,同樣是 GPIO 引腳,卻需要把 PE2\PE3 配置為浮空輸
入模式,而其他配置為輸出模式 —— 很好理解,因為 LED 指示燈是由 CPU
動點亮的,而中斷引腳 PE2\PE3,是外界按鍵驅動的,相對於 CPU 來說,是“輸
入”。

步驟三 EXTI 的配置。此步相當於單片機的中斷配置,使用的函數是
EXTI_Config();函數。
void EXTI_Config(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2); // 選擇
GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3);
EXTI_ClearITPendingBit(EXTI_Line3); 
EXTI_ClearITPendingBit(EXTI_Line2);
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
該函數中,首先指明當前系統中使用哪個引腳作為觸發外部中斷的引腳,這
個直接使用固件庫中提供的 GPIO_EXTILineConfig();函數即可。我們指明了
PE2\PE3 引腳作為觸發中斷引腳。
然後使用 EXTI_ClearITPendingBit();函數清除中斷標誌位元。關於中斷標誌位元,
大家應該都很熟悉。我們進入中斷服務程式後,首先做的就是清除中斷標誌位元,
否則它會不斷回應中斷,不斷進入中斷函數。當然,我們這裡做這個步驟,只是
為了預防萬一,您也可以刪除此句試驗下。
另外需要說明的是 EXTI_Line3,這個表示的是中斷線 3。對於外部中斷中的
GPIO,有 16 個中斷線,分別是 0-15,剛好對應於每個 GPIO 埠的 0-15 引腳。
接下來設置外部中斷結構體的成員,比如 EXTI_Mode_Interrupt 即為中斷請
求,還有一個是 EXTI_Mode_Event,事件請求。這裡就有一個問題了,事件和
中斷到底啥關係呢?請參考如下語句(網路上查的):
“事件:是表示檢測有一某件觸發事件發生了。
中斷:有某個事件發生並產生中斷,並跳轉到對應的中斷處理常式中。
事件可以觸發中斷,也可以不觸發
中斷有可能被更優先的中斷遮罩,事件不會
事件本質上就是一個觸發信號,是用來觸發特定的外設模組或核心本身(喚醒).
事件只是一個觸發信號(脈衝),而中斷則是一個固定的電平信號” 我們採用的觸發方式是上升沿觸發 EXTI_Trigger_Rising,使用的中斷線是
EXTI_Line2 EXTI_Line3,實際上就是指明使用的是 GPIO 的第 2 引腳和
3 引腳。最後不要忘了務必要使能它,呵呵。

步驟四 NVIC 配置。先解釋下 NVIC,它的中文全稱是“嵌套向量中斷控
制器。”我們進行 NVIC 配置時,採用的是 NVIC_Config();函數,下面列出該函
數:
void NVIC_Config(void)
{
   NVIC_InitTypeDef NVIC_InitStructure;
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
   NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQChannel; //通道 
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);
   //-------------------------------------------------------
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
   NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQChannel; //通道
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);
}
該函數的編寫分兩個部分,一個部分是專門針對中斷線 2 的,另一個部分針
對中斷線 3 的。實際上學習外部中斷,只要其中一個即可。由於芯達 STM32
發板上配置了兩個按鍵,都可以用作外部中斷的學習,因此我們這裡列出了兩個
中斷線。
整個函數比較簡單,從函數名即可知道其含義。大家在查看這些函數的時候,
請務必查看他們具體是如何實現的。比如 NVIC_PriorityGroupConfig();函數,不
能只看這個函數是用於優先順序組配置,還要稍微關注下它的實現。操作是,按兩下
“ Go To Definiton of ‘NVIC_PriorityGroupConfig’”
如下圖所示,即可查看該函數的具體實現。

步驟五 中斷服務副程式的編寫。經過以上四個步驟,我們已經把中斷配置
完畢。剩下的工作,就是編寫中斷服務副程式,實現進入中斷後會如何處理。我
們在這裡舉了 PE2 上的開關按下後的動作:

void EXTI2_IRQHandler(void)
{
        if ( EXTI_GetITStatus(EXTI_Line2) != RESET )
        {
            //---------------------------------------------------------------
            EXTI_ClearITPendingBit(EXTI_Line2);
            /*====LED34-ON=======*/
            GPIO_SetBits(GPIOB , GPIO_Pin_8);
            GPIO_SetBits(GPIOB , GPIO_Pin_9);
            GPIO_ResetBits(GPIOE , GPIO_Pin_0);
            GPIO_SetBits(GPIOE , GPIO_Pin_1);
            Delay(0xfffff);
            Delay(0xfffff);
            Delay(0xfffff);
        }

}
EXTI_GetITStatus()函數的返回值如果不是 RESET,說明此時確實有中斷發
生了,因此,第一步,把中斷標誌位元清除,以防它不斷地進入中斷。然後點亮
LED 指示燈。怎麼點亮 LED 燈,這個就不詳細展開解釋,讀者可根據自己的實
際情況來編寫程式。
值得說明的是,該函數應該寫在 stm32f10x_it.c 檔中,並且中斷服務子程
序的函數名,必須嚴格按照 startup_stm32f10x_hd.s 文件中的中斷向量表中,對
應的向量名進行。如果擔心寫錯函數名,可以直接打開 startup_stm32f10x_hd.s檔,找到如下部分:

__Vectors DCD __initial_spTop ; Top of Stack
DCD Reset_Handler ;// Reset Handler
DCD NMI_Handler ; //NMI Handler
DCD HardFault_Handler ;// Hard Fault Handler
DCD MemManage_Handler //; MPU Fault Handler
DCD BusFault_Handler ; //Bus Fault Handler
DCD UsageFault_Handler ;// Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler ; External Interrupts
DCD WWDG_IRQHandler ; //Window Watchdog
DCD PVD_IRQHandler ;// PVD through EXTI Line detect
DCD TAMPER_IRQHandler ; 
//=========================================
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 HighPriority or CAN1 TX
DCD USB_LP_CAN1_RX0_IRQHandler ; USB LowPriority 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
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__Vectors_End

我們現在使用的是中斷線 2 的處理函數,因此是上面紅色粗體所示的函數名:
EXTI2_IRQHandler


步驟六 編寫 while 閉環程式,指明沒有中斷發生時,系統應該運行什麼
程式。我們編寫了一個閉環:當沒有中斷發生時,不斷地讓指示燈 LED1
LED2 進行閃爍處理。按下按鍵後,關掉指示燈 LED1 LED2,同時點亮對應


LED3 或者 LED4


沒有留言: