05 详细的中断讲解

news/2024/11/15 11:32:06/文章来源:https://www.cnblogs.com/Lavender-edgar/p/18329053

目录
  • 前言
  • 一、什么是中断
  • 二、如何使用中断
    • 1.stm32中断结构
      • 1.1 AFIO中断引脚选择
      • 1.2 EXTI边缘检测
      • 1.3 NVIC优先级配置
    • 2.配置stm32的中断
      • 1.打开时钟
      • 2.配置GPIO口
      • 3.配置AFIO控制
      • 4.配置EXTI功能
      • 5.配置NVIC
      • 6.配置完整代码
    • 3.书写中断服务函数
  • 总结

前言

又鸽了几天的文章,最近在做一个手表项目,这个项目用到了很多知识,特别是中断的知识特别的多,所以这一篇文章来讲讲外部中断,等下一章说一下内部中断。

一、什么是中断

例如你现在在搞一个项目,然后突然看到你自己写的便条,上面写着今天该写文章了,然后你就会停下手中的项目,转去写文章,当文章写完后又继续的做项目,这个过程就是一个中断。

也就是说中断就是一个打断当前执行的任务,转去执行另外一个任务,当这个任务执行完成后就会返回执行被打断的任务。

img

上面就是中断执行的一个逻辑。

二、如何使用中断

上面我们简单的了解了一下中断,大概了解了中断是需要外部信号的,但是光有外部信号进来也不行,我们还需要配置内部,就比如上面举的例子,你看到了便条,但是你忘记这件事了,是不是就会忽略掉那个便条,stm32也是一样,你设置了外部的信号,但是你没设置stm32内部,让它知道这个信号是中断,这样是没用的,所以我们要对stm32进行配置。

在配置之前首先要了解stm32处理中断的硬件环境,这样我们才知道如何配置。

1.stm32中断结构

img

因为我们这里讲的是外部中断,在stm32中控制外部中断的是EXTI控制器,所以这里有GPIO口,GPIO口经过AFIO引脚选择器后选择出引脚转到EXTI检测器后会到NVIC中进行排队触发,如果前面有正在执行的中断,NVIC会根据这个中断的抢占优先级来进行强占,如果没有正常排队;如果同时有两个中断同时触发,会根据它们之间的响应优先级来进行排队响应。

1.1 AFIO中断引脚选择

这个连接这GPIO口的所有引脚,进入了这个器件后,这个器件会将同一个号码的引脚分为一个引脚,比如说PA1、PB1、PC1....分为一个引脚,其他的引脚也是这样的分类,我们配置引脚为中断接受引脚后,AFIO会将这个引脚设置为对应的名字,然后将这个引脚发送给EXTI进行检测和控制,这里可以看到上图有一个16,代表的是只能接受16个引脚。

1.2 EXTI边缘检测

当配置好后,就可以将配置的引脚设置进EXTI中进行配置模式,配置好后进入NVIC进行配置抢占优先级和响应优先级。

1.3 NVIC优先级配置

到NVIC中就开始配置优先级,当优先级配置好后,NVIC就会让配置好的这个中断进行执行。

这样就是一个中断的执行过程,下面就是介绍一下配置了。

2.配置stm32的中断

了解了上面的那些元器件,接下来就是代码的配置实现了。

1.打开时钟

我们在做32的时候要,无论是做什么都需要打开对应的时钟,打开后才能正常的使用。

在上面的硬件介绍中我们了解到,需要打开GPIO的时钟、AFIO的时钟。

为什么不打开EXTI和NVIC的时钟呢?因为EXTI是和GPIO在一起的,当打开了GPIO的时钟,EXTI的时钟就打开了,而NVIC是在内核中的,这个时钟是在单片机启动有时钟时就可以直接使用,所以不用再麻烦的打开时钟进行操作。

AFIO的时钟是属于APB2中的,所以打开时钟的代码也很简单:

RCC_APB2PriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

其中RCC_APB2Periph_GPIOx是你要开启的GPIO口的时钟,这里就不具体举例子了。

2.配置GPIO口

打开时钟后就可以配置GPIO口了,一般我们使用GPIO口来接受中断信号,所以需要配置GPIO口,配置的方法之前在将IO口的操作时已经讲了,主要是GPIO口该是什么模式来进行接受呢?

其实和输入一样,如果这个按钮是接地,那这个就设置为上拉输入,如果是接电源,那就下拉输入:

GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;   // 这里默认为接地
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_x;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOx, &GPIO_InitStruct);

3.配置AFIO控制

配置完成后我们接下来AFIO控制,了解过AFIO的都知道,AFIO是GPIO重映像的一个部件,在32中有一些引脚有一个重映像功能,如果我们需要使用到这个重映像的话就需要使用AFIO进行重映像配置。

在这也是,其实你可以理解为将接受中断信号的引脚重映像为中断引脚,配置的方法很简单,只需要使用下面的一个语句就可以了:

