1 、简介

ARM Coetex-M3内核共支持256个中断,其中16个内部中断,240个外部中断和可编程的256级中断优先级的设置。STM32目前支持的中断共84个(16个内部+68个外部),还有16级可编程的中断优先级的设置,仅使用中断优先级设置8bit中的高4位。

STM32可支持68个中断通道,已经固定分配给相应的外部设备,每个中断通道都具备自己的中断优先级控制字节PRI_n(8位,但是STM32中只使用4位,高4位有效),4个通道的8位中断优先级控制字构成一个32位的优先级寄存器。68个通道的优先级控制字至少构成17个32位的优先级寄存器。

4bit的中断优先级可以分成2组,从高位看,前面定义的是抢占式优先级,后面是响应优先级。按照这种分组,4bit一共可以分成5组

  • 第0组:所有4bit用于指定响应优先级;
  • 第1组:最高1位用于指定抢占式优先级,后面3位用于指定响应优先级;
  • 第2组:最高2位用于指定抢占式优先级,后面2位用于指定响应优先级;
  • 第3组:最高3位用于指定抢占式优先级,后面1位用于指定响应优先级;
  • 第4组:所有4位用于指定抢占式优先级。

所谓抢占式优先级和响应优先级,他们之间的关系是:具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套。

当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。每一个中断源都必须定义2个优先级。

有几点需要注意的是:

  1. 如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结果;
  2. 抢占式优先级别相同的中断源之间没有嵌套关系;
  3. 如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个中断源指定任意有效的响应优先级别。

2 、GPIO外部中断

STM32中,每一个GPIO都可以触发一个外部中断,但是,GPIO的中断是以组为一个单位的,同组间的外部中断同一时间只能使用一个。比如说,PA0,PB0,PC0,PD0,PE0,PF0,PG0这些为1组,如果我们使用PA0作为外部中断源,那么别的就不能够再使用了,在此情况下,我们只能使用类似于PB1,PC2这种末端序号不同的外部中断源。每一组使用一个中断标志EXTIx。EXTI0 – EXTI4这5个外部中断有着自己的单独的中断响应函数,EXTI5-9共用一个中断响应函数,EXTI10-15共用一个中断响应函数。

线 0~15:对应外部 IO 口的输入中断。

GPIO引脚 中断标志位 中断处理函数
PA0~PG0 EXTI0 EXTI0_IRQHandler
PA1~PG1 EXTI1 EXTI1_IRQHandler
PA2~PG2 EXTI2 EXTI2_IRQHandler
PA3~PG3 EXTI3 EXTI3_IRQHandler
PA4~PG4 EXTI4 EXTI4_IRQHandler
PA5~PG5 EXTI5 EXTI9_5_IRQHandler
PA6~PG6 EXTI6  
PA7~PG7 EXTI7  
PA8~PG8 EXTI8  
PA9~PG9 EXTI9  
PA10~PG10 EXTI10 EXTI15_10_IRQHandler
PA11~PG11 EXTI11  
PA12~PG12 EXTI12  
PA13~PG13 EXTI13  
PA14~PG14 EXTI14  
PA15~PG15 EXTI15  

线 16:连接到 PVD 输出。

线 17:连接到 RTC 闹钟事件。

线 18:连接到 USB 唤醒事件。

对于中断的控制,STM32有一个专用的管理机构:NVIC。

3、 程序开发

上面那些概念只是对STM32的中断系统有一个大概的认识,用程序说话将会更能够加深如何使用中断。使用外部中断的基本步骤如下:

  1. 设置好相应的时钟;
  2. 设置相应的中断;
  3. IO口初始化;
  4. 把相应的IO口设置为中断线路(要在设置外部中断之前)并初始化;
  5. 在选择的中断通道的响应函数中中断函数

