当前位置:   article > 正文

STM32学习笔记(三)——STM32的中断_stm32中断学习

stm32中断学习

STM32学习笔记(三)——STM32的中断

一、中断编程的原理

1.1 什么是中断

1.1.1 生活中的中断

中断:正在进行的事务被突发事件打断,转而去处理这个突发事件,突发事件处理完成后回到被打断的事务继续执行,这一处理突发事件的过程叫中断

在这里插入图片描述

1.1.2 单片机中的中断

常规程序:main方法和被main方法调用的程序;由于main方法的执行而得到执行的程序,叫常规程序

在这里插入图片描述

用电脑给STM32串口发送程序,只要电脑发来了数据,STM32就必须马上处理这个数据,如果不及时处理,电脑发送新的数据,就会覆盖之前传送的数据,造成数据的丢失

为了实现,来了数据,立马处理这个数据的功能,我们写了一个方法(也就说写了一个函数,函数内部代码的功能为,先接收数据,再处理数据)在这里插入图片描述

流程为:在这里插入图片描述
我们将这样突发的事件,叫中断源
在main中程序叫常规程序
由于中断源触发而调用的程序叫中断响应函数

STM32中的中断概念:
由于中断源的触发,常规程序被打断,CPU转而运行中断响应函数,而后又回到常规程序的执行,这一过程叫做中断。

1.1.3 为什么要使用中断

突发事件有:
突发性:随机的在任意时刻发生、无预兆
紧急性:需要马上被处理

1.2 中断处理过程

保存现场:记录常规程序执行到哪了
清楚中断源:接电话,第一步按接听键挂断电话铃声
还原现场:还原导出常规程序执行的步骤,继续执行

在这里插入图片描述

1.3 中断的优先级

在这里插入图片描述

中断优先级:

  • 优先级的值小,优先级越高
  • 抢占优先级高的中断会对抢占优先级低的发生中断嵌套
  • 发生中断嵌套时,会发生排队,总优先级高的中断排在前面

在这里插入图片描述

例子1
执行A中断的过程总发生了中断B和C.
中断A先发生,而后中断B发生, 但中断B的抢占优先级高,所以发生中断嵌套

在这里插入图片描述

例子2
执行A中断的过程总发生了中断B和C.
中断A先发生,而后中断B和C同时发生, 且B和C的抢占优先级不比A的高,不发生中断嵌套
但需要判断B和C的中断优先级B为1100(12) C为0101(5) 根据优先级数低的优先级高,所以C先发生

在这里插入图片描述

例子3
执行A中断的过程总发生了中断B和C.
中断A先发生,而后中断B和C同时发生, 且B和C的抢占优先级不比A的高,不发生中断嵌套
但需要判断B和C的中断优先级B为0101(5) C为0100(4) 根据优先级数低的优先级高,所以C先发生

在这里插入图片描述

1.4 两种中断源类型

“脉冲型”中断源(罕见):中断提示信号一闪而过
“电平型”中断源(常见):中断信号持续,直到手动关闭,因此必须在中断响应函数结束前清除中断

在这里插入图片描述

在这里插入图片描述

1.5 中断源的四种状态

在这里插入图片描述

二、STM32的NVIC

2.1 NVVIC简介

NVIC(Nested Vectored Interrupt Controller)嵌套中断向量控制器,是一种核心外设,位于Cortex-M3内核中,负责管理中断

在这里插入图片描述

2.2 中断协作模型

中断源:由片上外设产生,同一片上外设可产生多个中断源
NVIC:管理中断,负责中断进入和中断退出,中断优先级设置等。
Flash:等于电脑里硬盘,存储写的中断响应函数程序
在这里插入图片描述

2.3 NVIC的内部结构

开关部分:负责中断屏蔽,将项目中使用不到中断源开关断开,进行屏蔽
中断优先级:由4个bit位进行存储,
中断仲裁:将存储的中断优先级拿出来进行比较,看看谁优先

在这里插入图片描述

中断优先级分组:我们可以根据需要,设置不同的分组方式

在这里插入图片描述

2.4 中断向量表

Flash存储器中,有各种代码,CPU在中断发生时,如何定位是执行这个中断的中断响应函数呢?

中断向量表:看成一个目录,Flash存储器内部从地址0开始的一段区域,按照中断号排列,每4个字节(STM32是32位处理器,1个字节8bit,4字节正好32位)存储一个中断响应函数地址

在这里插入图片描述

表在:中文参考手册9.1.2节
在这里插入图片描述

2.5 NVIC编程

编程接口:
在这里插入图片描述

