外部中断可产生中断和事件:
产生中断;报告NVIC模块
产生事件;外设触发器

外部中断有20个线;0~15对应IO的引脚
编写思路:
- 使能IO口时钟,配置输入(AFIO来配置GPIO)
- 开启AFIO时钟,设置IO与中断线的映射关系
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
- 配置中断分组NVIC,使能中断
typedef struct
{
uint8_t NVIC_IRQChannel; 指定要使能或禁用的中断通道
例如: TIM3_IRQn表示定时器3中断
uint8_t NVIC_IRQChannelPreemptionPriority; 指定NVIC_IRQChannel对应的抢占优先级,值越小优先级越高, 抢占优先级决定了当多个中断同时发生时的响应顺序
uint8_t NVIC_IRQChannelSubPriority;//NVIC_IRQChannel对应的子优先级(响应优先级)
当多个中断的抢占优先级相同时,子优先级决定响应顺序
FunctionalState NVIC_IRQChannelCmd;//NVIC_IRQChannel定义的中断通道
设置为ENABLE时,该中断通道将被使能并可触发中断服务
} NVIC_InitTypeDef;
- 初始化EXTI,选择触发方式
cs
/**
* @brief 配置外部中断/事件线路(EXTI Line)与GPIO引脚的映射关系
* @param GPIO_PortSource: 指定GPIO端口源,例如GPIO_PortSourceGPIOA、GPIO_PortSourceGPIOB等
* @param GPIO_PinSource: 指定GPIO引脚源,例如GPIO_PinSource0、GPIO_PinSource1等
* @note 调用前需先使能AFIO时钟(RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE))
* @note 功能:将指定端口的指定引脚连接到对应的EXTI Line(如PinSource2对应EXTI_Line2)
* @example GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2);
* → 将GPIOE的Pin2引脚映射到EXTI_Line2线路
*/
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
cs
typedef struct
{
uint32_t EXTI_Line; //指定要使能或禁用的EXTI线
多个线可用逻辑或组合(如EXTI_Line0 | EXTI_Line1)
EXTIMode_TypeDef EXTI_Mode;//指定EXTI线的工作模式
// EXTI_Mode_Interrupt: 产生中断请求
// EXTI_Mode_Event: 产生事件触发信号
EXTITrigger_TypeDef EXTI_Trigger;//EXTI线的触发边沿类型
//EXTI_Trigger_Rising: 上升沿触发
// EXTI_Trigger_Falling: 下降沿触发
// EXTI_Trigger_Rising_Falling: 双边沿触发
FunctionalState EXTI_LineCmd;// 指定所选EXTI线的新状态
// 设置为ENABLE时,对应的EXTI线将被激活 */
} EXTI_InitTypeDef;
- 编写EXTI中断函数,查询中断标志位,执行函数,清除中断标志位

cs
/**
* @brief 检查指定EXTI线路的中断请求状态
* @param EXTI_Line: 指定要检查的EXTI线路,可使用逻辑或组合多条线路
* 例如: EXTI_Line0 或 (EXTI_Line0 | EXTI_Line1)
* @retval ITStatus: 中断状态(SET = 中断挂起未处理; RESET = 无中断请求)
* @note 通常在中断服务函数中调用此函数确认具体触发源
* @note 读取EXTI_PR寄存器对应位的值来判断中断状态
* @example if(EXTI_GetITStatus(EXTI_Line2) != RESET) { ... }
*/
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)//读取EXTI_PR寄存器对应位的值来判断中断状态
cs
/**
* @brief 清除指定EXTI线路的中断挂起标志
* @param EXTI_Line: 指定要清除的EXTI线路,可使用逻辑或组合多条线路
* 例如: EXTI_Line0 或 (EXTI_Line0 | EXTI_Line1)
* @note 必须在中断处理完成后调用此函数,否则会持续触发中断
* @note 通过向EXTI_PR寄存器的对应位写入1来清除标志(写入0无效)
* @example EXTI_ClearITPendingBit(EXTI_Line2); // 清除EXTI2的中断标志
*/
void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
代码实现(按键按下灯亮)
cs
#include "exti.h"
#include "led.h"
#include "SysTick.h"
#include "key.h"
/*******************************************************************************
* 函 数 名 : My_EXTI_Init
* 函数功能 : 外部中断初始化
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void My_EXTI_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
//时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);//选择GPIO管脚用作外部中断线路
//NVIC初始化
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//选择中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //初始化VIC寄存器
//
EXTI_InitStructure.EXTI_Line = EXTI_Line0;//指定要使能或禁用的EXTI线
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//指定EXTI线的工作模式-中断请求
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;//触发边沿类型-双边沿
EXTI_InitStructure.EXTI_LineCmd=ENABLE;//激活
EXTI_Init(&EXTI_InitStructure);
}
/*******************************************************************************
* 函 数 名 : EXTI0_IRQHandler
* 函数功能 : 外部中断0函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) == 1)//查询标志位
{
delay_ms(10);//消抖
if(KEY_UP==1)
{
LED2=0;
}
}
EXTI_ClearITPendingBit(EXTI_Line0);//清楚标志位
}