2.1认识外部中断
概念:在主程序运行过程中,出现了特定的中断触发条件,使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完后又返回原来被暂停的位置继续运行
对于互联型产品,外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,对于其它
产品,则有19个能产生事件/中断请求的边沿检测器。每个输入线可以独立地配置输入类型(脉冲
或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏
蔽。挂起寄存器保持着状态线的中断请求。
主要特性:
每个中断/事件都有独立的触发和屏蔽
每个中断线都有专用的状态位
支持多达20个软件的中断/事件请求
检测脉冲宽度低于APB2时钟宽度的外部信号。参见数据手册中电气特性部分的相关参数。
STM32外部中断架构

2.STM32外部中断机制框架

1.边沿检测:上升沿、下降沿或双边沿
2.软件配置中断或事件寄存器
3.屏蔽中断寄存器或事件寄存器
4.请求挂起寄存器
5.中断发送给NVIC中断控制器
6.事件则产生一个脉冲响应
2.2复用功能
概念:处理器的引脚本身默认就是一个普通的GPIO,但是他可以被复用成其他功能,称之为一个引脚的复用功能(比如上面的STM32外部中断架构)
2.3重映射
概念:重映射属于复用功能的另外一个功能,可以把具有特殊功能的引脚,分配到其他引脚上去,如果某个功能被重映射了,那么这个功能将不再遵循其默认的分配
2.4中断嵌套控制器NVIC
Cortex-M3内核支持256个中断,其中包含了16个内核中断(异常)和240个外部中断,并且具有256级的可编程中断设置。但是,STM32并没有使用CM3内核的全部东西,而是只用了它的一部分。STM32有84个中断,包括16个内核中断(异常)和68个可屏蔽中断,具有16级可编程的中断优先级。而STM32F103系列上面,16个内核中断(异常)不变,而可屏蔽中断只有60个(在107系列才有68个) 优先级号越小,优先级越高
2.中断优先级分组
这60个中断,怎么管理呢?这就涉及到STM32的中断分组。STM32可以将中断分成5个组,分别为组0-4;同时,对每个中断设置一个抢占优先级和响应优先级。分组配置是由SCB->AIRCR寄存器的bit10-8来定义的。SCB->AIRCR是在哪里的呢?由于这是CM3内核定义的,具体的分配关系如下所示:
CM3中定义了8个Bit用于设置中断源的优先级,而STM32只选用其中的4个Bit抢占优先级的级别高于响应优先级,而数值越小所代表的的优先级越高,介绍一下抢占优先级、响应优先级的区别:
·高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的;
·抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断;
·抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行;
·如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
除此之外有两点需要注意:
·打断的情况只会与抢占优先级有关,和响应优先级无关
·一般情况下,系统代码执行过程中,只设置一次中断优先级分组,比如分组2,设置好分组之后一般不会再改变分组。随意改变分组会导致中断管理混乱,程序出现意想不到的执行结果
3.中断优先级控制函数结构体
·中断优先级控制函数
NVIC_SetPriorityGrouping()
·中断优先级控制结构体参数
NVIC_IRQChannel:定义初始化的是哪一个中断
NVIC_IRQChannelPreemptionPriority: 定义此中断的抢占优先级别
NVIC_IRQChannelSubPriority: 定义此中断的响应优先级别
NVIC_IRQChannelCmd:该中断是否使能
NVIC_Init() :函数初始化NVIC寄存器
4.中断优先级设置步骤
1、系统运行后先设置中断优先级分组。调用函数。
2、针对每个中断,设置对应的抢占优先级和响应优先级。
3、如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。
小项目:外部中断按键控制LED灯
软件流程设计
1.初始化系统
初始化GPIO、EXTI外设时钟
初始化按键和LED引脚(按键引脚为PA0,LED引脚为PA1)
初始化EXTI外部中断条件
初始化NVIC嵌套中断控制器
void Shake_Init(void)
{
GPIO_InitTypeDef GPIOEXTI; //GPIO结构体
EXTI_InitTypeDef Exti_Initstruct;//中断结构体
NVIC_InitTypeDef NVIC_Initstruct;//NVIC结构体
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);//初始化GPIOA和引脚复用时钟
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置NVIC优先级分组
GPIOEXTI.GPIO_Mode = GPIO_Mode_IPU;//模式为上拉输入
GPIOEXTI.GPIO_Pin = GPIO_Pin_0; //引脚为PA0
GPIO_Init(GPIOA, &GPIOEXTI); //初始化GPIO结构体
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//配置外部中断线GPIO
Exti_Initstruct.EXTI_Line = EXTI_Line0; //配置外部中断线
Exti_Initstruct.EXTI_LineCmd = ENABLE; //外部中断线使能
Exti_Initstruct.EXTI_Mode = EXTI_Mode_Interrupt; //配置外部中断模式
Exti_Initstruct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//边沿检测
EXTI_Init(&Exti_Initstruct); //初始化中断结构体
NVIC_Initstruct.NVIC_IRQChannel = EXTI0_IRQn; //配置中断通道
NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE; //该中断是否使能
NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = 0; //定义抢占优先级
NVIC_Initstruct.NVIC_IRQChannelSubPriority = 0; //定义响应优先级
NVIC_Init(&NVIC_Initstruct); //初始化NVIC结构体
}
2.编写外部中断函数
判断中断发生控制LED灯
//编写外部中断函数
void EXTI0_IRQHandler()
{
if ( EXTI_GetITStatus(EXTI_Line0) != RESET) //检测中断
{
GPIO_ResetBits(GPIOA, GPIO_Pin_1);
delay(1000);
GPIO_SetBits( GPIOA, GPIO_Pin_1);
delay(1000); //中断发生则LED亮1s灭1s
EXTI_ClearITPendingBit(EXTI_Line0); //清除中断
}
}