我用的是正点的
STM32F103
来进行学习,板子和教程是野火的指南者
。之后的这个系列笔记开头未标明的话,用的也是这个板子和教程。
十一、通过EXTI外部中断实现 按键控制LED
- [十一、通过EXTI外部中断实现 按键控制LED](#十一、通过EXTI外部中断实现 按键控制LED)
-
- 1、按键模块
- 2、中断模块
-
- 初始化EXTI用来产生中断
-
- 配置中断优先级
- [初始化EXTI 使PA0触发外部中断](#初始化EXTI 使PA0触发外部中断)
- 编写中断服务函数
- 3、main()函数修改
- 4、初始化总结
十一、通过EXTI外部中断实现 按键控制LED
1、按键模块
按键原理图
可以看到在未按下时,引脚是低电平,按下之后变成高电平。
按键程序思路
- 初始化Key1 Key2所在GPIO的时钟
void RCC_APB2PeriphClockCmd(u32 RCC_APB2Periph, FunctionalState NewState)
第一个参数为设置何处时钟,第二个参数为ENABLE或者DISABLE
- 新建Key1 Key2对应的GPIO结构体
GPIO_InitTypeDef GPIO_InitStructure;
成员分别包括 引脚、时钟速率、模式
- 初始化GPIO结构体
GPIO_InitStructure.GPIO_Pin = macKEY1_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = macKEY1_GPIO_Mode;
因为在按下按键后会有一个电压上升沿,所以GPIO模式应该设置为 浮空输入(FLOATING)
- 使用GPIO引脚初始化函数
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
GPIOx: 指向要配置的 GPIO 端口(如 GPIOA, GPIOB 等)。
GPIO_InitStruct: 指向包含引脚配置的结构体的指针。
如:
GPIO_Init ( macKEY1_GPIO_PORT, & GPIO_InitStructure );
- 检测按键是否被按下
uint8_t Key_Scan ( GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, uint8_t ucPushState, uint8_t * pKeyPress )
- 读取按键的当前状态。
- 如果按键处于按下状态,延时一段时间(消抖)。
- 再次读取按键状态,确认按下后,标记按键被按下过。
- 如果按键释放并且之前标记过按下,则认为按键被单击,返回1。
- 否则返回0。
2、中断模块
初始化EXTI用来产生中断
配置中断优先级
static void EXTI_NVIC_Config(void)
这个 EXTI_NVIC_Config
函数用于配置嵌套向量中断控制器(NVIC),以便为外部中断(EXTI)设置适当的中断优先级和使能。具体来说,它配置了 EXTI0 线路的中断。
- 配置优先级分组
c
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
配置 NVIC 的优先级分组。NVIC_PriorityGroup_1
表示中断优先级分组 1,该分组将优先级划分为两部分:抢占优先级和子优先级。
NVIC_PriorityGroup_1
通常将 4 位优先级分为 1 位抢占优先级和 3 位子优先级。抢占优先级用于打断其他中断,子优先级用于决定同级别抢占优先级中断的处理顺序。
- 配置 EXTI0 中断
-
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
配置中断通道为
EXTI0_IRQn
,即外部中断线 0 对应的中断通道。
-
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
设置抢占优先级为 1。抢占优先级越低,优先级越高。
-
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
设置子优先级为 1。在抢占优先级相同的情况下,子优先级越低,优先级越高。
-
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
使能 EXTI0 中断通道。
- 初始化 NVIC
c
NVIC_Init(&NVIC_InitStruct);
调用 NVIC_Init
函数,使用配置好的 NVIC_InitStruct
结构体初始化 NVIC。
这样,当 EXTI0 中断发生时,NVIC 会根据配置的优先级正确处理中断。
初始化EXTI 使PA0触发外部中断
这段代码用于初始化外部中断/事件控制器(EXTI),使能 GPIOA 的第 0 引脚(PA0)触发的外部中断。下面是详细解释每一行代码的作用:
- 使能 AFIO 时钟
c
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
- 使能替代功能(Alternate Function I/O, AFIO)时钟。AFIO 控制 GPIO 引脚的重映射和外部中断配置。
RCC_APB2PeriphClockCmd
函数用来配置外设时钟,RCC_APB2Periph_AFIO
表示 AFIO 模块。
- 配置 GPIO 引脚与 EXTI 线的连接
c
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
- 配置 GPIOA 的第 0 引脚(PA0)连接到 EXTI 线 0。
GPIO_EXTILineConfig
函数将指定的 GPIO 引脚连接到对应的 EXTI 线。GPIO_PortSourceGPIOA
: 指定 GPIOA 端口。GPIO_PinSource0
: 指定端口的第 0 引脚。
- 配置 EXTI 线
-
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
配置 EXTI 线 0(对应 PA0)。
-
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
配置 EXTI 模式为中断模式。
-
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
配置 EXTI 触发方式为上升沿触发(即信号从低电平变为高电平时触发中断)。
-
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
使能 EXTI 线。
- 初始化 EXTI
c
EXTI_Init(&EXTI_InitStruct);
- 调用
EXTI_Init
函数,使用配置好的EXTI_InitStruct
结构体初始化 EXTI。 - 该函数根据结构体配置,将 EXTI 线 0 设置为上升沿触发的中断模式,并使能该中断线。
这样,当 PA0 引脚的电平从低变高时,会触发 EXTI 线 0 的中断。
编写中断服务函数
-
在启动文件
startup_stm32f10x_hd.s
中找到中断函数名为EXTI0_IRQHandler
-
在中断源文件
stm32f10x_it.c
中添加中断函数
-
当EXTI0被触发时,开关绿灯
-
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
使用此函数检测到中断时,返回1或0。
-
macLED1_TOGGLE();
利用
bsp_led.h
里的函数翻转绿灯
-
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
利用此函数来清除中断位,防止一直在中断内。
3、main()函数修改
添加按键、中断 和 LED 的初始化函数
4、初始化总结
按键初始化
- 按键时钟初始化
- 按键GPIO初始化
NVIC嵌套向量中断初始化
- 配置NVIC的优先级分组
- 配置GPIO引脚与EXTI事件线的连接
- NVIC初始化
EXTI外部中断初始化
- EXTI时钟初始化
- EXTI事件线初始化
LED初始化
- LED时钟初始化
- LED的GPIO初始化
interrupt(IT)中断初始化
- 在启动文件中找到对应的函数名
- 编写中断函数并添加到头文件中