STM32 中断初识

前段时间经常用stm32f4 discovery,但是因为对NVIC , EXTI不是很了解,所以使用的过程中一直都在避免使用中断,这两天没什么事决定来学习一下stm32 的中断,写一下自己的心得,如有谬误之处,欢迎指正。
我把用到的几份文档寄存器的文档(RM0090)、《Cortex-M技术参考手册》、《Cortex™-M4 Devices Generic User Guide》、《ARMv7-M Architecture Reference Manual》放在百度云,需要的自取http://pan.baidu.com/s/1hq4L328 密码:4g91

关于与NVIC和EXTI有关的寄存器

先说EXTI吧,
EXTI 控制器的主要特性如下:
● 每个中断/事件线上都具有独立的触发和屏蔽
● 每个中断线都具有专用的状态位
● 支持多达 23 个软件事件/中断请求
● 检测脉冲宽度低于 APB2 时钟宽度的外部信号。
(摘自介绍寄存器的文档(RM0090))
在RM0090的241页有这样的介绍:

STM32 中断初识_第1张图片

从图中看出和外部中断有关的寄存器有:上升沿触发选择、下降沿触发选择、软件中断事件寄存器、中断屏蔽寄存器、挂起请求寄存器、事件屏蔽寄存器和NVIC中断控制寄存器等。此外就是对输入线的理解了。
在243页有对输入线如下描述:

STM32 中断初识_第2张图片

也就是说对于一个外部中断线可以和多个stm32的GPIO相连,当你要使用哪一个IO的时候只要对SYSCFG_EXTICR对应的位设置就好了,在中断屏蔽寄存器或事件屏蔽寄存器对应位可以设置使用哪一个中断线。这三个寄存器截图如下:(分别在页码:196~198、244、244)

STM32 中断初识_第3张图片

其中SYSCFG_EXTICR有SYSCFG_EXTICR1~SYSCFG_EXTICR4共4组设置16个线。
在以上2个寄存器都设置好后可以设置时钟的触发沿了,配置下面两个寄存器:(在246页)

STM32 中断初识_第4张图片

在上面的EXTI寄存器都设置好后就可以设置NVIC了,关于NVIC的描述在RM0090中描述较少,但是说了“更多关于异常和 NVIC 编程的说明, 请参考《ARM Cortex™-M4F 技术参考手册》中的第 5 章:异常和第 8 章:嵌套向量中断控 制器。”在网上搜了一下,没找到《ARM Cortex™-M4F 技术参考手册》名字一模一样的资料。但是我找到了个这样的资料《Cortex-M技术参考手册》,在64页找到了一个这样的寄存器描述:

STM32 中断初识_第5张图片
图片下面说其他寄存器在ARMv7-M Architecture Reference Manual中有描述,实际上我去官网也下了,但是没找到什么有用信息(也许有但我这英语渣是没找到)。但是在官网找到了一份这个文档DUI0553A_cortex_m4_dgug.pdf,打开一看,它就是Cortex™-M4 Devices Generic User Guide。在4.2节找到了描述NVIC的部分。在这部分分别描述了ISER(中断使能寄存器)、ICER(中断除能寄存器)、ISPR(中断挂起寄存器)、ICPR(中断解挂寄存器)、IABR(中断激活标志寄存器)、IPR(中断优先级分组寄存器)、STIR(软件触发中断寄存器)的描述。这些寄存器除了STIR外都是7个一组,共有240个位可设置,这些寄存器每一位都对应于一个中断向量表中的一个位置,中断向量表可以在RM0090的234页找到。在IAR里测试的时候没有IPR这个寄存器,查看NVIC的结构体发现寄存器名字是IP。看了下网上有些人写IPR,有些人写IP,不过可以自己看一下自己的NVIC结构体。
此外就是关于优先级分组设置,在System control block的AIRCR寄存器中设置

STM32 中断初识_第6张图片

AIRCR寄存器为异常模式提供优先级分组的控制。在最下面还说了,如果你想要写这个寄存器,你就要在VECTKEY区域写入0x5fa,用的时候可别忘了,下面是AIRCR的位说明。

