STM32学习笔记(2):外部中断的使用
- 格式:docx
- 大小:23.16 KB
- 文档页数:7
Stm32 学习笔记3—外部中断1、外部中断程序编写方法①时钟(RCC)初始化②I/O端口初始化③EXTI 配置,在这里配置需要选择哪个引脚作为中断引脚④NVIC 配置,这也是比单片机多出来的部分,我们必须把NVIC 中对应的通道使能,并且设置优先级别⑤编写中断处理程序2、EXTI配置void exti_config(){EXTI_InitTypeDef EXTI_InitStructure;GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);/*设置PA0作为中断线路*//*EXTI_ClearITPendingBit(EXTI_Line0); */EXTI_InitStructure.EXTI_Line = EXTI_Line0; /*设置外部中断线0*/EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;/*设置线路为中断请求*/EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; /*下降沿触发*/EXTI_InitStructure.EXTI_LineCmd = ENABLE;/*线路使能*/EXTI_Init(&EXTI_InitStructure);/*初始化中断*/}①EXTI_InitTypeDef 结构体EXTI_InitTypeDef定义于文件“stm32f10x_exti.h”:typedef struct {u32 EXTI_Line;EXTIMode_TypeDef EXTI_Mode;EXTIrigger_TypeDef EXTI_Trigger;FunctionalState EXTI_LineCmd;} EXTI_InitTypeDef;参数说明EXTI_Line16连接PVD输出,EXTI_Line17连接RTC报警事件,EXTI_Line18连接USB唤醒EXTI_LineCmd设为ENABLE或者DISABLE②函数GPIO_EXTILineConfig:选择GPIO管脚用作外部中断线路原型:void GPIO_EXTILineConfig(u8 GPIO_PortSource, u8 GPIO_PinSource)输入:GPIO_PortSource: 选择用作事件输出的GPIO端口原型:void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)输入:参见结构EXTI_InitTypeDef3、NVIC配置void nvic_config(){NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);/*配置主从优先级*/NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;/*外部中断线0*/NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; /*抢断优先级*/NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; /*从优先级*/NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);/*初始化NVIC*/}①NVIC_InitTypeDef structureNVIC_InitTypeDef定义于文件“stm32f10x_nvic.h”:typedef struct{u8 NVIC_IRQChannel;u8 NVIC_IRQChannelPreemptionPriority;u8 NVIC_IRQChannelSubPriority;FunctionalState NVIC_IRQChannelCmd;} NVIC_InitTypeDef;参数说明:NVIC_IRQChannel设置NVIC_IRQChannel中的先占优先级。
STM32之外部中断EXTISTM32中断控制线支持19个外部中断/事件请求,每个中断都有对应状态位和独立的触发与屏蔽设置。
STM32F103的19个外部中断为:线0-15:对应GPIO口的输入中断。
线16:连接到PVD输出(掉电检测,掉电时可立即保存重要数据作用)。
线17:连接RTC闹钟事件。
线18:连接到USB唤醒事件。
每个IO口都可作为外部中断输入口的STM32的IO口远多于16个,而IO口使用的中断线只有16个。
为此,GPIO管脚GPIOx.0~GPIOx.15(X=A,F,G)分别对应中断线0-15.这样每个中断线对应了7个IO口。
如线0对应着GPIOA.0,GPIOB.0,GPIOC.0,GPIOD.0,GPIOE.0,GPIOF.0,GPIOG.0但是每个中断线每次只能连接到1个IO口上。
这样就需要通过相关的配置来决定对应的中断线被配置到哪个GPIO上了。
GPIO和中断线的映射关系如下图:GPIO与中断映射配置通过函数来实现void GPIO_EXTILineConfig (uint8_t GPIO_PortSource,uint8_t GPIO_PinSource)例如:GPIO_EXTILineConfig(GPIO_PortSourceGPIOE , GPIO_PinSource2);即外部中断线2就和GPIOE映射起来了,显然是GPIOE.2与EXTI2中断线连接起来了。
接着需设置中断触发方式:void EXTI_Init (EXTI_InitTypeDef * EXTI_InitStruct)例如:EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line=EXTI_Line4;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);以上例子设置了中断线line4的中断为下降沿触发。
STM32 外部中断配NVIC_Configuration 函数实现配置嵌套向量中断中断优先级并使能中断。
其中的NVIC_PriorityGroupConfig 函数配置中断优先级的组织方式,STM32 的嵌套向量中断控制器可以配置16 个可编程的优先等级,使用了4 位表示中断优先级(2 的4 此方就是16),16 个可编程的优先等级又可以分为主优先级和次优先级,例如参数NVIC_PriorityGroup_1表示1bit 主优先级(pre-emption priority)3 bits 次优先级(subpriority )。
一、配置中断1、分配中断向量表:/* Set the Vector Table base location at 0x20000000 */NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);2、设置中断优先级:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置中断优先级3、初始化外部中断:/*允许EXTI4中断*/NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQChannel; //中断通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= PreemptionPriorityValue; //占先优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应(次级)优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道中断使能NVIC_Init(&NVIC_InitStructure); //初始化中断注意:如果我们配置的外部针脚为PA4,或PB4,或PC4,PD4等,那么采用的外部中断也必须是EXTI4,同样,如果外部中断针脚是PA1,PB1,PC1,PD1 那么中断就要用EXTI1,其他类推。
STM32中外部中断与外部事件这张图是一条外部中断线或外部大事线的暗示图,图中信号线上划有一条斜线,旁边标记19字样的注释,表示这样的线路共有19套。
图中的蓝色虚线箭头,标出了外部中断信号的传输路径,首先外部信号从编号1的芯片管脚进入,经过编号2的边沿检测,通过编号3的或门进入中断“挂起哀求寄存器”,最后经过编号4的与门输出到NVIC 中断控制器;在这个通道上有4个控制选项,外部的信号首先经过边沿检测电路,这个边沿检测电路受升高沿或下降沿挑选寄存器控制,用户可以用法这两个寄存器控制需要哪一个边沿产生中断,由于挑选升高沿或下降沿是分离受2个平行的寄存器控制,所以用户可以同时挑选升高沿或下降沿,而假如惟独一个寄存器控制,那么只能挑选一个边沿了。
接下来是编号3的或门,这个或门的另一个输入是“软件中断/大事寄存器”,从这里可以看出,软件可以优先于外部信号哀求一个中断或大事,既当“软件中断/大事寄存器”的对应位为“1”时,不管外部信号如何,编号3的或门都会输出有效信号。
一个中断或大事哀求信号经过编号3的或门后,进入挂起哀求寄存器,到此之前,中断和大事的信号传输通路都是全都的,也就是说,挂起哀求寄存器中记录了外部信号的电平变幻。
外部哀求信号最后经过编号4的与门,向NVIC中断控制器发出一个中断哀求,假如中断屏蔽寄存器的对应位为“0”,则该哀求信号不能传输到与门的另一端,实现了中断的屏蔽。
明了了外部中断的哀求机制,就很简单理解大事的哀求机制了。
图中红色虚线箭头,标出了外部大事信号的传输路径,外部哀求信号经过编号3的或门后,进入编号5的与门,这个与门的作用与编号4的与门类似,用于引入大事屏蔽寄存器的控制;最后脉冲发生器把一个跳变的信号改变为一个单脉冲,输出到芯片中的其它功能模块。
在这张图上我们也可以知道,从外部激励信号来看,中断和大事是没有分离的,只是在芯片内部分开,一路信号会向CPU产生中断哀求,另一路信号会向其它功能模块发送脉冲触发信号,其它功能模块如何相应这个触发信号,则由对应的模块自己打算。
使用HAL库开发STM32GPIO口基础使用与外部中断GPIO(General Purpose Input/Output)是STM32系列微控制器上常见的功能模块之一,它用于与外部设备进行数据交互。
本文主要介绍如何使用HAL库来配置和使用STM32的GPIO口,并实现外部中断功能。
在使用GPIO口之前,我们首先需要了解STM32芯片上的GPIO引脚的命名方式。
以STM32F103C8T6为例,它具有32个GPIO引脚,从PA0到PA15和PB0到PB15、其中,GPIO口的命名方式为"A"加上引脚的编号。
例如,PA0表示GPIOA的第0个引脚,PB10表示GPIOB的第10个引脚。
1.引入头文件和宏定义首先,在代码文件的顶部引入"stm32f1xx_hal.h"头文件。
然后,在需要使用GPIO功能的地方,定义一个GPIO_InitTypeDef结构体变量,并通过它来配置GPIO的参数。
2.配置GPIO模式和速度在设置GPIO口之前,需要配置GPIO的模式和速度。
通过设置GPIO_InitStruct结构体变量的对应成员变量来实现。
例如,要将PA5配置为推挽输出模式,可以使用如下语句:```GPIO_InitStruct.Pin = GPIO_PIN_5;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);```这里,GPIO_PIN_5表示PA5引脚,GPIO_MODE_OUTPUT_PP表示推挽输出模式,GPIO_SPEED_FREQ_HIGH表示高速模式。
3.配置GPIO引脚在配置好GPIO模式和速度后,可以通过HAL_GPIO_Init函数来配置GPIO引脚,并进行初始化。
EXTI外设STM32有76个中断,包括16个内核中断和60个可屏蔽外部中断,具有16级可编程的中断优先级。
根据中断触发源的不同,外部中断也是可以分为:●内置外设的触发。
此时,对应的IO口(若为输出)必须设置为复用功能,并使能外设的时钟。
在中断向量表中有53个中断通道与之对应(除下述的7个)。
●如下图所示,在外设方框中有EXTI外设部分,说明了IO口也可以作为中断的触发源,用也检测外部输入信号的边沿变化,在中断向量表中有7个中断通道与之对应分别是:EXTI15_10_IRQ Channel; EXTI9_5_IRQChannel; EXTI4_IRQChannel; EXTI3_IRQChannel; EXTI2_IRQChannel; EXTI1_IRQChannel; EXTI0_IRQChannel。
注意:1.我们知道,当IO口作为通用GPIO时,只能输入或者输出高低电平;若IO口要作为外部中断源,则必须配置为复用AFIO(虽然IO口作为输入时,没有复用一说,但是这里说的配置为复用AFIO是指使能AFIO的时钟)。
2.又见下图,虽然EXTI外设和AFIO外设都是挂在APB2总线上,但是在使用EXTI外设时只需要使能的时钟时AFIO时钟。
(!!!千万别忘记启动RCC_APB2Periph_AFIO!!!,否则管脚只能做普通高低电平来用。
)STM32的EXTI外设控制器寄存器支持19 个外部中断/ 事件请求。
每个中断设有状态位,每个中断/ 事件都有独立的触发和屏蔽设置(IMR和EMR)。
STM32的19个外部中断对应着19路中断线,分别是EXTI_Line0-EXTI_Line18:线0~15:对应外部IO口的输入中断。
线16:连接到PVD 输出。
PVD(Programmable Voltage Detector),即可编程电压监测器。
应用于STM32ARM芯片中,作用是监视供电电压,在供电电压下降到给定的阀值以下时,产生一个中断,通知软件做紧急处理。
野⽕F1开发板STM32案例-外部中断(按键)使⽤野⽕F1开发板STM32案例-外部中断(按键)使⽤硬件平台野⽕STM32F103ZET6 霸道V2开发板正点原⼦F1系列开发板软件平台Keil MDK 5.31串⼝调试助⼿Gitee .中断相关概念中断配置寄存器# 配置中断时,使⽤ISER、 ICER 和 IP 寄存器,## ISER 是中断使能寄存器## ICER 是中断清除寄存器## IP 是中断优先级寄存器中断优先级1. 数值越⼩,优先级越⾼2. STM32F103 中只使⽤4位,⾼4位有效。
3. ⽤于表达优先级的⾼ 4 位⼜被分组成抢占式优先级和响应优先级,称为“亚优先级”或“副优先级”4. 每个中断源都需要被指定这两种优先级。
中断配置步骤1.使能外设中断6. 设置中断优先级分组初始化 NVIC_InitTypeDef 结构体,设置抢占优先级和响应优先级,使能中断请求。
typedef struct{uint8_t NVIC_IRQChannel; //中断源uint8_t NVIC_IRQChannelPreemptionPriority; //抢占优先级uint8_t NVIC_IRQChannelSubPriority; //响应优先级FunctionalState NVIC_IRQChannelCmd; //中断使能或失能} NVIC_InitTypeDef;NVIC_IRQChannel 中断源:中断源的设置,不同的外设中断,中断源不⼀样NVIC_IRQChannelPreemptionPriority //抢占优先级NVIC_IRQChannelSubPriority //响应优先级NVIC_IRQChannelCmd //中断使能或失能:使能配置为 ENABLE,失能配置为 DISABLE。
NVIC_IRQChannel //中断源/****** Cortex-M3 Processor Exceptions Numbers ***************************************************/NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt *//****** STM32 specific Interrupt Numbers *********************************************************/WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */TAMPER_IRQn = 2, /*!< Tamper Interrupt */RTC_IRQn = 3, /*!< RTC global Interrupt */FLASH_IRQn = 4, /*!< FLASH global Interrupt */RCC_IRQn = 5, /*!< RCC global Interrupt */EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */STM32F103 中断向量表EXTI外部中断1. STM32F10x 外部中断/事件控制器(EXTI)包含多达 20 个⽤于产⽣事件/中断请求的边沿检测器。
STM32F4事件和中断使用步骤事件的产生过程和中断的产生过程一样可由EXTI_InitStructure.EXTI_Mode来配置为中断模式或事件模式1中断模式是通过一系列过程产生,然后等待处理器来干某件事情2事件模式是通过一系列过程产生,产生的是一个事件(比如一个方波或唤醒闹钟)外部中断:步骤1 嵌套向量中断控制器 NVIC 配置1)定义中断/事件初始化类型结构体(已定义在misc文件里)NVIC_InitTypeDef NVIC_InitStructure;2)定义在那个中断线NVIC_InitStructure.NVIC_IRQChannel=3)指定中断抢占优先级NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=4)指定中断响应子优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority=5)使能中断通道NVIC_InitStructure.NVIC_IRQChannelCmd=6)调用中断初始化函数NVIC_Init(&NVIC_InitStructure);步骤2 EXTI外部中断/事件控制配置1)定义外部中断/事件初始化结构体EXTI_InitTypeDef EXTI_InitStructure;已定义在xxx_exti文件2)外部中断对应GPIO引脚初始化配置3)启用SYSCFG所在总线的时钟RCC_APB2PeriphClockCmd();已定义在xxx_rcc文件里4)调用步骤1配置NVIC5)连接GPIO引脚到外部中断线SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOx,EXTI_PinSou rcex);已定义在xxx_syscfg文件6)初始化外部中断/事件结构体的成员EXTI_InitStructure.EXTI_Line=EXTI_Linex;//中断线xEXTI_InitStructure.EXTI_Mode=; //中断模式或事件模式xxx_exti文件里EXTIMode_TypeDef结构体EXTI_InitStructure.EXTI_Trigger=; //触发方式上升,下降,边沿在EXTITrigger_TypeDef结构体EXTI_InitStructure.EXTI_LineCmd=ENABLE;//中断线的状态启用或禁用(DISABLE)EXTI_Init(&EXTI_InitStructure);//依据上面的参数初始化已在xxx_exti文件里定义。
STM32外部中断处理流程外部中断是指引发中断的事件来自于MCU外部的输入引脚或外设,需要通过配置寄存器和中断服务程序来处理外部中断。
在STM32系列MCU中,外部中断处理可分为以下几个步骤。
1.配置中断引脚要使用外部中断功能,首先需要配置中断引脚。
对于STM32,外部中断引脚由GPIO口提供,需要通过GPIO配置寄存器设置相关引脚的工作模式、上下拉和中断触发方式等。
具体配置方法可以参考芯片手册。
2.配置中断控制器外部中断的中断源需要连接到中断控制器(NVIC),通过配置NVIC的相关寄存器来使能外部中断。
NVIC是位于ARM Cortex-M内核内部的外设,用于管理和分配中断优先级。
3.编写中断服务程序(ISR)中断服务程序(Interrupt Service Routine, ISR)是用于处理中断事件的函数,当外部中断引发时,MCU会跳转到相应的ISR进行处理。
在编写ISR时,需要注意以下几点:-确定中断源:可以通过读取中断状态寄存器来判断是哪个外部中断引起的中断。
-处理中断事件:根据中断源的不同,进行相应的处理。
例如,可以读取输入引脚状态、处理外设状态等。
-清除中断标志位:要在ISR内部清除中断标志位,以允许MCU再次响应该外部中断。
具体方法是通过读取相应的寄存器或调用相关函数清除中断标志位。
4.配置中断优先级中断优先级用于确定ISR的响应顺序,优先级较高的中断先被处理。
在STM32中,中断优先级可以通过配置中断控制器的相关寄存器进行设置。
5.启用中断在完成上述步骤后,需要启用相应的中断引脚和中断控制器。
具体方法是通过设置GPIO寄存器来使能中断引脚,并通过设置NVIC寄存器来使能相关中断。
6.处理中断请求一旦发生外部中断事件,MCU就会跳转到相应的ISR进行中断处理。
在ISR中,可以根据需要调用其他的函数或执行其他的操作。
处理完成后,可以通过清除中断标志位和退出中断函数来结束中断处理。
中断对于开发嵌入式系统来讲的地位绝对是毋庸置疑的,在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中。