
STM32的NVIC理解 例程: /* Configure one bit for preemption priority */5 A: k+ f$ V' n; O/ P- V7 p. e3 r - t7 ~6 g5 Z3 U% r' s+ _5 a% W NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);& Y+ b! e: A' V% q: J4 u- q /* Enable the WAKEUP_BUTTON_EXTI_IRQn Interrupt *// a9 y1 y* O/ q M" x( {. M0 Y7 B NVIC_InitStructure.NVIC_IRQChannel = WAKEUP_BUTTON_EXTI_IRQn;3 a' ]" n H5 ^% \+ |/ P NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = PreemptionPriorityValue; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;+ o: U& \3 e3 y! `& H8 w+ ~ NVIC_Init(&NVIC_InitStructure); " p2 F8 c8 h( k# X+ l /* Enable the KEY_BUTTON_EXTI_IRQn Interrupt */% d; A) I1 j' x- b& q) T NVIC_InitStructure.NVIC_IRQChannel = KEY_BUTTON_EXTI_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;/ e* P3 g! O, Y; K* D; u$ S NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;' C/ i+ q: E0 w' ~) T NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;* i/ j9 i, I: \' @* I NVIC_Init(&NVIC_InitStructure);$ B8 Y2 `/ N4 I y + T1 a+ p$ c6 C7 `7 x Q" `2 |3 g /* Configure the SysTick Handler Priority: Preemption priority and subpriority */- I( x4 d! I) g [1 j' ?* a, Z NVIC_SetPriority(SysTick_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), !PreemptionPriorityValue, 0)); ![]() 这两日被些许琐事所牵,身心俱累,本无心记录,但回想前几天的点滴收获,无录甚是可惜,于是身倚椅,旁敲键盘记之,唯慰藉自己及共享同道仁友。废言不再多,就此入题。 NVIC,中文名嵌套中断向量控制器,是Cortex-M3系列控制器内部独有集成单元,与CPU结合紧密,降低中断延迟时间并且能更加高效处理后续中断。举个例子,比如火车站买票,那些火车站的规章制度就是NVIC,规定学生和军人有比一般人更高优先级,它们则给你单独安排个窗口,同学与同学之间也有区别,那就是你也得排队,也就是你的组别(抢断优先级)和你的排队序号(响应优先级)决定你何时能买到票。 抢断优先级,顾名思义,能再别人中断是抢占别人中断,实现中断嵌套。响应优先级则只能排队,不能抢在前面插别人的对,即不能嵌套。 STM32中指定优先级的寄存器为4位,其定义如下: 第0组:所有4位用于指定响应优先级7 t( M5 u' N8 S+ C 第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级$ X: x( |' \% A C 第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级 第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级 第4组:所有4位用于指定抢占式优先级 以上定义也称作中断优先级分组,相关内容在STM32固件库的misc.h文件中有详细定义。 基础了解了就可以对中断进行操作了。 第一步:使用void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)函数对优先级分组配置。NVIC_PriorityGroup可以配置为 NVIC_PriorityGroup_0 => 选择第0组 NVIC_PriorityGroup_1 => 选择第1组3 Y! K4 ?0 D1 y# h% q# C9 _2 b NVIC_PriorityGroup_2 => 选择第2组$ J5 \$ W0 ~8 Z NVIC_PriorityGroup_3 => 选择第3组" i$ ^) H' {* q# \" E9 @ NVIC_PriorityGroup_4 => 选择第4组 例如:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0)配置为0组。 第二步:中断初始化结构体配置,结构体类型定义如下: typedef struct { uint8_t NVIC_IRQChannel; uint8_t NVIC_IRQChannelPreemptionPriority; //抢断优先级 uint8_t NVIC_IRQChannelSubPriority; //响应优先级 FunctionalState NVIC_IRQChannelCmd; } NVIC_InitTypeDef; 例如:STM32外部中断0配置如下 EXTI_NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; EXTI_NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级别(0~1) EXTI_NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7; //响应优先级别(0~7) EXTI_NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 第三步:中断初始化结构体初始化操作如下 NVIC_Init(&EXTI_NVIC_InitStructure); 第四步:开关总中断操作。在STM32中是通过改变CPU优先级来允许和禁止中断的。 (1) 下面两个函数等效关闭总中断 void NVIC_SETPRIMASK(void); 6 ^4 [, Q0 x9 [! `, h2 ^- T4 T& T void NVIC_SETFAULTMASK(void); (2) 下面两个函数等效开放总中断 void NVIC_RESETPRIMASK(void); 8 p5 h& n) f9 M' d7 c2 A void NVIC_RESETFAULTMASK(void); (3) 常用操作是先关后开中断 NVIC_SETPRIMASK(); // Disable Interrupts NVIC_RESETPRIMASK(); // Enable Interrupts 两种类型函数要成对使用。 STM32有43个channel的settable的中断源;AIRC(Application Interrupt and Reset Register)寄存器中有用于指定优先级的4 bits。这4个bits用于分配preemption优先级和sub优先级,在STM32的固件库中定义如下 #define NVIC_PriorityGroup_0 ((u32)0x700): y3 m) }: S; Z9 g2 M. g5 t #define NVIC_PriorityGroup_1 ((u32)0x600) #define NVIC_PriorityGroup_2 ((u32)0x500) #define NVIC_PriorityGroup_3 ((u32)0x400) #define NVIC_PriorityGroup_4 ((u32)0x300) : y9 f* K ~ t8 `5 F 形象化的理解是:1 Q. b& ^0 E1 I0 g. ` " ?2 h5 `1 c% c 你是上帝,6 |2 z$ k5 M6 J+ M a( y7 C* R 造了43个人,这么多人要分社会阶级和社会阶层了;4 Y8 P2 E0 J, F) z4 T 因为“阶级”的词性比较重;"阶层"比较中性,. c4 J2 }2 b- \+ |3 t: A& n% Z& B 所以preemption优先级->阶级;每个阶级内部,有一些阶层,sub优先级->阶层; 如果按照NVIC_PriorityGroup_4这么分,就分为了16个阶级(1个阶层就是1个preemption优先级),0个阶层;高阶级的人,可以打断低阶级的正在做事的人(嵌套),最多可以完成1个中断和15级嵌套。 每个阶级(每个preemption优先级),你来指定这43人中,谁进入该阶级;一个人叫EXTI0_IRQChannel,你指定他进入“阶级8”,则 NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;. h- D7 E, ^+ h, T3 s/ [ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8; // 指定抢占式优先级别1,可取0-15, t* ?2 L$ a9 l$ B / L w% k0 M7 ?! T+ e B 另外,在同一阶级内部,一个人在做事的时候,另外一个人不能打断他;(preemption优先级别相同的中断源之间没有嵌套关系)' _: E9 I) g" K8 P. m% {- m1 ^ 还有,如果他们两个同时想做事,因为没有阶层,那么就根据Vector table中的物理排序,让排名靠前的人去做; 又有1个人SPI1_IRQChannel,设定如下 _* g5 j A# N% I NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQChannel;* S" g- K* [; H! L+ P3 } NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定抢占式优先级别1,可取0-15 ; z3 b* m3 @7 E6 m3 g+ [ SPI1_IRQChannel的阶级高,EXTI0_IRQChannel做事的时候可以打断(嵌套)。, B0 w5 }; F% s# L4 s 1 K, |. A& Y3 T2 c |: G3 W* y / @' x' p& y: m) B1 F( h 如果按照NVIC_PriorityGroup_3这么分,就分为了8个阶级(1个阶级是1个preemption优先级),每个阶级内有2个阶层(sub优先级);高阶级的人,可以打断低阶级的正在做事的人(嵌套),最多可以完成1个中断和7级嵌套。 8 r& T% |8 c: \& X q; W `9 I% C0 m 每个阶级(每个preemption优先级),你来指定这43人中,谁进入该阶级;一个人叫EXTI0_IRQChannel,你指定他进入“阶级3”,则: NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 指定抢占式优先级别1,可取0-77 W2 c/ u# S5 D: E( z 还需要指定他的阶层:7 `6 s( ]0 q* w* w+ l NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定响应优先级别0,可取0-1 另有1个人叫EXTI9_5_IRQChannel,他的阶级和阶层设定如下. i5 [1 V7 s% i9 v7 G NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;' Q2 C$ Y( Z6 f# X$ ] NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 指定抢占式优先级别0,可取0-7 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1 Q0 Y v/ N) C* |; F 那么这两个人是同一阶级的兄弟,一个人在做事的时候,另外一个人不能打断他;(preemption优先级别相同的中断源之间没有嵌套关系) 如果他们两个同时想做事,因为前者的阶层高,所以前者优先。 还有一个人叫USART1_IRQChannel,他的阶级和阶层设定如下 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 指定抢占式优先级别0,可取0-7( F% c3 p5 Y7 A" G) j, R" a NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1( D* \+ }- `! H3 a USART1_IRQChannel的优先级最高,当前面两个人做事的时候,他都可以打断(嵌套)。, h9 q; G3 f: x2 K2 ^ " V4 k# Z( I) C- o* e $ g3 V) g$ o+ q |