STM32 NVIC 中斷優先級管理
- CM3 內核支持 256 個中斷,其中包含了 16 個內核中斷和 240 個外部中斷,并且具有 256級的可編程中斷設置。
- STM32 并沒有使用 CM3 內核的全部東西,而是只用了它的一部分。STM32 有 84 個中斷,包括 16 個內核中斷和 68 個可屏蔽中斷,具有 16 級可編程的中斷優先級。
- STM32 的 68 個可屏蔽中斷,在 STM32F103 系列上面,又只有 60 個(在 107 系列才有 68 個)。因為我們開發板選擇的芯片是 STM32F103 系列的所以我們就只針對 STM32F103 系列這 60 個可屏蔽中斷進行介紹。
中斷管理方法:
首先,對STM32中斷進行分組,組0~4。同時,對每個中斷設置一個搶占優先級和一個響應優先級值。這里簡單介紹一下 STM32 的中斷分組:STM32 將中斷分為 5 個組,組 0~4。該分組的設置是由 SCB->AIRCR 寄存器的 bit10~8 來定義的。具體的分配關系如表 4.5.1 所示:
搶占優先級和響應優先級的區別:
- 高優先級的搶占優先級是可以打斷正在進行的低搶占優先級中斷的(值越小越高),在搶占優先級不同的情況下響應優先級是沒有用的。
- 搶占優先級相同的中斷,高響應優先級不可以打斷低響應優先級的中斷。
- 搶占優先級相同的中斷,當兩個中斷同時發生的情況下,哪個響應優先級高,哪個先執行。
- 如果兩個中斷的搶占優先級和響應優先級都是一樣的話,則看哪個中斷先發生就先執行;
舉例:
假定設置中斷優先級組為2,然后設置中斷3(RTC中斷)的搶占優先級為2,響應優先級為1。 中斷6(外部中斷0)的搶占優先級為3,響應優先級為0。中斷7(外部中斷1)的搶占優先級為2,響應優先級為0。那么這3個中斷的優先級順序為:中斷7>中斷3>中斷6。
一般情況下,系統代碼執行過程中,只設置一次中斷優先級分組,比如分組2,設置好分組之后一般不會再改變分組。隨意改變分組會導致中斷管理混亂,程序出現意想不到的執行結果。
中斷優先級分組函數:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
設置為分組二舉例:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
怎么設置單個中斷的搶占優先級和響應優先級:
中斷設置相關寄存器
- __IO uint8_t IP[240]; //中斷優先級控制的寄存器組
- __IO uint32_t ISER[8]; //中斷使能寄存器組
- __IO uint32_t ICER[8]; //中斷失能寄存器組
- __IO uint32_t ISPR[8]; //中斷掛起寄存器組
- __IO uint32_t ICPR[8]; //中斷解掛寄存器組
- __IO uint32_t IABR[8]; //中斷激活標志位寄存器組
MDK中NVIC寄存器結構體
typedef struct
{__IO uint32_t ISER[8]; uint32_t RESERVED0[24]; __IO uint32_t ICER[8]; uint32_t RSERVED1[24]; __IO uint32_t ISPR[8]; uint32_t RESERVED2[24]; __IO uint32_t ICPR[8]; uint32_t RESERVED3[24]; __IO uint32_t IABR[8]; uint32_t RESERVED4[56]; __IO uint8_t IP[240]; uint32_t RESERVED5[644]; __O uint32_t STIR;
} NVIC_Type;
每個中斷怎么設置優先級?
① 中斷優先級控制的寄存器組:IP[240]
全稱是:Interrupt Priority Registers。240個8位寄存器,每個中斷使用一個寄存器來確定優先級。STM32F10x系列一共60個可屏蔽中斷,使用IP[59]~IP[0]。每個IP寄存器的高4位用來設置搶占和響應優先級(根據分組),低4位沒有用到。
② 中斷使能寄存器組:ISER[8]
作用:用來使能中斷
32位寄存器,每個位控制一個中斷的使能。STM32F10x只有60個可屏蔽中斷,所以只使用了其中的ISER[0]和ISER[1]。ISER[0]的bit0到bit31 分別對應中斷0到31。ISER[1]的bit0到bit27對應中斷32~59;
③ 中斷失能寄存器組:ICER[8]
作用:用來失能中斷
32位寄存器,每個位控制一個中斷的失能。STM32F10x只有60個可屏蔽中斷,所以只使用了其中的ICER[0]和ICER[1]。ICER[0]的bit0到bit31分別對應中斷0到31。ICER[1]的bit0到bit27對應中斷32~59;配置方法跟ISER一樣。
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
④中斷掛起控制寄存器組:ISPR[8]
作用:用來掛起中斷
⑤中斷解掛控制寄存器組:ICPR[8]
作用:用來解掛中斷
static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn);
static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn);
static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn)
⑥中斷激活標志位寄存器組:IABR [8]
作用:只讀,通過它可以知道當前在執行的中斷是哪一個如果對應位為1,說明該中斷正在執行。
static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)
中斷參數初始化函數
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
typedef struct
{uint8_t NVIC_IRQChannel; //設置中斷通道uint8_t NVIC_IRQChannelPreemptionPriority;//設置搶占優先級uint8_t NVIC_IRQChannelSubPriority; //設置響應優先級FunctionalState NVIC_IRQChannelCmd; //使能/使能
} NVIC_InitTypeDef;
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 搶占優先級為1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子優先級位2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據上面指定的參數初始化NVIC寄存器
中斷優先級設置步驟
① 系統運行后先設置中斷優先級分組。調用函數:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);整個系統執行過程中,只設置一次中斷分組。
②針對每個中斷,設置對應的搶占優先級和響應優先級:
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
③ 如果需要掛起/解掛,查看中斷當前激活狀態,分別調用相關函數即可。