中断系统
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。
中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回。
STM32中断68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设。
使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级NVIC:嵌套中断向量控制器,用来统一分配中断优先级和管理中断的,是一个内核外设,CPU的小助理。
NVIC基本结构
NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
EXTI简介
EXTI(Extern Interrupt)外部中断EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序。
支持的触发方式:上升沿/下降沿/双边沿/软件触发支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断(如PA0与PB0不能同时触发中断,用的是一个通道,触发EXT0)
通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
触发响应方式:中断响应(EXTI_Mode_Interrupt)/事件响应(EXTI_Mode_Event),(如果选择触发事件,那外部中断的信号就不会通向CPU了,而是通向其它外设,用来触发其它外设的操作。
EXTI基本结构
AFIO复用IO口
AFIO主要用于引脚复用功能的选择和重定义在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择。
代码书写步骤:
根据上面的EXTI基本结构,我们可以得知配置。
第一,要选择GPIO来触发中断,自然打开GPIOA的时钟,并完成GPIOA结构体的相应初始化。根据需求,选择上拉输入( GPIO_Mode_IPU),还是浮空输入(GPIO_Mode_IN_FLOATING)。
第二,要选择AFIO进行中断引脚选择,也要打开AFIO的时钟,也是在APB2总线上。(需要几个GPIO口中断通道就要配置几次)RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//打开时钟void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);//中断引脚配置,端口源选择,引脚源选择。
第三,进行EXTI外部中断配置,EXTI的时钟是默认开的,不用配置RCC,结构体初始化,引出四个结构体。
EXTI_InitTypeDef EXTI_InitStructure;EXTI_Line ==EXTI_Line14;//中断线路,如果我们选择14线,也可以或,几个线路一起配置。EXTI_LineCmd = ENABLE;//线路控制,使能。EXTI_Mode = EXTI_Mode_Interrupt;//触发响应方式:中断响应/事件响应,这里我们选择触发中断模式。
EXTI_Trigger = EXTI_Trigger_Falling;//触发方式是选择上升沿(Rising),还是下降沿(Falling),还是双边沿(Rising_Falling))。EXTI_Init(&EXTI_InitStructure);
第四,进行NVIC中断向量控制器配置,作用是用来统一分配中断优先级和管理中断。NVIC的库函数头文件,是在misc.h中,有五个库函数,我们只需两个,一个是NVIC初始化,一个的中断优先级分组配置。(需要几个GPIO口中断通道就要配置几次)NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先分组,分两组,抢占优选机各两位,)0~3。
NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel =EXTI15_10_IRQn; //选择中断请求通道,用的PB14,所以选择15_10
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//中断请求通道使能NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级为1
NVIC_Init(&NVIC_InitStructure);
第五,就可以书写中断服务函数了,这个函数名是在启动文件start里,根据自己的配置找到自己的服务函数。
void EXTI15_10_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line14) == SET)//外部中断获取中断状态
{IR_Flag = 1;//在中断函数内设一个标志,外部函数再检测这个变量标志,进行操作,中断服务函数一定要快。EXTI_ClearITPendingBit(EXTI_Line14);//外部中断清除中断挂起位,一定要手动清楚
}
}