中断适合突发的,剧烈的事件。
中断概念:主程序运行过程中出现了特定的中断触发条件,cpu暂停当前程序去处理中断事件,处理完毕后再返回暂停前的位置继续执行。
中断有优先级,高优先级中断可以中断低优先级中断。
外部事件中断所涉及到的外设:
GPIO、AFIO、EXIT、NVIC
发生中断时:EXTI检测指定GPIO的电平信号,当其指定的GPIO口产生指定的电平变化时,EXTI立刻向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序。
GPIO允许中断的发生与检测,中断由GPIO获取信号作为起始
AFIO为数据选择器,由于只有16个中断源,而引脚有16×7个引脚,所以规定每个引脚只能拥有一个中断,也就是说如果GPIOA1作为中断源,则GPIOB1、C1就无法作为中断源。AFIO用来选择哪一个端口的哪一个引脚连接中断源。
EXIT是外部中断外设,可以检测指定GPIO的电平信号(由AFIO选择),检测到指定的电平信号(上升沿/下降沿/双边沿)后向NVIC发出中断申请。
NVIC是嵌套中断向量控制器,用来对众多外设的中断进行优先级排序,为cpu处理中断提供方便。
NVIC中规定了中断的优先级分为抢占优先级和响应优先级,抢占优先级决定了此中断是否能够中断别的中断,响应优先级决定了某个正在运行的中断结束后,此中断是否是第一个被执行的中断。抢占优先级和响应优先级共用一个四位寄存器,具体分配的多少由优先级分组决定。
优先级分组设置好后,所有的众多外设全按照此分组分配优先级。(数字越小优先级越高)
外部事件中断流程:
以下是具体的代码:
//实现指南者按键1的中断配置
void EXTI_Key1_Init(void)
{
//-------------------------------------配置GPIO-----------------------------------------
//开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
//定义结构体
GPIO_InitTypeDef GPIO_InitStruct;
//设置结构体成员
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;//按键默认接低电平,按下开关变成高电平,所以输入模式为下拉电阻,默认低电平
//应用结构体函数
GPIO_Init(GPIOA,&GPIO_InitStruct);
//-------------------------------------配置AFIO-----------------------------------------
//开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
//选择引脚连接中断通道
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
//-------------------------------------配置EXTI-----------------------------------------
//定义结构体
EXTI_InitTypeDef EXTI_InitStruct;
//配置结构体变量
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStruct);
//-------------------------------------配置NVIC-----------------------------------------
//分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//配置成2,2的分布,2bit抢占优先级,2bit响应优先级。
//定义结构体
NVIC_InitTypeDef NVIC_InitStruct;
//配置结构体成员
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
//应用结构体
NVIC_Init(&NVIC_InitStruct);
//-------------------------------------编写中断函数-----------------------------------------
//中断函数编写在了stm32f10x_it.c中,使用中断函数须在main.c中引用其头文件
}
//中断函数
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0) == SET)//发现中断标志位为1,说明按下了按键(其实此处不检测也可以?)
{
count++;
OLED_ShowNum(1,2,count,2);//如果执行则将数字从0变成1
EXTI_ClearITPendingBit(EXTI_Line0);//清除标志位,防止一直进入中断函数。
}
}
编写代码过程中的一些细节:
1.NVIC的中断源和中断函数名不同,NVIC中断源是“EXTI0_IRQn”,中断函数名是“EXTI0_IRQHandler”,中断源在stm32f10x.h文件中,中断函数名字在启动文件 startup_stm32f10x_hd.s中
2.NVIC的固件库函数在misc.h和misc.c中
3.关于多文件编程中的跨文件变量,跨文件变量只能是某个文件的全局变量,假如int变量count在a.c中定义,想要在b.c中使用,则只需要在b.h中写:extern int count;。不需要在a.h中声明,如若声明,则会报错。
4.中断函数可以编写在自己写的文件中(应该是可以在任何文件中),只需要引用此文件即可,但是stm32标准库中建议中断函数都写在stm32f10x_it.c中,使用时引用stm32f10x_it.h即可。