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