STM32中断应用概览
STM32 中断非常强大,每个外设都可以产生中断
什么是中断?
中断:处理器在顺序执行程序指令流的过程中突然被别的请求打断而中止执行当前的程序,转而去处理别的事情,待其处理完了别的事情,然后重新回到之前程序中断的点继续执行之前的程序指令,异常也叫中断
还可以近一步将中断分为 外中断(中断) 和 内中断(异常);
中断 和 异常 有什么区别?
中断:是指由于外部设备事件所引起的中断,如通常的磁盘中断、打印机中断等;
异常:是指由于 CPU 内部事件所引起的中断,如程序出错(非法指令、地址越界)。
在STM32方面–外部中断,体现在外设水平;系统异常,体现在内核水平
STM32系统异常清单
STM32外部中断清单
…
中断优先级
- 中断优先级分为两种,可编程和不可编程,可编程的表示可以自己修改中断优先级,不可编程的就不能修改
- 对于STM32中断优先级,决定着内核优先响应谁的中断请求
- 小值优先原则,中断优先级数值越小,中断就会被优先相应
- 中断优先级按照优先级分组配置
- 中断优先级寄存器 NVIC_IPRx, 用来配置外部中断的优先级, IPR 宽度为 8bit
- 原则上每个外部中断可配置的优先级为 0~255,数值越小,优先级越高
- 绝大多数 CM3 芯片都会精简设计,以致实际上支持的优先级数减少,在F103 中,只使用了高 4bit
抢占优先级 和 响应优先级
STM32的中断向量具有两个属性,一个为抢占属性,另一个为响应属性,其属性编号越小,表明它的优先级别越高。抢占是指打断其他中断的属性因为具有这个属性会出现嵌套中断(在执行中断服务函数A的过程中被中断B打断,执行完中断服务函数B 再继续执行中断服务函数A;如果A并不能打断事件B,A就会被挂起)
- 通过优先级分组,可以管理中断的响应顺序
- 只有抢占优先级才由抢占中断权限,发生中断嵌套,打断就发生中断嵌套,没有能力打断,那就被挂起
- 如果中断抢占优先级相同,不发生抢占
- 如果多个挂起的中断具有相同的抢占优先级,则子优先级高的先行,如果子优先级相同,则IRQ(通常指外部中断请求)编号小的先行
抢占优先级>子优先级>IRQ编号
NVIC寄存器(嵌套矢量中断控制器)
- 可编程的优先级,通过嵌套向量中断控制器(NVIC)实现
中断编程顺序
- 初始化要连接到EXTI的GPIO
- 初始化EXTI用于产生中断/事件
void EXTI_Key_Config(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
//配置中断优先级
EXTI_NVIC_Config();
//初始化GPIO
/*开启LED相关的GPIO外设时钟*/
RCC_APB2PeriphClockCmd( KEY1_INT_GPIO_CLK, ENABLE);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
/*调用库函数,初始化GPIO*/
GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);
//初始化EXTI
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
- 初始化NVIC,用于处理中断
void EXTI_NVIC_Config()
{
NVIC_InitTypeDef NVIC_InitStructure;
//配置NVIC为优先组1
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//配置中断源
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
//配置抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
//配置子优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
- 编写中断服务函数(在stm32f10x_it.c中实现)
中断服务函数的函数名要与启动文件中的函数名一致
void EXTI0_IRQHandler (void)
{
if(EXTI_GetITStatus(EXTI_Line0 != RESET))
{
LED1_TOGGLE;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
- main函数
int main(void)
{
//来到这里的时候,系统时钟已经被配置成72M 默认
/* LED 端口初始化 */
LED_GPIO_Config();
EXTI_Key_Config();
while (1)
{
}
}