STM32-NVIC中断管理实现[直接操作寄存器]

发布者:tyloo820最新更新时间:2017-02-06 来源: eefocus关键字:stm32  NVIC  中断管理 手机看文章 扫描二维码
随时随地手机看文章

    cortex-m3支持256个中端,其中包含了16个内核中断,240个外部中断。stm32只有84个中断,包括16个内核中断和68个可屏蔽中断。stm32f103上只有60个中断,f107上才有68个中断。

 

    中断是stm32很基础的一个功能,学会使用中断,才可以更好的使用其他的外设。理解stm32的中断,必须要先从stm32的中断优先级分组是怎么回事。要理解优先级分组,就要先理解什么是先占优先级,和次占优先级。  

 

    先占优先级的概念等同于51单片机中的中断。假设有两中断先后触发,已经在执行的中断先占优先级如果没有后触发的中断 先占优先级更高,就会先处理先占优先级高的中断。也就是说又有较高的先占优先级的中断可以打断先占优先级较低的中断。这是实现中断嵌套的基础。

 

    次占优先级只在同一先占优先级的中断同时触发时起作用,先占优先级相同,则优先执行次占优先级较高的中断。次占优先级不会造成中断嵌套。 如果中断的两个优先级都一致,则优先执行位于中断向量表中位置较高的中断。

 

还需要注意的一点是 这里的中断优先级 高是指  是指是否更接近0级,0级优先级是最高的。

 

那么最低的优先级可以是多少?这就涉及了优先级分组的概念。 stm32 通过一个中断向量控制器(NVIC),来分配先占优先级和次占优先级的数量。

 

arm cortex-m3 内核中拥有一个3位宽度的的PRIGROUP数据区,用来指示一个8位数据序列中的小数点的位置从而表示中断优先级的分组。

 

举个例子可以更好的理解: 如果PRIGROUP 数据位000  即为0  说明8位数据序列中小数位置在第1位的左边  为xxxxxxx.y   用于表示中断优先级的分组的含义就是   用7位的数据宽度来表示  先占优先级的数量 即为128  用1位的数据宽度来表示 次占优先级数量 即为 2 


 

所以arm cortex-m3中有2的三次方 即为8个优先级分组 。 

 

但是stm32中只有5个优先级分组,表示方法略有不同

 

    MDK中定义的中断相关的寄存器结构体为:

typedef struct

{

  vu32 ISER[2];

  u32  RESERVED0[30];

  vu32 ICER[2];

  u32  RSERVED1[30];

  vu32 ISPR[2];

  u32  RESERVED2[30];

  vu32 ICPR[2];

  u32  RESERVED3[30];

  vu32 IABR[2];

  u32  RESERVED4[62];

  vu32 IPR[15];

} NVIC_TypeDef;


ISER[2]:中断使能寄存器组

 

stm32可屏蔽中断共有60个,这里用了两个32位的寄存器,可以表示64个中断。stm32只用了前60位。 若要使能某个中断,则必须设置相应的ISER位为1。

具体每一位对应的中断关系如下:(参见 MDK下的 stm32f10x_nvic.h)


#define WWDG_IRQChannel              ((u8)0x00)  /* Window WatchDog Interrupt */

#define PVD_IRQChannel               ((u8)0x01)  /* PVD through EXTI Line detection Interrupt */

#define TAMPER_IRQChannel            ((u8)0x02)  /* Tamper Interrupt */

#define RTC_IRQChannel               ((u8)0x03)  /* RTC global Interrupt */

#define FLASH_IRQChannel             ((u8)0x04)  /* FLASH global Interrupt */

#define RCC_IRQChannel               ((u8)0x05)  /* RCC global Interrupt */

#define EXTI0_IRQChannel             ((u8)0x06)  /* EXTI Line0 Interrupt */

#define EXTI1_IRQChannel             ((u8)0x07)  /* EXTI Line1 Interrupt */

#define EXTI2_IRQChannel             ((u8)0x08)  /* EXTI Line2 Interrupt */