STM32 中断初识_第7张图片

寄存器查的差不多了,总结一下设置的步骤:
1.设置优先级分组,使用寄存器:SCB->AIRCR 。
2.设置中断优先级(抢占优先级和响应优先级),设置中断使能,使用寄存器:NVIC->IP[0]~IP[7]和NVIC->ISER[0]~ISER[7]。到这里NVIC设置好了。
3.配置外部中断的源输入,使用寄存器SYSCFG->EXTICR[1]-EXTICR[4]。
4.使能外部中断输入线,使用寄存器EXTI->IMR。
5.配置外部中断触发方式,使用寄存器EXTI->RTSR或FTSR。

下面是我用stm32f4-discovery的测试程序:

/******************************
*       NVIC寄存器了解
*       2015\9\12
*       code by:dancetorhythm
******************************/
#include "stm32f4xx.h"
#include "misc.h"
#include "stm32f4xx_exti.h"
unsigned int timingdelay=0;
void delay(unsigned int );
void ledInit();
void EXTI1Config();//寄存器设置
void EXTI2Config();//使用固件库接口设置
void main(){
  //SysTick_Config(SystemCoreClock/1000);
  ledInit();
  EXTI1Config();
  //EXTI2Config();
  GPIOA->MODER&=0xfffffffc;     //PA0输入模式,无上拉下拉
  GPIOA->PUPDR&=0xfffffffc;  
  while(1){
    //add your code   
  }
}
void delay(unsigned int ntime){
  timingdelay=ntime;
  while(timingdelay);
}
void EXTI1Config(){
  SCB->AIRCR=0x05af0000|0x4000;//抢占优先级3位,响应优先级1位
  NVIC->IP[6]=0xe0;           //抢占优先级8,响应优先级0
  NVIC->ISER[0]|=(1<<6);      //中断使能

  EXTI->IMR|=(1<<0);    //开放来自0线的中断请求
  EXTI->FTSR|=(1<<0);   //设置0线下降沿触发

  SYSCFG->EXTICR[1]&=0xffffff00;//配置中断线0到PA0

}
void EXTI2Config(){
  NVIC_InitTypeDef NVIC_InitStruct;
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3); //3位抢占优先级
  NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn;//选择EXTI0通道
  NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=8;//抢占优先级为8
  NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;//响应优先级0
  NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
  NVIC_Init(&NVIC_InitStruct);

  EXTI_InitTypeDef EXTI_InitStruct;
  EXTI_InitStruct.EXTI_Line=EXTI_Line0;//选择输入线0
  EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;//选择中断模式
  EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Rising;//选择上升沿
  EXTI_InitStruct.EXTI_LineCmd=ENABLE;
  EXTI_Init(&EXTI_InitStruct);

}
void ledInit(){
  RCC->AHB1ENR|=0x00000009;//使能GPIOD和GPIOA时钟,此外ABCDEFGHI端口对应AHB1最低位
  RCC->APB2ENR|=(1<<14);  //SYSCFG EN

  GPIOD->MODER&=0x00ffffff;
  GPIOD->MODER|=0X55000000;//设置D15、14,D13、12为通用输出模式

  GPIOD->OTYPER&=0xffff0fff;//设置D15,14,13,12为推挽输出

  GPIOD->OSPEEDR&=0x00ffffff;
  GPIOD->OSPEEDR|=0xff000000;//设置IO速率为100MHz

  SYSCFG->CMPCR=0x00000001;

  GPIOD->PUPDR&=0x00ffffff;//无上拉无下拉
  GPIOD->BSRRH=0xf000;

}
void EXTI0_IRQHandler(void){
  uint32_t tmp;
  if(EXTI->PR&0x00000001!=0){
    tmp=(~GPIOD->ODR)&0x0000f000;
    GPIOD->ODR&=0xffff0fff;
    GPIOD->ODR|=tmp;

    EXTI->PR=(1<<0);
  }
}
void SysTick_Handler(void){
  if(timingdelay){
    timingdelay--;
  }
}

你可能感兴趣的:(cortex-M)