STM32CubeMX外部中断

news2025/1/18 9:07:03

建议提前学习:使用STM32CubeMX实现按下按键,电平反转;

目录

EXTI

中断

中断的概念

抢占优先级与响应优先级

 中断分组

事件

上升沿,下降沿以及双边沿触发

上升沿,下降沿以及双边沿的概念

上升沿,下降沿以及双边沿触发

EXTI中断/事件线

中断服务函数

NVIC

中断的流程框图

STM32CubeMX配置

电路图分析

引脚配置

K2中断配置 

K1按键下拉输入

LED1和LED2配置为输出

 生成文件

Keil编写程序 

__HAL_GPIO_EXTI_GET_IT()

作用

__HAL_GPIO_EXTI_GET_IT()内部实现

使用说明

__HAL_GPIO_EXTI_CLEAR_IT()

作用

__HAL_GPIO_EXTI_CLEAR_IT()内部实现

使用

中断分组的函数在哪里

中断函数

哪里可以查看中断服务函数名字

STM32CubeMX为我们生成的中断服务函数在哪里

代码

宏定义部分

while(1)中代码

中断服务函数


EXTI

STM32的EXTI有事件中断两种形式。

推荐一个文档:事件与中断区别;

中断:一定会有一个中断函数需要执行。有CPU的参与

事件:事件可以没有函数,他不需要CPU参与。事件可以触发一些操作,比如触发DMA,触发ADC采样等等。

中断

中断的概念

首先,我们需要了解什么是中断。我们都知道,程序都是按照我们编写的顺序进行的,从上到下依次进行。但是很显然,这样会导致程序运行很死板,无法处理突发事件。于是就有了中断。

CPU你可以理解为一个非常听话的人,他会完美的按照你的指令执行任务,但是又过于死板。举个例子:

(1)假设你有一个小孩。你跟小孩说让他做完作业再出房间看电视。

(2)按照正常情况,他是先做完作业,然后出房间,最后看电视。但是你这个时候有紧急事情要处理,要出去有点事要处理,但是现在你在厨房做菜。如果你直接就折磨走了,显然会造成事故。怎么办呢?

(3)于是你就让小孩停止做作业,出来做饭。但是我说了,小孩认为做饭不是他的事情,不听你的。于是你拿出皮带,强行要求小孩做饭。(有点小残忍呀,嘿嘿)

这个打断小孩做作业,让他做饭,就叫做中断

(4)然后小孩做完饭做了一半,你回来了。就让小孩再去做作业?你想吃饭时间再让他去做作业,很显然太残忍。于是你让他先看电视去休息。

这个打断小孩做饭(第一层中断),他还没做完饭(第一层中断还没有完成)就让他去看电视(第二层中断),叫做中断嵌套

抢占优先级与响应优先级

一个中断响应有抢占优先级响应优先级。有什么区别呢?

抢占优先级(概念)抢占优先级就和他的名字一样。很霸道,如果我的抢占优先级比你高,那么我就打断你现在的行为,让你做其他事情不需要等待正在执行的中断执行完

(举例)依旧拿上面这个小孩作为例子,打断小孩做饭(第一层中断),他还没做完饭就让他去看电视(第二层中断),这个叫做中断嵌套,同时也体现了,第二层中断的抢占优先级高于第一层中断。

响应优先级(概念)响应优先级就是等待响应,他不会突然打断现在执行的中断。如果有一个中断正在执行,这个时候先后来了两个中断,这三个中断的抢占优先级是一样的。那么就先等待第一个正在执行的中断执行完,然后判断后来的两个中断响应优先级,响应优先级高的任务先执行。

(举例)假设你现在下班了,同时有两个选择,第一个是打一小时游戏,第二个是陪女友逛街。显然打游戏的优先级高于陪女友逛街。那么你就会先打一小时游戏,等一个小时之后再去陪女友逛街。这种先执行一个任务,再执行另外一个任务,这个就体现了响应优先级。

 如果来了两个中断,首先我们判断它的抢占优先级(也可以叫做主优先级),如果抢占优先级一致。那么才开始判断响应优先级(也可以叫做从优先级)。

