一、中断的概念:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。
二、中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。
三、中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回。
四、中断处理过程
1、中断请求
在中断请求被响应之前会一直发送中断请求。
2、中断源识别
当系统同时有多个中断源发出的中断请求时,系统往往只能相应并处理一个中断,这就要求CPU对来到的中断请求进行判优,选择出同一时间优先级最高的给予响应和处理。
3、中断响应
中断响应时,CPU要向中断源发出中断响应信号,还要保护现场即将FLAGS压入堆栈,将下一条指令的CS压入堆栈,将下一条指令的IP压入堆栈。还要将终端的入口赋给IP和SP。
4、中断处理
保护软件现场(把中断服务子程序中要用到的寄存器的内容压入堆栈)、开中断(为了可以嵌套)、执行中断处理程序、关中断、恢复现场。
5、中断返回
利用IRET进行中断返回会将堆栈中保存的信息弹出到P和CS和FLAGS中。
五、stm32中断
1、68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设(中断源)。
2、使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级。
如上图,当有多个中断请求时,NVIC会设置优先级,CPU根据优先级再依次处理中断。
六、EXTI(Extern Interrupt)外部中断
EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
支持的触发方式:上升沿/下降沿/双边沿/软件触发
支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断
通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
触发响应方式:中断响应/事件响应
AFIO主要用于引脚复用功能的选择和重定义
在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择。
根据如上结构,EXTI外部中断的步骤应该为:
1.配置RCC,打开需要用到的GPIO外设时钟;
2.配置GPIO,选择端口为输入模式;
3.配置AFIO,选择用到的这一路的GPIO,连接到后面的EXTI;
4.配置EXTI,选择边沿触发方式,上升沿,下降沿或双边沿,选择触发响应方式,可以选择中断响应和事件响应;
5.配置NVIC,给中断选择一个合适的优先级。
完成以上步骤后,中断信号就能通过NVIC进入CPU了,CPU才能收到中断信号,跳转到相应的中断服务函数中去执行。
七、对射式红外传感器计次
接线图
EXTI外部中断初始化及中断函数
#include "stm32f10x.h" // Device header
uint16_t CountSensor_Count;
void CountSensor_Init(void)
{
//1.配置RCC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //GPIOB时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //AFIO时钟使能
//2.配置GPIO
GPIO_InitTypeDef GPIO_InitStructure; //引脚初始化
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//3.配置AFIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14); //选择用作EXTI线的GPIO引脚
4.配置EXTI
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line14; //第14线路
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中断使能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //选择中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
EXTI_Init(&EXTI_InitStructure);
5.配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //启用14通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //设置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //设置响应优先级
NVIC_Init(&NVIC_InitStructure);
}
uint16_t CountSensor_Get(void)
{
return CountSensor_Count;
}
void EXTI15_10_IRQHandler(void) //中断函数
{
if (EXTI_GetITStatus(EXTI_Line14) == SET) //中断标志位判断,确认是EXTI14
{
CountSensor_Count ++;
EXTI_ClearITPendingBit(EXTI_Line14); //清除中断标志位
}
}
main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"
int main(void)
{
OLED_Init();
CountSensor_Init();
OLED_ShowString(1, 1, "Count:");
while (1)
{
OLED_ShowNum(1, 7, CountSensor_Get(), 5);
}
}