STM32外部中断EXTI学习笔记
1.实现功能
当按下按键KEY1、KEY2时,实现绿色灯、蓝色灯与当前状态相反,即当前为亮,按下熄灭。即《STM32库开发实战指南:基于STM32F103(第二版)》的第17章实验内容。
2. 实验环境
开发板:野火指南者(STM32F103VE)
STM32库版本:STM32F10x_StdPeriph_Lib_V3.5.0
IDE:KEIL5
硬件原理图:
3. 在LED.c中增加如下内容
1 #include "LED.h" 2 #include "stm32f10x.h" 3 4 5 6 void LED_ON(GPIO_TypeDef* GPIOX, uint16_t GPIO_XPIN) 7 { 8 GPIOX->BRR = GPIO_XPIN; 9 10 } 11 12 13 void LED_OFF(GPIO_TypeDef* GPIOX, uint16_t GPIO_XPIN) 14 { 15 GPIOX->BSRR = GPIO_XPIN; 16 17 } 18 19 void LED_TOGGLE(GPIO_TypeDef* GPIOX, uint16_t GPIO_XPIN) 20 { 21 GPIOX->ODR ^= GPIO_XPIN; 22 } 23 24 25 26 //绿色灯控制,传送1为点亮LED,传送0为熄灭LED 27 void Green_LED(uint16_t i) 28 { 29 if(1 == i) 30 { 31 LED_ON(GPIOB,GPIO_Pin_0); 32 } 33 else if(0 == i) 34 { 35 LED_OFF(GPIOB,GPIO_Pin_0); 36 } 37 38 39 } 40 41 //蓝色灯控制,传送1为点亮LED,传送0为熄灭LED 42 void Blue_LED(uint16_t i) 43 { 44 if(1 == i) 45 { 46 LED_ON(GPIOB,GPIO_Pin_1); 47 } 48 else if(0 == i) 49 { 50 LED_OFF(GPIOB,GPIO_Pin_1); 51 } 52 53 54 } 55 56 void Green_LED_Toggle(void) 57 { 58 LED_TOGGLE(GPIOB,GPIO_Pin_0); 59 } 60 61 62 void Blue_LED_Toggle(void) 63 { 64 LED_TOGGLE(GPIOB,GPIO_Pin_1); 65 } 66 67 68 69 void GPIO_LED_Init(void) 70 { 71 GPIO_InitTypeDef GPIO_GREEN,GPIO_BLUE; 72 73 74 //配置绿色灯所在GPIO GROUP及PIN 75 GPIO_GREEN.GPIO_Mode = GPIO_Mode_Out_PP; 76 GPIO_GREEN.GPIO_Speed = GPIO_Speed_50MHz; 77 GPIO_GREEN.GPIO_Pin = GPIO_Pin_0; 78 79 //配置蓝色灯所在GPIO GROUP及PIN 80 GPIO_BLUE.GPIO_Mode = GPIO_Mode_Out_PP; 81 GPIO_BLUE.GPIO_Speed = GPIO_Speed_50MHz; 82 GPIO_BLUE.GPIO_Pin = GPIO_Pin_1; 83 84 //使能绿色、蓝色LED所在GPIO GROUP时钟 85 //当GPIO配置为输出时,RCC_APB2PeriphClockCmd()时钟使能一定要放在GPIO_Init()函数前 86 //即实际要写入配置寄存器前,否则LED工作不起来 87 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); 88 89 //初始化绿色、蓝色LED所在GPIO GROUP 90 GPIO_Init(GPIOB,&GPIO_GREEN); 91 GPIO_Init(GPIOB,&GPIO_BLUE); 92 93 //初始状态为熄灭状态 94 Green_LED(0); 95 Blue_LED(0); 96 97 98 }
4. 在LED.h中增加如下内容
1 #ifndef __LED_H 2 #define __LED_H 3 4 #include "stm32f10x.h" 5 6 7 void LED_ON(GPIO_TypeDef* GPIOX, uint16_t GPIO_XPIN); 8 void LED_OFF(GPIO_TypeDef* GPIOX, uint16_t GPIO_XPIN); 9 void Green_LED(uint16_t i); 10 void Blue_LED(uint16_t i); 11 void GPIO_LED_Init(void); 12 void Green_LED_Toggle(void); 13 void Blue_LED_Toggle(void); 14 15 16 17 #endif
5.在EXTI_KEY.c中增加如下内容
1 #include "KEY_EXTI.h" 2 #include "stm32f10x.h" 3 4 5 void GPIO_KEY_Init(void) 6 { 7 GPIO_InitTypeDef GPIO_KEY1,GPIO_KEY2; 8 9 //使能KEY1、KEY2所在GPIO GROUP时钟 10 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 11 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); 12 13 14 //配置KEY1 15 GPIO_KEY1.GPIO_Mode = GPIO_Mode_IN_FLOATING; 16 GPIO_KEY1.GPIO_Pin = GPIO_Pin_0; 17 18 //配置KEY2 19 GPIO_KEY2.GPIO_Mode = GPIO_Mode_IN_FLOATING; 20 GPIO_KEY2.GPIO_Pin = GPIO_Pin_13; 21 22 GPIO_Init(GPIOA,&GPIO_KEY1); 23 GPIO_Init(GPIOC,&GPIO_KEY2); 24 25 26 27 } 28 29 void NVIC_KEY_Init(void) 30 { 31 NVIC_InitTypeDef NVIC_KEY1,NVIC_KEY2; 32 33 //设置优先级组类型 34 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 35 36 //配置中断NVIC控制寄存器 KEY1 37 NVIC_KEY1.NVIC_IRQChannel = EXTI0_IRQn; 38 NVIC_KEY1.NVIC_IRQChannelPreemptionPriority = 1; 39 NVIC_KEY1.NVIC_IRQChannelSubPriority = 1; 40 NVIC_KEY1.NVIC_IRQChannelCmd = ENABLE; 41 42 //配置中断NVIC控制寄存器 KEY2 43 NVIC_KEY2.NVIC_IRQChannel = EXTI15_10_IRQn; 44 NVIC_KEY2.NVIC_IRQChannelPreemptionPriority = 1; 45 NVIC_KEY2.NVIC_IRQChannelSubPriority = 2; 46 NVIC_KEY2.NVIC_IRQChannelCmd = ENABLE; 47 48 //初始化NVIC中断控制寄存器 49 NVIC_Init(&NVIC_KEY1); 50 NVIC_Init(&NVIC_KEY2); 51 52 53 } 54 55 56 57 void EXTI_KEY_Init(void) 58 { 59 EXTI_InitTypeDef EXTI_KEY1,EXTI_KEY2; 60 61 //使能KEY1、KEY2所在GPIO GROUP时钟及外部中断AFIO寄存器 62 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE); 63 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO,ENABLE); 64 65 //选择中断、事件的中断源,即通过设定AFIO_EXTICRx寄存器的值来选择使用哪个GPIO GROUP的哪个PIN 66 GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); 67 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13); 68 69 //配置KEY1 70 EXTI_KEY1.EXTI_Line = EXTI_Line0; 71 EXTI_KEY1.EXTI_Mode = EXTI_Mode_Interrupt; 72 EXTI_KEY1.EXTI_Trigger = EXTI_Trigger_Rising; 73 EXTI_KEY1.EXTI_LineCmd = ENABLE; 74 75 //配置KEY2 76 EXTI_KEY2.EXTI_Line = EXTI_Line13; 77 EXTI_KEY2.EXTI_Mode = EXTI_Mode_Interrupt; 78 EXTI_KEY2.EXTI_Trigger = EXTI_Trigger_Rising; 79 EXTI_KEY2.EXTI_LineCmd = ENABLE; 80 81 82 //初始化KEY1、KEY2 83 EXTI_Init(&EXTI_KEY1); 84 EXTI_Init(&EXTI_KEY2); 85 86 87 }
6. 在EXTI_KEY.h中增加如下内容
1 #ifndef __KEY_EXTI_H 2 #define __KEY_EXTI_H 3 #include "stm32f10x.h" 4 5 #define EXTI_KEY1_IRQHandler EXTI0_IRQHandler 6 #define EXTI_KEY2_IRQHandler EXTI15_10_IRQHandler 7 8 9 10 void GPIO_KEY_Init(void); 11 void NVIC_KEY_Init(void); 12 void EXTI_KEY_Init(void); 13 14 15 #endif
7. 在stm32f10x_it.c中最后处增加如下内容
1 void EXTI_KEY1_IRQHandler(void) 2 { 3 if(EXTI_GetITStatus(EXTI_Line0) == SET) 4 { 5 Green_LED_Toggle(); 6 7 EXTI_ClearITPendingBit(EXTI_Line0); 8 } 9 10 } 11 12 13 14 void EXTI_KEY2_IRQHandler(void) 15 { 16 if(EXTI_GetITStatus(EXTI_Line13) == SET) 17 { 18 Blue_LED_Toggle(); 19 20 EXTI_ClearITPendingBit(EXTI_Line13); 21 } 22 23 }
8. 在stm32f10x_it.h文件中声明如下函数
void EXTI_KEY1_IRQHandler(void); void EXTI_KEY2_IRQHandler(void);
9. 在main.c文件中增加如下语句
1 #include "stm32f10x.h" 2 #include "LED.h" 3 #include "KEY_EXTI.h" 4 5 #define TRUE 1 6 #define FALSE 0 7 8 9 10 11 int main(void) 12 { 13 14 GPIO_LED_Init(); 15 GPIO_KEY_Init(); 16 NVIC_KEY_Init(); 17 EXTI_KEY_Init(); 18 19 while(TRUE) 20 { 21 22 } 23 24 25 return 0; 26 }
总结:
1.有三个主要的结构体,即GPIO_InitTypeDef、NVIC_InitTypeDef、EXTI_InitTypeDef,此三个结构体初始化完,中断设置工作基本算是完成了。
2.在设置EXTI_InitTypeDef时,时钟使能时需要使能AFIO这个寄存器,与此对应的寄存器AFIO_EXTICRx的值是来选择使用哪个GPIO GROUP的哪个PIN。
3.NVIC组优先级可用NVIC_PriorityGroupConfig()来设置
4.GPIO作为输出时,时钟使能void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)一定要在void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)前,否则GPIO输出异常,本实验遇到的这是LED无任何反应,放在GPIO_Init()前则输出正常。
5.中断服务函数名要与中断源在.s启动文件的中断名一致,例如这里EXT0_IRQn在.s中的中断向量名为EXTI0_IRQHandler,此对应可以参考stm32f10x.h中IRQn_Type枚举变量、.s文件中的中断向量名。
具体实现步骤:
1、设置EXTI外部中断硬件中实际使用到的GPIO口,这里按键使用到的GPIOA的PIN0、GPIOC的PIN13,具体设置如下
1.1、使能GPIO时钟,使用RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)库函数
1.2、初始化GPIO_InitTypeDef结构体成员,此为按键输入,所以不需要初始化GPIO_Speed成员
1.3、将GPIO_InitTypeDef结构体的值写入到对应GPIO寄存器中,使用GPIO_Init(GPIO_TypeDef * GPIOx, GPIO_InitTypeDef * GPIO_InitStruct)库函数
2、设置EXTI对应的寄存器
2.1、使能EXTI、AFIO时钟,使用RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)库函数,EXTI挂载在APB2总线上,所以需要使用此函数。
2.1、选择外部中断信号源,使用GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)库函数设置
2.2、初始化EXTI_InitTypeDef结构体成员
2.3、将EXTI_InitTypeDef结构体的值写入到对应的EXTI寄存器中,使用EXTI_Init(EXTI_InitTypeDef * EXTI_InitStruct)库函数设置
3、设置NVIC中断控制寄存器
3.1、设置中断优先级组,使用NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)库函数
3.2、初始化NVIC_InitTypeDef结构体成员
3.3、将NVIC_InitTypeDef结构体的值写入NVIC对应的寄存器中,使用NVIC_Init(NVIC_InitTypeDef * NVIC_InitStruct)库函数
4、编写中断服务程序,这里为控制蓝、绿LED灯的熄灭
实验源码:
链接:https://pan.baidu.com/s/1A_s6dIIfhYpRk9TuTTXctw
提取码:sd3u