中断优先级分组:移动中间的虚线,具体分配几个bit位给抢占优先级,分几个bit给子优先级
NVIC初始化:对NVIC某一路中断源进行初始化

在这里插入图片描述

NVIC_PriorityGroupConfig()函数详解:

在这里插入图片描述

NVIC_Init()

在这里插入图片描述

在这里插入图片描述

2.6 NVIC编程实例

根据中断编程模型,将中断编程分为三个部分:

在这里插入图片描述
在这里插入图片描述

问题1:如何让片上外设产生中断源?

  • 不同的片上外设开启方式不同
  • USART1外设开启某中断源的方法:USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);

问题2:如何配置NVIC?

  • 为啥NVIC不用开启时钟?因为NVIC在内核里,只要一上电就有时钟(大脑不能休眠)
  • 1.设置中断优先级分组
  • 2.填写初始化调查问卷(写名,填问题)

问题3:如何编写中断响应函数

  • 弱方法:标注为weak的方法可以被同名的方法覆盖,一开始中断向量表指向的是弱方法进行占位,当我们编写同名函数后,就指向了我们所编写的函数代码
  • 步骤:
    • 在.s文件中找到中断响应函数
    • 写一个同名函数覆盖它 void xxx_IRQHandler(void){}v
      void USART1_IRQHandler(void) { //具体的中断响应代码//主函数外部 }

总结:
在这里插入图片描述

三、STM32的EXTI简介

3.1 EXTI简介

EXTI(External Interrupt/Event Controller)外部中断/事件控制器
EXTI是stm32外设的众多片上外设之一,能够检测外部输入信号的变化边沿,并由此产生中断

在这里插入图片描述

3.2 EXTI的内部结构

在这里插入图片描述

事件和中断区别:
事件:指突发事件本身,一般是一个脉冲信号,事件处理过程不需要CPU介入

在这里插入图片描述

3.3 EXTI的通道

实际项目中有多个外部输入信号,故将此电路复制多份。
EXTI01~19合起来才是一个完整的片上外设

在这里插入图片描述

EXTI这么多通道用来作什么呢?

  • 让所有的IO口都具有触发中断的能力
    使用PA0触发外部中断了 就不能使用PB0、PC0…了
    在这里插入图片描述
  • 其它功能在这里插入图片描述

3.4 EXTI的寄存器组

在这里插入图片描述

其中:
上升沿选择寄存器和下降沿选择寄存器:对应硬件电路的上升沿 下降沿 和双边沿的边沿选择

软件触发寄存器:对应硬件图软件触发
中断屏蔽寄存器:对应开关
挂起寄存器:对应那个框
事件屏蔽寄存器:控制事件屏蔽的开关

3.4 EXTI的标准库编程

3.4.1 EXTI标准库编程接口

在这里插入图片描述

EXTI_Init():

  • 初始化EXTI20个通道中的某一个
  • 参数结构体指针类型(填调查问卷方式)在这里插入图片描述
    例子:
    在这里插入图片描述

EXTI_GenerateSWInterrupt()

  • 产生软件中断在这里插入图片描述

EXTI_GetFlagStatus()

  • 获取中断标志位(硬件图中的4,获取中断挂起的bit位)在这里插入图片描述

EXTI_ClearFlag()

  • 清除标志位(硬件图中的4,清楚中断挂起的bit位)在这里插入图片描述

EXTI_GetITStatus()

  • 中断屏蔽寄存器与上中断挂起寄存器的值,中断屏蔽开关闭合同时中断被触发,中断挂起寄存器值也为1,函数才返回1在这里插入图片描述

EXTI_ClearITPendingBit()

  • 同EXTI_ClearFlag()在这里插入图片描述
3.4.2 EXTI标准库编程实验
3.4.2.1 实验介绍

在这里插入图片描述

曾经我们通过while循环读读取上次和当前的值,变化代表按键发生了动作
现在我们用外部中断的方法,在上升沿到来时,EXTI外设产生中断,NVIC模块对中断进行管理,触发中断响应函数

3.4.2.2 实验思路

在这里插入图片描述

GPIO片上外设:对按键使用的IO进行初始化

AFIO片上外设:EXTI有20个通道,拿出0-15个通道,对应GPIOx的0-15号引脚,引脚组x由AFIO选择,通过复用器选择编号在这里插入图片描述
在这里插入图片描述

EXTI片上外设:使用外部中断,产生中断源

NVIC核内外设:配置中断参数在这里插入图片描述

编写中断响应函数
- 调用函数

  • 找到.s文件在这里插入图片描述
  • 写同名函数覆盖
    在这里插入图片描述
    函数里写:
  • 清除中断源 EXTI_ClearITPendingBit(EXTI_Line1);
  • 编写功能函数
#include "stm32f10x.h"
#include "stm32f10x_pal.h"

int main(void)
{
	//4.1设置中断优先级分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	PAL_Init();
	//1.初始化IO引脚
	//将PA0和PA1分别设置为输入上拉模式
	//开启GPIOA的时钟
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//PA0,PA1
	GPIO_InitTypeDef GPIOInitStruct;
	GPIOInitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOA,&GPIOInitStruct);
	//2.配置EXTI的引脚映射
	//开启AFIO的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	//PA0->EXTI0
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
	//PA1->EXTI1
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1);
	//3.配置EXTI
	//3.1初始化EXTI0
	EXTI_InitTypeDef EXTIInitStruct;
	EXTIInitStruct.EXTI_Line = EXTI_Line0;
	EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTIInitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTIInitStruct);
	//3.2初始化EXTI1
	EXTIInitStruct.EXTI_Line = EXTI_Line1;
	EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTIInitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTIInitStruct);
	
	//4.初始化NVIC
	//4.2初始化某一路的中断
	NVIC_InitTypeDef NVICInitStruct;
	
	//4.2.1EXTI0
	NVICInitStruct.NVIC_IRQChannel = EXTI0_IRQn;
	NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVICInitStruct.NVIC_IRQChannelSubPriority = 2;
	NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVICInitStruct);
	//4.2.2EXTI1
	NVICInitStruct.NVIC_IRQChannel = EXTI1_IRQn;
	NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVICInitStruct.NVIC_IRQChannelSubPriority = 2;
	NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVICInitStruct);
	
	//5.初始化PC13
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	
	GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_OD; //open-drain开漏模式
	GPIOInitStruct.GPIO_Pin = GPIO_Pin_13;
	GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;

	GPIO_Init(GPIOC,&GPIOInitStruct);
	
	
	while(1)
	{
	}
}