需要注意的一点是,抢占优先级0比抢占优先级1要大,响应优先级0比响应优先级1大

 中断分组

stm32的中断是存在分组的,有5种分组方式。如果我们选择了分组2,那么抢占优先级只有0-3,不存在抢占优先级4。

事件

依旧是上面这个例子

现在小孩(CPU)在看电视,但是突然来了一个上门快递。你(硬件)去开门签收快递。

这个过程小孩没有参与(CPU),全过程交给了你(硬件)。这个叫做事件

 我暂时还没用过事件,我所能想到的是通过事件触发ADC,然后利用DMA将数据存入SRAM。

此章节只讲中断!!!

上升沿,下降沿以及双边沿触发

上升沿,下降沿以及双边沿的概念

上升沿:低电平到高电平的这个过程

下降沿:高电平到低电平的这个过程

双边沿:上升沿+下降沿

上升沿,下降沿以及双边沿触发

这个触发表示,发生上升沿或者下降沿才会触发中断。具体是怎么触发,这个需要我们自己配置。

EXTI中断/事件线

EXTI 有 20 个中断/事件线,每个 GPIO 都可以被设置为输入线,占用 EXTI0 至 EXTI15,还有另外4根用于特定的外设事件。

我们需要注意一个点,就是如果我们PA0设置为外部中断引脚,那么PB0就不能为中断引脚。因为所有PIN0都公用同一根中断线

 

中断服务函数

外部中断虽然有16根中断,但是外部中断服务函数却只有7个。EXTI0—EXTI4五个中断线分别各占一个中断服务函数。但是EXTI5—EXTI9这5个中断线公用一个中断服务函数,EXTI10—EXTI15这6个中断线公用一个中断服务函数

NVIC

所有中断最后都是由NVIC才处理,这里涉及到内核相关知识了,属于我的知识盲区。感兴趣的可以去看CM3内核的NVIC部分内容。

总结:记住所有中断由NVIC处理即可,他与内核有关

中断的流程框图

不知道与或非门概念的,看:二值逻辑变量与基本逻辑运算;

使用中断之前,我建议先了解一下STM32F103的中断机制,以上升沿触发为例,如下

看不懂没关系,接着往下看,你记住那几个函数什么时候使用就行。但是有基础的建议看完,之后接触其他型号的单片机上手更快

(1)边缘检测电路检测输入线,如果检测到上升沿,上升沿触发选择寄存器将会置1。这里需要注意,我们这里使用的是外部中断,非软件中断,所以软件中断事件寄存器为0。(软件中断就是定时器中断,ADC中断等等)但是这是或门,所以有1出1。2处输出为1

(2)因为我们是中断,而非事件,所以事件屏蔽寄存器位0。与门是有0出0,所以与门2输出为0

(3)因为我们使用的是中断,所以中断屏蔽寄存器要设置为1。(这个在GPIO初始化的时候就已经设置好了)

(4)因为断屏蔽寄存器已经为1了。现在我们2处的或门输出为1,那么与门1输出1给NVIC,这个时候将会触发中断。

STM32CubeMX配置

实验要体现中断,我打算利用,按下按键K1,绿灯电平反转,然后while等待。这个时候将K2配置为中断,按下K2,蓝灯和绿灯电平都反转。(注意,如果K2不是中断,K1没有松手,无论你怎么按K2都没有现象改变呀。因为会堵死在while循环里面,一直等待你K1松手)

电路图分析

首先我们看电路图都知道按下按键为高电平。那么我们可以设置K2为上升沿触发。K1为下拉输入。 

引脚配置

K2中断配置 

(1)第一步,配置GPIO模式

配置中断的时候,GPIO mode里面有6个选项

(1)前面三个表示中断,后面三个是事件。 

(2)第一个是上升沿触发中断,第二个是下升沿触发中断,第三个是双边升沿触发中断

(3)第四个是上升沿触发事件,第五个是下升沿触发事件,第六个是双边升沿触发事件

然后配置为下拉。注意

(1)在标准库里面,外部中断要配置成输入。这里HAL库虽然没说GPIO是输出还是输入,但是我们需要知道,外部中断是要配置成输入

