新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 調(diào)試 ARM STM32 外部中斷 遇到的一個問題

調(diào)試 ARM STM32 外部中斷 遇到的一個問題

作者: 時間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
問題背景: STM32f103zet6的PB9和PE0腳分別外接一個按鍵,希望通過這兩個按鍵可以產(chǎn)生外部中斷,點亮該按鍵對應(yīng)的LED。使用EXTI[9:5]通道。
首先配置RCC:
void RCC_Configuration() {     ErrorStatus HSEStartUpStatus;     RCC_DeInit(); //將外設(shè)RCC寄存器設(shè)為缺省值     RCC_HSEConfig(RCC_HSE_ON); //使能HSE     HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待HSE就緒     if(HSEStartUpStatus == SUCCESS) //判斷HSE是否起振成功     {                                          RCC_HCLKConfig(RCC_SYSCLK_Div1);  //設(shè)置AHB時鐘(HCLK) = 系統(tǒng)時鐘         RCC_PCLK2Config(RCC_HCLK_Div2);  //設(shè)置高速APB2時鐘(PCLK2)= 系統(tǒng)時鐘          RCC_PCLK1Config(RCC_HCLK_Div2);  //設(shè)置低速APB1時鐘(PCLK1)= 系統(tǒng)時鐘/2           /*****保證在將PLL切換時鐘源之前使能Flash預(yù)取緩存*****/         FLASH_SetLatency(FLASH_Latency_2); //設(shè)置等待時間 = 2個周期         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//使能預(yù)取指緩存                             /*                     這里插入設(shè)置需要開啟的外設(shè)的時鐘,比如                     RCC_ADCCLKConfig(RCC_PCLK2_Div4); //設(shè)置ADC時鐘=PCLK/4 =9MHz                     */          //設(shè)置PLL的輸入時鐘 = HSE時鐘頻率;倍頻系數(shù) = PLL輸入時鐘×9         RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);          RCC_PLLCmd(ENABLE); //使能PLL          //檢查指定的RCC標志位(PLL就緒位)設(shè)置與否,若為否, 則等待         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)         {/*NULL*/ }          RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //設(shè)置系統(tǒng)時鐘(SYSCLK)為PLL          //0x00:HSI作為系統(tǒng)時鐘; 0x04:HSE作為系統(tǒng)時鐘;0x08:PLL作為系統(tǒng)時鐘         while(RCC_GetSYSCLKSource() != 0x08) //等待直到PLL作為系統(tǒng)時鐘源         {/*NULL*/ }           }            /*****這里根據(jù)具體需要開啟相應(yīng)的時鐘*****/           // PB9: WORK PE0: ALARM           RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);           RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);  //開啟功能復(fù)用I/O時鐘            }

然后配置GPIO:
void GPIO_Configuration(void) //設(shè)置GPIO {           GPIO_InitTypeDef GPIO_InitStructure;                      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;                  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        GPIO_Init(GPIOB, &GPIO_InitStructure);                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;                  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        GPIO_Init(GPIOE, &GPIO_InitStructure);                      }
再然后配置NVIC:
void NVIC_Configuration(void) {           NVIC_InitTypeDef NVIC_InitStructure; //定義中斷參數(shù)結(jié)構(gòu)體變量 #ifdef  VECT_TAB_RAM             NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);//設(shè)置向量表的位置和偏移(0x20000000)  #else             NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//設(shè)置向量表的位置和偏移(0x20000000)    #endif            NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //選擇使用優(yōu)先級分組第0組                     /*使能EXTI[9:5]通道,0級先占優(yōu)先級,0級次占優(yōu)先級*/     NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     NVIC_Init(&NVIC_InitStructure);      } 
最后配置EXTI:
void EXTI_Configuration(void) //配置外部中斷/事件控制器 {     EXTI_InitTypeDef EXTI_InitStructure;      GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5|GPIO_PinSource6);           EXTI_InitStructure.EXTI_Line = 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);  } 
main函數(shù)如下:
int main(void) {      RCC_Configuration();      GPIO_Configuration();      NVIC_Configuration();      EXTI_Configuration();              while (1)   { } } 
中斷服務(wù)函數(shù)如下:
void EXTI9_5_IRQHandler(void) {      if (EXTI_GetITStatus(EXTI_Line5) != RESET)      {           if(led_bit3)           {                GPIO_SetBits(GPIOB,GPIO_Pin_9);                led_bit3=0;           }           else           {                GPIO_ResetBits(GPIOB,GPIO_Pin_9);                led_bit3=1;           }                EXTI_ClearFlag(EXTI_Line5);      }            if(EXTI_GetITStatus(EXTI_Line6) != RESET)      {           if(led_bit1)           {                GPIO_SetBits(GPIOE,GPIO_Pin_0);                led_bit1=0;           }           else           {                GPIO_ResetBits(GPIOE,GPIO_Pin_0);                led_bit1=1;           }           EXTI_ClearFlag(EXTI_Line6);      } }
問題描述:1. 按兩個按鍵中的隨便一個,都沒反應(yīng),原因是沒進入中斷服務(wù)函數(shù)。
2. 只使用其中一個按鍵產(chǎn)生中斷,屏蔽另一個按鍵,結(jié)果正常,LED可以被點亮。
也就是說,只開其中一個按鍵中斷是可以的,同時打開兩個按鍵中斷,則不行。
問題解決:經(jīng)過一定時間的糾結(jié)與不知所措,為何一個就可以,兩個同時就不可以??吹紼XTI_Configuration()中:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5|GPIO_PinSource6);  EXTI_InitStructure.EXTI_Line = EXTI_Line5|EXTI_Line6;
索性不使用那個或,每個都單獨配置一下。于是乎:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6);  EXTI_InitStructure.EXTI_Line = EXTI_Line5; EXTI_InitStructure.EXTI_Line = EXTI_Line6;
還是不行,經(jīng)過若干次的組合嘗試:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6);  EXTI_InitStructure.EXTI_Line = EXTI_Line6; EXTI_InitStructure.EXTI_Line = EXTI_Line5;  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6);  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);  EXTI_InitStructure.EXTI_Line = EXTI_Line5; EXTI_InitStructure.EXTI_Line = EXTI_Line6;  ...  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);  GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource6);  EXTI_InitStructure.EXTI_Line = EXTI_Line5|EXTI_Line6; 

