下面,我们看看关于NVIC寄存器的描述,都在哪些手册里面有提到 在使用STM32F10x standard peripheral library写有关于stm32中断的程序的时候,需要开启某个特定中断的控制位,除了对应外设的寄存器之外,还需要设置NVIC的相关寄存器的对应位。例如: - /****** STM32 specific Interrupt Numbers *********************************************************/% O* _* v" g1 H- F: z# E
- WWDG_IRQn = 0, /*!< Window WatchDog Interrupt *// i, P: B! M( I/ w4 Z( N0 u
- PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */5 j5 t, r! D y* E8 g
- TAMPER_IRQn = 2, /*!< Tamper Interrupt */. J/ I- A( N. f0 c
- RTC_IRQn = 3, /*!< RTC global Interrupt */+ ^' S8 A/ q0 \# i; i
- FLASH_IRQn = 4, /*!< FLASH global Interrupt */6 y1 v& I9 d. T. k. z( \
- RCC_IRQn = 5, /*!< RCC global Interrupt */; S& b1 K0 S: \) { f' Q
- EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
' M' n% y2 L! I* B - EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */9 o* d6 J* O! b, w" B3 X" l
- EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */
( o( M) l/ {; |! u* e" M8 h5 Q+ v - EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */
: l! v3 o/ c0 Z+ b" |6 a3 P- u4 ~ - EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */. a2 t+ }6 t% [9 l' C0 F
- DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */' y+ I4 P9 ]# X
- DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */6 g# U% Q9 M5 ?) {% y+ e7 E
- DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */
9 `+ z0 A. _( K0 ] - DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */# w1 A& j9 G6 u% I
- DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */
6 M' E' K9 L' y - DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */
2 _/ L. l9 n) p1 I - DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */
& @9 X- s! U1 [( t( G# p1 R& s* E, K2 s
% n( J4 @" l6 Y. w! K8 J- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
8 a7 D' U& m0 p: j+ \' N - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;6 L& M8 q1 \! C! S
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
; W1 @* l$ d8 l y; W# J! N. e - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;1 Y% H; k6 ], g% l
- NVIC_Init(&NVIC_InitStructure);
复制代码
/ q5 N# ^1 @; u/ |8 e& U+ j而NVIC_Init()这个函数: - /**1 m" u d9 D) E) s! a* N& ^/ {
- * @brief Initializes the NVIC peripheral according to the specified; S' p" P: [1 ^5 z! ?+ y
- * parameters in the NVIC_InitStruct.& k9 n+ P4 Z& j" T2 f+ }! S
- * @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
! G% b( X; }1 \0 |& u- Z: Z& Z( X3 n - * the configuration information for the specified NVIC peripheral.
* @3 N% u L0 U8 a) K/ H - * @retval None* {( x, K5 b- v# [2 p, z0 J5 }1 {
- */- V% o. k+ ?6 h N2 X& } P% K
- void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
: _# d1 Z% m7 P1 M: I& j7 A - {
0 s% j, _! \4 l4 S, H+ B. { - uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
. h F" Q9 o2 `! i# D/ y6 z: U# h - ! w; e5 e3 ~ H$ d+ ?
- /* Check the parameters */
: e* m" a1 z! K) o - assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
4 ?& s& \2 A4 n6 V; {9 c - assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority)); " _9 O+ `$ f7 x% n/ g
- assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
# ?" H. G$ c% d2 ^ - & J; r, P- H( m2 U, C# l8 X
- if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)# n0 s" P) G0 M2 K
- {
/ L6 b2 E( r( V* X3 @ - /* Compute the Corresponding IRQ Priority --------------------------------*/ - i9 R' E6 K; F
- tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
. b6 o3 D% D% W - tmppre = (0x4 - tmppriority);; f$ G% _, ~( A C/ M8 h3 L
- tmpsub = tmpsub >> tmppriority;
5 z4 q) D6 e: X. t0 w - ( S: X9 G: c& I/ _0 y
- tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;& u7 \% U% q2 n- O, ?7 [; a
- tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
2 \ y) ?3 h% ]$ K9 R - tmppriority = tmppriority << 0x04;
8 V# l! Y# C: \3 D3 C5 { - $ H, n5 {6 s# h
- NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
- O2 k6 f& h* ~0 Y - 0 Y' t1 ]* N: L/ w- [3 C- q
- /* Enable the Selected IRQ Channels --------------------------------------*/. C# V' [4 @+ Z8 S" Z- D' S2 b
- NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =+ U+ k( _/ o% R
- (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);* o u2 o, u& I4 |
- }
2 X8 z/ j: _( ~! g$ s - else
4 s4 h2 Y, m Y/ M - {8 V7 K8 _0 L( F9 S& D/ M5 I
- /* Disable the Selected IRQ Channels -------------------------------------*/6 m& i, E- a9 S0 |" @8 V& C
- NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
; G! c8 z, E3 W! G - (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);: {4 E9 i/ m! F/ t
- }7 C2 }: r6 I5 O' ^, z4 V" @8 i
- }
复制代码 1 R5 _6 y. s; ]( m( }( W/ R
可以看到,它会去设置几个寄存器:NVIC的IP,ISER,ICER等等,NVIC是基址,为: - #define SCS_BASE (0xE000E000) /*!< System Control Space Base Address */
8 H2 |# o" \# r0 d - #define NVIC_BASE (SCS_BASE + 0x0100) /*!< NVIC Base Address */
9 n+ }8 W% M8 g. H; [7 ? - #define SCB_BASE (SCS_BASE + 0x0D00) /*!< System Control Block Base Address */0 i) C! y8 K( J% e' R
- 6 Q5 j% a% h4 i9 A+ \
- / n: M+ J7 b" S' X; {
- #define NVIC ((NVIC_Type *) NVIC_BASE) /*!< NVIC configuration struct */
复制代码 ! ?8 G* p- i1 v* q
NVIC_Type为: - /** @addtogroup CMSIS_CM3_NVIC CMSIS CM3 NVIC& X( M& ^6 x8 c: l$ o
- memory mapped structure for Nested Vectored Interrupt Controller (NVIC) i3 l# h& t* O1 A
- @{3 C9 y+ r( t6 C! \6 c" A
- */5 u9 ?6 A6 i8 z. E5 O
- typedef struct. b; M" B0 \. K2 E- ?9 T/ G' \
- {7 x v: i. @5 F
- __IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */ M; m4 R- ?+ `' g9 I# @" h
- uint32_t RESERVED0[24];
3 y9 Z9 Z5 X0 l1 Z* M+ B# G/ T - __IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */
' g( O8 k3 v1 K+ ~. f, R- H& `) @ - uint32_t RSERVED1[24]; a& j+ E6 h- E" `
- __IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */
p: k: ^9 r0 m2 ~$ _. @' u; e/ N/ i* b; O - uint32_t RESERVED2[24];
0 A: v4 F. Y8 m" C2 N& { - __IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */- Y2 ^- g2 y& W/ R) }
- uint32_t RESERVED3[24]; 2 s- p$ U, X! G: }) j! F. _
- __IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register *// m6 D% s: Z, A- Q3 `( n
- uint32_t RESERVED4[56]; ; j) R* ^, n" E( c" v; _9 s/ c
- __IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) */
) T5 r& K* H# A3 G$ d- h2 J - uint32_t RESERVED5[644];
1 [! [3 w$ r3 j3 X - __O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */' R8 ~* b5 K- v9 d+ m/ }
- } NVIC_Type;
6 i& T# B" m, y: g U - /*@}*/ /* end of group CMSIS_CM3_NVIC */
复制代码
. A2 G+ S1 U- i0 P1 h2 G从上面可以了解到的是,NVIC的寄存器的基址是没有错的,《The Definitive Guide to the ARM Cortex-M3》 85页有个比较详细的内存图;或者查看《Cortex-M3 Technical Reference Manual Revision r1p1》3.4 System address map,6.3 NVIC programmers model: 2 [" U2 G; D M. B
5 f& p) H6 u9 M9 D0 F7 u+ D3 |以及:
, _% |! N8 F% ]. V. \
# a! D" S I8 [( H) w
B3.4 Nested Vectored Interrupt Controller (NVIC)的相关说明,例如:
H: X( m P U: O7 o! z/ ?
3 j3 f/ E, K7 c( M5 e
当然,你看权威指南也可以的,在其APPENDIX D:NVIC Registers Quick Reference里面也有所描述。 但还有一个问题,我怎么知道这个Interrupt Set-Enable Registers寄存器的哪个位对应哪个中断呢?例如NVIC_ISER0的第0位对应哪个呢,其实,上面的表B3-31的说明已经说了,每一位对应一个中断号,所以我们还得看看stm32F103对应的中断号,可以查阅《RM0008:Reference manual》的第10章,Interrupts and events中的中断向量表,找到对应MD容量的那个表Table 63. Vector table for other STM32F10xxx devices,前面16个M3内核的中断,不可以从这个寄存器里控制,所以不管,我们从WWDG开始,可以看到这个表中的第一列即对应于寄存器中的某位(超过31的自己换算一下即可):
+ g; Z# x3 Y, M7 t1 x
: s% x2 q$ }- p- T% K) F
可以看到,STM32F10x standard peripheral library文件stm32f10x.h中的中断号的定义是能够与这里对应上的。 另外,stm32F103RB的Datasheet(CD00161566)里面的2.3.5 Nested vectored interrupt controller (NVIC)提到F103仅有43个可屏蔽中断,所以只需用到NVIC_ISER0和NVIC_ISER1来设置启用外设中断。
$ U& v* M3 j6 v, A& K! u |