由于我用的开发板没有引出相应的芯片引脚,所以只能用按键来触发相应的中断。根据原理图,K0/K1/K2连接的是PF2/PF3/PF4,因此我将用EXTI2/EXTI3/EXTI4三个外部中断。PG13/PG14/PG15分别连接了三个LED灯。中断的效果是按下按键,相应的LED灯将会被点亮。

3.1、设置相应的时钟

首先需要打开GPIOG和GPIOF(因为按键另外一端连接的是PF口)。然后由于是要用于触发中断,所以还需要打开GPIO复用的时钟(需要用到外设的重映射功能时才需要使能AFIO的时钟)。相应的函数在GPIO的学习笔记中有了详细了解释。详细代码如下:

void RCC_cfg()
{//打开PG PF端口时钟,并且打开复用时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG | RCC_APB2Periph_GPIOF  | RCC_APB2Periph_AFIO, ENABLE);
}

  设置相应的时钟所需要的RCC函数在stm32f10x_rcc.c中,所以要在工程中添加此文件

3.2、设置好相应的中断

设置相应的中断实际上就是设置NVIC,在STM32的固件库中有一个结构体NVIC_InitTypeDef,里面有相应的标志位设置,然后再用NVIC_Init()函数进行初始化。详细代码如下:

void NVIC_cfg()
{NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);            //选择中断分组2NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQChannel;     //用3.5的库所有IQRChannel全部变成IQRn选择中断通道2NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //抢占式中断优先级设置为0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;         //响应式中断优先级设置为0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //使能中断NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQChannel;     //选择中断通道3NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  //抢占式中断优先级设置为1NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;         //响应式中断优先级设置为1NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //使能中断NVIC_Init(&NVIC_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel;     //选择中断通道5NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //抢占式中断优先级设置为2NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;         //响应式中断优先级设置为2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //使能中断NVIC_Init(&NVIC_InitStructure);
}

用3.5的库,所有的USART1_IRQChannel,全部变成:USART1_IRQn。  

#include<stm32f10x_lib.h>和#include<stm32f10x.h>的区别:

  1. #include<stm32f10x_lib.h>是ST公司V2.0的库函数使用的头文件,
  2. #include<stm32f10x.h>是ST公司V3.5及以后版本统一使用的库函数头文件了,说白了就是把原来的stm32f10x_lib.h,换成了#include<stm32f10x.h>,规范了代码,不需要包含那么多的头文件了。

由于有3个中断,因此根据前文所述,需要有3个bit来指定抢占优先级,所以选择第2组。又由于EXTI5-9共用一个中断响应函数,所以EXTI5选择的中断通道是EXTI9_5_IRQChannel,详细信息可以在头文件中查询得到。用到的NVIC相关的库函数在stm32f10x_nivc.c中,需要将此文件复制并添加到工程中。

3.3、IO口初始化
void IO_cfg()
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;                          //选择引脚2GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                 //输出频率最大50MHzGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                      //带上拉电阻输出GPIO_Init(GPIOE,&GPIO_InitStructure);GPIO_ResetBits(GPIOE,GPIO_Pin_2);                                    //将PE.2引脚设置为低电平输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4; //选择引脚2 3 4GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;               //选择输入模式为浮空输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                   //输出频率最大50MHzGPIO_Init(GPIOF,&GPIO_InitStructure);                                 //设置Pf.2/PF.3/PF.5GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14|GPIO_Pin_15; //选择引脚13,14,15GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出频率最大50MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //带上拉电阻输出 GPIO_Init(GPIOD,&GPIO_InitStructure);
}

其中连接外部中断的引脚需要设置为输入状态,而连接LED的引脚需要设置为输出状态,初始化PE.2是为了使得按键的另外一端输出低电平。GPIO中的函数在stm32f10x_gpio.c中。

3.4、 把相应的IO口设置为中断线路

由于GPIO并不是专用的中断引脚,因此在用GPIO来触发外部中断的时候需要设置将GPIO相应的引脚和中断线连接起来,具体代码如下:

