闲话
写具体内容之前,说点闲话。不知道大家有没有这样的体验,在学单片机(stm32)的中断的时候,首先学习的就是外部中断,也就是EXTI这个外设。因为总以为只要是中断讲的就是外部中断,因此以为学习了EXTI就是学完了中断,但是又发现只要用中断就要用NVIC以及SCB中的AIRCR这个寄存器。所有就会很混乱,到底那个才是中断的最合理的学习对象。
其实学习中断,最应该仔细研究的是NVIC和SCB,NVIC和SCB都是内核的外设,NVIC这个外设就是用来管理所有的中断的,但是有它还不够,注意这里说的是中断,不包括异常。我们学习的时候是不是总被一句话洗脑,就是不区分中断和异常。这样是为了让我们不去纠结什么是中断什么是异常,但是如果去深究寄存器对着二者的管理的话,必须区别开来。就像这里NVIC管理的都是中断,它管不了异常,并且在对优先级进行分组的时候,NVIC还没法进行分组,它只有资格对内核提供的240个中断源对应的中断进行优先级的设置,我们知道NVIC的IP寄存器就是对240个中断进行优先级设置的,每个IP寄存器是8bit,但是我们也知道这8bit是要分为抢占和子优先级的,也就是要把8bit分为两组,每组分别为几位呢?这个NVIC是没有能力去做的,需要SCB中的寄存器来设置,具体的是SCB中的AIRCR(应用程序中断及复位控制寄存器)中的8~10bit的prigroup位断来设置的。闲话篇讲了太多了,都成了正经话了,停,跳入正经话篇。
中断和异常
不要嫌麻烦,中断就是中断,异常就是异常。说的好记忆一点,中断是芯片外设的中断,异常是内核级别的中断。一个是外设级别,一个是内核级别。
cortex-m3/4在设计的时候在内核水平上有15个异常,编号为1-15,大于15的都是外设水平的中断,其实在CM3权威指南上说的很清楚,我这里只是自己的理解简单化。
如上所述,虽然设计了15个异常和240个中断,但是不一定都得用上,我们随便看一下一个stm32f1xx系列的编程手册的NVIC寄存器映射图,就可以看到,不是所有用来控制中断的寄存器都用上了:
画红线的分别是使能、除能、挂起、解挂寄存器的最后几个位,它们都只用到了81个中断,很明显没有到240,同样没截图出来的还有中断有效位寄存器和中断优先级寄存器以及软件触发中断寄存器,这几个寄存器都只用到了81个。
虽然我们只用到了81个,但是我们在编程的时候肯定是要写一个通用的代码的,也就是说得把这个可能用到的中断都用一个数据类型给封装起来,你用不用我都有,这也就是我们CMSIS库中文件core_cm3.h中结构体NVIC_Type结构体为何那样定义的原因:
typedef struct
{
__IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register */
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) */
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */
} NVIC_Type;
/*@}*/ /* end of group CMSIS_CM3_NVIC */
我们对着上面NVIC寄存器映射图来看。
首先我们要知道NVIC的基地址是0xE000E100。
这无论是从编程手册还是代码中都可以找到,不是信口开河。另外提一点,我们一直说NVIC是内核外设,从这个SCS_BASE(0xE000E000)地址也可以看出来,我们的存储器映射图看过吗?
红色框的起始地址是0xE0000000,也就是0xE0000000~0xFFFFFFFF这段内存对应的都是M3内部外设,NVIC(0xE000E100)正好在这个地址范围内,就是内核外设。
从NVIC的映射图可以看到ISER起始地址是NVIC基地址加