(2)

如果我们是上升沿触发,输入要配置为下拉或者无上下拉。

如果我们是下升沿触发,输入要配置为上拉或者无上下拉。

如果我们是双边升沿触发,上下拉配置随便。

(2)第二步,配置NVIC(这个专门负责中断的)

∆ 这里我们需要配置中断分组(这个随便你自己怎么配置,只要注意抢占优先级和响应优先级符合中断分组就行)

∆ 建议把按照抢占优先级和响应排序打开,这样我们就能直观的知道中断顺序。(这里需要注意一个点,我们只开启了PC13的中断,但是怎么会有折磨多中断呢?原因是因为其他中断是系统中断,不需要理会

∆ 使能中断需要勾选,如果你没有勾选,中断也就不会产生。

∆ 5和6分别是配置抢占优先级和响应优先级的。

这里有一个东西需要注意!!!我是写写程序验证实验的时候才发现的!!!

Time base: System tick timer的抢占优先级要高于(不能等于)外部中断的优先级。否则会出现在外部中断中无法调用延时函数的情况。(HAL_Delay()这个函数是滴答定时器,使用的是滴答定时器中断实现的。只需了解)

K1按键下拉输入

LED1和LED2配置为输出

因为LED是外接高电平,所以引脚初始化为高电平输出。否则你刚开机,灯就已经亮了。

GPIO配置

 生成文件

如果还不会生成文件的,看:STM32CubeMX新建工程并点亮一个LED;的文件生成部分

Keil编写程序 

我们先介绍它的函数使用,再进行程序编写吧。此处我们只会讲解需要用到的函数,其他的不怎么常用的,等各位入门了自己可以研究。

这里会涉及到中断的流程框图的内容,如果没看懂的人,直接看函数的使用说明即可。

__HAL_GPIO_EXTI_GET_IT()

作用

(1)获取中断线的是否发起中断请求。这个是什么意思呢?

(2)上面我说了,EXTI0—EXTI4五个中断线分别各占一个中断服务函数。但是EXTI5—EXTI9这5个中断线公用一个中断服务函数。那么就会出现一个问题,现在我PA5和PA7两个引脚都有中断,当其中一个引脚发生中断,他们会同时进入相同的中断服务函数EXTI9_5_IRQHandler

(3)那么这个时候__HAL_GPIO_EXTI_GET_IT()这个函数的作用就有了,我们可以在EXTI9_5_IRQHandler这个中断函数里面先进行一个if判断,是哪一个中断线发生中断请求。

__HAL_GPIO_EXTI_GET_IT()内部实现

 __HAL_GPIO_EXTI_GET_IT()其实不是一个函数,而是一个宏定义。如下

/**
  * @brief  Checks whether the specified EXTI line is asserted or not.
  * @param  __EXTI_LINE__: specifies the EXTI line to check.
  *          This parameter can be GPIO_PIN_x where x can be(0..15)
  * @retval The new state of __EXTI_LINE__ (SET or RESET).
  */
#define __HAL_GPIO_EXTI_GET_IT(__EXTI_LINE__) (EXTI->PR & (__EXTI_LINE__))

(1)我们看这个宏定义,发现其实它是对PR这一个寄存器进行操作,那么我们可以尝试翻阅STM32F103数据手册。发现PR这一个寄存器可以查看中断是否被挂起。让我们让PR寄存器&(有0 出0)对应的PIN脚(比如GPIO_PIN_13就是0x2000,正好对应PR13),那么就可以获取这一个中断线是否有中断请求。(这里看不懂,直接看后面,这一部分是给有基础的人看的。我最后面会告诉你们什么时候需要使用,记住即可。

(2)这个PR就是挂起寄存器,如果外部来了符合我们设置的脉冲,那么这个寄存器将会被挂起,也就是输出为1。(结合上面那个流程图)

这个PR有32bit,但是只有前20bit被使用,这一一对应了20根中断/事件线。如果是中断/事件线13发生中断响应,那么PR13将会被挂起(也就是1)

(3)我们可以通过读取PR,来确认到底是拿一根中断/事件线发生了中断响应。这样就很好的处理了EXTI5—EXTI9这5个中断线公用一个中断服务函数,EXTI10—EXTI15这6个中断线公用一个中断服务函数的尴尬问题。

使用说明

//EXTI15_10的中断服务函数
void EXTI15_10_IRQHandler(void) 
{
    //确保是否产生了 EXTI Line 13中断
    if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_13) != RESET)
     {

     }
}

