🙌秋名山码民的主页
😂oi退役选手,Java、大数据、单片机、IoT均有所涉猎,热爱技术,技术无罪
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
获取源码,添加WX
目录
- 1. 前言
- 2. NVIC
- 2.1 NVIC寄存器简介
- 2.2 中断优先级的定义
- 2.3 优先级分组
- 2.3 中断编程
- 3. 外部中断/事件控制器(EXTI)
- 3.1 EXTI功能框图
- 3.2 中断事件线
- 3.3 EXTI初始化结构体
- 3.4 按键中断
- 最后
1. 前言
STM32中断:
中断是一种机制,允许外部事件或者特定条件的发生打断正常的程序执行流程,从而执行特定的中断服务程序。这有助于实现实时响应和处理外部事件的能力。
STM32微控制器中的中断包括两种类型:内部中断和外部中断。
- 内部中断:由微控制器内部的特定事件触发,例如定时器溢出、串行通信完成等。
- 外部中断:由外部设备或者传感器触发,例如按键按下、传感器检测到特定条件等。
在STM32中,中断控制器(NVIC)负责管理和协调所有中断请求。通过配置中断优先级、使能或禁用特定中断,开发者可以实现对中断的灵活控制。
几乎每个引脚都可以单独设置中断,具体的可以去查看,《中文参考手册》。
参考资料:《STM32F10X-中文参考手册》中断和事件章节
《野火STM32手册》
2. NVIC
NVIC是嵌套向量中断控制器,控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设。
2.1 NVIC寄存器简介
NVIC寄存器包括以下几种功能:
- 中断优先级:NVIC允许针对每个可能的中断源设置优先级,通过设置优先级来确定中断的响应顺序。通常,较低的数值表示更高的优先级。
- 中断使能:可以通过NVIC寄存器来使能或禁用特定的中断源,以控制中断请求的触发。
- 中断向量表偏移寄存器:用于指定中断服务程序(ISR)的地址,当特定中断触发时,处理器会跳转到相应的中断服务程序开始执行。
typedef struct {__IO uint32_t ISER[8]; // 中断使能寄存器uint32_t RESERVED0[24];__IO uint32_t ICER[8]; // 中断清除寄存器uint32_t RSERVED1[24];__IO uint32_t ISPR[8]; // 中断使能悬起寄存器uint32_t RESERVED2[24];__IO uint32_t ICPR[8]; // 中断清除悬起寄存器uint32_t RESERVED3[24];__IO uint32_t IABR[8]; // 中断有效位寄存器uint32_t RESERVED4[56];__IO uint8_t IP[240]; // 中断优先级寄存器(8Bit wide)uint32_t RESERVED5[644];__O uint32_t STIR; // 软件触发中断寄存器
} NVIC_Type;
一般只用ISER、ICER和IP这三个寄存器,ISER用来使能中断,ICER用来失能中断,IP用来设置中断优先级。
2.2 中断优先级的定义
数值越小,优先级越高, 在F103系列中,只用到了0-4,但是原则上有0-255,
用于表达优先级的这4bit,又被分组成抢占优先级和子优先级。
- 有多个中断同时响应,抢占优先级高的就会抢占抢占优先级低的优先得到执行
- 抢占优先级相同,就比较子优先级
- 抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高
2.3 优先级分组
2.3 中断编程
三个步骤:
- 使能外部中断
- 初始化NVIC_InitTypeDef结构体
typedef struct {uint8_t NVIC_IRQChannel; // 中断源uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级uint8_t NVIC_IRQChannelSubPriority; // 子优先级FunctionalState NVIC_IRQChannelCmd; // 中断使能或者失能
} NVIC_InitTypeDef;
- 编写中断服务函数,一般写在stm32f10x_it.c这个库中
3. 外部中断/事件控制器(EXTI)
外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求
3.1 EXTI功能框图
斜杠20,表示在控制器内部类似的信号线路有20个, EXTI总共有20个中断/事件线
红色代表产生中断,绿色代表产生事件
产生中断线路目的是把输入信号输入到NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用, 并且是电路级别的信号传输,属于硬件级的。
3.2 中断事件线
EXTI有20个中断/事件线,每个GPIO都可以被设置为输入线,占用EXTI0至EXTI15, 还有另外七根用于特定的外设事件,见表 EXTI中断_事件线 。
4根特定外设中断/事件线由外设触发,具体用法参考《STM32F10X-中文参考手册》中对外设的具体说明。
EXTI0至EXTI15用于GPIO,通过编程控制可以实现任意一个GPIO作为EXTI的输入源。由表 EXTI中断_事件线 可知, EXTI0可以通过AFIO的外部中断配置寄存器1(AFIO_EXTICR1)的EXTI0[3:0]位选择配置为PA0、 PB0、PC0、PD0、PE0、PF0、PG0、PH0或者PI0
3.3 EXTI初始化结构体
typedef struct {uint32_t EXTI_Line; // 中断/事件线EXTIMode_TypeDef EXTI_Mode; // EXTI模式EXTITrigger_TypeDef EXTI_Trigger; // 触发类型FunctionalState EXTI_LineCmd; // EXTI使能
} EXTI_InitTypeDef;
- EXTI_Line:EXTI中断/事件线选择,可选EXTI0至EXTI19,可参考表 EXTI中断_事件线 选择。
- EXTI_Mode:EXTI模式选择,可选为产生中断(EXTI_Mode_Interrupt)或者产生事件(EXTI_Mode_Event)。
- EXTI_Trigger:EXTI边沿触发事件,可选上升沿触发(EXTI_Trigger_Rising)、 下降沿触发( EXTI_Trigger_Falling)或者上升沿和下降沿都触发( EXTI_Trigger_Rising_Falling)。
- EXTI_LineCmd:控制是否使能EXTI线,可选使能EXTI线(ENABLE)或禁用(DISABLE)。
3.4 按键中断
- 初始化用来产生中断的GPIO;
- 初始化EXTI;
- 配置NVIC;
- 编写中断服务函数;
宏定义:
//引脚定义
#define KEY1_INT_GPIO_PORT GPIOA
#define KEY1_INT_GPIO_CLK (RCC_APB2Periph_GPIOA\|RCC_APB2Periph_AFIO)
#define KEY1_INT_GPIO_PIN GPIO_Pin_0
#define KEY1_INT_EXTI_PORTSOURCE GPIO_PortSourceGPIOA
#define KEY1_INT_EXTI_PINSOURCE GPIO_PinSource0
#define KEY1_INT_EXTI_LINE EXTI_Line0
#define KEY1_INT_EXTI_IRQ EXTI0_IRQn#define KEY1_IRQHandler EXTI0_IRQHandler#define KEY2_INT_GPIO_PORT GPIOC
#define KEY2_INT_GPIO_CLK (RCC_APB2Periph_GPIOC\|RCC_APB2Periph_AFIO)
#define KEY2_INT_GPIO_PIN GPIO_Pin_13
#define KEY2_INT_EXTI_PORTSOURCE GPIO_PortSourceGPIOC
#define KEY2_INT_EXTI_PINSOURCE GPIO_PinSource13
#define KEY2_INT_EXTI_LINE EXTI_Line13
#define KEY2_INT_EXTI_IRQ EXTI15_10_IRQn
NVIC配置
static void NVIC_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;/* 配置NVIC为优先级组1 */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);/* 配置中断源:按键1 */NVIC_InitStructure.NVIC_IRQChannel = KEY1_INT_EXTI_IRQ;/* 配置抢占优先级:1 */NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;/* 配置子优先级:1 */NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;/* 使能中断通道 */NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/* 配置中断源:按键2,其他使用上面相关配置 */NVIC_InitStructure.NVIC_IRQChannel = KEY2_INT_EXTI_IRQ;NVIC_Init(&NVIC_InitStructure);
}
EXIT中断配置
void EXTI_Key_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;/*开启按键GPIO口的时钟*/RCC_APB2PeriphClockCmd(KEY1_INT_GPIO_CLK,ENABLE);/* 配置 NVIC 中断*/NVIC_Configuration();/*--------------------------KEY1配置---------------------*//* 选择按键用到的GPIO */GPIO_InitStructure.GPIO_Pin = KEY1_INT_GPIO_PIN;/* 配置为浮空输入 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure);/* 选择EXTI的信号源 */GPIO_EXTILineConfig(KEY1_INT_EXTI_PORTSOURCE, \KEY1_INT_EXTI_PINSOURCE);EXTI_InitStructure.EXTI_Line = KEY1_INT_EXTI_LINE;/* EXTI为中断模式 */EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;/* 上升沿中断 */EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;/* 使能中断 */EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);/*--------------------------KEY2配置------------------*//* 选择按键用到的GPIO */GPIO_InitStructure.GPIO_Pin = KEY2_INT_GPIO_PIN;/* 配置为浮空输入 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);/* 选择EXTI的信号源 */GPIO_EXTILineConfig(KEY2_INT_EXTI_PORTSOURCE, \KEY2_INT_EXTI_PINSOURCE);EXTI_InitStructure.EXTI_Line = KEY2_INT_EXTI_LINE;/* EXTI为中断模式 */EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;/* 下降沿中断 */EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;/* 使能中断 */EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);
}
中断服务函数
void KEY1_IRQHandler(void)
{//确保是否产生了EXTI Line中断if (EXTI_GetITStatus(KEY1_INT_EXTI_LINE) != RESET) {// LED1 取反LED1_TOGGLE;//清除中断标志位EXTI_ClearITPendingBit(KEY1_INT_EXTI_LINE);}
}void KEY2_IRQHandler(void)
{//确保是否产生了EXTI Line中断if (EXTI_GetITStatus(KEY2_INT_EXTI_LINE) != RESET) {// LED2 取反LED2_TOGGLE;//清除中断标志位EXTI_ClearITPendingBit(KEY2_INT_EXTI_LINE);}
}
最后
如果本文对你有所帮助,还请三连支持一下博主!