GPIO_EXTILineConfig(GPIO_PortSourceGPIOx, GPIO_PinSourcex);

其中GPIO_PortSourceGPIOx是GPIO组,如果要设置为GPIOB的,那这里就写GPIO_PortSourceGPIOB

GPIO_PinSourcex是GPIO口中需要配置的引脚,比如说是12引脚,那这里就填写GPIO_PinSource12

4.配置EXTI功能

配置完成AFIO后现在就要来配置EXTI中断控制器了,配置方法其实和GPIO口的配置一样,首先创建一个结构体,然后配置结构体中的内容,然后交给初始化函数就可以了,配置代码如下:

EXTI_InitTypeDef EXTI_InitStruct = {0};
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;   // 设置中断模式
EXTI_InitStruct.EXTI_LineCmd = ENABLE;    // 使能中断通道
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;     // 触发模式
EXTI_InitStruct.EXTI_Line = EXTI_Linex;   // 设置通道
EXTI_Init(&EXTI_InitStruct);

其中EXTI_Linex是设置通道,比如上面设置12引脚为中断模式,那这里就填写EXTI_Line12即可。

5.配置NVIC

现在需要配置个NVIC就可以将stm32的中断配置完成了,配置NVIC的步骤也是和配置GPIO一样,但是在设置之前需要给NVIC一个分组,这个分组的作用是设置抢占优先级和响应优先级的范围,每个组的抢占和响应可选的值不一样,下面是分组对应的优先级的范围:

组名 抢占优先级 响应优先级
NVIC_PriorityGroup_0 0~4 0
NVIC_PriorityGroup_1 0~3 0~1
NVIC_PriorityGroup_2 0~2 0~2
NVIC_PriorityGroup_3 0~1 0~3
NVIC_PriorityGroup_4 0 0~4

配置的代码如下:

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

这里设置是组二,这个设置NVIC的组只有设置的第一次有用,如果你在其他再次调用了这个函数,组配置的不一样那也不会进行更改,相当于只要执行了一次这个函数就再也修改不了了,设置完成后就可以开始配置NVIC了:

NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;    // 选择启用的IRQ通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;   // 设置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;          // 设置响应优先级
NVIC_Init(&NVIC_InitStruct);

这里需要注意一下,这里的抢占和响应的优先级如果超过了配置的组中的优先级,那会出问题,不要超过即可。

这里EXTI15_10_IRQn是设置启用的通道,前面配置的通道需要在这变为IRQ通道,这里可以在源码中进行查看对应的通道,比如说我配置的是2引脚,那么这里写EXTI2_IRQn

这里就写完配置中断的代码了,全部的代码如下:

6.配置完整代码

// 开启时钟
RCC_APB2PriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);    // 这里需要对应的GPIO口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);// 配置GPIO口
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;   // 这里默认为接地
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_x;    // 这里需要写响应的引脚
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOx, &GPIO_InitStruct);// 配置AFIO
GPIO_EXTILineConfig(GPIO_PortSourceGPIOx, GPIO_PinSourcex);    // 这里需要写具体的GPIO口和引脚// 配置EXTI
EXTI_InitTypeDef EXTI_InitStruct = {0};
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;   // 设置中断模式
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStruct.EXTI_Line = EXTI_Linex;   // 这里需要写具体的通道
EXTI_Init(&EXTI_InitStruct);// 配置NVIC组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_x);  // 这里要写具体的组// 配置NVIC
NVIC_InitStruct.NVIC_IRQChannel = EXTI15_10_IRQn;    // 选择启用的IRQ通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;   // 设置抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;          // 设置响应优先级
NVIC_Init(&NVIC_InitStruct);

配置完成中断后,stm32知道要执行中断了,但是中断的内容却没有,就比如你现在看到字条了,你知道要写文章了,已经停止做项目的操作了,但是你不知道该写什么文章,所以我们现在要做的就是告诉32,你触发了这个中断后要进行什么操作。

这一步就叫做写中断服务函数,让它接收到这个中断后能转去执行对应的函数和内容。

3.书写中断服务函数

这里中断服务函数的函数名不是想叫什么就可以叫什么的,而是在启动文件中已经标注好了的,我们只需要给它拿下来就可以了

img

这里可以看到很多,我们找在NVIC配置好的那个IRQ通道的名称的就可以了,比如是EXTI2_IRQn,那这里我们要的是EXTI2_IRQHandler,一样的道理,这里就以这个EXTI2_IRQHandler举例子,那我们开始写函数:

void EXTI2_IRQHandler(void)
{}

这样中断函数就写好了,现在就是需要在里面填写内容了,内容一般是自己来规定的,但是有一些内容需要写好,首先是判断中断标志位,要判断一下是不是这个引脚触发的,函数如下:

EXTI_GetITStatus(EXTI_Linex);

EXTI_Linex是设置的通道,然后这个函数的返回值是SETRESET,当触发时返回SET,没触发时返回RESET

