中断
中断机制:主程序正常运行时,【发生中断事件】打断CPU运行,保存任务的地址(栈空间,先进后出,【压栈】)。转而【执行中断服务程序】(快进快出无参无返回),执行完成后,在将主函数运行状态出栈。
内核中断数:1~240 32中有64个和16个可编程的
中断事件:
中断优先级在ST芯片中分为4个组。如图所示
红色部分就是ST的
首先,对STM32中断进行分组,组0~4。同时,对每个中断设置一个抢占优先级和一个响应优先级值。分组配置是在寄存器SCB->AIRCR中配置(注意:数字越小,优先级越高):
-
第0组: 所有4位用于指定响应优先级
-
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
-
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
-
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
-
第4组:所有4位用于指定抢占式优先级
STM32 中断是怎么进入到中断服务程序的?
在STM32中,为了区分不同的中断,每个设备有自己的中断号。系统有0-255一共256个中断。系统有一张中断向量表,用于存放256个中断的中断服务程序入口地址。每个入口地址对应一段代码,即中断服务程序。
外部中断产生
1.外部I/O口对应中断线
2,设置触发寄存器 --上升沿触发,下降沿触发,双边触发
3,中断信号产生
4,中断屏蔽寄存器是否允许中断产生,允许中断产生 (这个中断屏蔽寄存器需要使能)
5,NVIC中断控制器便设置: (1)分组 (2)优先级 (3)使能中断通道(是否有处理这个中断的渠道)
6,处理中断:编写中断服务函数
注意:配置了某个中断,一定要写中断服务函数
中断服务函数里面一定要记得清中断
实例代码exti.c
#include "exti.h"
//粗延时
void delayms(int n)
{
int i, j;
for(i=0; i<n; i++)
for(j=0; j<40000; j++);
}
//PA0引脚按键KEY1中断初始化
void Exti_PA0_KEY1_Init(void)
{
// GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
//使能GPIO A组时钟,
// RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
// GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; //引脚0
// GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; //输入模式
// GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉
// GPIO_Init(GPIOA, &GPIO_InitStruct);
//使能SYSCFG时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
//开这个时钟是因为在I/O对应中断线时,这个中断线在这个寄存器上,可以根据上面图看出来!
//设置IO口与中断线的映射关系。确定什么引脚对应哪个中断线 PA0 -- EXTI0 (可变)
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
EXTI_InitStruct.EXTI_Line = EXTI_Line0; //中断线0 (可变)
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式
EXTI_InitStruct.EXTI_Trigger= EXTI_Trigger_Falling; //下降沿触发
EXTI_InitStruct.EXTI_LineCmd= ENABLE; //中断线使能
//初始化线上中断,设置触发条件等。
EXTI_Init(&EXTI_InitStruct);
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 这里已经在main.c中编写过了,这里不用再分组了
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn; //NVIC通道,在stm32f4xx.h可查看通道 (可变)
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x01; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x01; //响应优先级
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; //使能
//配置中断分组(NVIC),并使能中断。
NVIC_Init(&NVIC_InitStruct);
}
//编写中断服务函数。这个函数不需要程序员在主函数调用,满足条件CPU自行调用的函数
void EXTI0_IRQHandler(void)
{
//判断中断标志是否为1
if(EXTI_GetITStatus(EXTI_Line0) == SET)
{
delayms(15); //延时消抖
//判断是否按下
if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0)
{
//变更灯状态
GPIO_ToggleBits(GPIOF, GPIO_Pin_9);
}
}
//清空标志位
EXTI_ClearITPendingBit(EXTI_Line0);
}
对应的main.c
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
int main(void)
{
//NVIC分组(一个工程当中只能配置一次分组)抢占优先级2位,值范围:0~3;响应优先级2位,值范围:0~3;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//LED灯初始化
Led_Init();
//按键初始化
Key_Init();
//中断
Exti_PA0_KEY1_Init();
while(1)
{
GPIO_ToggleBits(GPIOE, GPIO_Pin_14);
delayms(1000);
}
return 0;
}