調(diào)試 ARM STM32 外部中斷 遇到的一個(gè)問題
首先配置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時(shí)鐘(HCLK) = 系統(tǒng)時(shí)鐘 RCC_PCLK2Config(RCC_HCLK_Div2); //設(shè)置高速APB2時(shí)鐘(PCLK2)= 系統(tǒng)時(shí)鐘 RCC_PCLK1Config(RCC_HCLK_Div2); //設(shè)置低速APB1時(shí)鐘(PCLK1)= 系統(tǒng)時(shí)鐘/2 /*****保證在將PLL切換時(shí)鐘源之前使能Flash預(yù)取緩存*****/ FLASH_SetLatency(FLASH_Latency_2); //設(shè)置等待時(shí)間 = 2個(gè)周期 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);//使能預(yù)取指緩存 /* 這里插入設(shè)置需要開啟的外設(shè)的時(shí)鐘,比如 RCC_ADCCLKConfig(RCC_PCLK2_Div4); //設(shè)置ADC時(shí)鐘=PCLK/4 =9MHz */ //設(shè)置PLL的輸入時(shí)鐘 = HSE時(shí)鐘頻率;倍頻系數(shù) = PLL輸入時(shí)鐘×9 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); RCC_PLLCmd(ENABLE); //使能PLL //檢查指定的RCC標(biāo)志位(PLL就緒位)設(shè)置與否,若為否, 則等待 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {/*NULL*/ } RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //設(shè)置系統(tǒng)時(shí)鐘(SYSCLK)為PLL //0x00:HSI作為系統(tǒng)時(shí)鐘; 0x04:HSE作為系統(tǒng)時(shí)鐘;0x08:PLL作為系統(tǒng)時(shí)鐘 while(RCC_GetSYSCLKSource() != 0x08) //等待直到PLL作為系統(tǒng)時(shí)鐘源 {/*NULL*/ } } /*****這里根據(jù)具體需要開啟相應(yīng)的時(shí)鐘*****/ // PB9: WORK PE0: ALARM RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //開啟功能復(fù)用I/O時(shí)鐘 }
然后配置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)先級(jí)分組第0組 /*使能EXTI[9:5]通道,0級(jí)先占優(yōu)先級(jí),0級(jí)次占優(yōu)先級(jí)*/ 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. 按兩個(gè)按鍵中的隨便一個(gè),都沒反應(yīng),原因是沒進(jìn)入中斷服務(wù)函數(shù)。
2. 只使用其中一個(gè)按鍵產(chǎn)生中斷,屏蔽另一個(gè)按鍵,結(jié)果正常,LED可以被點(diǎn)亮。
也就是說(shuō),只開其中一個(gè)按鍵中斷是可以的,同時(shí)打開兩個(gè)按鍵中斷,則不行。
問題解決:經(jīng)過一定時(shí)間的糾結(jié)與不知所措,為何一個(gè)就可以,兩個(gè)同時(shí)就不可以??吹紼XTI_Configuration()中:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5|GPIO_PinSource6); EXTI_InitStructure.EXTI_Line = EXTI_Line5|EXTI_Line6;
索性不使用那個(gè)或,每個(gè)都單獨(dú)配置一下。于是乎:
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ù)的第二個(gè)參數(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 等價(jià)于0x05|0x06,即0x07。而這個(gè)當(dāng)然與我們要用的兩個(gè)按鍵無(wú)關(guān)。
總結(jié):GPIO_EXTILineConfig()的第二參數(shù)只能是GPIO_PinSource0~15中的一個(gè),若要需要配置多個(gè),只能單獨(dú)配置,不能使用”或”。這種寫法可能是受EXTI_InitStructure.EXTI_Line = EXTI_Line5|EXTI_Line6;這種寫法的影響。
評(píng)論