引言
在平時的工作中,我們經常會遇到這樣的情況:有人來找你做一些事情,而且這些事情要比手頭的工作更重要。那現在就需要停下手中的工作,先去完成突然到來的這部分工作。這樣的情況也類似於圖論中的關鍵路徑中,突然在當前事件之前插入了一個新的事件,那我們不得不先去完成之前的那個任務,才能繼續完成后面的工作。
上述情況是非常常見的,那在STM32中,我們如果遇到了比當前任務更緊急的事情需要去處理,我們應該怎么辦呢?這個時候,我們需要通過中斷來完成這樣的任務。
在現實生活中,突然出現的任務一定有輕重緩急之分。如果同時出現許多的臨時任務,我們一定會首先評估他們誰更需要先被處理掉,然后再依次進行處理。在STM32中,我們也需要這樣的功能,多個中斷來臨的時候,我們需要首先判斷這個中斷緊不緊急,然后再考慮處理的先后順序。那我們是由什么來控制這樣的順序的呢?毫無疑問,這就是通過嵌套向量中斷控制器(NVIC)完成的。
NVIC簡介
CM3內核支持256個中斷,包括16個內核中斷和250個外部中斷,同時具有256級的可編程中斷設置。而STM32只使用了一部分。STM32擁有84個中斷,包括16個內核中斷和68個可屏蔽中斷(STM32F107系列才使用了68個可屏蔽中斷),還擁有16級可編程的中斷優先級。STM32F103系列只使用了60個可屏蔽中斷。
STM32中控制中斷優先級的寄存器組是IP[240]
。是由240個8bit的寄存器組成的。而STM32F103只用了前六十個(0 ~ 59)。在STM32F103系列單片機中,這8bit也沒有全部使用,而是只使用了其高四位(4 ~ 7位)。下圖是中斷分組的分配情況。
優先級分組 | 搶占優先級 | 響應優先級 | 高四位描述 |
---|---|---|---|
0 | 0級 | 0 ~ 15級 | 0bit用於搶占優先級 4bit用於響應優先級 |
1 | 0 ~ 1級 | 0 ~ 7級 | 1bit用於搶占優先級 3bit用於響應優先級 |
2 | 0 ~ 3級 | 0 ~ 3級 | 2bit用於搶占優先級 2bit用於響應優先級 |
3 | 0 ~ 7級 | 0 ~ 1級 | 3bit用於搶占優先級 1bit用於響應優先級 |
4 | 0 ~ 15級 | 0級 | 4bit用於搶占優先級 0bit用於響應優先級 |
響應優先級又稱為子優先級。
數值越小,優先級越高。
這里需要關注的是,搶占優先級的級別高於子優先級。高搶占優先級的中斷可以在低搶占優先級中斷執行的過程中被響應,反之則不行。這就是所謂的中斷嵌套。換句話說呢,就是高搶占優先級中斷可以搶占低搶占優先級中斷的執行。當多個中斷同時到來,而且他們的搶占優先級相同,則先進入子優先級更高的中斷。
但是,當搶占優先級相同的情況下,高子優先級中斷不能打斷低子優先級中斷,也就是不能實現中斷嵌套。這種情況下,高子優先級中斷必須先等待低子優先級中斷執行完成,在進行自己的中斷。
軟件部分
配置某個中斷優先級的步驟如下:
- 配置中斷優先級分組
- 配置某一中斷的優先級
配置中斷優先級分組
這一步可以通過函數 NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
來完成。關於優先級分組的內容上文已經做過了講解。這里提供一個使用范例:
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
配置某一個中斷的優先級
這一步我們需要用到一個函數 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_Init
函數初始化
這里給出一個范例:
NVIC_InitTypeDef NVIC_InitStructure; //聲明結構體
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //聲明中斷名稱
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //設置搶占優先級為2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //設置響應優先級為3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中斷
NVIC_Init(&NVIC_InitStructure); //對上述配置進行初始化
至此,我們就完成了對某一中斷優先級的配置,再根據不同的中斷配置不同的觸發條件等信息,就可以完成在特定條件下的中斷。這里不再展開敘述。
關於NVIC和中斷嵌套的更多的神奇理解可以參考下面這篇文章的后半部分:STM32 NVIC