外部中断的使用

STM32学习笔记:外部中断的使用

中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在C51单片机时代,一共只有5个中断,其中2个外部中断,2个定时/计数器中断和一个串口中断,但是在STM32中,中断数量大大增加,而且中断的设置也更加复杂。今天就将来探讨一下关于STM32中的中断系统。

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共用一个中断响应函数。

对于中断的控制,STM32有一个专用的管理机构:NVIC。对于NVIC的详细解释,可以参考《ARM Cortex-M3权威指南》,Joseph Yiu著,宋岩译,北京航空航天大学出版社出版,第8章NVIC与中断控制。中断的使能,挂起,优先级,活动等等部都是NVIC在管理的。因为我学习STM32重点在于如何开发程序,所以内部的一些东西,在此我就不详细说明了,有感兴趣的可以参看上面提到的那本数。

3 程序开发

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

1. 设置好相应的时钟;

2. 设置相应的中断;

3. IO口初始化;

4. 把相应的IO口设置为中断线路(要在设置外部中断之前)并初始化;

5. 在选择的中断通道的响应函数中中断函数。

由于我用的奋斗开发板没有引出相应的芯片引脚,所以只能用按键来触发相应的中断。根据原理图,K1/K2/K3连接的是PC5/PC2/PC3,因此我将用EXTI5/EXTI2/EXTI3三个外部中断。PB5/PD6/PD3分别连接了三个LED灯。中断的效果是按下按键,相应的LED灯将会被点亮。

1、设置相应的时钟

首先需要打开GPIOB、GPIOC和GPIOE(因为按键另外一端连接的是PE口)。然后由于是要用于触发中断,所以还需要打开GPIO复用的时钟。相应的函数在GPIO的学习笔记中有了详细了解释。详细代码如下:

