中斷系統(tǒng)全解析:從匯編編程到考點(diǎn)精講)
在實(shí)際的單片機(jī)開發(fā)中中斷系統(tǒng)是連接硬件事件與軟件響應(yīng)的核心橋梁。無論是按鍵觸發(fā)、定時(shí)器溢出還是串口接收到數(shù)據(jù)都需要通過中斷機(jī)制來確保CPU能夠及時(shí)響應(yīng)而無需持續(xù)輪詢。對(duì)于學(xué)習(xí)單片機(jī)匯編語言的同學(xué)而言中斷系統(tǒng)既是課程的重點(diǎn)也是期末考試的必考難點(diǎn)。它涉及中斷源、中斷向量、中斷允許控制、中斷優(yōu)先級(jí)、現(xiàn)場(chǎng)保護(hù)與恢復(fù)等一系列緊密關(guān)聯(lián)的概念任何一個(gè)環(huán)節(jié)理解不到位都可能導(dǎo)致程序運(yùn)行異常。本文將以典型的8051系列單片機(jī)為背景深入講解中斷系統(tǒng)的完整工作機(jī)制。我們將從最基本的中斷概念入手逐步拆解中斷響應(yīng)的全過程并結(jié)合具體的匯編代碼示例演示如何編寫中斷服務(wù)程序。更重要的是我們將針對(duì)常見的考點(diǎn)和易錯(cuò)習(xí)題進(jìn)行剖析幫助你不僅理解原理更能應(yīng)對(duì)考試和實(shí)際編程中的問題。通過本文你將掌握中斷系統(tǒng)的配置流程、中斷服務(wù)程序的編寫規(guī)范并學(xué)會(huì)排查中斷不響應(yīng)、中斷嵌套混亂等典型問題。1. 理解中斷系統(tǒng)從硬件事件到軟件響應(yīng)中斷的本質(zhì)是一種硬件觸發(fā)的機(jī)制它允許CPU暫停當(dāng)前正在執(zhí)行的程序轉(zhuǎn)而去處理一個(gè)更緊急的事件處理完畢后再返回原程序繼續(xù)執(zhí)行。這個(gè)過程類似于你在看書時(shí)電話鈴響了你標(biāo)記下當(dāng)前的閱讀位置保護(hù)現(xiàn)場(chǎng)去接電話執(zhí)行中斷服務(wù)程序接完電話后再回來從標(biāo)記的位置繼續(xù)看書恢復(fù)現(xiàn)場(chǎng)。1.1 中斷系統(tǒng)的核心組件在8051單片機(jī)中中斷系統(tǒng)主要由以下幾個(gè)部分構(gòu)成中斷源能夠產(chǎn)生中斷請(qǐng)求信號(hào)的來源。8051通常有5個(gè)固定的中斷源INT0外部中斷0由P3.2引腳引入。T0定時(shí)器/計(jì)數(shù)器0溢出中斷。INT1外部中斷1由P3.3引腳引入。T1定時(shí)器/計(jì)數(shù)器1溢出中斷。TI/RI串行口中斷包含發(fā)送完成(TI)和接收完成(RI)。中斷向量每個(gè)中斷源在程序存儲(chǔ)器ROM中都有一個(gè)固定的入口地址稱為中斷向量。當(dāng)某個(gè)中斷被響應(yīng)時(shí)CPU會(huì)自動(dòng)跳轉(zhuǎn)到對(duì)應(yīng)的中斷向量地址去執(zhí)行程序。這是中斷服務(wù)程序ISR的起點(diǎn)。中斷允許寄存器IE這是一個(gè)可編程的寄存器用于控制整個(gè)中斷系統(tǒng)的總開關(guān)以及每個(gè)中斷源的獨(dú)立開關(guān)。只有相應(yīng)的中斷允許位被置1該中斷請(qǐng)求才有可能被CPU響應(yīng)。中斷優(yōu)先級(jí)寄存器IP當(dāng)多個(gè)中斷同時(shí)請(qǐng)求時(shí)IP寄存器用于設(shè)定它們的優(yōu)先順序。高優(yōu)先級(jí)的中斷可以打斷正在執(zhí)行的低優(yōu)先級(jí)中斷服務(wù)程序?qū)崿F(xiàn)中斷嵌套。定時(shí)器/計(jì)數(shù)器控制寄存器TCON其中的某些位用于標(biāo)識(shí)外部中斷的觸發(fā)方式電平觸發(fā)/邊沿觸發(fā)以及定時(shí)器溢出標(biāo)志。1.2 中斷響應(yīng)的完整流程理解中斷響應(yīng)流程是應(yīng)對(duì)考題的關(guān)鍵。整個(gè)過程可以分為以下幾個(gè)階段中斷請(qǐng)求中斷源事件發(fā)生如定時(shí)器溢出、外部引腳電平變化相應(yīng)的中斷請(qǐng)求標(biāo)志位如TF0、IE0被硬件自動(dòng)置1。中斷判優(yōu)如果多個(gè)中斷請(qǐng)求同時(shí)發(fā)生硬件會(huì)根據(jù)IP寄存器的設(shè)置和固定的內(nèi)部順序INT0 T0 INT1 T1 串口來決定優(yōu)先響應(yīng)哪一個(gè)。中斷響應(yīng)如果CPU處于開中斷狀態(tài)EA1且該中斷源被允許如EX01則在當(dāng)前指令執(zhí)行完畢后CPU響應(yīng)中斷。硬件自動(dòng)完成三件事將下一條指令的地址即斷點(diǎn)地址壓入堆棧保護(hù)。清除正在響應(yīng)的中斷源請(qǐng)求標(biāo)志位對(duì)于邊沿觸發(fā)的外部中斷和定時(shí)器中斷硬件會(huì)自動(dòng)清除對(duì)于串口中斷和電平觸發(fā)的外部中斷需要軟件手動(dòng)清除。根據(jù)中斷源將程序計(jì)數(shù)器PC跳轉(zhuǎn)到對(duì)應(yīng)的中斷向量地址。執(zhí)行中斷服務(wù)程序ISR程序員在中斷向量地址處通常放置一條跳轉(zhuǎn)指令如LJMP跳轉(zhuǎn)到實(shí)際的中斷處理代碼段。在ISR中首先要做的是保護(hù)現(xiàn)場(chǎng)將PSW、ACC等可能被破壞的寄存器壓棧然后執(zhí)行具體的處理邏輯最后在返回前恢復(fù)現(xiàn)場(chǎng)。中斷返回ISR執(zhí)行到最后一條指令RETI時(shí)硬件自動(dòng)將之前壓棧的斷點(diǎn)地址彈出到PCCPU從而返回到主程序被中斷的地方繼續(xù)執(zhí)行。RETI指令還會(huì)通知中斷系統(tǒng)本次中斷處理已結(jié)束。2. 環(huán)境準(zhǔn)備與核心寄存器詳解在動(dòng)手編寫代碼前必須清楚如何配置控制中斷系統(tǒng)的各個(gè)寄存器。這些寄存器的每一位都對(duì)應(yīng)著特定的控制功能。2.1 中斷允許寄存器IE - Interrupt EnableIE寄存器地址為A8H支持位尋址。它控制著中斷的總開關(guān)和分開關(guān)。位符號(hào)地址功能說明7EAAFH總中斷允許控制位。EA1CPU開放所有中斷EA0CPU屏蔽所有中斷。6-AEH保留位。5ET2ADH定時(shí)器2中斷允許位8052系列才有。4ESACH串行口中斷允許位。ES1允許串口中斷。3ET1ABH定時(shí)器1中斷允許位。ET11允許T1中斷。2EX1AAH外部中斷1允許位。EX11允許INT1中斷。1ET0A9H定時(shí)器0中斷允許位。ET01允許T0中斷。0EX0A8H外部中斷0允許位。EX01允許INT0中斷。配置示例若想允許外部中斷0和定時(shí)器0中斷需要設(shè)置EA1, EX01, ET01。SETB EA ; 打開總中斷開關(guān) SETB EX0 ; 允許外部中斷0 SETB ET0 ; 允許定時(shí)器0中斷 ; 或者使用字節(jié)操作 MOV IE, #10000011B ; EA1, EX01, ET012.2 中斷優(yōu)先級(jí)寄存器IP - Interrupt PriorityIP寄存器地址為B8H支持位尋址。它用于設(shè)置5個(gè)基本中斷源的優(yōu)先級(jí)默認(rèn)為0低優(yōu)先級(jí)。位符號(hào)地址功能說明7-BFH保留位。6-BEH保留位。5PT2BDH定時(shí)器2優(yōu)先級(jí)8052。4PSBCH串行口中斷優(yōu)先級(jí)。3PT1BBH定時(shí)器1中斷優(yōu)先級(jí)。2PX1BAH外部中斷1優(yōu)先級(jí)。3PT0B9H定時(shí)器0中斷優(yōu)先級(jí)。0PX0B8H外部中斷0優(yōu)先級(jí)。規(guī)則某位設(shè)為1對(duì)應(yīng)中斷源為高優(yōu)先級(jí)設(shè)為0則為低優(yōu)先級(jí)。當(dāng)兩個(gè)不同優(yōu)先級(jí)的中斷同時(shí)請(qǐng)求時(shí)先響應(yīng)高優(yōu)先級(jí)。當(dāng)兩個(gè)相同優(yōu)先級(jí)的中斷同時(shí)請(qǐng)求時(shí)按內(nèi)部查詢順序INT0 - T0 - INT1 - T1 - 串口響應(yīng)。高優(yōu)先級(jí)中斷可以打斷正在執(zhí)行的低優(yōu)先級(jí)中斷服務(wù)程序反之則不能。2.3 定時(shí)器/計(jì)數(shù)器控制寄存器TCONTCON的低4位與外部中斷相關(guān)高4位與定時(shí)器相關(guān)。地址88H支持位尋址。位符號(hào)地址功能說明7TF18FH定時(shí)器1溢出標(biāo)志。溢出時(shí)硬件置1響應(yīng)中斷后硬件清0或軟件清0。6TR18EH定時(shí)器1運(yùn)行控制位。軟件置1啟動(dòng)清0停止。5TF08DH定時(shí)器0溢出標(biāo)志。同TF1。4TR08CH定時(shí)器0運(yùn)行控制位。同TR1。3IE18BH外部中斷1請(qǐng)求標(biāo)志。檢測(cè)到INT1引腳有效信號(hào)時(shí)硬件置1響應(yīng)中斷后硬件清0邊沿觸發(fā)模式。2IT18AH外部中斷1觸發(fā)方式控制。IT11邊沿觸發(fā)下降沿有效IT10電平觸發(fā)低電平有效。1IE089H外部中斷0請(qǐng)求標(biāo)志。同IE1。0IT088H外部中斷0觸發(fā)方式控制。同IT1。注意對(duì)于電平觸發(fā)的外部中斷CPU在響應(yīng)中斷后不會(huì)自動(dòng)清除IE0/IE1標(biāo)志。因此必須在中斷服務(wù)程序中通過撤銷INT0/INT1引腳上的低電平信號(hào)來使硬件自動(dòng)清0否則會(huì)引發(fā)中斷重復(fù)響應(yīng)。2.4 中斷向量表中斷向量是固定的入口地址。編寫程序時(shí)必須將跳轉(zhuǎn)到實(shí)際ISR的指令放在這些地址上。中斷源中斷向量地址ROM說明外部中斷0 (INT0)0003H通常放置LJMP INT0_ISR定時(shí)器0 (T0)000BH通常放置LJMP TIMER0_ISR外部中斷1 (INT1)0013H通常放置LJMP INT1_ISR定時(shí)器1 (T1)001BH通常放置LJMP TIMER1_ISR串行口 (TI/RI)0023H通常放置LJMP UART_ISR3. 匯編語言中斷編程實(shí)戰(zhàn)理解了寄存器我們就可以開始編寫一個(gè)完整的中斷程序。我們將以實(shí)現(xiàn)一個(gè)功能為例利用外部中斷0INT0接按鍵控制一個(gè)LED接P1.0的亮滅同時(shí)利用定時(shí)器0中斷實(shí)現(xiàn)約1秒的延時(shí)用于LED閃爍的頻率控制。3.1 項(xiàng)目需求與硬件連接分析功能系統(tǒng)上電后LED以1秒為周期閃爍。當(dāng)按下連接在INT0P3.2引腳上的按鍵時(shí)LED狀態(tài)立即翻轉(zhuǎn)亮變滅或滅變亮然后繼續(xù)以新的狀態(tài)閃爍。硬件假設(shè)單片機(jī)AT89C51/52或其他兼容8051內(nèi)核的單片機(jī)。LED陽極通過限流電阻接VCC陰極接P1.0。P1.0輸出0時(shí)LED亮輸出1時(shí)LED滅。按鍵一端接地另一端接INT0P3.2引腳。單片機(jī)內(nèi)部上拉電阻使引腳常態(tài)為高電平按鍵按下時(shí)變?yōu)榈碗娖健>д窦僭O(shè)為12MHz一個(gè)機(jī)器周期為1μs。3.2 程序結(jié)構(gòu)與初始化代碼首先我們需要進(jìn)行中斷系統(tǒng)和定時(shí)器的初始化。ORG 0000H ; 程序起始地址 LJMP MAIN ; 跳轉(zhuǎn)到主程序 ORG 0003H ; 外部中斷0向量地址 LJMP EXT0_ISR ; 跳轉(zhuǎn)到外部中斷0服務(wù)程序 ORG 000BH ; 定時(shí)器0中斷向量地址 LJMP TIMER0_ISR ; 跳轉(zhuǎn)到定時(shí)器0服務(wù)程序 ORG 0030H ; 主程序放在向量區(qū)之后 MAIN: MOV SP, #60H ; 設(shè)置堆棧指針避開工作寄存器區(qū)和位尋址區(qū) LCALL INIT ; 調(diào)用初始化子程序 LOOP: SJMP LOOP ; 主循環(huán)等待中斷發(fā)生 ; 初始化子程序 INIT: ; 1. 初始化LED狀態(tài)假設(shè)初始為滅 SETB P1.0 ; P1.0輸出高電平LED滅 ; 2. 設(shè)置外部中斷0為邊沿觸發(fā) SETB IT0 ; IT01下降沿觸發(fā) ; 3. 配置定時(shí)器0為模式116位定時(shí)器 MOV TMOD, #01H ; TMOD0000 0001BT0模式1T1模式0未用 ; 4. 計(jì)算定時(shí)器初值12MHz晶振定時(shí)50ms ; 機(jī)器周期 12 / 12MHz 1μs ; 定時(shí)50ms需要計(jì)數(shù)次數(shù) N 50000 ; 初值 X 65536 - 50000 15536 3CB0H MOV TH0, #3CH ; 高8位 MOV TL0, #0B0H; 低8位 ; 5. 啟動(dòng)定時(shí)器0 SETB TR0 ; TR01啟動(dòng)T0 ; 6. 開啟中斷 SETB EX0 ; 允許外部中斷0 SETB ET0 ; 允許定時(shí)器0中斷 SETB EA ; 開啟總中斷 RET關(guān)鍵點(diǎn)解釋ORG偽指令用于指定后續(xù)代碼存放的起始地址。必須將跳轉(zhuǎn)指令準(zhǔn)確放在中斷向量地址上。定時(shí)器初值計(jì)算是??伎键c(diǎn)。模式1是16位計(jì)數(shù)器最大計(jì)數(shù)值65536。初值 65536 - 所需計(jì)數(shù)值。初始化順序先配置觸發(fā)方式、定時(shí)器模式再賦初值、啟動(dòng)定時(shí)器最后打開中斷允許位。這個(gè)順序可以避免意外中斷。3.3 中斷服務(wù)程序編寫中斷服務(wù)程序需要完成現(xiàn)場(chǎng)保護(hù)、核心邏輯處理和現(xiàn)場(chǎng)恢復(fù)。; 定時(shí)器0中斷服務(wù)程序 - 用于產(chǎn)生1秒延時(shí)基準(zhǔn) TIMER0_ISR: PUSH ACC ; 保護(hù)現(xiàn)場(chǎng)將ACC壓棧 PUSH PSW ; 保護(hù)現(xiàn)場(chǎng)將PSW壓棧 ; 重裝定時(shí)器初值為下一次50ms定時(shí)做準(zhǔn)備 MOV TH0, #3CH MOV TL0, #0B0H ; 軟件計(jì)數(shù)器減1假設(shè)R7作為50ms計(jì)數(shù)器 DJNZ R7, TIMER0_EXIT ; 如果R7不為0跳轉(zhuǎn)到退出 ; 如果R7為0說明20個(gè)50ms到了即1秒 MOV R7, #20 ; 重置軟件計(jì)數(shù)器為20 CPL P1.0 ; 取反P1.0LED狀態(tài)翻轉(zhuǎn) TIMER0_EXIT: POP PSW ; 恢復(fù)現(xiàn)場(chǎng)PSW出棧 POP ACC ; 恢復(fù)現(xiàn)場(chǎng)ACC出棧 RETI ; 中斷返回必須用RETI ; 外部中斷0服務(wù)程序 - 響應(yīng)按鍵立即翻轉(zhuǎn)LED EXT0_ISR: PUSH ACC PUSH PSW ; 按鍵消抖簡單延時(shí) LCALL DELAY_10MS ; 再次檢測(cè)INT0引腳確認(rèn)是有效按鍵防干擾 JB P3.2, EXT0_EXIT ; 如果P3.2已經(jīng)是高電平則認(rèn)為是干擾退出 ; 執(zhí)行核心功能翻轉(zhuǎn)LED CPL P1.0 ; 等待按鍵釋放避免一次按下多次觸發(fā) WAIT_RELEASE: JNB P3.2, WAIT_RELEASE ; 如果P3.2還是低電平循環(huán)等待 EXT0_EXIT: POP PSW POP ACC RETI ; 一個(gè)簡單的10ms延時(shí)子程序用于按鍵消抖 DELAY_10MS: MOV R6, #20 D1: MOV R5, #250 DJNZ R5, $ DJNZ R6, D1 RET關(guān)鍵點(diǎn)解釋現(xiàn)場(chǎng)保護(hù)與恢復(fù)中斷可能發(fā)生在任何時(shí)刻必須保護(hù)中斷程序中會(huì)用到的所有寄存器如ACC、PSW、B以及通用寄存器Rn。通常使用PUSH和POP指令成對(duì)操作。PSW保護(hù)了標(biāo)志位和當(dāng)前工作寄存器組。定時(shí)器中斷在ISR中必須重裝初值否則下次定時(shí)會(huì)從0開始計(jì)數(shù)導(dǎo)致定時(shí)不準(zhǔn)。使用軟件計(jì)數(shù)器如R7來實(shí)現(xiàn)更長的定時(shí)如1秒。外部中斷消抖機(jī)械按鍵會(huì)產(chǎn)生抖動(dòng)需要在檢測(cè)到中斷后延時(shí)再判斷避免誤觸發(fā)。防干擾與等待釋放JB P3.2, EXT0_EXIT用于排除干擾脈沖。WAIT_RELEASE循環(huán)確保按鍵松開后才退出防止一次按下產(chǎn)生多次中斷。中斷返回必須使用RETI指令它除了恢復(fù)PC還會(huì)通知中斷控制系統(tǒng)該中斷已處理完畢允許響應(yīng)新的同級(jí)或低級(jí)中斷。4. 核心考點(diǎn)與典型習(xí)題剖析掌握了基本編程后我們針對(duì)考試中常見的題型和易錯(cuò)點(diǎn)進(jìn)行深入分析。4.1 考點(diǎn)一中斷響應(yīng)條件與流程判斷常見題型判斷在某種特定條件下如某條指令執(zhí)行期間某個(gè)中斷請(qǐng)求是否會(huì)被響應(yīng)何時(shí)響應(yīng)例題假設(shè)CPU正在執(zhí)行一條MOVX A, DPTR指令訪問外部RAM需2個(gè)機(jī)器周期此時(shí)外部中斷0INT0引腳上出現(xiàn)了一個(gè)有效的下降沿IT01。已知EA1EX01且無其他中斷請(qǐng)求。問INT0中斷是否會(huì)被響應(yīng)何時(shí)響應(yīng)分析與解答條件滿足EA和EX0都已打開INT0請(qǐng)求有效滿足中斷響應(yīng)條件。響應(yīng)時(shí)機(jī)CPU會(huì)在當(dāng)前指令執(zhí)行完畢后去查詢中斷請(qǐng)求標(biāo)志。MOVX指令需要2個(gè)機(jī)器周期。因此INT0的中斷請(qǐng)求會(huì)在該MOVX指令的第二個(gè)機(jī)器周期結(jié)束時(shí)被采樣到并在該指令執(zhí)行完畢后即下一條指令開始前進(jìn)入中斷響應(yīng)周期。答案會(huì)被響應(yīng)。響應(yīng)發(fā)生在MOVX A, DPTR指令執(zhí)行完畢之后。關(guān)鍵記憶點(diǎn)中斷采樣發(fā)生在每個(gè)指令的最后一個(gè)機(jī)器周期。響應(yīng)發(fā)生在當(dāng)前指令執(zhí)行完下一條指令開始前。長指令如乘除、MOVX執(zhí)行期間發(fā)生中斷也需要等該指令執(zhí)行完。4.2 考點(diǎn)二中斷優(yōu)先級(jí)與嵌套分析常見題型給定中斷允許和優(yōu)先級(jí)設(shè)置分析多個(gè)中斷同時(shí)或先后發(fā)生時(shí)的響應(yīng)順序。例題設(shè)置IE 8FH (10001111B) IP 06H (00000110B)。請(qǐng)分析(1) 若INT0和T1中斷同時(shí)請(qǐng)求誰先被響應(yīng)(2) 若CPU正在執(zhí)行T1的中斷服務(wù)程序此時(shí)INT0請(qǐng)求中斷會(huì)怎樣(3) 若CPU正在執(zhí)行INT0的中斷服務(wù)程序此時(shí)T1請(qǐng)求中斷會(huì)怎樣寄存器分析IE 10001111BEA1, ES0, ET11, EX10, ET01, EX01。允許INT0、T0、T1中斷。IP 00000110BPX10, PT01, PX00。T0為高優(yōu)先級(jí)INT0和T1為低優(yōu)先級(jí)。解答同時(shí)請(qǐng)求INT0和T1同時(shí)請(qǐng)求且均為低優(yōu)先級(jí)。此時(shí)按內(nèi)部查詢順序決定。查詢順序?yàn)镮NT0 - T0 - INT1 - T1 - 串口。因此INT0先于T1被響應(yīng)。T1執(zhí)行中INT0請(qǐng)求T1為低優(yōu)先級(jí)INT0也為低優(yōu)先級(jí)。同級(jí)或低級(jí)中斷不能打斷正在執(zhí)行的中斷服務(wù)程序。因此CPU不會(huì)響應(yīng)INT0直到T1的ISR執(zhí)行完畢返回主程序后才會(huì)響應(yīng)INT0。INT0執(zhí)行中T1請(qǐng)求同理T1不能打斷INT0。但這里有一個(gè)陷阱T1的中斷請(qǐng)求標(biāo)志TF1在請(qǐng)求時(shí)已被置1。雖然本次不能打斷但當(dāng)INT0執(zhí)行完RETI返回后CPU會(huì)立即檢測(cè)到仍有未處理的T1中斷請(qǐng)求因?yàn)門F1未被清除并且此時(shí)INT0的ISR已結(jié)束所以會(huì)緊接著響應(yīng)T1中斷而不會(huì)先返回主程序。這種現(xiàn)象看起來像是“連續(xù)中斷”。4.3 考點(diǎn)三中斷標(biāo)志位的清除常見題型分析中斷服務(wù)程序中是否需要手動(dòng)清除中斷標(biāo)志以及不清除會(huì)導(dǎo)致什么問題。例題在電平觸發(fā)的外部中斷服務(wù)程序中為什么通常需要等待外部信號(hào)恢復(fù)高電平如果不這樣做可能發(fā)生什么分析與解答原因?qū)τ陔娖接|發(fā)方式ITx0其中斷請(qǐng)求標(biāo)志IEx是由外部引腳P3.2/P3.3的低電平直接置位的。CPU響應(yīng)中斷后硬件不會(huì)自動(dòng)清除IEx標(biāo)志。只要引腳上低電平持續(xù)存在IEx就保持為1。后果如果ISR執(zhí)行完畢返回后引腳低電平仍然存在CPU會(huì)立即再次檢測(cè)到有效的中斷請(qǐng)求從而再次進(jìn)入同一個(gè)ISR。這就導(dǎo)致了中斷的重復(fù)響應(yīng)仿佛程序“卡死”在中斷里。解決方案在電平觸發(fā)的中斷服務(wù)程序中必須確保在返回前外部引腳的低電平信號(hào)已消失如等待按鍵釋放。通常通過循環(huán)檢測(cè)引腳狀態(tài)實(shí)現(xiàn)如示例代碼中的WAIT_RELEASE部分。對(duì)比記憶中斷源觸發(fā)方式請(qǐng)求標(biāo)志清除方式外部中斷0/1邊沿觸發(fā)IE0/IE1CPU響應(yīng)中斷后硬件自動(dòng)清除。外部中斷0/1電平觸發(fā)IE0/IE1硬件不會(huì)自動(dòng)清除。需在ISR中確保外部信號(hào)恢復(fù)高電平。定時(shí)器0/1溢出TF0/TF1CPU響應(yīng)中斷后硬件自動(dòng)清除。也可軟件查詢清0。串行口發(fā)送/接收TI/RI硬件不會(huì)自動(dòng)清除。必須在ISR中用軟件指令清除CLR TI 或 CLR RI。4.4 考點(diǎn)四現(xiàn)場(chǎng)保護(hù)與恢復(fù)的細(xì)節(jié)常見題型給出一個(gè)有缺陷的中斷服務(wù)程序找出其中現(xiàn)場(chǎng)保護(hù)/恢復(fù)的錯(cuò)誤。例題以下定時(shí)器中斷服務(wù)程序片段有什么問題TIMER_ISR: MOV A, #55H ADD A, R0 MOV R0, A RETI分析與解答 該ISR沒有進(jìn)行任何現(xiàn)場(chǎng)保護(hù)。它直接使用了A累加器、R0寄存器以及R0指向的RAM單元。如果主程序或更高優(yōu)先級(jí)中斷也在使用這些資源中斷返回后這些資源的值已被改變導(dǎo)致主程序運(yùn)行出錯(cuò)。正確做法在ISR入口處將要用到的寄存器如ACC, PSW, DPTR, B以及R0-R7壓棧保護(hù)在ISR退出前以相反順序出?;謴?fù)。TIMER_ISR: PUSH ACC PUSH PSW PUSH 00H ; 假設(shè)R0是0組寄存器其地址為00H ; ... 中斷處理邏輯 ... POP 00H POP PSW POP ACC RETI注意PUSH和POP的操作對(duì)象是直接地址。對(duì)于工作寄存器R0-R7需要根據(jù)當(dāng)前使用的寄存器組確定其對(duì)應(yīng)的RAM地址00H-07H對(duì)應(yīng)第0組08H-0FH對(duì)應(yīng)第1組以此類推。5. 常見問題排查與調(diào)試技巧在實(shí)際編程和實(shí)驗(yàn)過程中中斷相關(guān)的問題往往比較隱蔽。下面列出常見的問題現(xiàn)象和排查思路。5.1 中斷完全不響應(yīng)現(xiàn)象按鍵按下LED無反應(yīng)定時(shí)時(shí)間到程序無動(dòng)作。排查清單總中斷開關(guān)是否打開檢查EA位是否設(shè)置為1。這是最容易被忽略的一步。特定中斷允許位是否打開檢查EX0、ET0等相應(yīng)位是否設(shè)置為1。中斷觸發(fā)方式設(shè)置是否正確檢查IT0/IT1。如果是邊沿觸發(fā)確保信號(hào)有下降沿如果是電平觸發(fā)確保低電平持續(xù)時(shí)間足夠長。中斷向量地址是否正確檢查ORG偽指令是否寫錯(cuò)地址以及跳轉(zhuǎn)指令LJMP或AJMP是否寫對(duì)了中斷服務(wù)程序的標(biāo)號(hào)。堆棧空間是否足夠中斷響應(yīng)和現(xiàn)場(chǎng)保護(hù)需要壓棧如果堆棧指針SP初始設(shè)置過小可能導(dǎo)致堆棧溢出覆蓋程序數(shù)據(jù)引發(fā)不可預(yù)知的錯(cuò)誤。通常將SP初始化為60H或更高。硬件連接是否正確用萬用表或邏輯分析儀檢查中斷引腳的電平變化是否符合預(yù)期。5.2 中斷只響應(yīng)一次或響應(yīng)異?,F(xiàn)象按鍵第一次按下有效后續(xù)無效或者LED瘋狂閃爍不受控制。排查清單中斷標(biāo)志是否被正確清除這是最常見的原因。對(duì)于串口中斷必須用CLR TI或CLR RI在ISR中手動(dòng)清除標(biāo)志。對(duì)于電平觸發(fā)的外部中斷必須在ISR中等待外部信號(hào)恢復(fù)高電平否則會(huì)不斷重復(fù)進(jìn)入中斷。對(duì)于邊沿觸發(fā)的外部中斷和定時(shí)器中斷硬件會(huì)自動(dòng)清除一般無需軟件干預(yù)。但如果中斷被禁止EA0或EXx0時(shí)發(fā)生了中斷請(qǐng)求標(biāo)志位會(huì)被置1并保持直到中斷被允許。這種情況需要在初始化時(shí)手動(dòng)清除可能遺留的標(biāo)志位CLR IE0等。中斷服務(wù)程序執(zhí)行時(shí)間是否過長如果ISR執(zhí)行時(shí)間超過了中斷事件的間隔可能會(huì)丟失中斷。例如定時(shí)器50ms溢出一次但I(xiàn)SR執(zhí)行需要60ms那么第二次溢出時(shí)CPU還在執(zhí)行第一次的ISR且由于同級(jí)中斷不能嵌套第二次中斷請(qǐng)求可能被忽略。優(yōu)化ISR代碼或?qū)⒑臅r(shí)操作移到主循環(huán)。是否存在中斷嵌套沖突檢查IP寄存器設(shè)置。如果高優(yōu)先級(jí)中斷的ISR執(zhí)行時(shí)間很長可能會(huì)“餓死”低優(yōu)先級(jí)中斷。5.3 現(xiàn)場(chǎng)保護(hù)導(dǎo)致的數(shù)據(jù)錯(cuò)亂現(xiàn)象主程序中的變量值在中斷發(fā)生后莫名其妙地改變。排查清單是否保護(hù)了所有被修改的寄存器仔細(xì)檢查ISR凡是用到的ACC、PSW、B、DPTR、Rn以及直接地址單元如果主程序也可能使用就必須保護(hù)。PUSH和POP是否成對(duì)且順序相反必須遵循“先進(jìn)后出”原則。是否錯(cuò)誤地改變了工作寄存器組PSW中的RS1和RS0位決定了當(dāng)前使用哪組R0-R7。如果在ISR中改變了PSW且未妥善保護(hù)返回主程序后主程序使用的R0-R7就變成了另一組導(dǎo)致數(shù)據(jù)錯(cuò)亂。一個(gè)常見的做法是在ISR開始時(shí)通過設(shè)置PSW切換到一個(gè)專用于中斷的寄存器組這樣就不需要保護(hù)R0-R7但退出前要恢復(fù)原PSW。6. 最佳實(shí)踐與擴(kuò)展方向6.1 中斷編程最佳實(shí)踐保持ISR短小精悍中斷服務(wù)程序應(yīng)只處理最緊急、最核心的任務(wù)如置標(biāo)志位、讀數(shù)據(jù)、清中斷等。復(fù)雜的計(jì)算、延時(shí)、通信等操作應(yīng)放到主循環(huán)中基于標(biāo)志位來處理。使用軟件標(biāo)志進(jìn)行通信ISR與主程序之間通過軟件標(biāo)志位變量或字節(jié)變量來傳遞信息。這是最安全、最清晰的異步通信方式。注意重入問題避免在ISR和主程序中共用非原子操作的全局變量。如果共用應(yīng)考慮使用關(guān)中斷CLR EA和開中斷SETB EA來保護(hù)臨界區(qū)但關(guān)中斷時(shí)間要盡可能短。初始化時(shí)清除殘留中斷標(biāo)志在開啟中斷前先清除TCON、SCON中可能殘留的中斷請(qǐng)求標(biāo)志位避免一開中斷就誤入中斷。合理規(guī)劃堆棧空間根據(jù)中斷嵌套層數(shù)和現(xiàn)場(chǎng)保護(hù)的數(shù)據(jù)量預(yù)留足夠的堆??臻g通常SP初始值設(shè)為60H或更高。6.2 擴(kuò)展方向中斷與低功耗設(shè)計(jì)在許多單片機(jī)應(yīng)用中低功耗是關(guān)鍵指標(biāo)。中斷是實(shí)現(xiàn)低功耗休眠-喚醒模式的基石。休眠模式通過執(zhí)行特定指令如8051的ORL PCON, #01H進(jìn)入Idle模式CPU停止工作但外設(shè)定時(shí)器、串口、外部中斷仍可運(yùn)行。中斷喚醒當(dāng)使能的中斷事件發(fā)生時(shí)CPU被喚醒退出休眠模式執(zhí)行對(duì)應(yīng)的ISR之后繼續(xù)執(zhí)行進(jìn)入休眠模式指令之后的代碼。編程模式主程序完成初始化后進(jìn)入循環(huán)處理任務(wù) - 進(jìn)入休眠 - 被中斷喚醒- 處理中斷 - 返回循環(huán)。這樣CPU只在有事件需要處理時(shí)才工作極大降低了平均功耗。掌握中斷系統(tǒng)不僅是應(yīng)對(duì)考試更是為后續(xù)學(xué)習(xí)更復(fù)雜的單片機(jī)應(yīng)用如實(shí)時(shí)操作系統(tǒng)RTOS的基礎(chǔ)打下堅(jiān)實(shí)基礎(chǔ)。建議在理解本文示例的基礎(chǔ)上嘗試修改代碼實(shí)現(xiàn)中斷嵌套、用中斷方式掃描矩陣鍵盤、用中斷方式實(shí)現(xiàn)串口數(shù)據(jù)收發(fā)等實(shí)驗(yàn)從而真正融會(huì)貫通。