__HAL_GPIO_EXTI_CLEAR_IT()

作用

(1)外部中断的PR寄存器发生了触发信号之后,会被置1。使用完之后PR寄存器并不会自己清0。

(2)这样将会导致一个问题,PR(挂起寄存器)一直为1,然后中断屏蔽寄存器在GPIO配置的时候就已经置1了。就会导致,会持续向NVIC中断控制器发起请求,中断会持续进行,进行完这次中断之后,再重新进行一次这个中断

(3)因为我们只希望来一次触发信号,就执行一次中断。而不是来一次触发信号,就一直执行中断。所以我们就要使用__HAL_GPIO_EXTI_CLEAR_IT()来清除PR寄存器。

__HAL_GPIO_EXTI_CLEAR_IT()内部实现

 我们看下面__HAL_GPIO_EXTI_CLEAR_IT()的内部实现,发现很有意思的一点,就是__HAL_GPIO_EXTI_CLEAR_IT()不是一个函数

我们发现是向PR寄存器相应位写入1,才是清除标志位,写0没反应。所以这里是等于!!! 

/**
  * @brief  Clears the EXTI's line pending bits.
  * @param  __EXTI_LINE__: specifies the EXTI lines to clear.
  *          This parameter can be any combination of GPIO_PIN_x where x can be (0..15)
  * @retval None
  */
#define __HAL_GPIO_EXTI_CLEAR_IT(__EXTI_LINE__)      (EXTI->PR = (__EXTI_LINE__))

使用

void KEY1_IRQHandler(void)
{
    //确保是否产生了 EXTI Line 13中断
    if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_13) != RESET)
     {
        ...
        //清除中断标志位
        __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_13);
     }
}

中断分组的函数在哪里

很多人都是从学习标准库转到HAL库的,所以我这里说一下STM32CubeMX的中断分组在哪里。纯新手可以了解一下。

//1,点击这个函数,按F12
HAL_Init();

//2,跳转到这个函数之后,往下翻,会看见这一行。注意我配置的中断分组为4

  /* Set Interrupt Group Priority */
  HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

中断函数

哪里可以查看中断服务函数名字

STM32的中断服务函数都是由指定名称的。比如外部中断线EXTI10到15引起中中断,会进入EXTI15_10_IRQHandler这个中断服务函数。那么我们应该如何寻找我们的对应中断服务函数呢?

STM32CubeMX为我们生成的中断服务函数在哪里

代码

现在各位应该已经了解了STM32的外部中断的。我就直接上代码

宏定义部分

/* Private defines -----------------------------------------------------------*/
#define K2_Pin GPIO_PIN_13
#define K2_GPIO_Port GPIOC
#define K2_EXTI_IRQn EXTI15_10_IRQn
#define K1_Pin GPIO_PIN_0
#define K1_GPIO_Port GPIOA
#define LED_G_Pin GPIO_PIN_0
#define LED_G_GPIO_Port GPIOB
#define LED_B_Pin GPIO_PIN_1
#define LED_B_GPIO_Port GPIOB

while(1)中代码

  while (1)
  {
    /* USER CODE END WHILE */
			if(HAL_GPIO_ReadPin(K1_GPIO_Port,K1_Pin) == SET)
			{
				//软件消抖,延时20ms,如果按键并联了电容,就不用考虑这个
				HAL_Delay(20);
				if(HAL_GPIO_ReadPin(K1_GPIO_Port,K1_Pin) == SET)
				{
					//按下K1,绿灯亮
					HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin);
				}
				//等待松手
				while(HAL_GPIO_ReadPin(K1_GPIO_Port,K1_Pin) == SET);
			}
    /* USER CODE BEGIN 3 */
  }

中断服务函数