void EXTI0_IRQHandler(void)
{
	//清除中断
	EXTI_ClearITPendingBit(EXTI_Line0);
	//点亮LED-向PC13写0
	GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
	
}

void EXTI1_IRQHandler(void)
{
	//清除中断
	EXTI_ClearITPendingBit(EXTI_Line1);
	//熄灭LED
	GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

若是PA5和PA6产生中断,其中断处理函数为同一个,在调用中断处理函数时,怎么知道是哪个中断产生的呢?

  • 只需要判断其中断挂起寄存器的值,若为1,则代表是这个中断源产生的中断
#include "stm32f10x.h"
#include "stm32f10x_pal.h"

int main(void)
{
	//4.1设置中断优先级分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	PAL_Init();
	//1.初始化IO引脚
	//将PA0和PA1分别设置为输入上拉模式
	//开启GPIOA的时钟
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA,ENABLE);
	//PA0,PA1
	GPIO_InitTypeDef GPIOInitStruct;
	GPIOInitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;
	GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOA,&GPIOInitStruct);
	//2.配置EXTI的引脚映射
	//开启AFIO的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	//PA0->EXTI0
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5);
	//PA1->EXTI1
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource6);
	//3.配置EXTI
	//3.1初始化EXTI0
	EXTI_InitTypeDef EXTIInitStruct;
	EXTIInitStruct.EXTI_Line = EXTI_Line5;
	EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTIInitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTIInitStruct);
	//3.2初始化EXTI1
	EXTIInitStruct.EXTI_Line = EXTI_Line6;
	EXTIInitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTIInitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTIInitStruct.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTIInitStruct);
	
	//4.初始化NVIC
	//4.2初始化某一路的中断
	NVIC_InitTypeDef NVICInitStruct;
	
	//4.2.1EXTI0
	NVICInitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;
	NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVICInitStruct.NVIC_IRQChannelSubPriority = 2;
	NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVICInitStruct);
	//4.2.2EXTI1

	
	//5.初始化PC13
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
	
	GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_OD; //open-drain开漏模式
	GPIOInitStruct.GPIO_Pin = GPIO_Pin_13;
	GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;

	GPIO_Init(GPIOC,&GPIOInitStruct);
	
	
	while(1)
	{
	}
}

void EXTI9_5_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line5) == SET)//EXTI 
	{
		EXTI_ClearITPendingBit(EXTI_Line5);	//清除中断
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
	}
	//不写if else原因:可能同时为1 两个都执行
	if(EXTI_GetITStatus(EXTI_Line6) == SET)
	{
		EXTI_ClearITPendingBit(EXTI_Line6);//清除中断
		GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

3.5 EXTI的标准库编程方法总结

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/83629
推荐阅读
相关标签
  

闽ICP备14008679号