標籤:
學會知識只需要不段的積累和提高,但是如何將知識系統的講解出來就需要深入的認知和系統的瞭解。外部中斷和事件學習難度並不高,不過涉及到STM32的電源控制部分,還是值得認真瞭解的,在本文中我將以實際代碼為例詳細講解這些內容,希望對每一個閱讀者有協助。
1.外部中斷
如果已經學習了SysTick系統時鐘滴答實驗,掌握了Cortex-M3中斷的相關知識,那麼外部中斷也是比較好理解的,和SysTick中斷一樣,外部中斷也是當有訊號觸發時,如果中斷屏蔽寄存器允許觸發,就會產生中斷,這時CPU尋找中斷向量表,找到入口函數,就會正確的執行相關代碼,因為外部中斷本身就是依託於普通GPIO口的上升沿或者下降沿訊號的,所以本例中以按鍵作為測試外部中斷的硬體電路。
根據工作原理圖:KEY1 ~ PC4; KEY2 ~ PB10;
KEY3 ~ PC13; KEY4 ~ PA0;
其中KEY1,2,3作為外部中斷引腳,KEY4作為喚醒引腳,後續會講解。
知曉了工作原理圖,下面就要確定其對應的中斷線號了,這個在參考手冊外部中斷/事件線路映像章節中有詳細的說明,這裡部分:
從上面可以看出,不同地區的相同位置的管腳共用同一個中斷線號,依次類推,上面的四個管腳分別對應的中斷線號為EXIT4, EXIT10, EXIT13,EXIT0,在這裡還有個注意點:那就是一個中斷線號只能反過來對應一個管腳,這就需要設計外部中斷硬體電路時不要重複,如PA0和PB0不能同時設計為外部中斷。
瞭解了這些之後,如果熟悉STM32設計流程的話,那麼就知道順序是:
1.外部中斷管腳GPIO初始化,代碼如下:
/***************************************************************** function : EXTI_GPIO_Config* Description : 外部中斷觸發對應GPIO口配置 KEY1 PC4 外部中斷4 KEY2 PB10 外部中斷10 KEY3 PC13 外部中斷13 KEY4 PA0 WAKEUP喚醒事件* input : 無* output : 無*****************************************************************/void EXTI_GPIO_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = EXTI_KEY1_Pin; GPIO_Init(EXTI_KEY1_Port, &GPIO_InitStructure); GPIO_EXTILineConfig(EXTI_KEY1_PortSource, EXTI_KEY1_PinSource); //將GPIO複用為外部中洞觸發連接埠 GPIO_InitStructure.GPIO_Pin = EXTI_KEY1_Pin; GPIO_Init(EXTI_KEY2_Port, &GPIO_InitStructure); GPIO_EXTILineConfig(EXTI_KEY2_PortSource, EXTI_KEY2_PinSource); GPIO_InitStructure.GPIO_Pin = EXTI_KEY3_Pin; GPIO_Init(EXTI_KEY3_Port, &GPIO_InitStructure); GPIO_EXTILineConfig(EXTI_KEY3_PortSource, EXTI_KEY3_PinSource); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; GPIO_InitStructure.GPIO_Pin = EXTI_KEY4_Pin; GPIO_Init(EXTI_KEY4_Port, &GPIO_InitStructure); GPIO_EXTILineConfig(EXTI_KEY4_PortSource, EXTI_KEY4_PinSource);}
2.外設EXTI初始化
3.在中斷屏蔽寄存器中允許對應中斷觸發
/***************************************************************** function : EXTI_MODE_Config* Description : 外部中斷觸發配置及向量表開啟對應中斷 其中KEY1作為中斷進入_WFE模式 KEY2和KEY3作為普通中斷點亮對應LED燈 KEY4作為事件用來喚醒CPU* input : 無* output : 無*****************************************************************/void EXTI_MODE_Config(void){ EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; EXTI_DeInit(); EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //外部按鍵觸發中斷 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿觸發 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //外部中斷使能 EXTI_InitStructure.EXTI_Line = EXTI_KEY1_Line; //外部中斷線號4 EXTI_Init(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line = EXTI_KEY2_Line; //外部中斷線號10 EXTI_Init(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Line = EXTI_KEY3_Line; //外部中斷線號13 EXTI_Init(&EXTI_InitStructure); EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event; //外部按鍵觸發事件 EXTI_InitStructure.EXTI_Line = EXTI_KEY4_Line; //外部中斷線號0 EXTI_Init(&EXTI_InitStructure); //PWR_WakeUpPinCmd(ENABLE); //PA0作為喚醒引腳使能 NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0); //向量表位於FLASH中,位移0 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /*在向量表中啟用對應的中斷線號*/ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannel = EXTI_KEY1_IRQn; NVIC_Init(&NVIC_InitStructure); // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;// NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; NVIC_InitStructure.NVIC_IRQChannel = EXTI_KEY2_3_IRQn; NVIC_Init(&NVIC_InitStructure);}
4.中斷函數處理
按鍵PC4對應外部中斷入口,因為按鍵預設高電平,當有按鍵按下時,就會產生下降沿訊號,觸發中斷,此時CPU就在中斷向量表裡查詢外部中斷的入口地址,如PC4對應的入口地址就是void EXTI4_IRQHandler(void) ,開始執行中斷中內容,具體實現流程可參考SysTick章節。
/***************************************************************** function : EXTI4_IRQHandler* Description : 外部中斷4入口函數,實現LED點亮以及系統進入_WFE模式* input : 無* output : 無*****************************************************************/void EXTI4_IRQHandler(void) { led_light_up(0); EXTI_ClearFlag(EXTI_Line4); //清除中斷線號4 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE); //進入WFE停止低功耗模式 僅事件能喚醒 SystemInit(); //退出STOP模式要初始化時鐘,因為睡眠時切換到內部時鐘 LED1_OFF();}
在stm32的標頭檔和開機檔案設計中,中斷線號10~15共用相同的入口函數,因此需要在中斷中進行判斷,來確定是那個訊號觸發了中斷。
/***************************************************************** function : EXTI15_10_IRQHandler* Description : 外部中斷10和13共用中斷入口,通過觸發後狀態檢查確定 觸發中斷的管腳並執行相應代碼。* input : 無* output : 無*****************************************************************/void EXTI15_10_IRQHandler(void) { ITStatus EXTI10_Status; ITStatus EXTI13_Status; EXTI10_Status = EXTI_GetITStatus(EXTI_Line10); //獲得外部中斷10的狀態 EXTI13_Status = EXTI_GetITStatus(EXTI_Line13); //獲得外部中斷13的狀態
if(EXTI10_Status == SET)
{
led_light_up(1);
}
if(EXTI13_Status == SET)
{
led_light_up(2);
}
EXTI_ClearFlag(EXTI_Line10 | EXTI_Line13); /*清除外部中斷10或者13的掛起位 */
}
外部中斷涉及到的知識並並不多,不過仔細觀察上面的代碼,就會發現KEY4(PA0)並沒有配置為中斷,而配置為了事件,且被設定為喚醒引腳,KEY1(PC4)在中斷裡不只點亮了LED,還調用了PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFE); 這種功能其實很有用,涉及到低功耗和外來事件喚醒,下面我來詳細說明。
2.外來事件和中斷的區別和聯絡
外來事件和中斷都是由管腳訊號觸發的,參考:
這張圖可以很直觀的看出中斷和事件的區別,當外部有訊號輸入時,如果通過了了事件屏蔽寄存器,那麼事件訊號就進入脈衝觸發器,引發一個脈衝訊號,直接傳遞給相應的外設,用於觸發,這就是一個純硬體的過程,理解DMA的應該知道,這個方式不需要CPU參與,但是這也有它的缺點,如功能比較單一,僅能提供訊號,不能提供資訊,也就是只能產生指定功能的事件。如果通過中斷屏蔽寄存器,就被直接送到CPU中,產生中斷,如進入上面的入口函數開始處理。從這就可看出,事件是單純硬體觸發執行的過程,與CPU本身設計支援有關,而中斷中則可以軟體實現各種功能,而低功耗模式和事件喚醒就是stm32支援的事件之一。
3.低功耗模式和事件喚醒
低功耗模式是嵌入式設計用於可行動裝置的重要功能,在這種狀態下,CPU會關閉時鐘,從而降低耗電,延長單次使用時間。
上面進入的就是停機-低功耗-WFE模式,因此只能由按鍵4事件喚醒。其實低功耗模式還有待機模式以及睡眠模式,這裡並沒有使用到,以後如果用到會穿插講解。中斷無法喚醒,另外,當CPU退出停止模式時,會強制切換到內部時鐘,因此在進入停止模式後一句要加上SystemInit()重新設定系統時鐘,避免時鐘改變。具體代碼參考:http://files.cnblogs.com/files/zc110747/7.EXTI_LED.7z
STM32學習筆記(九) 外部中斷,待機模式和事件喚醒