void EXTI15_10_IRQHandler(void)
{
	//确保是否产生了 EXTI Line 13中断
	if (__HAL_GPIO_EXTI_GET_IT(K2_Pin) != RESET)
	 {
            //再次强调!!!Time base: System tick timer的抢占优先级要高于(不能等于)外部中断的优先级
			//软件消抖,延时20ms,如果按键并联了电容,就不用考虑这个
			HAL_Delay(20);
		 //判断是不是K2被按下
		 if(HAL_GPIO_ReadPin(K2_GPIO_Port,K2_Pin) == SET)
		 {
		 		//按下K2,绿灯灭,蓝灯亮,
				HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin);
				HAL_GPIO_TogglePin(LED_B_GPIO_Port, LED_B_Pin);
		 }
			//清除中断标志位
			__HAL_GPIO_EXTI_CLEAR_IT(K2_Pin);
	 }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构-双链表思路解析及代码实现

双链表是单链表的进阶版,单链表是1-2-3-4 一个个排排坐链接,只管向后拉手,其主要思想是当前节点与下一节点的关系,那么双链表就多了一层关系,当前节点不仅和一下一点连起来,也要和上一节点串联起来。与前与…

【全志T113-S3_100ask】13-1 Linux c语言ioctl驱动oled(iic、ssd1306)屏幕

【全志T113-S3_100ask】13-1 Linux C通过ioctl驱动oled[ssd1306]屏幕 背景(一)i2c关键结构体1、i2c_rdwr_ioctl_data结构体2、struct i2c_msg结构体(二)i2c关键代码1、写函数2、读函数(三)对oled的操作&…

深度学习和神经网络的介绍(一)

1、深度学习和神经网络 1.1 深度学习的介绍 目标: 知道什么是深度学习知道深度学习和机器学习的区别能够说出深度学习的主要应用场景知道深度学习的常见框架 1.1.1 深度学习的概念 深度学习是机器学习的分支,是一种以人工神经网络为架构&#xff0c…

计算机网络4小时速成:计算机网络基础,计网组成,计网分类,性能指标,标准化组织,计网结构模型,五层模型

计算机网络4小时速成:计算机网络基础,计网组成,计网分类,性能指标,标准化组织,计网结构模型,五层模型 2022找工作是学历、能力和运气的超强结合体,遇到寒冬,大厂不招人&…

05_TCP并发服务器

知识点1【TCP并发服务器】 1、多线程(常用) 2、解决上述问题:端口复用 仅仅是端口的复用 3、并发服务器 多进程实现 总结: 知识点2【HTTP协议】 HTTP基于TCP 1、HTTP协议的概述 2、Webserver 通信过程 3、Web编程开发 知识…

Cadence orcad 批量设置原理图标题栏

前言 作为一份规范的原理图文件,必须要有Title Block,一般是在右下角的原理图信息,包括标题,图纸尺寸,设计师,时间,页码等等。 这里需要两个操作: 一、批量修改Title Block的信息 …

Go语言进阶篇,单元测试、基准测试的性能测试、内存占用测试

在go语言中的单元测试比较有意思,比如测试一个函数是很方便的,只需要将文件名修改为_test.go这样的后缀即可,我们新建一个目录xxx,然后新建xxx_test.go文件,当然这个xxx的名字你可以按照功能来命名,如下&am…

Java开发:多线程编程

本章篇幅主要记录多线程编程相关的知识,如有纰漏,望指出。 话不多说,正式开启多线程之旅... 目录 一、多线程使用方式 A、Thread B、Runnable(推荐) C、Callable 二、线程的五个状态 三、线程停止 四、线程休…

LabVIEW性能和内存管理 7 LabVIEW中局部和全局变量的内存分配

LabVIEW性能和内存管理 7 LabVIEW中局部和全局变量的内存分配 本文介绍LabVIEW性能和内存管理的几个建议7。 LabVIEW Cleanup – LabVIEW cleans upmany references when the owning VI goes idle and others when the process closes – Manually closereferences t…

Bean的作用域和生命周期

