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