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

STM32学习笔记(三)——STM32的中断本文详细介绍了 STM32 的中断编程原理 包括中断的概念 中断处理过程 中断优先级 NVIC 的结构与编程 以及 EXTI 外部中断 事件控制器 的使用

大家好,欢迎来到IT知识分享网。

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

一、中断编程的原理

1.1 什么是中断

1.1.1 生活中的中断

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

在这里插入图片描述

1.1.2 单片机中的中断

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

在这里插入图片描述

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

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

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


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 中断协作模型

2.3 NVIC的内部结构

在这里插入图片描述

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

在这里插入图片描述

2.4 中断向量表

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

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

在这里插入图片描述

2.5 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简介

在这里插入图片描述

3.2 EXTI的内部结构

在这里插入图片描述

在这里插入图片描述

3.3 EXTI的通道

在这里插入图片描述

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 实验介绍

在这里插入图片描述

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); } 

若是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); } } 

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

在这里插入图片描述

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/114291.html

(0)
上一篇 2025-12-09 16:20
下一篇 2025-12-09 16:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信