#define EXTI3_IRQChannel             ((u8)0x09)  /* EXTI Line3 Interrupt */

#define EXTI4_IRQChannel             ((u8)0x0A)  /* EXTI Line4 Interrupt */

#define DMA1_Channel1_IRQChannel     ((u8)0x0B)  /* DMA1 Channel 1 global Interrupt */

#define DMA1_Channel2_IRQChannel     ((u8)0x0C)  /* DMA1 Channel 2 global Interrupt */

#define DMA1_Channel3_IRQChannel     ((u8)0x0D)  /* DMA1 Channel 3 global Interrupt */

#define DMA1_Channel4_IRQChannel     ((u8)0x0E)  /* DMA1 Channel 4 global Interrupt */

#define DMA1_Channel5_IRQChannel     ((u8)0x0F)  /* DMA1 Channel 5 global Interrupt */

#define DMA1_Channel6_IRQChannel     ((u8)0x10)  /* DMA1 Channel 6 global Interrupt */

#define DMA1_Channel7_IRQChannel     ((u8)0x11)  /* DMA1 Channel 7 global Interrupt */

#define ADC1_2_IRQChannel            ((u8)0x12)  /* ADC1 et ADC2 global Interrupt */

#define USB_HP_CAN_TX_IRQChannel     ((u8)0x13)  /* USB High Priority or CAN TX Interrupts */

#define USB_LP_CAN_RX0_IRQChannel    ((u8)0x14)  /* USB Low Priority or CAN RX0 Interrupts */

#define CAN_RX1_IRQChannel           ((u8)0x15)  /* CAN RX1 Interrupt */

#define CAN_SCE_IRQChannel           ((u8)0x16)  /* CAN SCE Interrupt */

#define EXTI9_5_IRQChannel           ((u8)0x17)  /* External Line[9:5] Interrupts */

#define TIM1_BRK_IRQChannel          ((u8)0x18)  /* TIM1 Break Interrupt */

#define TIM1_UP_IRQChannel           ((u8)0x19)  /* TIM1 Update Interrupt */

#define TIM1_TRG_COM_IRQChannel      ((u8)0x1A)  /* TIM1 Trigger and Commutation Interrupt */

#define TIM1_CC_IRQChannel           ((u8)0x1B)  /* TIM1 Capture Compare Interrupt */

#define TIM2_IRQChannel              ((u8)0x1C)  /* TIM2 global Interrupt */

#define TIM3_IRQChannel              ((u8)0x1D)  /* TIM3 global Interrupt */

#define TIM4_IRQChannel              ((u8)0x1E)  /* TIM4 global Interrupt */

#define I2C1_EV_IRQChannel           ((u8)0x1F)  /* I2C1 Event Interrupt */

#define I2C1_ER_IRQChannel           ((u8)0x20)  /* I2C1 Error Interrupt */

#define I2C2_EV_IRQChannel           ((u8)0x21)  /* I2C2 Event Interrupt */

#define I2C2_ER_IRQChannel           ((u8)0x22)  /* I2C2 Error Interrupt */

#define SPI1_IRQChannel              ((u8)0x23)  /* SPI1 global Interrupt */

#define SPI2_IRQChannel              ((u8)0x24)  /* SPI2 global Interrupt */

#define USART1_IRQChannel            ((u8)0x25)  /* USART1 global Interrupt */

#define USART2_IRQChannel            ((u8)0x26)  /* USART2 global Interrupt */

#define USART3_IRQChannel            ((u8)0x27)  /* USART3 global Interrupt */

#define EXTI15_10_IRQChannel         ((u8)0x28)  /* External Line[15:10] Interrupts */

#define RTCAlarm_IRQChannel          ((u8)0x29)  /* RTC Alarm through EXTI Line Interrupt */

#define USBWakeUp_IRQChannel         ((u8)0x2A)  /* USB WakeUp from suspend through EXTI Line Interrupt */

#define TIM8_BRK_IRQChannel          ((u8)0x2B)  /* TIM8 Break Interrupt */

#define TIM8_UP_IRQChannel           ((u8)0x2C)  /* TIM8 Update Interrupt */