void RCC_cfg() {    //打开PE PD PC PB端口时钟,并且打开复用时钟    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOC |  RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); }  设置相应的时钟所需要的RCC函数在stm32f10x_rcc.c中,所以要在工程中添加此文件。

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;  //选择中断通道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 = EXTI9_5_IRQChannel;  //选择中断通道5    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占式中断优先级设置为2   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  //响应式中断优先级设置为2   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          //使能中断    NVIC_Init(&NVIC_InitStructure);  }  由于有3个中断,因此根据前文所述,需要有3个bit来指定抢占优先级,所以选择第2组。又由于EXTI5-9共用一个中断响应函数,所以EXTI5选择的中断通道是EXTI9_5_IRQChannel,详细信息可以在头文件中查询得到。用到的NVIC相关的库函数在stm32f10x_nivc.c中,需要将此文件复制并添加到工程中。具体位置可以查看关于GPIO的笔记。这段代码编译起来没有任何问题,但是在链接的时候就会报错,需要把STM32F10xR.LIB加入工程中,具体位置在…\Keil\ARM\RV31\LIB\ST\STM32F10xR.LIB。

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_5; //选择引脚2 3 5   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //选择输入模式为浮空输入   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //输出频率最大50MHz    GPIO_Init(GPIOC,&GPIO_InitStructure);           //设置PC.2/PC.3/PC.5         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6;     //选择引脚3 6    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //输出频率最大50MHz   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;     //带上拉电阻输出    GPIO_Init(GPIOD,&GPIO_InitStructure);        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;             //选择引脚5    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //输出频率最大50MHz   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //带上拉电阻输出    GPIO_Init(GPIOB,&GPIO_InitStructure);      }  其中连接外部中断的引脚需要设置为输入状态,而连接LED的引脚需要设置为输出状态,初始化PE.2是为了使得按键的另外一端输出低电平。GPIO中的函数在stm32f10x_gpio.c中。

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

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

具体代码如下: void EXTI_cfg() {   EXTI_InitTypeDef EXTI_InitStructure;   //清空中断标志    EXTI_ClearITPendingBit(EXTI_Line2);   EXTI_ClearITPendingBit(EXTI_Line3);    EXTI_ClearITPendingBit(EXTI_Line5);    //选择中断管脚PC.2 PC.3 PC.5    GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2);   GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource3);   GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5);    EXTI_InitStructure.EXTI_Line = EXTI_Line2 | EXTI_Line3 | EXTI_Line5; //选择中断线路2 3 5   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。

5. 写中断响应函数

STM32不像C51单片机那样,可以用过interrupt关键字来定义中断响应函数,STM32的中断响应函数接口存在中断向量表中,是由启动代码给出的。默认的中断响应函数在stm32f10x_it.c中。因此我们需要把这个文件加入到工程中来。  在这个文件中,我们发现,很多函数都是只有一个函数名,并没有函数体。我们找到EXTI2_IRQHandler()这个函数,这就是EXTI2中断响应的函数。我的目标是将LED灯点亮,所以函数体其实很简单: void EXTI2_IRQHandler(void) {   //点亮LED灯    GPIO_SetBits(GPIOD,GPIO_Pin_6);   //清空中断标志位,防止持续进入中断   EXTI_ClearITPendingBit(EXTI_Line2); }  void EXTI3_IRQHandler(void)  {   GPIO_SetBits(GPIOD,GPIO_Pin_3);   EXTI_ClearITPendingBit(EXTI_Line3);  }  void EXTI9_5_IRQHandler(void) {   GPIO_SetBits(GPIOB,GPIO_Pin_5);   EXTI_ClearITPendingBit(EXTI_Line5); }  由于EXTI5-9是共用一个中断响应函数,因此所有的EXTI5 – EXTI9的响应函数都写在这个里面。

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函数函数体中都是调用初始化配置函数,然后进入死循环,等待中断响应。

时间: 2024-11-07 08:05:16

外部中断的使用的相关文章

《零死角玩转STM32》-17-EXTI外部中断/事件控制器

/* * 本文中的相关图片来自火哥的教程,只作为随笔记录,无侵权之意 * 21:25:46, 2017-04-08 */ EXTI:外部中断/事件控制器.STM32F429共有23根,其中EXTI0~EXTI15,分别对应GPIO中的PX0 ~ PX15,另外7根线有如下用途: (中间省略了EXTI1 ~ EXTI15) EXTI功能框图如下所示: 按照图中的序号标识,可以清晰的看出外部GPIO引脚上的电平变化是如何传递到内核,即GPIO -> EXTI -> NVIC,并触发相应的中断/事件

掌握所有IO口的外部中断

外部中断配置流程 1.初始化IO口工作在普通IO.上拉输入状态. 2.首先开IO口组中断(P0IE=1.P1IE=1.P2IE=1): 3.开组内对应的具体某IO口中断(P0IEM.P1IEM.P2IEM该寄存器里面的对应位对应相应的IO口): 4.上升沿还是下降沿触发(PICTL寄存器): 5.开CPU总中断EA=1; #include <cc2530.h> void main() { //步骤1 P0SEL &=0xDF;//P05口表示为普通IO口 P0DIR &=0xD

STM32外部中断

0.STM32F103上测试 #include <stm32f10x.h> void GPIO_Config(void); void NVIC_Config(void); void EXTI_Config(void); int main(void) { GPIO_Config(); NVIC_Config(); EXTI_Config(); while(1): } void GPIO_Config(void) { /*定义一个GPIO_InitTypeDef类型的结构体,本类型在stm32f1

[ZYNQ-7]PS处理PL外部中断的简单实例的剖析 (参考米联miz702n)

Zynq的ARM通过GIC中断控制器来接收核仲裁所有的中断.由于中断向量表只有4Bytes大小,仅仅正好存放一条跳转语句,因此当产生一个外部中断时,中断处理的大致过程:PC内容保存到LR_IRQ用于中断返回,拷贝CPSR到SPSR_IRQ以反应中断模式,屏蔽其他中断,紧接着将PC设置为中断向量表入口.CPU完成现场保护.确认中断源,并调用相关的中断处理函数.恢复CPSR,恢复CPU现场,中断返回. main.c of simplified Interrupt instance (from miz

STM32F4——NVIC中断优先级及外部中断

NVIC中断优先级 一.简介: CM4内核可以支持256个中断,包括16个内核中断和240个外部中断,256级的可编程中断设置.对于STM32F4没有用到CM4内核的所有东西,只是用到了一部分,对于STM32F40和41系列共有92个中断,其中有10个内核中断和82个可屏蔽中断,常用的为82个可屏蔽中断. 二.相关寄存器: ISER[8]-中断使能寄存器组,用来使能中断,每一位控制一个中断,由于上面已经说明了控制82个可屏蔽的中断,因此利用ISER[0~2]这三个32位寄存器就够了.一下的几个寄

LPC1768外部中断与GPIO中断

LPC1768的外部中断严格来说只有四个,分别是EINT0,EINT1,EINT2,EINT3,技术手册上有如下说明 控制这四个外部中断靠以下寄存器 这三个寄存器的0 1 2 3位分别代表中断的0 1 2 3,EXTINT寄存器表示中断是否发生,在发生中断的时候该寄存器会置位,可以通过写1清零,EXTMODE寄存器表示触发模式,有电平触发和变化沿触发两种,EXTPOLAR与EXTMODE,在电平触发模式下,决定高电平还是低电平触发,在变化沿触发的情况下决定上升沿还是下降沿触发 这三个中断分别相关

CC2540开发板学习笔记(三)&mdash;&mdash;外部中断

一.实验内容 通过外部中断方式依次按下按键S1控制LED1的亮灭 二.实验过程 1.电路原理图同上 2.中断的概念 比如说我们在执行main函数时,突然来了个指令.优先级比现在执行的main还高,那我们便选择跳过去执行优先级高的,完了之后再执行main函数,中断就类似这样一个概念,使用中断可以减少CPU的无效浪费,降低能耗. 3.寄存器调度 (1)LED1的初始化..同前两节,就是SEL,DIR,INP三个,还有附初始状态. (2)外部中断初始化(S1的外部中断初始化) 按键S1外部中断初始化方

中断之外部中断

. ARM Cortex M3共有256个中断. STM32F103CB共有43个外部中断和16个内部中断. 具有相同数值编号的IO口被分配为同一组,共用一条中断请求线,如下图: 所以共有15条中断线,另外 ●EXTI线16连接到PVD输出●EXTI线17连接到RTC闹钟事件●EXTI线18连接到USB唤醒事件 寄存器:1.外部中断配置寄存器    AFIO_EXTxCR1------->用于选择输入中断源  Pin 0..3 AFIO_EXTxCR2------->用于选择输入中断源  Pi

28335外部中断

/*****************************************************************************Copyright: 2014,TkaiFile name: main.cDescription:28335外部中断测试Author: Version: v1.0Date: 2014.05.27History: 无*****************************************************************

STM32——外部中断EXIT实现

外部中断实现步骤: 一.初始化,包括:1.AFIO时钟中断和GPIO时钟使能:                          2.GPIO初始化                          3.设置EXTI线                          4.中断向量初始化 二.中断服务函数 采用PB9作为外部中断源,具体实现程序如下: 一.初始化 1 void EXTI_PB9_Init(void) 2 3 { 4 5 GPIO_InitTypeDef GPIO_InitStru