1. Bean 的作用域 对于全局变量,局部变量等的作用域相信大家都已经很清楚了,但是对于对象作用域有点摸不着头脑,下面通过一个简单的案例,康康对象的作用域 1.1 案例引入 现有一个公共的 Bean 对象 package com.bean.model;import org.springframework.stereotype.Componen…

【IEEE2017】RL:机器人库:一种面向对象的机器人应用程序的方法

RL:机器人库:一种面向对象的机器人应用程序的方法 摘要: 摘要:我们讨论了机器人库(RL)的架构和软件工程原理。在机器人系统、研究项目、工业应用和教育的需求的驱动下,我们确定了相关的设计需求…

linux上如何搭建Java环境

一 linux软件安装常用的方式对比 Linux下的软件安装,主要有如下三种,“正规”程度依次递减: 1、使用标准的yum/apt/yast包管理程序安装 2、使用标准rpm/deb或厂商自己的安装包(比如nVidia的显卡驱动用的bin包)安装 …

黑*头条_第2章_文章列表前端成形与后端变身

黑*头条_第2章_文章列表前端成形与后端变身 文章目录黑*头条_第2章_文章列表前端成形与后端变身文章列表前端成形与后端变身学习目标1.前端工程结构1.1 环境准备1.1.1 导入工程1.1.2 测试运行1.2 weex 跨终端前端框架1.3 工程结构说明1.4 源码结构1.5 WEEX UI2.文章列表前端开发…

算法实验题(涉外黄成老师!!!)

日期 2022.11.19 目录 实验报告一 第一题 2 实验报告二 第二题 3 实验报告三 第三题 4 实验报告四 第四题 5 实验报告五 第五题 6 实验报告六 第六题 7 实验报告一 第一题 一、实验目的 由1,3,4,5,7,8这六个数字所组…

剑指 Offer II 021. 删除链表的倒数第 n 个结点【链表】

难度等级:中等 上一篇算法: 82. 删除排序链表中的重复元素 II【链表】 力扣此题地址: 剑指 Offer II 021. 删除链表的倒数第 n 个结点 - 力扣(LeetCode) 1.题目:删除链表的倒数第 n 个结点 给定一个链表&a…

DWGViewX Pro 2021.4.X Crack by Cracki

DWGViewX pro 2021.4.X --Ω578867473 DWGViewX 是一个 ActiveX 组件,可让您在一个查看器中管理和查看 DWG、DXF 和 DWF 工程图。查看 R14 到 2022 版本的 DWG、DXF 和 DWF。加载本地磁盘或网络网站上的图纸,并使用查看器缩放、平移、旋转图纸、打开/关闭…

Java中的线程

线程 什么是线程&#xff1a; 什么是多线程&#xff1a; 学习目的&#xff1a; 多线程的创建 方式一&#xff1a;继承Thread类 public class MyThread{public static void main(String[] args) {Thread thread01 new Thread01();thread01.start();for (int i 0; i < 5; …

翻倍增长!C-V2X商业化“提速”,新一代模组加速“助跑”

C-V2X正在逐步走向商业的规模化部署&#xff0c;由此也带动了C-V2X模组需求的高速增长。 高工智能汽车研究院监测数据显示&#xff0c;今年1-9月中国市场&#xff08;不含进出口&#xff09;乘用车前装标配搭载V2X技术新车交付上险为10.58万辆&#xff0c;同比增长283.33%&…

计算机视觉|投影与三维视觉

这一篇将学习投影与三维视觉&#xff0c;沿用上一篇 计算机视觉|针孔成像&#xff0c;相机内外参及相机标定&#xff0c;矫正的重要性 摄像机内参数矩阵M、畸变参数、旋转矩阵R、平移向量T以及但影响矩阵H。回顾放射和投影变换&#xff0c;并使用POSIT算法从一幅图像中查找获得…

基于stm32单片机有害气体监测检测Proteus仿真

资料编号&#xff1a;097 下面是相关功能视频演示&#xff1a; 97-基于stm32单片机有害气体监测检测Proteus仿真&#xff08;仿真源码全套资料&#xff09;功能介绍&#xff1a;检测当前的有害气体浓度&#xff0c;LCD1602显示&#xff0c;并且可以自动打开关闭风扇&#xff…