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); //选择中断分组2 NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQChannel; //用3.5的库所有IQRChannel全部变成IQRn选择中断通道2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQChannel; //选择中断通道3
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占式中断优先级设置为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应式中断优先级设置为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure); NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel; //选择中断通道5
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占式中断优先级设置为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //响应式中断优先级设置为2
NVIC_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; //选择引脚2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出频率最大50MHz
GPIO_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 4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //选择输入模式为浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出频率最大50MHz
GPIO_Init(GPIOF,&GPIO_InitStructure); //设置Pf.2/PF.3/PF.5 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14|GPIO_Pin_15; //选择引脚13,14,15
GPIO_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.4
GPIO_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 4
EXTI_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

STM32(3)——外部中断的使用的更多相关文章

  1. STM32的外部中断配置及使用

    STM32的外部中断配置及使用 配置1:GPIO: 配置外部中断为输入模式: 配置2:EXTI: 配置外部中断线和触发模式: 配置3:NVIC: 配置外部中断源和中断优先级: 需要注意的是:RCC_A ...

  2. STM32 GPIO外部中断总结

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

  3. STM32之外部中断控制

    一.STM32外部中断 1.STM32外部中断结构图 如上图所示:主要包括四个环节,GPIO.AFIO.EXTI.NVIC.以STM32F103VE(100脚)为例说明硬件模块的数量: GPIO:   ...

  4. 浅谈stm32的外部中断

    简述 本文简单介绍stm32外部中断的一般操作步骤,后续会补充外部中断的相关内容 stm32的中断控制器支持19个外部中断/事件请求: line0~line15:这16条line分别对应不同GPIO口 ...

  5. STM32之外部中断

    图1.0 图1.1 中断控制器支持23条中断线,其中16条是IO管脚中断线,分别是EXTI0~EXTI15:  图 1.2 另外七根中断线如下图: 中断线和管脚的对应关系:EXTI0~EXTI15 和 ...

  6. STM32之EXTI——外部中断

    互联网的广大网友,大家早上中午晚上好.EXTI...故名思义..EX表外,出..I表示Intrrupt..所以合起来就是外部中断...说到这..我觉得我最近的六级水平(背单词)又进了一步,稍微自夸了下 ...

  7. 转别人的 STM32外部中断使用注意事项

    前言:这些问题都是我之前在工作中遇到的,后来觉得需要总结,自己记忆不好,所以在这个给自己打个mark. 一:触发方式 STM32 的外部中断是通过边沿来触发的,不支持电平触发: 二:外部中断分组 ST ...

  8. stm32寄存器版学习笔记03 外部中断

    stm32的每个I/O口都可以作为中断输入,要把I/O口设置为外部中断输入,必须将I/O口设置为上拉/下拉输入 或 浮空输入(但浮空的时候外部一定要带上拉或下拉电阻,否则可能导致 中断不停的触发),干 ...

  9. stm32 外部中断学习

    今天我们看看STM32的外部中断实验. STM32 供 IO 口使用的中断线只有 16 个,但是 STM32 的 IO 口却远远不止 16 个,那么 STM32 是怎么把 16 个中断线和 IO 口一 ...

  10. STM32 外部中断详解(原理+配置代码)

    本文介绍了STM32基于标准外设库的外部中断配置,以及基于参考手册如何更加寄存器配置外部中断 文章目录 1 前言 2 STM32的外部中断 3 中断服务函数的映射关系 4 外部中断的配置 5 寄存器的 ...

随机推荐

  1. matlab练习程序(Hilbert图像置乱)

    正好刚写了Hibert生成曲线,不如再加一篇应用的程序. 关于Hilbert图像置乱,我在网上搜的应用领域主要集中在数字水印和图像加密上,而这两个领域我都没怎么接触过. 大部分的图像置乱都是如下图的置 ...

  2. 服务器bios&raid管理

    新服务器配置流程 https://github.com/alces-software/knowledgebase/wiki/server-dell-rseries-r630 dell DTK(sysc ...

  3. Tcpdump usage examples

    In most cases you will need root permission to be able to capture packets on an interface. Using tcp ...

  4. SqlServer存储过程示例

    /* 步骤1 删除本地及海关单证待分派表.报关单表中的数据 delete from W_DOCUMENTS; delete from W_DOCUMENTS_TEST; delete from W_D ...

  5. 【Leetcode】【Easy】Valid Palindrome

    Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignori ...

  6. June 16th 2017 Week 24th Friday

    Progress is the activity of today and the assurance of tomorrow. 进步是今天的活动,明天的保证. The best preparatio ...

  7. python接口测试-项目实践(四)拼接出预期结果

    四 字符串拼接 空值处理 当某字段接口数据为空,则不显示相关字串. 比如字串原本是 "...,净资产收益率:ROE%",当接口数据中ROE为空,不显示',净资产收益率:%' 三目运 ...

  8. PCI PCI-X PCI-E介绍

    1.PCI 外设互联标准(或称个人电脑接口,Personal Computer Interface),实际应用中简称PCI(Peripheral Component Interconnect),是一种 ...

  9. 从零开始Vue项目实战(一)-准备篇

    从前参与过一个react项目的代码编写,大神搭建的框架,我主要负责业务逻辑代码编写,现在回想起来似乎又什么都不会,现在为了巩固前端知识,决定用Vue来做这个项目的移动端网站,我本人Vue是从零开始的, ...

  10. POJ 2531 深搜剪枝

    题意:全局最大割. 分析:有相应的算法,数据量很小,可以枚举源点,汇点,最大流. 这里用DFS,状态定义:分成两个集合,刚开始S集合全部点,然后一个一个放,这是一个回溯的过程. 没剪枝也过了. 剪枝技 ...