中斷和事件(Interrupts and events)
嵌套向量中斷控制器(Nested vectored interrupt controller -NVIC)
-
中斷是相對CPU而言的,因此例如IIC、定時器這些芯片內產生的中斷也被稱為外部中斷,不能狹隘的理解為由芯片外的信號觸發
-
EXTI被稱為外部中斷/事件控制器(External interrupt/event controller)
-
什么是中斷?什么是事件
-
EXTI的23個中斷事件線與中斷的關系? 在同一時刻每個中斷線只能相應一個GPIO端口的中斷,不能夠同時相應所有端口的中斷事件
-
優先級定義
在
NVIC
有一個專門的寄存器:中斷優先級寄存器NVIC_IPRx
用來配置外部中斷的優先級,IPR
寬度為8bit
,原則上每個外部中斷可配置的優先級為0~255
,數值越小,優先級越高。在STM32F4
中使用了高4位設置中斷優先級,也就是有16個可編程優先級。
中斷優先級被分組為搶占優先級和子優先級。如果有多個中斷同時響應,搶占優先級高的就會搶占搶占優先級低的優先得到執行,如果搶占優先級相同,就比較子優先級。如果搶占優先級和子優先級都相同的話,就比較他們的硬件中斷編號,編號越小,優先級越高。
寄存器介紹
上面說到 NVIC 控制着芯片的中斷相關功能, 那么肯定有很多對應的寄存器,在固件庫 core_cm3.h 文件內定義了一個 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;
在配置中斷時,我們通常使用的只有 ISER、 ICER 和 IP 這三個寄存器,ISER是中斷使能寄存器,ICER是中斷清除寄存器,IP 是中斷優先級寄存器。在固件庫 core_cm3.h文件后面,還提供了一些對 NVIC 操作的庫函數,這些函數都是遵循 CMSIS 標准, 所以只要是基於 Cortex-M3 內核的芯片都可以用這些函數來操作 NVIC,只不過我們很少這樣做,甚至不使用這些函數,因為在后面我們會有更簡單的辦法來配置中斷。至於這些函數內容,大家如果有興趣的話,可以打開我們庫函數版本任意程序,找到 core_cm3.h 文件查看即可。
這里多提一點__IO
的用法:
/* IO definitions (access restrictions to peripheral registers) */
#ifdef __cplusplus
#define __I volatile /*!< defines 'read only' permissions */
#else
#define __I volatile const /*!< defines 'read only' permissions */
#endif
#define __O volatile /*!< defines 'write only' permissions */
#define __IO volatile /*!< defines 'read / write' permissions */
其實就是將volatile關鍵字進行了重定義,用來區分讀寫,僅僅是語法提醒層面,並不強制。
中斷配置
前面講解了那么多中斷知識, 如果大家不理解也沒有關系, 我們會應用即可,等到后面 STM32 熟練了,再回過頭深入了解自然就會明白。要使用中斷我們就需要先配置它,通常都需經過這幾步:
(1)使能外設某個中斷,這個具體是由外設相關中斷使能位來控制,比如
定時器有溢出中斷,這個可由定時器的控制寄存器中相應中斷使能位來控制。
(2)設置中斷優先級分組,初始化 NVIC_InitTypeDef 結構體,設置搶占
優先級和響應優先級,使能中斷請求。
NVIC_InitTypeDef 結構體如下:
typedef struct
{
uint8_t NVIC_IRQChannel; //中斷源
uint8_t NVIC_IRQChannelPreemptionPriority; //搶占優先級
uint8_t NVIC_IRQChannelSubPriority; //響應優先級
FunctionalState NVIC_IRQChannelCmd; //中斷使能或失能
} NVIC_InitTypeDef;
下面我們對 NVIC_InitTypeDef 結構體成員進行一下簡單介紹。
1.NVIC_IRQChannel:中斷源的設置,不同的外設中斷,中斷源不一樣,自
然名字也不一樣,所以名字不能寫錯,否則不會進入中斷。中斷源放在stm32f10x.h 文件的 IRQn_Type結構體內,由於內容太多,這里就不復制所有中斷源,只截取一部分,如下:
typedef enum IRQn
{
//Cortex-M3 處理器異常編號
NonMaskableInt_IRQn = -14,
MemoryManagement_IRQn = -12,
BusFault_IRQn = -11,
UsageFault_IRQn = -10,
SVCall_IRQn = -5,
DebugMonitor_IRQn = -4,
PendSV_IRQn = -2,
SysTick_IRQn = -1,
//STM32 外部中斷編號
WWDG_IRQn = 0,
PVD_IRQn = 1,
TAMP_STAMP_IRQn = 2,
// 限於篇幅,中間部分代碼省略,具體的可查看庫文件 stm32f10x.h
DMA2_Channel2_IRQn = 57,
DMA2_Channel3_IRQn = 58,
DMA2_Channel4_5_IRQn = 59
}IRQn_Type;
2.NVIC_IRQChannelPreemptionPriority:搶占優先級,具體的值要根據優先級分組來確定,可以參考前面中斷優先級分組內容。
3.NVIC_IRQChannelSubPriority:響應優先級,具體的值要根據優先級分組
來確定,可以參考前面中斷優先級分組內容。
4.NVIC_IRQChannelCmd:中斷使能/失能設置,使能配置為 ENABLE,失能配置為 DISABLE。