專注差異化嵌入式產(chǎn)品解決方案 給智能產(chǎn)品定制注入靈魂給予生命
提供開發(fā)工具、應(yīng)用測(cè)試 完善的開發(fā)代碼案例庫(kù)分享
從全面的產(chǎn)品導(dǎo)入到強(qiáng)大技術(shù)支援服務(wù) 全程貼心伴隨服務(wù),創(chuàng)造無(wú)限潛能!
提供新的芯片及解決方案,提升客戶產(chǎn)品競(jìng)爭(zhēng)力
提供最新的單片機(jī)資訊,行業(yè)消息以及公司新聞動(dòng)態(tài)
摘要:美國(guó)微芯公司研制的PIC系列單片機(jī),其硬件結(jié)構(gòu)和指令系統(tǒng)采用了與眾不同的設(shè)計(jì)手法。在架構(gòu)上和概念上對(duì)傳統(tǒng)單片機(jī)進(jìn)行了一些突破性的變革,但也給這類單片機(jī)的應(yīng)用帶來(lái)了一些特殊問(wèn)題。本文針對(duì)PIC16F87X系列單片機(jī)中斷的特點(diǎn),及其在應(yīng)用過(guò)程中應(yīng)該注意的幾個(gè)問(wèn)題進(jìn)行必要的說(shuō)明。內(nèi)容包括中斷源、中斷邏輯、中斷相關(guān)的寄存器、中斷的延時(shí)、中斷的現(xiàn)場(chǎng)保護(hù)以及注意事項(xiàng)等。 四、 中斷的處理
前在世界一些著名的單片機(jī)產(chǎn)品系列中,PIC16F87X系列單片機(jī)是芯片內(nèi)部包含有外圍設(shè)備模塊數(shù)量最多的單片機(jī)品種之一。PIC16F874和PIC16F877單片機(jī)的芯片內(nèi)部集成了15個(gè)外圍設(shè)備模塊;PIC16F873和PIC16F876單片機(jī)的芯片內(nèi)部集成了12個(gè)外圍設(shè)備模塊。在最近推出的該系列的新型號(hào)中, PIC16F870單片機(jī)的芯片內(nèi)部集成了10個(gè)外圍設(shè)備模塊;PIC16F871單片機(jī)的芯片內(nèi)部集成了13個(gè)外圍設(shè)備模塊;PIC16F872單片機(jī)的芯片內(nèi)部也集成了10個(gè)外圍設(shè)備模塊(比PIC16F870多了1個(gè)USART模塊,少了1個(gè)SSP模塊)。
這些外圍設(shè)備模塊在啟用時(shí)以及在工作過(guò)程中,都或多或少地需要CPU參與控制、協(xié)調(diào)或交換數(shù)據(jù)等各種服務(wù)工作。由于CPU的運(yùn)行速度非常高,而各個(gè)外圍設(shè)備模塊的工作速度卻非常低,況且這些外圍設(shè)備模塊也不是頻繁地要求CPU對(duì)其服務(wù)。因此,通常采取一種讓眾多外圍設(shè)備模塊共享1個(gè)CPU,并且能夠及時(shí)得到CPU服務(wù)的調(diào)度方法——中斷。
一、 PIC16F87X的中斷源
PIC系列單片機(jī)是當(dāng)今世界上很有影響力的精簡(jiǎn)指令集(RISC)微控制器,具有豐富的中斷功能。其中功能強(qiáng)大的中、高擋型號(hào)的中斷源有18種之多。在PIC單片機(jī)家族中,排位屬于中上水平的PIC16F87X子系列單片機(jī)具備的中斷源多達(dá)14種。其中,單片機(jī)的型號(hào)不同,中斷源的種類、個(gè)數(shù)也不同,如表1所列。其不足之處是:中斷矢量只有1個(gè),并且各個(gè)中斷源之間也沒(méi)有優(yōu)先級(jí)別之分,不具備非屏蔽中斷。
表1 PIC16F87X單片機(jī)的中斷源及其數(shù)量
中斷源種類 | 中斷源志位 | 中斷源蔽位 | 873/ 876 | 874/ 877 | 870 | 871 | 872 |
外部觸發(fā)中斷INT | INTF | INTE | √ | √ | √ | √ | √ |
TMR0溢出中斷 | T0IF | T0IE | √ | √ | √ | √ | √ |
RB端口電平變化中斷 | RBIF | RBIE | √ | √ | √ | √ | √ |
TMR1溢出中斷 | TMR1IF | TMR1IE | √ | √ | √ | √ | √ |
TMR2中斷 | TMR2IF | TMR2IE | √ | √ | √ | √ | √ |
CCP1中斷 | CCP1IF | CCP1IE | √ | √ | √ | √ | √ |
CCP2中斷 | CCP2IF | CCP2IE | √ | √ | |||
SCI同步發(fā)送中斷 | TXIF | TXIE | √ | √ | √ | √ | |
SCI同步接收中斷 | RCIF | RCIE | √ | √ | √ | √ | |
SSP中斷 | SSPIF | SSPIE | √ | √ | √ | ||
SSP I2C總線碰撞中斷 | BCLIF | BCLIE | √ | √ | √ | ||
并行端口中斷 | PSPIF | PSPIE | √ | √ | |||
A/D轉(zhuǎn)換中斷 | ADIF | ADIE | √ | √ | √ | √ | √ |
E2PROM中斷 | EEIF | EEIE | √ | √ | √ | √ | √ |
13種 | 14種 | 10種 | 11種 | 10種 |
從表1中可以看出,各中斷源基本上都是與各個(gè)外圍設(shè)備模塊相對(duì)應(yīng)的。其中,多數(shù)外圍設(shè)備模塊對(duì)應(yīng)著1個(gè)中斷源(比如定時(shí)器/計(jì)數(shù)器TMR0模塊),有的外圍設(shè)備模塊對(duì)應(yīng)著2個(gè)中斷源(比如通用同步/接收/發(fā)送器SCI模塊),也有的外圍設(shè)備模塊沒(méi)有中斷源與之對(duì)應(yīng)(比如輸入/輸出端口RA和RC模塊),還有的中斷源沒(méi)有外圍設(shè)備模塊與之對(duì)應(yīng)(比如外部觸發(fā)中斷源INT)。
二、 PIC16F87X的中斷硬件邏輯
在PIC16F87X的子系列中,具體型號(hào)不同,中斷邏輯電路也存在著差異,中斷源的種類和個(gè)數(shù)也不同:最多的具備14種中斷源;最少的具備10種中斷源(詳見表1)。其中并行端口模塊和并行端口中斷源,只有40腳封裝的型號(hào)(PIC16F871、PIC16F874和PIC16F877)才會(huì)具備;而對(duì)于28腳封裝的型號(hào)(PIC16F870、PIC16F872、PIC16F873和PIC16F876)則不具備。
PIC16F87X系列單片機(jī)中斷系統(tǒng)的邏輯電路如圖1所示。每一種中斷源對(duì)應(yīng)著1個(gè)中斷標(biāo)志位(記為XXXF,F(xiàn)是Flag的第1個(gè)英文字母)和1個(gè)中斷屏蔽位或者叫中斷使能位(記為XXXE,E是Enable的第1個(gè)英文字母)。中斷源產(chǎn)生的中斷標(biāo)志信號(hào)是否得以向前傳遞,將受控于對(duì)應(yīng)的中斷屏蔽位。每一個(gè)中斷標(biāo)志位都對(duì)應(yīng)著1個(gè)觸發(fā)器。當(dāng)中斷源申請(qǐng)CPU中斷時(shí),與之對(duì)應(yīng)的觸發(fā)器就由硬件自動(dòng)置位,而該觸發(fā)器的清零是由用戶安排程序來(lái)實(shí)現(xiàn)的;每一個(gè)中斷屏蔽位也對(duì)應(yīng)著1個(gè)觸發(fā)器。該觸發(fā)器的置位和清零均是由用戶程序完成的。
圖1描繪的邏輯電路是1個(gè)由簡(jiǎn)單的門電路構(gòu)成的組合邏輯電路。將全部14個(gè)中斷源按2個(gè)梯隊(duì)并列排開,第1梯隊(duì)中只安排了3個(gè)中斷源,其余的中斷源全部安排到第2梯隊(duì)中。這樣做是為了與早期的PIC系列單片機(jī)型號(hào)相兼容(前些年研制出的單片機(jī)型號(hào)片內(nèi)配置的外圍設(shè)備模塊數(shù)量較少,相應(yīng)的中斷源的數(shù)量自然也就少,比如PIC16C61只有第1梯隊(duì)中的3個(gè)中斷源)。近期研制的一些PIC單片機(jī)新型號(hào)是在原有的單片機(jī)芯片基礎(chǔ)之上進(jìn)行一些功能擴(kuò)展而得來(lái)的。
所有的中斷源都受全局中斷屏蔽位(也可以稱為總屏蔽位)GIE的控制。第1梯隊(duì)的中斷源不僅受全局中斷屏蔽位的控制,還要受各自中斷屏蔽位的控制;第2梯隊(duì)的中斷源不僅受到全局中斷屏蔽位和各自中斷屏蔽位的控制,還要額外受到1個(gè)外設(shè)中斷屏蔽位PEIE的控制。
三、 中斷相關(guān)的寄存器
與中斷功能有關(guān)的特殊功能寄存器共有5個(gè):中斷控制寄存器INTCON、第1外圍設(shè)備中斷標(biāo)志寄存器PIR1、第1外圍設(shè)備中斷屏蔽寄存器(又稱中斷使能寄存器)PIE1、第2外圍設(shè)備中斷標(biāo)志寄存器PIR2和第2外圍設(shè)備中斷屏蔽寄存器PIE2。如表2所列,5個(gè)寄存器中共有40位,其中使用了30位。分別與圖1中的中斷邏輯電路的輸入邏輯信號(hào)成嚴(yán)格對(duì)應(yīng)關(guān)系,也與邏輯表達(dá)式成嚴(yán)格對(duì)應(yīng)關(guān)系。這5個(gè)寄存器都具有在RAM數(shù)據(jù)存儲(chǔ)器中統(tǒng)一編碼的地址。也就是說(shuō),PIC單片機(jī)可以把這5個(gè)特殊寄存器當(dāng)作普通寄存器單元來(lái)訪問(wèn)(即讀出或?qū)懭氩僮鳎?。這樣有利于減少指令集的指令類型和指令數(shù)量,也便于學(xué)習(xí)、記憶和編程。
單片機(jī)復(fù)位后,由硬件自動(dòng)對(duì)全局中斷屏蔽位進(jìn)行設(shè)置GIE=0,將屏蔽所有的中斷源。中斷返回指令“RETFIE”執(zhí)行后,也由硬件自動(dòng)對(duì)總屏蔽位進(jìn)行設(shè)置GIE=1,重新開放所有的中斷源。不論各種中斷屏蔽位和全局中斷屏蔽位GIE處于何種狀態(tài)(是開放還是禁止),當(dāng)某一中斷源的中斷條件滿足時(shí),都會(huì)發(fā)出中斷請(qǐng)求,相應(yīng)的中斷標(biāo)志位都會(huì)被置位(=1)。但是,是否能夠得到CPU的響應(yīng),則要根據(jù)該中斷源所涉及到的中斷屏蔽位的狀態(tài)而定。CPU響應(yīng)中斷后,由硬件自動(dòng)對(duì)全局中斷屏蔽位進(jìn)行清零(GIE=0),屏蔽所有的中斷源,以免發(fā)生重復(fù)中斷響應(yīng),然后,由硬件自動(dòng)把當(dāng)前的程序計(jì)數(shù)器PC值(即程序斷點(diǎn)地址)壓入堆棧(實(shí)際為硬件堆棧),并且把PC寄存器置以中斷向量地址(0004H),從而轉(zhuǎn)向并開始執(zhí)行中斷服務(wù)程序。進(jìn)入中斷服務(wù)程序后,程序中必須安排指令,檢查發(fā)出請(qǐng)求的中斷源(如果同時(shí)開放多個(gè)中斷源的話)。這可以通過(guò)檢查各個(gè)中斷源的標(biāo)志位來(lái)實(shí)現(xiàn)。一旦確定出發(fā)出申請(qǐng)的中斷源,就用軟件把該中斷源的標(biāo)志位人為地清零,否則,執(zhí)行中斷返回指令“RETFIE”。重開中斷后,由于中斷標(biāo)志位仍為“1”而引起CPU重復(fù)響應(yīng)同一個(gè)中斷請(qǐng)求。中斷服務(wù)程序的末尾必須放置1條中斷返回指令“RETFIE”。執(zhí)行該條指令后,不僅可以重開中斷,而且還可以由硬件自動(dòng)將保留在堆棧頂部的斷點(diǎn)地址彈出,并放回到程序計(jì)數(shù)器PC中,使CPU返回和繼續(xù)執(zhí)行被中斷的主程序。
1 中斷的延時(shí)響應(yīng)和延時(shí)處理
1次中斷過(guò)程,從中斷源發(fā)出請(qǐng)求到得到CPU的響應(yīng)必然存在一定的延遲時(shí)間。
在圖2中,第1行是系統(tǒng)時(shí)鐘脈沖信號(hào),每4個(gè)時(shí)鐘周期對(duì)應(yīng)1個(gè)指令周期。第2行就是指令周期信號(hào)。該信號(hào)只有在RC振蕩模式下,從OSC2腳上可以向片外送出。第3行是單片機(jī)外部引腳INT送入的中斷脈沖信號(hào)。外部中斷信號(hào)INT是用邊沿觸發(fā)的。假設(shè)預(yù)先設(shè)定的是INT中斷信號(hào)上升沿有效的話,則該信號(hào)的上升沿將會(huì)在1個(gè)時(shí)鐘周期后引發(fā)中斷標(biāo)志位INTF被置位。第4行代表INTF信號(hào)。每個(gè)指令周期內(nèi)的第2個(gè)時(shí)鐘脈沖上升沿時(shí),該信號(hào)被抽檢1次。一旦檢測(cè)到INTF信號(hào)被設(shè)置為“1”,則CPU會(huì)在接下來(lái)的1個(gè)指令周期內(nèi),將全局中斷屏蔽位GIE清零。第5行是全局中斷屏蔽位GIE。在GIE信號(hào)被清零的下一個(gè)指令周期內(nèi),程序計(jì)數(shù)器PC被置入中斷向量0004H,見圖2中第6行。同時(shí)在該指令周期內(nèi)完成到中斷服務(wù)程序的跳轉(zhuǎn),并且實(shí)現(xiàn)提取該子程序的首條指令,即指令(0004H),見圖2中第7行。在其后的1個(gè)指令周期內(nèi),正式開始執(zhí)行中斷服務(wù)程序的第1條指令,見圖2中第8行。自INT引腳輸入有效信號(hào),到中斷服務(wù)程序的第1條指令得到執(zhí)行,大約需要3~4個(gè)指令周期的延時(shí)。更精確的延遲時(shí)間取決于中斷事件的發(fā)生時(shí)機(jī)。
以上描述的只是1次中斷從申請(qǐng)到得到CPU的響應(yīng)的延遲時(shí)間。下面分析從CPU響應(yīng)1次中斷到該中斷得到有效處理的延遲時(shí)間。由于具有中斷功能的PIC系列單片機(jī)(低檔產(chǎn)品PIC16C5X和PIC12C5X系列不具備中斷功能),采用的是“多源中斷”的設(shè)計(jì)方案(即1個(gè)中斷向量對(duì)應(yīng)著多個(gè)中斷源),只有惟一的1個(gè)中斷向量,或者說(shuō)只有1個(gè)中斷服務(wù)程序入口地址。這就意味著,此類單片機(jī)的中斷服務(wù)程序只能編寫1個(gè)。這類單片機(jī)的硬件結(jié)構(gòu)得到了簡(jiǎn)化,那么,相應(yīng)的軟件設(shè)計(jì)上就得多開銷一些。在1個(gè)中斷服務(wù)程序中,若想對(duì)多個(gè)中斷源作出處理,就必須在進(jìn)入中斷服務(wù)程序后,首先執(zhí)行調(diào)查具體中斷源的一條或多條指令,其后才能對(duì)查到的中斷源作出有針對(duì)性的服務(wù)。如此以來(lái),就形成了1次中斷從CPU響應(yīng)到進(jìn)入針對(duì)性處理的延遲時(shí)間。該時(shí)間有長(zhǎng)有短,它會(huì)隨著被開放的中斷源的個(gè)數(shù)的增加而增加。最好情況是只有1個(gè)中斷源被開放,這時(shí)不需要檢測(cè)中斷源就可以立即進(jìn)入針對(duì)性處理;最壞情況是所有中斷源全部開放,此時(shí)用在檢測(cè)中斷源上的時(shí)間會(huì)最長(zhǎng)。
另外,PIC單片機(jī)中采用的是硬件堆棧結(jié)構(gòu)。其好處是既不占用程序存儲(chǔ)器
空間,也不占用數(shù)據(jù)存儲(chǔ)器空間,同時(shí)也不需用戶去操作堆棧指針;但此時(shí)也帶來(lái)1個(gè)不可回避的弱點(diǎn),即不具備像其他單片機(jī)指令系統(tǒng)中的壓棧(PUSH)和出棧(POP)指令那樣,實(shí)現(xiàn)中斷現(xiàn)場(chǎng)的保護(hù)會(huì)麻煩一些,并且占用的處理時(shí)間也相應(yīng)多一點(diǎn)。
2 中斷的現(xiàn)場(chǎng)保護(hù)問(wèn)題
中斷現(xiàn)場(chǎng)的保護(hù)是中斷技術(shù)中一個(gè)很重要的環(huán)節(jié)。在進(jìn)入中斷服務(wù)程序期間,只有返回地址,即程序計(jì)數(shù)器PC的值被自動(dòng)壓入堆棧。若需要保留其他寄存器的內(nèi)容,就得由程序員另想辦法。由于PIC單片機(jī)的指令系統(tǒng)中沒(méi)有像其他單片機(jī)那樣的PUSH(入棧)和POP(出棧)之類的指令,所以要用1段用戶程序來(lái)實(shí)現(xiàn)類似的功能。因?yàn)槭怯?段程序來(lái)實(shí)現(xiàn)現(xiàn)場(chǎng)保護(hù),而程序的執(zhí)行有可能會(huì)影響到W寄存器和STATUS寄存器,所以,首先應(yīng)該把這2個(gè)寄存器保護(hù)起來(lái),然后再去保存其他用戶認(rèn)為有必要保護(hù)的寄存器。并且在PIC單片機(jī)中,中斷現(xiàn)場(chǎng)數(shù)據(jù)不是保留到芯片的堆棧存儲(chǔ)區(qū)中,而是保留在用戶自己選擇的一些文件寄存器(即RAM數(shù)據(jù)存儲(chǔ)器單元)中,當(dāng)然一般應(yīng)該選擇通用寄存器來(lái)保護(hù)現(xiàn)場(chǎng)。下面給出的是1段原廠家最新提供的實(shí)現(xiàn)保護(hù)中斷現(xiàn)場(chǎng)的范例程序片段。
;將W、STATUS和PCLATH寄存器的內(nèi)容保存到臨時(shí)備份寄存器中
?。?]MOVWFW_TEMP ;復(fù)制W到它的臨時(shí)備份寄存器W_TEMP中
?。?]SWAPFSTATUS,W ;將STATUS寄存器高低半字節(jié)交換后放入W
[3]CLRFSTATUS ;不管當(dāng)前處在哪個(gè)體,都設(shè)置體0作當(dāng)前體
[4]MOVWFSTATUS_TEMP ;保存STATUS到體0上的臨時(shí)寄存器STATUS_TEMP
?。?]MOVF PCLATH, W ;把寄存器PCLATH內(nèi)容復(fù)制到W中
?。?]MOVWFPCLATH_TEMP ;經(jīng)W將PCLATH內(nèi)容轉(zhuǎn)到臨時(shí)寄存器PCLATH_TEMP
?。?]CLRFPCLATH ;不管當(dāng)前處在哪頁(yè),都把PCLATH設(shè)置成指向頁(yè)0(中斷服務(wù)程序的核心部分)
?。?]MOVFPCLATH_TEMP, W ;經(jīng)過(guò)W轉(zhuǎn)移
?。?]MOVWFPCLATH ;恢復(fù)PCLATH內(nèi)容
[10]SWAPFSTATUS_TEMP,W ;將STATUS_TEMP寄存器高低半字節(jié)交換后放入W
[11]MOVWFSTATUS ;把W內(nèi)容移動(dòng)到STATUS寄存器,(同時(shí)也把當(dāng)前體恢復(fù)到原先的體上)
?。?2]SWAPFW_TEMP,F ;將W_TEMP內(nèi)容高低半字節(jié)交換后放回
?。?3]SWAPFW_TEMP,W ;再次將W_TEMP內(nèi)容高低半字節(jié)交換后放入W
這段程序適用于PIC16CXX系列中各款型號(hào)的單片機(jī)。在這段例程之前,假設(shè)預(yù)先對(duì)于待保留的各個(gè)寄存器都分別定義了相應(yīng)的臨時(shí)備份寄存器。用后綴“_TEMP”表示臨時(shí)備份寄存器,例如“W”的臨時(shí)備份寄存器記為“W_TEMP”。對(duì)于這些臨時(shí)備份寄存器究竟需要定義多少個(gè),定義在通用寄存器區(qū)域中的哪個(gè)位置,都是值得考究的問(wèn)題。并且單片機(jī)的型號(hào)不同,其內(nèi)部的通用寄存器區(qū)域的分布也不同,因此這就使得臨時(shí)備份寄存器定義的數(shù)量和位置也不能相同。
例如,對(duì)于PIC16F873/874來(lái)說(shuō),要求寄存器W_TEMP必須在文件寄存器(即RAM數(shù)據(jù)存儲(chǔ)器)的體0和體1上各定義1個(gè),并且這2個(gè)W_TEMP寄存器單元必須具有相同的體內(nèi)地址碼(比如,在體0上把W_TEMP定義在20H單元,則在體1上就把另一個(gè)W_TEMP定義在A0H單元);而其他寄存器的臨時(shí)備份寄存器(如STATUS_TEMP和PCLATH_TEMP)都僅僅需要在體0上定義1個(gè)即可。
又例如,對(duì)于PIC16F87X子系列中的其他5款型號(hào)來(lái)說(shuō),情況有所不同。其文件寄存器各個(gè)體的頂端部分有16個(gè)地址空間,都會(huì)尋址到相同的16個(gè)物理單元上。這16個(gè)單元不需要體選尋址,或者說(shuō),尋址這16個(gè)單元與體選碼無(wú)關(guān),即與當(dāng)前所處的體無(wú)關(guān)。因此,將各個(gè)臨時(shí)備份寄存器都安排在這個(gè)位置(W_TEMP也只需要定義1個(gè)即可)最為合適。這樣做可以使得現(xiàn)場(chǎng)保護(hù)和現(xiàn)場(chǎng)恢復(fù)變得非常容易。中斷是一種隨機(jī)發(fā)生的事件。進(jìn)入中斷服務(wù)程序后,第1個(gè)要保存的應(yīng)該是工作寄存器W。原因是PIC單片機(jī)沒(méi)有在“不同寄存器”之間進(jìn)行直接傳遞的指令,這樣的功能得用W作中轉(zhuǎn)(需要2條指令)才能實(shí)現(xiàn),所以應(yīng)該先把W寄存器騰空(對(duì)應(yīng)程序中第1條指令)。急于騰空W寄存器,又不能破壞當(dāng)前狀態(tài)寄存器STATUS中的體選碼,還不能影響當(dāng)前狀態(tài)寄存器STATUS內(nèi)的標(biāo)志位,可又無(wú)法確定主程序所處的RAM數(shù)據(jù)存儲(chǔ)器當(dāng)前體是哪一個(gè),就只好在主程序所有可能選擇到的每一個(gè)RAM數(shù)據(jù)存儲(chǔ)器體上的相同位置,都定義1個(gè)W_TEMP臨時(shí)備份寄存器。
一旦把工作寄存器W騰空后,緊接著就應(yīng)將狀態(tài)寄存器STATUS的內(nèi)容轉(zhuǎn)移到W中。完成這一操作的指令也不能影響到STATUS寄存器內(nèi)部原有的標(biāo)志位,原因是STATUS寄存器的內(nèi)容在此之前還沒(méi)有安全地保護(hù)起來(lái)。經(jīng)過(guò)仔細(xì)分析得知,PIC16系列單片機(jī)的指令系統(tǒng)中有3條“MOV”傳送指令。但是,只有1條“MOVF f,W”是以RAM單元為源寄存器,以W為目標(biāo)寄存器的;而這條指令的操作過(guò)程又偏偏會(huì)影響“Z”標(biāo)志位。因此,該指令就不能使用了,只好用1條既有高、低半字節(jié)交換功能又有傳遞功能的“SWAPFSTATUS,W”來(lái)勉強(qiáng)頂替(對(duì)應(yīng)程序中第2條指令)。不過(guò)在此只利用它的傳遞功能,其交換功能帶來(lái)的多余操作還得記下來(lái),等到工作完成之后還得把它倒換回來(lái)。
STATUS寄存器的內(nèi)容已經(jīng)保存到W中時(shí),就可以大膽地將其清0了,以便把定義著STATUS_TEMP和PCLATH_TEMP的體0設(shè)置為當(dāng)前體(對(duì)應(yīng)程序中第3條指令)。經(jīng)過(guò)以上幾步特別需要謹(jǐn)慎的操作過(guò)后,就可以輕而易舉地將寄存器STATUS和PCLATH的內(nèi)容保存到各自的臨時(shí)備份寄存器中了(對(duì)應(yīng)程序中第4~6條指令)。
在單片機(jī)初始加電時(shí),自動(dòng)將PCLATH清0,以避免其內(nèi)容出現(xiàn)隨機(jī)值,也就是為了避免在以后的程序運(yùn)行過(guò)程中CPU發(fā)生不可預(yù)料的跳轉(zhuǎn),而造成程序的“跑飛”。由此可見,寄存器PCLATH對(duì)于程序的安全運(yùn)行是至關(guān)重要的,不可輕視。程序一旦進(jìn)入服務(wù)程序后,PCLATH的當(dāng)前值為何就無(wú)從考證,實(shí)際上就失去了對(duì)于PCLATH內(nèi)容的知情權(quán)。只好像單片機(jī)初始上電那樣將其清0,重新把它強(qiáng)行“拉入”知情范圍(對(duì)應(yīng)程序中第7條指令)。
PCLATH的內(nèi)容在2種情況下會(huì)影響到程序的走向:第1種情況是當(dāng)執(zhí)行GOTO和CALL這2條跳轉(zhuǎn)指令時(shí),11位地址碼來(lái)源于指令碼中,決定程序存儲(chǔ)器頁(yè)面的(PC值的)最高2位,來(lái)源于PCLATH<4:3>,即這種情況下只有PCLATH的2位影響程序走向。單單就這一種情況而言,只要用戶程序不超過(guò)第0頁(yè)(或稱頁(yè)0)的2KB范圍,對(duì)于程序員來(lái)說(shuō),PC值的最高2位可以忽略,因而PCLATH寄存器PCLATH<4:3>的2位也可以忽略。第2種情況是,以PCL為目標(biāo)的算術(shù)運(yùn)算、邏輯運(yùn)算或傳送操作指令(PIC16系列單片機(jī)的指令系統(tǒng)中具備14條這樣的指令),在操作過(guò)程中,自動(dòng)用PCLATH寄存器的低5位裝載PC的高5位PC<12:8>,影響程序走向的PCLATH內(nèi)容就多達(dá)5位。即使對(duì)于用戶程序不超過(guò)(第0頁(yè)范圍內(nèi)的)2KB的情況,也至少會(huì)有3位影響到程序的走向。對(duì)于程序員來(lái)說(shuō),PCLATH的內(nèi)容就不可忽略,必須保護(hù)。
總而言之,對(duì)于寄存器PCLATH的保護(hù)和處理(對(duì)應(yīng)程序中陰影標(biāo)出的部分指令,即第5~9條)并不是什么情況下都是必需的,但是在編寫中斷服務(wù)程序時(shí),統(tǒng)一安排這些指令也沒(méi)有任何壞處。只要主程序和中斷服務(wù)程序中都不需要修改PCLATH寄存器的內(nèi)容,就可以不保護(hù)它。具體地說(shuō),只有當(dāng)同時(shí)滿足以下2個(gè)條件時(shí),陰影標(biāo)出的部分指令(即第5~9條)才可以省略。
?。?)在主程序和中斷服務(wù)程序中不都存在跨頁(yè)跳轉(zhuǎn)。例如:用戶程序沒(méi)有使用第0頁(yè)2KB空間之外的程序存儲(chǔ)器,或者用戶程序雖然超出了2KB的范圍,但是,在主程序和中斷服務(wù)程序中沒(méi)有同時(shí)用到GOTO或CALL指令,都能滿足該條。
?。?) 在主程序和中斷服務(wù)程序中沒(méi)有同時(shí)使用以PCL為目標(biāo)的操作指令(比如查表)。
保護(hù)現(xiàn)場(chǎng)的操作次序與恢復(fù)現(xiàn)場(chǎng)的操作次序應(yīng)該相反。程序中的第8~11條就是按照相反的順序恢復(fù)寄存器PCLATH和 STATUS內(nèi)容的。但是,不要忘記保護(hù)現(xiàn)場(chǎng)時(shí)采用“SWAPF STATUS,W”指令產(chǎn)生的多余的交換操作,在此只好再采用同樣的方法將其交換回來(lái)(對(duì)應(yīng)程序中第10條指令)。最后2條指令,將W_TEMP內(nèi)容的高、低半字節(jié)交換了2遍,才被恢復(fù)到工作寄存器W中。如果只用1條傳送指令“MOVF W_TEMP,W”又會(huì)產(chǎn)生1個(gè)新的問(wèn)題:“MOVF W_TEMP,W”指令會(huì)影響“Z”標(biāo)志位,會(huì)破壞此前已經(jīng)被恢復(fù)的寄存器STATUS的內(nèi)容,這是我們所不希望的,也是不能容忍的。因此,在程序中利用了2條不影響標(biāo)志位的SWAP指令(即第12,13兩條指令)。雖然麻煩一點(diǎn),但可以使這個(gè)問(wèn)題得到圓滿的解決。
最后必須進(jìn)一步強(qiáng)調(diào)的是,并不是所有情況下編寫的中斷服務(wù)程序中都需要現(xiàn)場(chǎng)保護(hù),或者都需要像以上范例程序那樣進(jìn)行現(xiàn)場(chǎng)保護(hù)。有些情況下僅僅保護(hù)W、STATUS和PCLATH這3個(gè)寄存器還不夠。不過(guò)在此程序片段的基礎(chǔ)上,再增加或者減少需要保護(hù)的寄存器的個(gè)數(shù)都是輕而易舉的事。不要忘記,在保護(hù)任何文件寄存器之前都必須先把工作寄存器W保護(hù)起來(lái)才行得通。
3 需要注意的幾個(gè)問(wèn)題
(1)中斷標(biāo)志位的狀態(tài)與該中斷源是否產(chǎn)生中斷無(wú)關(guān)。換句話說(shuō),不管是否允許其中斷,只要滿足中斷的條件,中斷標(biāo)志位就會(huì)被置位。另外,也可以利用軟件將中斷標(biāo)志位置“1”或清“0”。
?。?)當(dāng)開放某一中斷源時(shí),該中斷源就是通過(guò)中斷標(biāo)志位向CPU申請(qǐng)中斷的。無(wú)論什么原因,只要將中斷標(biāo)志位置位,就會(huì)產(chǎn)生中斷。如果用軟件強(qiáng)行將中斷標(biāo)志位置位,也會(huì)產(chǎn)生中斷。
?。?)如果在中斷被屏蔽(或禁止)的情況下,中斷標(biāo)志位被置位,只要不被清除就會(huì)一直潛伏下來(lái),那么,一旦解除屏蔽,就會(huì)立即產(chǎn)生中斷。
(4)如果在中斷被禁止的情況下,中斷標(biāo)志位已經(jīng)被置位,但是,假如在允許其中斷之前將它清除,那么,即使解除禁止,它也不會(huì)產(chǎn)生中斷。
?。?)當(dāng)CPU相應(yīng)的任何一個(gè)中斷時(shí),全局中斷屏蔽位GIE將會(huì)自動(dòng)清0;當(dāng)中斷返回時(shí)它又會(huì)自動(dòng)恢復(fù)為1。如果在中斷處理期間用軟件將已經(jīng)復(fù)位的GIE重新置位,這時(shí)再出現(xiàn)中斷請(qǐng)求,就可以形成中斷嵌套。也就是說(shuō),如果在響應(yīng)某一中斷期間又響應(yīng)了其他中斷請(qǐng)求,就形成了中斷嵌套。發(fā)生中斷嵌套時(shí),前一中斷處理過(guò)程被暫停而進(jìn)入后一中斷處理,當(dāng)后一中斷過(guò)程被處理完畢之后,才會(huì)繼續(xù)處理前一中斷。照此方式,還可以形成多級(jí)嵌套,甚至自身嵌套。不過(guò)嵌套的級(jí)數(shù)絕對(duì)不能超過(guò)硬件堆棧的深度。
(6) 對(duì)于中斷響應(yīng)和處理時(shí)間有嚴(yán)格要求的應(yīng)用,保護(hù)現(xiàn)場(chǎng)的指令安排也應(yīng)考慮延時(shí)問(wèn)題。
?。?)如果同時(shí)發(fā)生多個(gè)中斷請(qǐng)求,得到優(yōu)先處理的中斷完全取決于在中斷服務(wù)程序中檢查中斷源的順序。原因是各個(gè)中斷源之間不存在優(yōu)先級(jí)別之分。
如果清除中斷標(biāo)志位的指令安排在中斷服務(wù)程序的尾部,就有可能丟失響應(yīng)在處理中斷期間該中斷源第2次中斷請(qǐng)求的機(jī)會(huì)。