#define TIM8_TRG_COM_IRQChannel      ((u8)0x2D)  /* TIM8 Trigger and Commutation Interrupt */

#define TIM8_CC_IRQChannel           ((u8)0x2E)  /* TIM8 Capture Compare Interrupt */

#define ADC3_IRQChannel              ((u8)0x2F)  /* ADC3 global Interrupt */

#define FSMC_IRQChannel              ((u8)0x30)  /* FSMC global Interrupt */

#define SDIO_IRQChannel              ((u8)0x31)  /* SDIO global Interrupt */

#define TIM5_IRQChannel              ((u8)0x32)  /* TIM5 global Interrupt */

#define SPI3_IRQChannel              ((u8)0x33)  /* SPI3 global Interrupt */

#define UART4_IRQChannel             ((u8)0x34)  /* UART4 global Interrupt */

#define UART5_IRQChannel             ((u8)0x35)  /* UART5 global Interrupt */

#define TIM6_IRQChannel              ((u8)0x36)  /* TIM6 global Interrupt */

#define TIM7_IRQChannel              ((u8)0x37)  /* TIM7 global Interrupt */

#define DMA2_Channel1_IRQChannel     ((u8)0x38)  /* DMA2 Channel 1 global Interrupt */

#define DMA2_Channel2_IRQChannel     ((u8)0x39)  /* DMA2 Channel 2 global Interrupt */

#define DMA2_Channel3_IRQChannel     ((u8)0x3A)  /* DMA2 Channel 3 global Interrupt */

#define DMA2_Channel4_5_IRQChannel   ((u8)0x3B)  /* DMA2 Channel 4 and DMA2 Channel 5 global Interrupt */


系统中断这里没有申明,所以导致一些系统中断无法使用,比如 systick的中断 这个在 stm32上最方便的定时器Systick[操作寄存器+库函数] 已经做了分析 

 

ICER[2]:中断清除寄存器组

结构同ISER[2],但是作用相反。 中断的清楚不是通过向ISER[2]中对应位写0实现的,而是在ICER[2]对应位写1清除的。

 

ISPR[2]:中断挂起控制寄存器组

每一位对应的中断和ISER是一样的。通过置1来挂起正在进行的中断,而执行同级或者更高级别的中断。

 

ICPR[2]:中断解挂寄存器组

结构和ISPR[2]相同,作用相反。置1将相应中断解挂。

 

IABR[2]:中断激活标志位寄存器组

中断和ISER[2]对应,如果为1,则表示该位所对应的中断正在执行。这是只读寄存器,由硬件自动清零。

 

IPR[15]:中断优先级控制的寄存器组

IPR寄存器组由15个32位寄存器组成。每个可屏蔽的中断占用8位,这样可以表示的可屏蔽中断为 15*4 =60个。而每个可屏蔽中断占用的8位并没有全部使用,而是只使用了高4位。这4位又分为抢占优先级和子优先级。抢占优先级在前,子优先级在后。而这两个优先级各占几位又要根据SCB->AIRCR中中断分组的设置来决定。

 

IPR寄存器描述:

stm32将中断分为5组,组0~4. 该分组由SCB->AIRCR寄存器的[10:8]三位来定义。具体关系如下:

 

AIRCR[10:8]分配情况分配结果
0111.xxxx00000位 表示  抢占优先级,4位  表示  相应优先级
1110y.xxx00001位 表示  抢占优先级,3位 表示  相应优先级
2101yy.xx00002为 表示  抢占优先级,2位 表示  相应优先级
3100yyy.x00003位 表示  抢占优先级,1位 表示  相应优先级
4011yyyy.00004位 表示  抢占优先级,0位 表示  相应优先级

 

中断管理实现如下:

//设置向量表偏移地址

//NVIC_VectTab:基址

//Offset:偏移量


void Nvic_SetVectorTable(u32 NVIC_VectTab, u32 Offset)     

      //检查参数合法性

    assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));

    assert_param(IS_NVIC_OFFSET(Offset));       

    SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);//设置NVIC的向量表偏移寄存器

    //用于标识向量表是在CODE区还是在RAM区


}