發(fā)現(xiàn)只拆開GPIO_EXTILineConfig()中的或,即可。
問題分析:就這樣,問題被瞎貓碰到死耗子地解決了。但是還是得找找為何這樣可以。
找到GPIO_EXTILineConfig()函數(shù)的定義:
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource) {   uint32_t tmp = 0x00;   /* Check the parameters */   assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));   assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));      tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));   AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;   AFIO->EXTICR[GPIO_PinSource >> 0x02] |= (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03))); }
由于兩種情況下的不同就在于GPIO_EXTILineConfig()函數(shù)的第二個參數(shù)。所以首先分析assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource)); 再找到IS_GPIO_PIN_SOURCE():
#define IS_GPIO_PIN_SOURCE(PINSOURCE) (((PINSOURCE) == GPIO_PinSource0) ||                                         ((PINSOURCE) == GPIO_PinSource1) ||                                         ((PINSOURCE) == GPIO_PinSource2) ||                                         ((PINSOURCE) == GPIO_PinSource3) ||                                         ((PINSOURCE) == GPIO_PinSource4) ||                                         ((PINSOURCE) == GPIO_PinSource5) ||                                         ((PINSOURCE) == GPIO_PinSource6) ||                                         ((PINSOURCE) == GPIO_PinSource7) ||                                         ((PINSOURCE) == GPIO_PinSource8) ||                                         ((PINSOURCE) == GPIO_PinSource9) ||                                         ((PINSOURCE) == GPIO_PinSource10) ||                                         ((PINSOURCE) == GPIO_PinSource11) ||                                         ((PINSOURCE) == GPIO_PinSource12) ||                                         ((PINSOURCE) == GPIO_PinSource13) ||                                         ((PINSOURCE) == GPIO_PinSource14) ||                                         ((PINSOURCE) == GPIO_PinSource15))
其中:
#define GPIO_PinSource0            ((uint8_t)0x00) #define GPIO_PinSource1            ((uint8_t)0x01) #define GPIO_PinSource2            ((uint8_t)0x02) #define GPIO_PinSource3            ((uint8_t)0x03) #define GPIO_PinSource4            ((uint8_t)0x04) #define GPIO_PinSource5            ((uint8_t)0x05) #define GPIO_PinSource6            ((uint8_t)0x06) #define GPIO_PinSource7            ((uint8_t)0x07) #define GPIO_PinSource8            ((uint8_t)0x08) #define GPIO_PinSource9            ((uint8_t)0x09) #define GPIO_PinSource10           ((uint8_t)0x0A) #define GPIO_PinSource11           ((uint8_t)0x0B) #define GPIO_PinSource12           ((uint8_t)0x0C) #define GPIO_PinSource13           ((uint8_t)0x0D) #define GPIO_PinSource14           ((uint8_t)0x0E) #define GPIO_PinSource15           ((uint8_t)0x0F)

這樣,一切就明朗了。
GPIO_PinSource5|GPIO_PinSource6 等價于0x05|0x06,即0x07。而這個當然與我們要用的兩個按鍵無關(guān)。
總結(jié):GPIO_EXTILineConfig()的第二參數(shù)只能是GPIO_PinSource0~15中的一個,若要需要配置多個,只能單獨配置,不能使用”或”。這種寫法可能是受EXTI_InitStructure.EXTI_Line = EXTI_Line5|EXTI_Line6;這種寫法的影響。



關(guān)鍵詞: 調(diào)試ARMSTM32外部中

評論


技術(shù)專區(qū)

關(guān)閉