## 中斷
### 簡介
- 中斷(Interrupt)是一種事件響應機制,可以使單片機在處理其他任務的同時及時響應并處理緊急事件,提高系統的實時性能和可靠性。
- 中斷是一種異步事件響應方式,當指定的事件發生時,中斷處理器會立即暫停當前程序執行,轉而執行中斷服務程序,處理完中斷事件后再返回原來的程序執行流程。
### 組成部分
- 在單片機中,中斷由中斷源、中斷控制器和中斷服務程序組成。
#### 中斷源
- 產生中斷事件的硬件設備或軟件程序,如定時器溢出、外部輸入信號、串口接收數據等。
#### 中斷控制器
- 負責檢測中斷源產生的中斷請求,并向CPU發送中斷信號,在CPU完成當前指令后跳轉到相應的中斷服務程序。
在32位單片機中,中斷控制器通常由NVIC(Nested Vector Interrupt Controller)實現。NVIC支持多達240個中斷源,可以靈活配置優先級、屏蔽中斷等設置。
下面是一個在STM32F4單片機上使用NVIC實現中斷初始化的示例代碼:
```c
// 初始化中斷
void init_interrupt(void) {
// 使能IRQ中斷
NVIC_SetPriorityGrouping(NVIC_PriorityGroup_4);
// 初始化中斷優先級
NVIC_Init(&NVIC_InitStructure);
}
```
#### 中斷服務程序
- 是一個用于處理特定中斷事件的程序。
- 包括清除中斷標志位、保存現場、執行特定操作、恢復現場等步驟,最后通過返回指令返回到原來的任務流程。
在32位單片機中,中斷服務程序通常由ISR(Interrupt Service Routine)實現。ISR是一種特殊的函數,具有固定的格式和命名規則,以便編譯器正確地生成中斷向量表和中斷服務程序入口地址。例如,對于外部中斷EXTI1的中斷服務程序,其函數定義應該如下所示:
```c
// EXTI1中斷服務程序
void EXTI1_IRQHandler(void) {
// 處理中斷事件
// ...
// 清除中斷標志位
EXTI_ClearITPendingBit(EXTI_Line1);
}
```
### 響應過程
- 中斷響應過程主要包括中斷源產生中斷請求、中斷控制器檢測到中斷請求、CPU暫停當前任務跳轉到中斷服務程序、中斷服務程序處理中斷事件、CPU返回原任務繼續執行等幾個步驟。
以下是中斷響應過程的詳細說明:
1. 中斷源產生中斷請求
當某個硬件設備或軟件程序產生了一個需要CPU立即處理的事件時,會向中斷控制器發送中斷請求信號。例如,當定時器溢出時,定時器會向中斷控制器發送一個定時器中斷請求。
2. 中斷控制器檢測到中斷請求
中斷控制器不斷檢測是否有中斷請求發生,當檢測到中斷請求時,會向CPU發送中斷信號,通知CPU有中斷事件需要處理。
在32位單片機中,中斷控制器通常由NVIC實現。NVIC會根據中斷優先級和屏蔽設置等信息來判斷是否響應中斷請求,并向CPU發送相應的中斷信號。
3. CPU暫停當前任務,跳轉到中斷服務程序
當CPU收到中斷信號后,會暫停正在執行的任務,并將當前指令的下一條指令地址(PC)保存到堆棧中,以便在中斷服務程序執行完后返回原來的任務流程。然后,CPU會從中斷向量表中讀取相應中斷源對應的中斷服務程序入口地址,并跳轉到該地址開始執行中斷服務程序。
4. 中斷服務程序處理中斷事件
中斷服務程序是用于處理特定中斷事件的程序,它包括清除中斷標志位、保存現場、執行特定操作、恢復現場等步驟,最后通過返回指令返回到原來的任務流程。
在中斷服務程序中,需要清除中斷標志位以便下一次中斷響應,例如,對于外部中斷EXTI1的中斷服務程序,可以使用以下代碼清除中斷標志位:
```c
// 清除中斷標志位
EXTI_ClearITPendingBit(EXTI_Line1);
```
5. CPU返回原任務繼續執行
當中斷服務程序執行完畢后,CPU會從堆棧中讀取之前保存的PC值,恢復執行原來的任務流程,即返回到之前暫停的任務處,繼續執行原來的指令。
### 中斷向量表
- 中斷向量表(Interrupt Vector Table)是一種特殊的數據結構,用于存儲所有中斷服務程序的入口地址。
- 在單片機啟動時,中斷向量表會被加載到固定的內存位置,并在中斷響應時被CPU使用。
- 它通常是一個連續的存儲區域,每個中斷源都占據一個固定的位置。
- 當中斷控制器檢測到中斷請求時,會將相應的中斷編號作為索引,從中斷向量表中讀取對應的中斷服務程序入口地址,并跳轉到該地址開始執行中斷服務程序。
以下是在STM32F4單片機上定義中斷向量表的示例代碼:
```c
// 中斷向量表
void (* const InterruptVectorTable[]) (void) __attribute__ ((section(".isr_vector"))) = {
(void (*)(void)) &_estack, // 棧指針
Reset_Handler, // 復位中斷
NMI_Handler, // 非屏蔽中斷
HardFault_Handler, // 硬件故障中斷
MemManage_Handler, // 存儲器管理中斷
BusFault_Handler, // 總線錯誤中斷
UsageFault_Handler, // 用法錯誤中斷
0, // 保留
0, // 保留
0, // 保留
0, // 保留
SVC_Handler, // 系統調用中斷
DebugMon_Handler, // 調試監視中斷
0, // 保留
PendSV_Handler, // 掛起中斷
SysTick_Handler, // 系統定時器中斷
// 外部中斷0~15的中斷服務程序
EXTI0_IRQHandler,
EXTI1_IRQHandler,
EXTI2_IRQHandler,
EXTI3_IRQHandler,
EXTI4_IRQHandler,
EXTI9_5_IRQHandler,
EXTI15_10_IRQHandler,
// 更多的外部中斷服務程序
};
```
### 注意事項
- 在使用中斷時,需要注意一些問題,如中斷的優先級、中斷嵌套、中斷延遲等,以確保系統的穩定性和可靠性。
#### 中斷優先級
- 中斷優先級可以決定哪個中斷優先處理。
- 在NVIC中,中斷優先級分為4位或3位,越高的值表示越低的優先級。
- 在設計中,需要根據具體應用場景來設置合理的中斷優先級,以避免因低優先級中斷被屏蔽而導致緊急事件無法及時處理的情況。
以下是在STM32F4單片機上設置中斷優先級的示例代碼:
```c
// 設置某個中斷的優先級
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 搶占優先級為1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; // 子優先級為1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
```
#### 中斷嵌套
- 中斷響應時,如果又有新的中斷請求產生,就會發生中斷嵌套。
- 在處理中斷嵌套時,需要注意保存現場和恢復現場的順序,以免出現逆序恢復導致系統錯誤的情況。
以下是在STM32F4單片機上處理中斷嵌套的示例代碼:
```c
// 外部中斷0服務程序
void EXTI0_IRQHandler(void) {
// 保存現場
NVIC_SystemHandlerPendingBitConfig(SYS_TICK, DISABLE); // 禁用SysTick中斷
__disable_irq(); // 禁用所有中斷
// 處理中斷
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)) {
EXTI_ClearITPendingBit(EXTI_Line0);
// 觸發外部中斷1
EXTI_GenerateSWInterrupt(EXTI_Line1);
}
// 恢復現場
__enable_irq(); // 使能所有中斷
NVIC_SystemHandlerPendingBitConfig(SYS_TICK, ENABLE); // 使能SysTick中斷
}
```
#### 中斷延遲
- 當中斷服務程序執行時間過長或存在阻塞操作時,會導致其他中斷響應受到影響,甚至出現錯誤。
- 在設計中,需要盡量避免中斷延遲,并采取一些手段優化中斷服務程序的執行效率,以確保系統實時性。
以下是降低一些常見中斷延遲的方法:
- 將中斷服務程序的執行時間盡量縮短;
- 禁止在中斷服務程序中使用延時函數、鎖存器等方式;
- 對于需要較長時間處理的中斷事件,可以通過將其放在主循環中異步處理的方式來避免中斷延遲。
#### 響應優先級和先占優先級
在中斷處理中,常常涉及到兩個概念:響應優先級和先占優先級。
響應優先級是指中斷請求發生時,CPU按照一定的優先級順序來處理多個中斷請求。具有更高響應優先級的中斷會在低優先級中斷之前得到處理。
先占優先級是指在某個中斷服務程序執行期間,不允許其他優先級低于其自身的中斷干擾它的執行。如果此時發生了優先級更高的中斷請求,則需要等待當前中斷服務程序執行完成后再進行處理,這就是優先級搶占。
在STM32F4單片機中,中斷響應優先級分為搶占優先級和響應優先級,其中搶占優先級用于決定同優先級中斷之間的搶占關系,而響應優先級則用于決定不同優先級中斷之間的響應順序。
以下是在STM32F4單片機中設置中斷優先級的示例代碼:
```c
// 設置中斷優先級
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 搶占優先級為1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; // 響應優先級為1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
```
在該示例中,搶占優先級為1,響應優先級為1,表示該中斷服務程序的優先級比所有響應優先級為2及以下的中斷都要高。
總之,在設計中斷處理過程時,需要合理設置中斷響應和搶占優先級,以滿足系統實時性和穩定性的要求。
### 注意事項:
#### 中斷開關
在使用中斷前,需要先打開中斷總開關,使得單片機可以響應中斷請求。在STM32F4單片機中,可以通過以下代碼打開中斷總開關:
```c
// 打開中斷總開關
__enable_irq();
```
在使用完中斷后,需要關閉中斷總開關,以避免產生其他不必要的中斷響應。在STM32F4單片機中,可以通過以下代碼關閉中斷總開關:
```c
// 關閉中斷總開關
__disable_irq();
```
#### 中斷優先級
在使用中斷時,需要根據實際需求設置中斷優先級,以確保不同優先級中斷的響應順序和搶占關系符合設計要求。如果中斷優先級設置不當,可能會導致系統性能下降或出現嚴重錯誤。
#### 中斷嵌套
當多個中斷同時發生時,可能會出現中斷嵌套的情況,這會影響中斷處理效率和正確性。因此,在編寫中斷服務程序時,需要考慮中斷嵌套的情況,并采取相應的措施避免嵌套帶來的問題。
#### 中斷延遲
當中斷服務程序執行時間過長或存在阻塞操作時,會導致其他中斷響應受到影響,甚至出現錯誤。因此,在設計中,需要盡量避免中斷延遲,并采取一些手段優化中斷服務程序的執行效率,以確保系統實時性。
#### 中斷與優先級反轉
中斷與優先級反轉是一種由于中斷優先級問題導致的系統問題,這可能會使得高優先級的任務被低優先級的中斷事件阻塞。在設計中需要避免出現中斷與優先級反轉的情況,并采取一些手段解決該問題。
總之,在使用中斷時,需要全面考慮系統的實時性、可靠性和穩定性,以確保中斷處理能夠達到預期的效果。
|