//设置NVIC分组

//NVIC_Group:NVIC分组 0~4 总共5组 


void Nvic_PriorityGroupConfig(u8 NVIC_Group)     

    u32 temp,temp1;      


      //配置向量表                  

    #ifdef  VECT_TAB_RAM

        Nvic_SetVectorTable(NVIC_VectTab_RAM, 0x0);

    #else   

        Nvic_SetVectorTable(NVIC_VectTab_FLASH, 0x0);

    #endif


    temp1=(~NVIC_Group)&0x07;//取后三位

    temp1<<=8;

    temp=SCB->AIRCR;  //读取先前的设置

    temp&=0X0000F8FF; //清空先前分组

    temp|=0X05FA0000; //写入钥匙

    temp|=temp1;       

    SCB->AIRCR=temp;  //设置分组   

}



//设置NVIC 

//NVIC_PreemptionPriority:抢占优先级

//NVIC_SubPriority       :响应优先级

//NVIC_Channel           :中断编号

//NVIC_Group             :中断分组 0~4

//注意优先级不能超过设定的组的范围!否则会有意想不到的错误

//组划分:

//组0:0位抢占优先级,4位响应优先级

//组1:1位抢占优先级,3位响应优先级

//组2:2位抢占优先级,2位响应优先级

//组3:3位抢占优先级,1位响应优先级

//组4:4位抢占优先级,0位响应优先级

//NVIC_SubPriority和NVIC_PreemptionPriority的原则是,数值越小,越优先


void Nvic_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)     

    u32 temp;    


    u8 IPRADDR=NVIC_Channel/4;  //每组只能存4个,得到组地址 

    u8 IPROFFSET=NVIC_Channel%4;//在组内的偏移

    IPROFFSET=IPROFFSET*8+4;    //得到偏移的确切位置

    Nvic_PriorityGroupConfig(NVIC_Group);//设置分组

    temp=NVIC_PreemptionPriority<<(4-NVIC_Group);      

    temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);

    temp&=0xf;//取低四位


    if(NVIC_Channel<32)NVIC->ISER[0]|=1<

    else NVIC->ISER[1]|=1<<(NVIC_Channel-32);    

    NVIC->IPR[IPRADDR]|=temp<

}


关键字:stm32  NVIC  中断管理 引用地址:STM32-NVIC中断管理实现[直接操作寄存器]

上一篇:arm 学习笔记--C程序基础
下一篇:STM32F10X SPI操作flash MX25L64读写数据

推荐阅读最新更新时间:2024-03-16 15:32