void EXTI_cfg()
{EXTI_InitTypeDef EXTI_InitStructure;//清空中断标志EXTI_ClearITPendingBit(EXTI_Line2);EXTI_ClearITPendingBit(EXTI_Line3);EXTI_ClearITPendingBit(EXTI_Line4);//选择中断管脚PF.2 PF.3 PF.4GPIO_EXTILineConfig(GPIO_PortSourceGPIOF, GPIO_PinSource2);GPIO_EXTILineConfig(GPIO_PortSourceGPIOF, GPIO_PinSource3);GPIO_EXTILineConfig(GPIO_PortSourceGPIOF, GPIO_PinSource4);EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3 | EXTI_Line4; //选择中断线路2 3 4EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;       //设置为中断请求,非事件请求EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //设置中断触发方式为上下降沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;                       //外部中断使能EXTI_Init(&EXTI_InitStructure);
}
EXTI_cfg中需要调用到的函数都在stm32f10x_exti.c。

3.5、写中断响应函数

STM32不像C51单片机那样,可以用过interrupt关键字来定义中断响应函数,STM32的中断响应函数接口存在中断向量表中,是由启动代码给出的。默认的中断响应函数在stm32f10x_it.c中。因此我们需要把这个文件加入到工程中来。

在这个文件中,我们发现,很多函数都是只有一个函数名,并没有函数体。我们找到EXTI2_IRQHandler()这个函数,这就是EXTI2中断响应的函数。我的目标是将LED灯点亮,所以函数体其实很简单:

void EXTI2_IRQHandler(void)
{//点亮LED灯GPIO_SetBits(GPIOG,GPIO_Pin_13);//清空中断标志位,防止持续进入中断EXTI_ClearITPendingBit(EXTI_Line2);
}void EXTI3_IRQHandler(void)
{GPIO_SetBits(GPIOG,GPIO_Pin_14);EXTI_ClearITPendingBit(EXTI_Line3);
}void EXTI4_IRQHandler(void)
{GPIO_SetBits(GPIOG,GPIO_Pin_15);EXTI_ClearITPendingBit(EXTI_Line5);
}

  由于EXTI5-9是共用一个中断响应函数,因此所有的EXTI5 – EXTI9的响应函数都写在这个里面。

3.6、 写主函数
#include "stm32f10x_lib.h"void RCC_cfg();
void IO_cfg();
void EXTI_cfg();
void NVIC_cfg();int main()
{RCC_cfg();IO_cfg();NVIC_cfg();EXTI_cfg();while(1);
}

 main函数前是函数声明,main函数函数体中都是调用初始化配置函数,然后进入死循环,等待中断响应 

大部分参考:http://blog.sina.com.cn/s/blog_49cb42490100rp7b.html

转载于:https://www.cnblogs.com/happying30/p/9440130.html

