芯达STM32入门系列教程之九《初试STM32中断》
- 格式:pdf
- 大小:564.02 KB
- 文档页数:9
STM32中断和事件库函数:void EXTI_DeInit(void) {EXTI->IMR = 0x00000000;//屏蔽所有中断 EXTI->EMR = 0x00000000;//屏蔽所有事件EXTI->RTSR = 0x00000000; //禁止所有上升沿触发 EXTI->FTSR = 0x00000000; //禁止所有下降沿触发 EXTI->PR = 0x000FFFFF;//挂起位全部清空 }void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct) {该函数接收一个结构体,按照下面的结构体配置EXTI 寄存器 typedef struct {uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled.This parameter can be any combination of @ref EXTI_Lines */EXTI_IMR EXTI_EMREXTI_RTSR EXTI_FTSREXTI_SWIER EXTI_PR写“1”清除读到“1”有请求读到“0”无请求写“0” 屏蔽中断写“1” 开放中断写“0” 屏蔽事件 写“1” 开放事件写“0” 禁止 写“1” 允许上升 写“0” 禁止下降沿触发 写“1” 允许下降沿触发SWIER 写“1”PR 挂起EXTIMode_TypeDef EXTI_Mode; /*!< Specifies the mode for the EXTI lines.This parameter can be a value of @ref EXTIMode_TypeDef */EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines. This parameter can be a value of @ref EXTIMode_TypeDef */FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines.This parameter can be set either to ENABLE or DISABLE */}EXTI_InitTypeDef;uint32_t tmp = 0;tmp = (uint32_t)EXTI_BASE;if (EXTI_InitStruct->EXTI_LineCmd != DISABLE){/* Clear EXTI line configuration 屏蔽中断和事件*/EXTI->IMR &= ~EXTI_InitStruct->EXTI_Line;EXTI->EMR &= ~EXTI_InitStruct->EXTI_Line;tmp += EXTI_InitStruct->EXTI_Mode;*(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line; //开放中断或事件/* Clear Rising Falling edge configuration 禁止上升沿触发和下降沿触发*/EXTI->RTSR &= ~EXTI_InitStruct->EXTI_Line;EXTI->FTSR &= ~EXTI_InitStruct->EXTI_Line;/* Select the trigger for the selected external interrupts */if (EXTI_InitStruct->EXTI_Trigger == EXTI_Trigger_Rising_Falling)//允许上升沿触发和下降沿触发{/* Rising Falling edge */EXTI->RTSR |= EXTI_InitStruct->EXTI_Line;EXTI->FTSR |= EXTI_InitStruct->EXTI_Line;}else//允许上升沿触发或下降沿触发{tmp = (uint32_t)EXTI_BASE;tmp += EXTI_InitStruct->EXTI_Trigger;*(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;}}else//需要配置的线路取反再与Mode或运算,及相应线路的中断屏蔽位或事件屏蔽位写“0”,屏蔽事件或中断{tmp += EXTI_InitStruct->EXTI_Mode;/* Disable the selected external lines */*(__IO uint32_t *) tmp &= ~EXTI_InitStruct->EXTI_Line;}}void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line) //软件中断事件寄存器EXTI_SWIER对应线路写“1”,产生一个软件触发{EXTI->SWIER |= EXTI_Line;}FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line) //读取挂起寄存器PR对应线路的值{FlagStatus bitstatus = RESET;if ((EXTI->PR & EXTI_Line) != (uint32_t)RESET){bitstatus = SET;}else{bitstatus = RESET;}return bitstatus;}void EXTI_ClearFlag(uint32_t EXTI_Line)//挂起寄存器PR对应线路写“1”清除{EXTI->PR = EXTI_Line;}ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)//如果对应线路开放该线路中断,则读取PR的值{ITStatus bitstatus = RESET;uint32_t enablestatus = 0;enablestatus = EXTI->IMR & EXTI_Line;if (((EXTI->PR & EXTI_Line) != (uint32_t)RESET) && (enablestatus != (uint32_t)RESET)){bitstatus = SET;}else{bitstatus = RESET;}return bitstatus;}void EXTI_ClearITPendingBit(uint32_t EXTI_Line) //挂起寄存器PR对应线路写“1”清除{EXTI->PR = EXTI_Line;}从ITStatus EXTI_GetITStatus(uint32_t EXTI_Line)函数和函数名来看,感觉IT是在中断函数中使用的,Flag是在中断和事件中使用的。
STM32中断过程详解对于 STM32 讲(还是以Timer2例),外部中断通道位置 28(35 号优先级)是给外部设备 TIME2 的,但 TIME2本身能够引起中断的中断源或事件有好多个,比如更新事件(上溢/下溢)、输入捕获、输出匹配、DMA 申请等。
所有TIME2 的中断事件都是通过一个 TIME2 的中断通道向 STM32 内核提出中断申请,那么 STM32 中如何处理和控制 TIME2 和它众多的、不同的、中断申请呢?1.因为cortex_m3 内核对于每一个外部中断通道都有相应的控制字和控制位,用于单独的和总的控制该中断通道。
它们包括有:中断优先级控制字:PRI_n(前面有提到过)中断允许设置位:在 ISER 寄存器中中断允许清除位:在 ICER 寄存器中中断悬挂 Pending(排队等待)位置位:在 ISPR 寄存器中(类似于置中断通道标志位)中断悬挂 Pending(排队等待)位清除:在 ICPR 寄存器中(用于清除中断通道标志位)正在被服务(活动)的中断(Active)标志位:在 IABR 寄存器中,(只读,可以知道当前内核正在处理哪个中断通道)2.作为外围设备 TIME2 本身也包括更具体的,管理自己不同中断的中断控制器(位),它们主要是自身各个不同类型中断的允许控制位,和各自相应的中断标志位(STM32 的手册中有详细的说明)。
理解上面两点之后,我们可以全程、全面和综合的来了解 TIME2 的中断过程,以及如何控制的。
①初始化过程首先要设置寄存器 AIRC 中 PRIGROUP 的值,规定系统中的抢先优先级和子优先级的个数(在 4 个 bits 中占用的位数);设置 TIME2 本身的寄存器,允许相应的中断,如允许 UIE(TIME2_DIER 的第[0]位)。
STM32中断系统中断的定义:指当出现需要时,CPU暂时停止当前程序的执行转而执行处理新情况的程序和执行过程。
即在程序运行过程中,系统出现了一个必须由CPU立即处理的情况,此时,CPU暂时中止程序的执行转而处理这个新的情况的过程就叫做中断。
概述ARM Cortex-m3内核支持256个“中断通道”(16个内核+240个外部)和可编程256级中断优先级设置。
STM32采用Cortex-m3内核,但是STM32并没有使用Cortex-m3的全部资源。
STM32目前支持84个“中断通道”(16个内核+68个外部)和可编程16级中断优先级设置。
STM32的外部中断通道已经固定分配给相应的外设。
(参考手册-中断向量表)中断源:触发中断的事件。
中断通道:中断通道是中断源向内核申请中断的入口;中断通道给中断源提供一个向内核申请中断的入口,中断源通过中断通道向内核提出中断申请一个中断通道可以对应多个中断源,也可只对应一个。
有的外设对应多个中断通道,有的只对应一个。
中断优先级是针对中断通道的。
(参考“参考手册”中断和异常向量表)P.130STM32优先级中断优先级是针对“中断向量”的,而不是针对中断源的。
STM32中断优先级:STM32的中断通道可以被配置为响应式优先级或抢占式优先级。
抢占式优先级:抢占式优先级的中断会打断当前的主程序或者中断程序运行(中断嵌套)。
对应每一个中断通道(如TIM2),Cortex-m3内核提供了一个8位的寄存器IP[x] (core_cm3.h),来确定该中断通道的抢占式优先级和响应式优先级。
在一个系统中,优先级的分组只有以下5种情况,具体采用哪一种,需要在初始化时写入到一个32位寄存器AIRC(Application Interrupt and Reset Register)(core_cm3.h)NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//设置优先级分组优先级冲突处理:1. 具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断的嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。
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中断流程处理中断,首先要知道stm32f10x_it.c这个文件,一般情况下是和main文件在同一个目录下的。
打开这个文件,我们可以看到xyz_IRQHandler函数的实现,虽然说是实现,但是几乎都是空的。
对了,这些函数就是要用户填写的中断处理函数,如果你用到了哪个中断来做相应的处理,你就要填写相应的中断处理函数,需要根据各外设的实际情况来填写,但是一般都会有关闭和开启中断。
在这个文件中还有很多系统相关的中断处理函数,例如系统时钟SysTickH andler。
具体的实现可以参考stm32\fwlib\FWLib\examples下的各例子。
到这里,我们也只不过看了中断的处理函数,而这些处理函数是如何被硬件中断调用的呢?嗯,说到这里就不得不提一下stm32f10x_vector.c这个文件了。
内容如下:typedef void( *intfunc )( void );typedef union { intfunc __fun; void * __ptr; } intvec_elem;/**************************************************************__sfe是IAR的“段操作符”segment operator。
表示取某个段的后一个字节的地址。
比如"CSTACK"定义为0x20001000~0x20001fff。
那__sfe( "CSTACK" ) 就得到0x20002000这个值,刚好用来初始化msp堆栈指针。
注意使用segment operator前,需要先定义段名如下:#pragma segment="CSTACK" RSTACK 程序返回用的,保存的是程序调用函数的返回地址, 你填写的数值X 2才是占用的字节数CSTACK 函数局部变量用的区域,所有的功能函数使用的局部变量都是从这个堆栈申请使用的,用完了再还回去。
STM32中断程序前段时间用STM32F103VBT6写了一个中断的函数,借此机会想了解下STM32的中断机制,用过之后发现STM32的中断配置相当灵活,稳定行很高,测试发现几乎没出过什么差错。
我在程序里开了三个中断,一个计数器用于精确延时用,另外两个为外部事件处理中断,下面一一详细介绍,方便初学者入门。
在进行STM32中断配置之前首先需要了解下它的中断部分:一、Cortex-M3中断机制在STM32处理器中有43个可屏蔽中断通道(?包含16个Cortex?-M3的中断线)。
共设置了16个可编程的优先等级(使用? 4位中断优先级);它的嵌套向?中断控制器(NVIC)和处?器核的接口紧密相连,可以实现低延迟的中断处?和有效处?地处?晚到的中断。
嵌套向?中断控制器管?着包括核异常等中断。
Cortex—M3是一个32位的核,在传统的单片机领域中,有一些不同于通用32位CPU应用的要求。
比如在工控领域,用户要求具有更快的中断速度,Cortex-M3采用了Tail-Chaining中断技术,完全基于硬件进行中断处理,最多可减少12个时钟周期数,在实际应用中可减少70%中断。
异常或者中断是处理器响应系统中突发事件的一种机制。
当异常发生时,Cortex—M3通过硬件自动将编程计数器(PC)、编程状态寄存器(XPSR)、链接寄存器(LR)和R0~R3、R12等寄存器压进堆栈。
在Dbus(数据总线)保存处理器状态的同时,处理器通过Ibus(指令总线)从一个可以重新定位的向量表中识别出异常向量,并获取ISR函数的地址,也就是保护现场与取异常向量是并行处理的。
一旦压栈和取指令完成,中断服务程序或故障处理程序就开始执行。
执行完ISR,硬件进行出栈操作,中断前的程序恢复正常执行。
图1为Cortex—M3处理器的异常处理流程。
二、STM32 SysTick 介绍Cortex-M3的内核中包含一个SysTick时钟。
SysTick为一个24位递减计数器,SysTick设定初值并使能后,每经过1个系统时钟周期,计数值就减1 。
STM32 入门系列教程初试STM32 中断(2010-04-23)其它啥也不说,我们先看下芯达STM32外部中断所采用电路,非常简单,如下图所示:该电路直接从STM32系列的CPU引脚直接引出两个GPIO(PE2/PE3),外加上拉电阻后,使用一个轻触开关接地。
很明显,按下开关时,PE2/PE3引脚接地,否则为高电平。
学习STM32中断时,我们可以一边回想单片机中断系统一边学习。
这里的思路就与单片机类似:当按下按键时,电平变动,使用上升或下降沿触发中断。
对于单片机来说,很简单,开中断即可。
但STM32却有所不同。
我们使能配置EXTI、NVIC中断后,还需要注意IO口时钟的使能。
笔者当初忽略了AFIO时钟,调试2天没有结果,重新查看datasheet时,发现AFIO时钟没有打开。
下面简单列出外部中断的编程思路:1、系统初始化,如系统时钟初始化,使之进入72MHZ主频;2、GPIO配置,务必注意打开GPIO时钟时,一定打开AFIO时钟。
3、EXTI配置,在这里配置需要选择哪个引脚作为中断引脚。
4、NVIC配置,这也是比单片机多出来的部分,我们必须把NVIC中对应的通道使能,并且设置优先级别。
5、使用while(1)进行死循环,并在中断程序中写入中断发生时应如何处理。
好吧,开始STM32的外部中断的编程之旅吧,详细的例程代码,请参考光盘中的《芯达STM32配套例程》文件夹。
本期例程使用的模板,是刚刚从STM32官网上下载的最新版本的3.0固件模板,其工程文件放在根目录下的\Project\Template\RVMDK目录中,点击工程文件即可打开。
同样只要关注main.c文件即可。
步骤一系统初始化,使用固件模板中自带的SystemInit();函数即可。
通过分析这个函数,我们会发现此函数把主频默认调整到72MHZ。
步骤二GPIO配置,这以后均是需要自己编写的函数,例程中采用GPIO_Config();函数,如下所示:{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE/*** LED1->PB8,LED2->PB9,LED3->PE0,LED4->PE1* Key1->PE2,Key2->PE3*/}在这里函数里,我们首先使能了GPIOB、GPIOE的时钟,因为我们使用PB8\PB9\PE0\PE1作为用户指示灯来验证外部中断,使用PE2\PE3作为中断触发引脚。
一、中断模块void NVIC_Configuration(void){NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //中断分组NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //设置定时器3为中断源NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; //设置抢占式优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; //设置响应优先级NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断NVIC_Init(&NVIC_InitStructure);}STM32的中断如此之多,配置起来并不容易,因此我们需要一个强大而方便的中断控制器NVIC。
要想用中断,首先要对NVIC初始化,其次定义并填充一个NVIC_InitTypeDef 类型的结构体。
结构体的四个成员分别是NVIC_IRQChannel,NVIC_IRQChannelPreemptionPriority,NVIC_IRQChannelSubPriority,NVIC_IRQChannelCmd。
第一个成员NVIC_IRQChannel,主要设置中断源,中断源可以为普通定时器,也可以是外部中断,串口中断都可以。
第二个成员NVIC_IRQChannelPreemptionPriority和第三个成员NVIC_IRQChannelSubPriority,主要取决于中断的分组。
中断分组一共有5组,中断分组的结果直接影响到抢占优先级和响应优先级的数量,而抢占优先级和响应优先级的数量是由一个4位的数字决定:第0组:所有4位都用来配置响应优先级,即有16种都不相同的响应优先级。
本文档免费下载,如果你觉得对你有帮助,情给好评并下载,我需要财富值,谢谢!/**********************STM32F103外部中断************************ *********************长沙理工大学3+1实验室********************* *************************2012年9月22日*************************/ #include"stm32f10x.h"//配置系统时钟************************************************************ void RCC_Configuration(void){ErrorStatus HSEStartUpStatus; //将外部时钟设置成枚举变量RCC_DeInit(); //复位RCC外部设备寄存器到默认值RCC_HSEConfig(RCC_HSE_ON); //打开外部时钟HSEStartUpStatus=RCC_WaitForHSEStartUp(); //检测外部时钟是否就绪if(HSEStartUpStatus==SUCCESS) //如果就绪(SUCCESS)则进行下一步程序{FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //开启flash缓冲功能(使能缓存)FLASH_SetLatency(FLASH_Latency_2); //延时两个周期RCC_HCLKConfig(RCC_SYSCLK_Div1); //设置AHB时钟为不分频的系统时钟RCC_PCLK1Config(RCC_HCLK_Div2); //设置AP1为2分频系统时钟(不能超过36M) RCC_PCLK2Config(RCC_HCLK_Div1); //设置AP1为为系统时钟频率(前面AHB 给定的时钟)RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); //设置外部时钟为PLL的上输入时钟并且倍频9 RCC_PLLCmd(ENABLE); //使能PLL时钟while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET) //检测PLL是否就绪RESET:就绪{}RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //配置外部时钟作为系统的时钟while(RCC_GetSYSCLKSource()!=0x08) //检测外部时钟是否作为PLL的输入时钟{}}}//配置GPIO函数************************************************ //功能:配置GPIO的输入输出模式void GPIO_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO初始化函数RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENA BLE); //使能GPIOA和GPIOB的时钟,配置其复用模式//配置GPIO口的输入*******GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1; //配置1脚为输入脚GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //配置GPIO为上拉输入模式GPIO_Init(GPIOA,&GPIO_InitStructure); //把配置好的GPIO口初始化一下// 配置GPIO的输出*******GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_3); //将PA2和PA3拉高GPIO_SetBits(GPIOB,GPIO_Pin_2); //将PA2和PA3拉高GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; //配置0脚为输出脚GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; // 配置GPIO为推挽输出模式GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //配置GPIO口的输出速率是50MGPIO_Init(GPIOA,&GPIO_InitStructure); //使能GPIOA口}//外部中断函数************************************************************************ ************* void EXTI_Configuration(void){EXTI_InitTypeDef EXTI_InitStructure; //初始化外部中断寄存器RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能IO时钟EXTI_ClearITPendingBit(EXTI_Line1); //清除IO口中断清除挂起位(清除中断标志位) EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; //设置外部中断触发(另一种是事件触发)EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //设置中断触发方式:上下沿触发方式EXTI_InitStructure.EXTI_Line=EXTI_Line1; //选择中断线路为1(即选择那个IO作为中断输入) EXTI_InitStructure.EXTI_LineCmd=ENABLE; //使能外部中断EXTI_Init(&EXTI_InitStructure); //初始化GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource1); //将GPIOA1挂到中断上}//中断分组函数***************************************************************void NIVC_Configuration(void){NVIC_InitTypeDef NVIC_InitStructure; //初始化中断分组函数//NVIC_PriorityGroupConfig:设置优先级分组(下面一句)NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置抢占式优先级:先占优先级0位,从优先级4位NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn; //将中断挂到GPIO1脚外部中断线1上NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; //设置响应式优先级:先占优先级1位,从先级3位NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; // 使能设置的外部中断通道请求NVIC_Init(&NVIC_InitStructure); //初始化}//中断服务函数********************************************************void EXTI1_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line1)!=RESET){//添加中断处理函数GPIO_ResetBits(GPIOA,GPIO_Pin_2); //点亮ledEXTI_ClearFlag(EXTI_Line1); //清除标志中断位EXTI_ClearITPendingBit(EXTI_Line1); //清除外部中断线1的挂起位}}//主函数*********************************************************************** int main(void){RCC_Configuration(); //调用系统时钟函数GPIO_Configuration(); //调用GPIONIVC_Configuration();EXTI_Configuration();while(1);}。
STM32入门系列教程初试STM32中断Revision0.01(2010-04-23)其它啥也不说,我们先看下芯达STM32外部中断所采用电路,非常简单,如下图所示:该电路直接从STM32系列的CPU引脚直接引出两个GPIO(PE2/PE3),外加上拉电阻后,使用一个轻触开关接地。
很明显,按下开关时,PE2/PE3引脚接地,否则为高电平。
学习STM32中断时,我们可以一边回想单片机中断系统一边学习。
这里的思路就与单片机类似:当按下按键时,电平变动,使用上升或下降沿触发中断。
对于单片机来说,很简单,开中断即可。
但STM32却有所不同。
我们使能配置EXTI、NVIC中断后,还需要注意IO口时钟的使能。
笔者当初忽略了AFIO时钟,调试2天没有结果,重新查看datasheet时,发现AFIO时钟没有打开。
下面简单列出外部中断的编程思路:1、系统初始化,如系统时钟初始化,使之进入72MHZ主频;2、GPIO配置,务必注意打开GPIO时钟时,一定打开AFIO时钟。
3、EXTI配置,在这里配置需要选择哪个引脚作为中断引脚。
4、NVIC配置,这也是比单片机多出来的部分,我们必须把NVIC中对应的通道使能,并且设置优先级别。
5、使用while(1)进行死循环,并在中断程序中写入中断发生时应如何处理。
好吧,开始STM32的外部中断的编程之旅吧,详细的例程代码,请参考光盘中的《芯达STM32配套例程》文件夹。
本期例程使用的模板,是刚刚从STM32官网上下载的最新版本的3.0固件模板,其工程文件放在根目录下的\Project\Template\RVMDK目录中,点击工程文件即可打开。
同样只要关注main.c 文件即可。
步骤一分析这个函数,我们会发现此函数把主频默认调整到72MHZ。
,这以后均是需要自己编写的函数,例程中采用/***LED1->PB8,LED2->PB9,LED3->PE0,LED4->PE1*Key1->PE2,Key2->PE3GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_Init(GPIOE,&GPIO_InitStructure);在这里函数里,我们首先使能了GPIOB、GPIOE的时钟,因为我们使用PB8\PB9\PE0\PE1作为用户指示灯来验证外部中断,使用PE2\PE3作为中断触发引脚。
注意它们的配置中,同样是GPIO引脚,却需要把PE2\PE3配置为浮空输入模式,而其他配置为输出模式——很好理解,因为LED指示灯是由CPU驱动点亮的,而中断引脚PE2\PE3,是外界按键驱动的,相对于CPU来说,是“输入”。
步骤三EXTI的配置。
此步相当于单片机的中断配置,使用的函数是EXTI_Config();函数。
大家应该都很熟悉。
我们进入中断服务程序后,首先做的就是清除中断标志位,否则它会不断响应中断,不断进入中断函数。
当然,我们这里做这个步骤,只是对于外部中断中的GPIO,有16个中断线,分别是接下来设置外部中断结构体的成员,比如求,还有一个是EXTI_Mode_Event中断到底啥关系呢?请参考如下语句(网络上查的):“事件:是表示检测有一某件触发事件发生了。
中断:有某个事件发生并产生中断,并跳转到对应的中断处理程序中。
事件可以触发中断,也可以不触发中断有可能被更优先的中断屏蔽,事件不会事件本质上就是一个触发信号,是用来触发特定的外设模块或核心本身(唤醒).事件只是一个触发信号(脉冲),而中断则是一个固定的电平信号”我们采用的触发方式是上升沿触发EXTI_Trigger_Rising,使用的中断线是EXTI_Line2和EXTI_Line3,实际上就是指明使用的是GPIO的第2引脚和第3引脚。
最后不要忘了务必要使能它,呵呵。
步骤四NVIC配置。
先解释下NVIC,它的中文全称是“嵌套向量中断控制器。
”我们进行NVIC配置时,采用的是NVIC_Config();函数,下面列出该函数:void NVIC_Config(void){NVIC_InitTypeDef NVIC_InitStructure;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);NVIC_InitStructure.NVIC_IRQChannel=EXTI2_IRQChannel;//通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;//=ENABLE;NVIC_Init(&NVIC_InitStructure);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);NVIC_InitStructure.NVIC_IRQChannel=EXTI3_IRQChannel;//通道NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;NVIC_Init(&NVIC_InitStructure);}该函数的编写分两个部分,一个部分是专门针对中断线2的,另一个部分针对中断线3的。
实际上学习外部中断,只要其中一个即可。
由于芯达STM32开发板上配置了两个按键,都可以用作外部中断的学习,因此我们这里列出了两个中断线。
整个函数比较简单,从函数名即可知道其含义。
大家在查看这些函数的时候,请务必查看他们具体是如何实现的。
比如NVIC_PriorityGroupConfig();函数,不能只看这个函数是用于优先级组配置,还要稍微关注下它的实现。
操作是,双击该函数名,选中它,然后右键,点击“Go To Definiton of ‘NVIC_PriorityGroupConfig’”,如下图所示,即可查看该函数的具体实现。
我EXTI_ClearITPendingBit(EXTI_Line2);生了,因此,第一步,把中断标志位清除,以防它不断地进入中断。
然后点亮LED指示灯。
怎么点亮LED灯,这个就不详细展开解释,读者可根据自己的实际情况来编写程序。
值得说明的是,该函数应该写在stm32f10x_it.c文件中,并且中断服务子程序的函数名,必须严格按照startup_stm32f10x_hd.s文件中的中断向量表中,对应的向量名进行。
如果担心写错函数名,可以直接打开startup_stm32f10x_hd.s 文件,找到如下部分:__Vectors DCD__initial_spTop;Top of StackDCD Reset_Handler;Reset HandlerDCD NMI_Handler;NMI HandlerDCD HardFault_Handler;Hard Fault HandlerDCD MemManage_Handler;MPU Fault HandlerDCD BusFault_Handler;Bus Fault HandlerDCD UsageFault_Handler;Usage Fault HandlerDCD0;ReservedDCD0;ReservedDCD0;ReservedDCD0;ReservedDCD SVC_Handler;SVCall HandlerDCD DebugMon_Handler;Debug Monitor HandlerDCD0;ReservedDCD PendSV_Handler;PendSV HandlerDCD SysTick_Handler;SysTick Handler;External InterruptsDCD WWDG_IRQHandler;Window WatchdogDCD PVD_IRQHandler;PVD through EXTI Line detectDCD TAMPER_IRQHandler;TamperDCD RTC_IRQHandler;RTCDCD FLASH_IRQHandler;FlashDCD RCC_IRQHandler;RCCDCD EXTI0_IRQHandler;EXTI Line0DCD EXTI1_IRQHandler;EXTI Line1DCD EXTI2_IRQHandler;EXTI Line2DCD EXTI3_IRQHandler;EXTI Line3DCD EXTI4_IRQHandler;EXTI Line4DCD DMA1_Channel1_IRQHandler;DMA1Channel1DCD DMA1_Channel2_IRQHandler;DMA1Channel2DCD DMA1_Channel3_IRQHandler;DMA1Channel3DCD DMA1_Channel4_IRQHandler;DMA1Channel4DCD DMA1_Channel5_IRQHandler;DMA1Channel5DCD DMA1_Channel6_IRQHandler;DMA1Channel6DCD DMA1_Channel7_IRQHandler;DMA1Channel7DCD ADC1_2_IRQHandler;ADC1&ADC2DCD USB_HP_CAN1_TX_IRQHandler;USB High Priority or CAN1TXDCD USB_LP_CAN1_RX0_IRQHandler;USB Low Priority or CAN1RX0DCD CAN1_RX1_IRQHandler;CAN1RX1DCD CAN1_SCE_IRQHandler;CAN1SCEDCD EXTI9_5_IRQHandler;EXTI Line9..5DCD TIM1_BRK_IRQHandler;TIM1BreakDCD TIM1_UP_IRQHandler;TIM1UpdateDCD TIM1_TRG_COM_IRQHandler;TIM1Trigger and CommutationDCD TIM1_CC_IRQHandler;TIM1Capture CompareDCD TIM2_IRQHandler;TIM2DCD TIM3_IRQHandler;TIM3DCD TIM4_IRQHandler;TIM4DCD I2C1_EV_IRQHandler;I2C1EventDCD I2C1_ER_IRQHandler;I2C1ErrorDCD I2C2_EV_IRQHandler;I2C2EventDCD I2C2_ER_IRQHandler;I2C2ErrorDCD SPI1_IRQHandler;SPI1DCD SPI2_IRQHandler;SPI2DCD USART1_IRQHandler;USART1DCD USART2_IRQHandler;USART2DCD USART3_IRQHandler;USART3DCD EXTI15_10_IRQHandler;EXTI Line15..10DCD RTCAlarm_IRQHandler;RTC Alarm through EXTI LineDCD USBWakeUp_IRQHandler;USB Wakeup from suspendDCD TIM8_BRK_IRQHandler;TIM8BreakDCD TIM8_UP_IRQHandler;TIM8UpdateDCD TIM8_TRG_COM_IRQHandler;TIM8Trigger and CommutationDCD TIM8_CC_IRQHandler;TIM8Capture CompareDCD ADC3_IRQHandler;ADC3DCD FSMC_IRQHandler;FSMCDCD SDIO_IRQHandler;SDIODCD TIM5_IRQHandler;TIM5DCD SPI3_IRQHandler;SPI3DCD UART4_IRQHandler;UART4DCD UART5_IRQHandler;UART5DCD TIM6_IRQHandler;TIM6DCD TIM7_IRQHandler;TIM7DCD DMA2_Channel1_IRQHandler;DMA2Channel1DCD DMA2_Channel2_IRQHandler;DMA2Channel2DCD DMA2_Channel3_IRQHandler;DMA2Channel3DCD DMA2_Channel4_5_IRQHandler;DMA2Channel4 &Channel5__Vectors_End我们现在使用的是中断线2的处理函数,因此是上面红色粗体所示的函数名:EXTI2_IRQHandler。