然后就是清除中断标志位,要手动进行一次复位,使得下一次能够正常的进行触发,函数如下:

EXTI_ClearITPendingBit(EXTI_Linex);

我们在中断服务函数中就先写好这样的代码:

void EXTI2_IRQHandler(void)
{if (EXTI_GetITStatus(EXTI_Linex) == SET){// 你自己的代码// ===========EXTI_ClearITPendingBit(EXTI_Linex);}
}

中断服务函数可以写在任意的位置,不需要在main函数中进行调用,这个中断函数的调用又系统来进行。

总结

在中断函数中尽量不要执行一些耗费大量时间的内容,我一般是使用变量来进行控制,控制变量然后在main函数中判断这个变量的值,然后才执行相应的操作,一般我用中断来进行按键的控制,因为这个效率比较高,但是抖动问题还是比较严重的,可以用做其他的地方。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/773250.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VS2022创建C C++ GTEST工程

原因 需要对带代码进行单元测试,选择在Visual studio 中使用GTEST 框架。 实施 创建一个常规的控制台可执行程序。然后使用NUGET安装包 安装GTEST 头文件和动态库,同时安装GTEST ADAPTER。安装可能提示找不到包源,此时需要根据提示配置一下,注意通配符很关键,不要问为甚吗…

攻防世界-简单的图片

攻防世界-简单的图片 1 首先拿到图片是一张非常朴实的图片用010打开发现没什么特别之处因为是png图片猜测是lsb隐写,这里一开始我用的zsteg发现提取不全用Stegsolve打开看看,尝试了半天发现什么特殊信息,最后发现位平面顺序即bit plane order这一选项要选择BGR,得到下图发现…

Logisim-006-2路选择器16位

仓库地址 https://gitee.com/gitliang/logisim-to-cpu

安装系统时没有网络无法完成设置进入系统

按下键盘上的 shift+f10 打开 命令提示符。在命令提示符中输入: oobe\bypassnro 然后按下回车(Enter按键),将重启电脑。根据指引进行设置。进行到下述界面时点击“我没有Internet链接”。然后点击“继续执行受限设置”。根据指引完成设置,进入系统。出处:微软社区问答 h…

工时管理必备:年度最佳软件推荐

国内外主流的10款工时软件对比:PingCode、Worktile、Monday.com、Todoist、GanttPro、TimeCamp、MyBatis、U8+ ERP、金蝶、用友软件。在选择合适的工时软件时,许多企业面临着如何从众多选项中找到最适合自己需求的系统的挑战。这个选择过程往往令人头疼,因为一个不合适的决定…

羽毛球比赛积分系统02

羽毛球比赛积分系统 1、产品愿景目标用户 学校的体育工作人员(老师、教练、裁判),学生和教师选手,赛事组织者,志愿者等羽毛球比赛的参与者。他们的需要或机会简化赛事安排和管理。 提高比赛的公正性和透明度。 实时掌握比赛成绩和排名。 增强赛事互动和参与体验。产品名称…

to do list

数学 图论 数据结构李超线段树dp动态dp字符串manacher语法科技(永远不嫌多)应该没人看吧,那我挂张奇怪的图本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18328919

CQOI2024AFO记——一半的奇迹

假的退役记居然那么多人看,吓得我赶紧把真的传上来了。我依然可以骄傲地说,我从未后悔过选择OI。一些微不足道的小事 day -?????? tyl:你会写退役记吗? 我:肯定会的。 day -????? 那个心碎的下午。我是最后一个离开的。Chery:唉,多好的孩子。少了点什么呢? (停…

vs2015+Qt环境问题汇总

1、出现一下莫名奇妙的qt头文件编译报错可能原因是Qt版本太高,建议降低版本,VS2015与Qt5.12.9可以编译通过 2、出现无法运行rc.exe错误左边项目资源管理器中右击-->属性-->常规->>目标平台选择8.13、打开.ui界面文件后提示打开错误  1、右击ui文件,然后点【添…

Verilog连续赋值、过程赋值、过程连续赋值总结

最近总是遇到systemverilog的赋值问题,查看了一下手册发现SV的赋值方式总的还是继承了verilog的赋值方式,而且verilog赋值方面的资料比较多,所以就写了先写一篇关于verilog的赋值总结。 连续赋值 连续赋值就是一旦赋值,输出将随输入改变而变化,一旦修改输入则立刻体现在输…

简单题 加强版

由简单版中,我们已经推出了 \[\sum_{d=1}^n\mu^2(d)d^{k+1}\sum_{t=1}^{\lfloor {\frac{n}{d}} \rfloor}\mu(t)t^k\sum_{i=1}^{\lfloor {\frac{n}{dt}} \rfloor}\sum_{j=1}^{\lfloor {\frac{n}{dt}} \rfloor}(i+j)^k \]我们设\(T=td\),则 设\(S(x)=\sum_{i=1}^x\sum_{j=1}^x(i…