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 }
LED.c

 

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
LED.h

 

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 }
EXTI_KEY.c

 

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
KEY_EXTI.h

 

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 }
View Code

 

8. stm32f10x_it.h文件中声明如下函数

void EXTI_KEY1_IRQHandler(void);
void EXTI_KEY2_IRQHandler(void);
View Code

 

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 }
main.c

 

总结:

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

 

 

 

posted @ 2019-03-17 20:15  秋水寒林  阅读(915)  评论(0编辑  收藏  举报