11 STM32F429 EXTI寄存器
外部中断/事件控制器 (EXTI) 管理了控制器的 23 个中断/事件线。每个中断/事件线都对应有一个
边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。EXTI 可以实现对每个中断/事件
线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。
例如: IO输入事件->中断/事件->控制 器
EXTI功能框图
大致顺序
- 配置上升/下降沿寄存器来规定是上升触发还是下降触发
- 到达软件中断时间寄存器后会查询 EXTI_IMR 和 EXTI_EMR相应位,如果允许产生该中断,则产生中断请求。
- 在挂起寄存器中相应位置1后,送入NVIC中断寄存器触发CPU中断处理.
用到的寄存器
软件中断寄存器
实验代码分析
对比
此次实验采用中断来控制LED灯的开关,它有以下好处
- 对比之前的实验是采用不断的轮询按键是否有输入来控制,会一直占用CPU资源,
- 采用中断只会在输入上升沿时发生中断并送往处理器进行处理,不会一直占用cpu
实验步骤
- 初始化要连接EXTI的GPIO
- 初始化EXTI用于产生的中断/事件
- 初始化NVIC,处理中断
- 编写中断服务函数
- main函数
代码分析
1.初始化要连接EXTI的GPIO
//bsp_exti.h
#ifndef __EXTI_H
#define __EXTI_H
#include "stm32f4xx.h"
//引脚定义
/*******************************************************/
#define KEY1_PIN GPIO_Pin_0
#define KEY1_GPIO_PORT GPIOA
#define KEY1_GPIO_CLK RCC_AHB1Periph_GPIOA
#define KEY2_PIN GPIO_Pin_13
#define KEY2_GPIO_PORT GPIOC
#define KEY2_GPIO_CLK RCC_AHB1Periph_GPIOC
/*******************************************************/
void EXTI_GPIO_Config(void);
#endif
//bsp_exti.c
#include"bsp_exti.h"
void EXTI_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*开启按键GPIO口的时钟*/
RCC_AHB1PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);
/*选择按键的引脚*/
GPIO_InitStructure.GPIO_Pin = KEY1_PIN;
/*设置引脚为输入模式*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
/*设置引脚不上拉也不下拉,浮空模式*/
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
/*使用上面的结构体初始化按键*/
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);
/*选择按键的引脚*/
GPIO_InitStructure.GPIO_Pin = KEY2_PIN;
/*使用上面的结构体初始化按键*/
GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);
}
2.初始化EXTI用于产生的中断/事件
在stm32f4xx_exti.h
exti初始化结构体
typedef struct
{
uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled.
This parameter can be any combination value of @ref EXTI_Lines */
EXTIMode_TypeDef EXTI_Mode; /*!< Specifies the mode for the EXTI lines.
This parameter can be a value of @ref EXTIMode_TypeDef */
EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines.
This parameter can be a value of @ref EXTITrigger_TypeDef */
FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines.
This parameter can be set either to ENABLE or DISABLE */
}EXTI_InitTypeDef;
初始化EXTI
/* 使能 SYSCFG 时钟 ,使用GPIO外部中断时必须使能SYSCFG时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* 连接 EXTI 中断源 到key1引脚 即找到pin对应SYSCFG_EXTICRx,选取对应portsource位*/
SYSCFG_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE,KEY1_INT_EXTI_PINSOURCE);
/* 选择 EXTI 中断源 */
EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
/* 中断模式 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 下降沿触发 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
/* 使能中断/事件线 */
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
为什么这里要使能SYSCFG时钟?
因为要先使能SYSCFG时钟使得其中一个SYSCFG_EXTICR能够配置并选择 EXTIx 外部中断的源输入.
3.初始化NVIC,处理中断
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置NVIC为优先级组1 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 配置中断源:按键1 即使NVICw*/
NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
/* 配置抢占优先级:1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 配置子优先级:1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断通道 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 配置中断源:按键2,其他使用上面相关配置 */
NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
NVIC_Init(&NVIC_InitStructure);
}
4.编写中断服务函数
在stm32f4xx.h中找到对应函数
在stm32f4xx_it.c中编写中断程序
void EXTI0_IRQHandler(void){
if(EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET){
/*中断来了*/
LED1_TOGGLE;
EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);
}
}
void EXTI15_10_IRQHandler(void){
if(EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET){
/*中断来了*/
LED2_TOGGLE;
EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);
}
}
5.编写main函数
#include "stm32f4xx.h"
#include "./led/bsp_led.h"
#include "./key/bsp_exti.h"
void Delay(__IO u32 nCount);
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
/* LED 端口初始化 */
LED_GPIO_Config();
/* 初始化EXTI中断,按下按键会触发中断,
* 触发中断会进入stm32f4xx_it.c文件中的函数
* KEY1_IRQHandler和KEY2_IRQHandler,处理中断,反转LED灯。
*/
EXTI_Key_Config();
/* 等待中断,由于使用中断方式,CPU不用轮询按键 */
while(1)
{
}
}
部分源代码
bsp_exti.c
#include "./key/bsp_exti.h"
/**
* @brief 配置嵌套向量中断控制器NVIC
* @param
* @retval 无
*/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 配置NVIC为优先级组1 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* 配置中断源:按键1 */
NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;
/* 配置抢占优先级:1 */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 配置子优先级:1 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断通道 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
/* 配置中断源:按键2,其他使用上面相关配置 */
NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief 配置 PA0 为线中断口,并设置中断优先级
* @param 无
* @retval 无
*/
void EXTI_Key_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
/*开启按键GPIO口的时钟*/
RCC_AHB1PeriphClockCmd(KEY1_INT_GPIO_CLK|KEY2_INT_GPIO_CLK ,ENABLE);
/* 使能 SYSCFG 时钟 ,使用GPIO外部中断时必须使能SYSCFG时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
/* 配置 NVIC */
NVIC_Configuration();
/* 选择按键1的引脚 */
GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
/* 设置引脚为输入模式 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
/* 设置引脚不上拉也不下拉 */
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
/* 使用上面的结构体初始化按键 */
GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
/* 连接 EXTI 中断源 到key1引脚 */
SYSCFG_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE,KEY1_INT_EXTI_PINSOURCE);
/* 选择 EXTI 中断源 */
EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;
/* 中断模式 */
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 上升沿触发 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
/* 使能中断/事件线 */
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* 选择按键2的引脚 */
GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;
/* 其他配置与上面相同 */
GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);
/* 连接 EXTI 中断源 到key2 引脚 */
SYSCFG_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE,KEY2_INT_EXTI_PINSOURCE);
/* 选择 EXTI 中断源 */
EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
/* 上升沿触发 */
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
/*********************************************END OF FILE**********************/