STM32(3)——外部中断的使用相关推荐

  1. STM32单片机外部中断配置讲解

    2019独角兽企业重金招聘Python工程师标准>>> 单片机外部中断简介 所谓外部中断,就是通过外部信号所引起的中断,如单片机引脚上的电平变化(高电平.低电平).边沿变化(上升沿. ...

  2. STM32的“外部中断”和“事件”区别和理解

    凡从事过ST MCU应用开发的人往往会遇到事件.中断事件 中断三个概念或术语.这三个概念彼此关联,有时会让人有点混淆或犯迷糊. 先拿一件生活中的事情打比方对上述三个概念做个基本的粗略理解,之后再分享一 ...

  3. 【STM32】外部中断实验代码详解

    文章目录 main.c exit.c exit.h STM32 的每个 IO 都可以作为外部 中断的中断输入口,这点也是 STM32 的强大之处. STM32F103 的 19 个外部中断为: 线 0 ...

  4. STM32开发 -- 外部中断详解

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/87376865 在讲三轴加速度计的时候,提到外部中断.接下来就看看中断为什么这 ...

  5. 【STM32】外部中断

    00. 目录 文章目录 00. 目录 01. 外部中断简介 02. 外部中断配置 03. 外部中断步骤 04. 硬件设计 05. 程序示例一 06. 程序示例二 07. 附录 08. 声明 01. 外 ...

  6. STM32之外部中断原理

    STM32 的每一个GPIO都能配置成一个外部中断触发源,这点也是 STM32 的强大之处.STM32 通过根据引脚的序号不同将众多中断触发源分成不同的组,比如:PA0,PB0,PC0,PD0,PE0 ...

  7. STM32单片机---外部中断

    外部中断 一.ARM Cortex-M3 的中断体系 二.代码思路 函数接口 1.为引脚选择使用哪个中断 2.配置外部中断 3.中断优先级配置 4.获取外部中断状态 5.清空外部中断标志位 中断优先级 ...

  8. STM32 EXTI外部中断及NVIC的抢占优先级和响应优先级解释

    1.中断类型 从之前的串口实验可以看出,STM32总共分为内部中断和外部中断,内部和外部的配置差别不是很大,外部中断只是多了一步,需要通过 GPIO_EXTILineConfig(uint8_t GP ...

  9. 蓝桥杯嵌入式学习STM32之外部中断EXTI详解

    先说点题外话. !是取逻辑反的意思, ~是按位取反的意思 !0x01=0: ~0x01=1111 1110; 进入正题 基本概念 STM32的每个IO都可以作为外部中断输入. STM32的中断控制器支 ...

  10. STM32 EXTI外部中断/事件

    一.EXTI外部中断/事件功能框图 1.中断线路:①-②-③-④-⑤ ①输入线:有19个中断/事件输入线(联网型有20个),通过寄存器将这些输入线设置为任意一个GPIO. ②边沿检测电路:选择上升沿触 ...

最新文章

  1. matlab中rat=1函数,matlab中的format rat是什么意思
  2. Python第三章-字符串
  3. 网络共享服务(三)之SAMBA
  4. Premiere Pro CC2019安装资料及安装教程
  5. Arcgis API for JavaScript在地图上实现手机定位信息的追踪显示
  6. 给老板汇报技术规划的一些要点
  7. 【Transformer】TransMix: Attend to Mix for Vision Transformers
  8. 二. linux基础命令
  9. Oracle 之instant client
  10. java大津法确定阈值,大津法得到自适应阈值
  11. C语言基础课第三次作业
  12. Galera集群server.cnf参数调整--前言
  13. win10下 switchhost权限修改问题
  14. mac电脑如何设置开机启动项
  15. 四川农大2020计算机专业录取分数线,四川农业大学2020年美术类本科专业录取分数线...
  16. (转)清华博士王垠的退学申请——研究生,无论你想不想搞研究,都该读读这篇文章。
  17. win10 按用户名访问计算机,win7访问win10系统时需要输入用户名密码的两种解决方法...
  18. java实现的俄罗斯方块游戏--powered by dustin
  19. QT 怎么获取linux本机的IP地址?
  20. 每日一题:现在你在玩一款游戏,叫做节奏大师。它有三种判定

热门文章

  1. tableSizeFor的理解
  2. Ping++ 牵手招商银行,正式为商户开放一网通支付渠道
  3. 快递鸟 物流跟踪订阅 即时查询快递 预约取件(在线下单)
  4. 【个人提升】如何克服惰性
  5. java 正则 惰性匹配_js正则表达式惰性匹配和贪婪匹配用法分析
  6. Linux网络——部署yum仓库
  7. 服务器开通网站来宾帐户,IIS 增加Internet来宾用户权限
  8. 2022年家用投影仪推荐 当贝F5和坚果J10S哪款画质更好?
  9. python自动化模拟浏览器
  10. 远程登陆服务器跑深度学习程序