STM32 串口调试UART1,调试笔记1
Usart1重新初始化之后,再次发送数据的时候,就会死在 while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET); 解决方法:注释掉原程序中的 // USART_ClearFlag(USART1, USART_FLAG_TC);
[单片机]
基于STM32的多功能数字钟(中文版)
/************************************************************************************** 程序功能:基于STM32的多功能数字钟(中文版) ************************************************************************************** 1、时钟的基准用STM32F103RCT6自带的RTC实现。 2、这三个按键的功能分别为: 设置 、 加 、 减 。(WAKEUP KEY0 KEY1) 三个按键作为这三个功能: 键盘上的WAKEUP用作 设置 ,KE
[单片机]
STM32 在 keil 环境下如何使用 cm_backtrace进行错误追踪
引言 我们在平常使用STM32单片机的时候,往往会碰到程序跑飞的情况,出现hard_fulat等错误,而我们在定位错误的时候,采用的方法往往是连上仿真器,一步一步单步调试,定位到具体的错误代码,再去猜测、排除、推敲错误原因,这样一个过程很是痛苦,而且在实际情况中,很多产品真机调试时必须断开仿真器或者说,问题确实存在,但是极难出现,所以在基于这样一个问题背景下,RTT 的大佬armink开发了一个基于 ARM Cortex-M系列的 MCU错误追踪库,用于帮助开发者解决上述问题。 CmBacktrace 的作用及适用平台 首先,CmBacktrace 是一款针对于 ARM Cortex-M 系列 MCU 的错误代码自动追踪、定位
[单片机]
<font color='red'>STM32</font> 在 keil 环境下如何使用 cm_backtrace进行错误追踪
基于STM32的焊缝底片数字化仪硬件设计
随着计算机技术的日益普及,计算机辅助评片系统愈来愈受检测人的青睐。针对胶片的气孔缺陷,设计了计算机辅助评片,并进行自动分级。为了保证缺陷智能检测中线阵CCD相机对胶片的数字化处理准确无失真,文中设计采用ARM处理器STM32F103C8T6为核心,光电编码器接入电路,电机驱动选用LMD18245芯片,驱动步进电机控制扫描机构的运动速度与线阵CCD线频率的匹配,从而确保工业胶片数字化和同步只能检测的准确无误,为未来工业射线检测提供重要保障和技术支持。 1 系统总体设计 本设计采用STM32F103作为集成控制芯片,增量式光电编码器作为采集启动信号,接收到由增量式编码器发出的A、B相信号,再由STM32 F103对步进电机驱动器发
[单片机]
基于<font color='red'>STM32</font>的焊缝底片数字化仪硬件设计
基于STM32微控制器处理先进电机控制方法
   变频器的问世和先进的电机控制方法让三相无刷电机(交流感应电机或永磁同步电机)曾经在调速应用领域取得巨大成功。这些高性能的电机驱动器过去主要用于工厂自动化系统和机器人。十年来,电子元器件的大幅降价使得这些电机驱动器能够进入对成本敏感的市场,例如:家电、空调或个人医疗设备。本文将探讨基于ARM的标准微控制器如何在一个被DSP和FPGA长期垄断的市场上打破复杂的控制模式,我们将以意法半导体的基于Cortex-M3 内核的STM32系列微控制器为例论述这个过程。     首先,我们回顾一下电机控制的基本原理。在电机控制系统内,为什么处理器非常重要?我们为什么需要非常好的计算性能?毕竟,Nicolas Tesla在一个世纪前发明交流电机
[嵌入式]
STM32串口通信库的详细代码分享
从箱底捞出来的f103,支持的c语言太基础,虽然性能很高,然而开发时间长难以快速的使用,一开始把 c++那些该有的都搬进来,结果当然是觉得有的函数都没有了。小小的写了一个库用来通过串口来DEBUG 一共有这几个函数,串口为PA9和PA10,在C8T6最小系统上面通过测试 Serial_Begin() 初始化USART,设定波特率 Serial_WriteLine() 传输数据并换行 Serial_Write() 传输数据,没有换行符 例: char str = { THIS IS STM32C8T6 }; void main() { Serial_Begin(115200); while(1) { Serial_WriteL
[单片机]
<font color='red'>STM32</font>串口通信库的详细代码分享
STM32CubeMX----杂记
(1)在使用FSMC作为LCD接口时,同时ENABLE了FreeRTOS,发现生成的工程文件,编译之后会出问题。 研究后发现问题出在“FreeRTOSConfig.h”这段代码: /* Cortex-M specific definitions. */ #ifdef __NVIC_PRIO_BITS /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ #define configPRIO_BITS __NVIC_PRIO_BITS #else #define configPRIO_BITS 4 #
[单片机]
STM32STM32之深入理解DMA
任何一个技术的出现都是为了解决当时出现的问题,任何一个技术既有优点也会有缺点,任何一个技术的适用都需要分场景,看条件。DMA也不例外。 1 直接存储器存取DMA(Direct Memory Access) DMA处于总线矩阵的前级,与内核cortex-M3同级别,属于主设备(Master)。DMA用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。 2 DMA工作过程 手册描述: 以上的官方描述信息量较大: 1) DMA会暂停系统总线若干个周期。意思是DMA工作时,CPU被挂起? 2) 然后总线仲裁器又执行循环调度。如何调
[单片机]
【<font color='red'>STM32</font>】<font color='red'>STM32</font>之深入理解DMA
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved