《單片機(jī)原理及應(yīng)用》課件1第6章_第1頁(yè)
《單片機(jī)原理及應(yīng)用》課件1第6章_第2頁(yè)
《單片機(jī)原理及應(yīng)用》課件1第6章_第3頁(yè)
《單片機(jī)原理及應(yīng)用》課件1第6章_第4頁(yè)
《單片機(jī)原理及應(yīng)用》課件1第6章_第5頁(yè)
已閱讀5頁(yè),還剩93頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第6章中斷及其應(yīng)用6.1中斷概述6.2中斷響應(yīng)控制6.3中斷過(guò)程6.4中斷的應(yīng)用及擴(kuò)展6.5系統(tǒng)化程序設(shè)計(jì)中的概念和方法6.6設(shè)計(jì)課目與演練——位移測(cè)量并顯示小結(jié)

習(xí)題

本章首先講述單片機(jī)的中斷概念,然后從硬件上說(shuō)明單片機(jī)怎樣控制中斷請(qǐng)求并產(chǎn)生響應(yīng),在中斷服務(wù)程序中應(yīng)該如何處理并返回,最后給出中斷應(yīng)用實(shí)例和擴(kuò)展方法。6.1中斷概述中斷系統(tǒng)是為了使單片機(jī)對(duì)外界異步事件具有處理能力而設(shè)置的。圖6-1中描述了中斷的一些基本概念。在MCU正在執(zhí)行程序的過(guò)程中,如果外部硬件或者內(nèi)部某個(gè)組件發(fā)出請(qǐng)求,要求MCU暫停當(dāng)前的工作,轉(zhuǎn)而去處理這個(gè)臨時(shí)事件;處理完畢后,再返回到原來(lái)被中斷的地方,繼續(xù)執(zhí)行原來(lái)的工作。這個(gè)過(guò)程就是中斷。實(shí)現(xiàn)這種功能的組成部件稱為中斷系統(tǒng)。向MCU發(fā)出中斷請(qǐng)求的信號(hào)源稱為中斷源。中斷發(fā)生前正在執(zhí)行的程序代碼稱為主程序。中斷發(fā)生時(shí),主程序被斷開(kāi)的程序代碼的位置稱為斷點(diǎn)。中斷之后所執(zhí)行的程序稱為中斷服務(wù)或者中斷子程序。圖6-1中斷的過(guò)程及基本概念描述單片機(jī)的中斷系統(tǒng)一般允許多個(gè)中斷源。當(dāng)幾個(gè)中斷源同時(shí)向MCU發(fā)出中斷請(qǐng)求時(shí),要求單片機(jī)既可以區(qū)分各個(gè)中斷源的請(qǐng)求,又要決策首先為哪一個(gè)中斷源服務(wù),這就要求進(jìn)行中斷優(yōu)先級(jí)的設(shè)定。單片機(jī)響應(yīng)中斷請(qǐng)求的順序稱為中斷的優(yōu)先級(jí)。當(dāng)單片機(jī)正在進(jìn)行一個(gè)中斷服務(wù)的時(shí)候,另一個(gè)優(yōu)先級(jí)較高的中斷源發(fā)出中斷請(qǐng)求,這時(shí),單片機(jī)可以中斷正在執(zhí)行的中斷服務(wù)程序,轉(zhuǎn)而去響應(yīng)這個(gè)更高級(jí)別的中斷請(qǐng)求,執(zhí)行其中斷服務(wù),然后再回到原低級(jí)中斷繼續(xù)處理,這個(gè)過(guò)程稱為中斷嵌套。

MCS—51系列單片機(jī)的中斷系統(tǒng)是8位單片機(jī)中功能較強(qiáng)的一種,可以提供5(6)個(gè)中斷請(qǐng)求源,具有兩個(gè)中斷優(yōu)先級(jí),可實(shí)現(xiàn)兩級(jí)中斷服務(wù)程序嵌套。6.2中斷響應(yīng)控制在中斷響應(yīng)控制過(guò)程中,有很多的寄存器參與其中,整體結(jié)構(gòu)如圖6-2所示。6.2.1中斷源由圖6-2可知,MCS—51中斷系統(tǒng)有5個(gè)中斷源(52增加了一個(gè)),通常分為三類:

外部中斷:包括、,由外部硬件電路產(chǎn)生。中斷的發(fā)生有電平觸發(fā)(51系列為低電平觸發(fā),其它的請(qǐng)參考芯片的DATASHEET)和邊沿觸發(fā)(51系列為下降沿觸發(fā))。對(duì)于電平觸發(fā),在MCU的時(shí)鐘周期內(nèi)如果檢測(cè)到有效的低電平信號(hào),則認(rèn)為產(chǎn)生中斷請(qǐng)求,CPU開(kāi)始執(zhí)行中斷處理。對(duì)于邊沿觸發(fā),在MCU的時(shí)鐘周期內(nèi)如果檢測(cè)到有高電平向低電平的變化信號(hào)(下降沿),則認(rèn)為產(chǎn)生中斷請(qǐng)求,開(kāi)始執(zhí)行中斷處理。圖6-2中斷響應(yīng)控制結(jié)構(gòu)

定時(shí)中斷:包括T0和T1(T2在8052系列才有),中斷產(chǎn)生于MCU內(nèi)部的定時(shí)/計(jì)數(shù)器的計(jì)數(shù)溢出。當(dāng)定時(shí)/計(jì)數(shù)器工作于計(jì)數(shù)方式時(shí),可以由T0、T1從外部輸入計(jì)數(shù)脈沖等。

串口中斷:對(duì)應(yīng)RX、TX。具體對(duì)應(yīng)的管腳參見(jiàn)圖1-4及管腳說(shuō)明。串口中斷也是由內(nèi)部電路產(chǎn)生的。當(dāng)串口的緩沖區(qū)接收到數(shù)據(jù)或發(fā)送數(shù)據(jù)結(jié)束時(shí),便產(chǎn)生中斷,通知MCU進(jìn)行下一步處理。

51系列單片機(jī)中斷源的管理是通過(guò)中斷入口地址(即中斷矢量)來(lái)實(shí)現(xiàn)的。對(duì)應(yīng)每一個(gè)中斷源的中斷請(qǐng)求,MCU響應(yīng)后,都有一個(gè)唯一的16位地址送到程序計(jì)數(shù)器PC中。中斷服務(wù)程序就是從這個(gè)地址開(kāi)始執(zhí)行的,所以稱之為中斷入口地址,也稱為中斷矢量。每一個(gè)中斷入口都占有8個(gè)連續(xù)的字節(jié),而且在程序存儲(chǔ)器中的位置是固定的(見(jiàn)程序存儲(chǔ)器結(jié)構(gòu),圖2-3),被對(duì)應(yīng)的中斷源所指向。6.2.2中斷請(qǐng)求標(biāo)志(TCON、SCON)在中斷請(qǐng)求被響應(yīng)前,中斷請(qǐng)求是由MCU鎖存在特殊功能寄存器TCON和SCON的中斷響應(yīng)標(biāo)志位中的。

1.?TCON(88H)中斷控制寄存器TCON的位定義格式如圖6-3所示。下面分別介紹各位的定義:

TF1、TF0:定時(shí)/計(jì)數(shù)器Ti的溢出標(biāo)志位。當(dāng)Ti啟動(dòng)計(jì)數(shù)后,從初始值開(kāi)始執(zhí)行加1操作。當(dāng)Ti計(jì)數(shù)溢出時(shí),由硬件置位TFi,向CPU請(qǐng)求中斷;響應(yīng)后,由硬件自動(dòng)清零。也可以由軟件來(lái)查詢?cè)摌?biāo)志,并由軟件清零。指令:CLRTF1(或CLRTF0等)。圖6-3中斷控制寄存器TCON

IE1、IE0:對(duì)應(yīng)、的外部中斷標(biāo)志位。當(dāng)外部觸發(fā)中斷后,置位相應(yīng)的標(biāo)志位,并且向CPU請(qǐng)求中斷。響應(yīng)后,由硬件自動(dòng)清零(邊沿觸發(fā)方式)。

IT1、IT0:外部中斷源觸發(fā)方式控制位。以IT1為例,其控制方式為:

IT1?=?0,外部中斷為電平觸發(fā)。這是系統(tǒng)啟動(dòng)或者復(fù)位后的默認(rèn)方式。當(dāng)為低電平時(shí),置位IE1。CPU在每個(gè)機(jī)器周期的S5P2采樣的輸入電平,當(dāng)采樣到低電平時(shí),置位IE1。采用電平觸發(fā)方式時(shí),外部中斷源必須保持低電平有效,直到該中斷被CPU響應(yīng)。采用電平觸發(fā)方式時(shí),CPU響應(yīng)中斷后,不能自動(dòng)清除IE1標(biāo)志位(軟件也不可清零),因此,在該中斷服務(wù)程序執(zhí)行完之前,外部中斷源必須被撤除,否則將產(chǎn)生另一次中斷。

IT1?=?1,外部中斷為邊沿觸發(fā)(下降沿)。CPU在每個(gè)機(jī)器周期的S5P2采樣的輸入電平。如果相鄰的兩次采樣,前面為高電平,后面為低電平,則采集到有效的下降沿,置位IE1,表示外部中斷向CPU申請(qǐng)中斷,直到CPU響應(yīng)中斷時(shí),才由硬件自動(dòng)清零IE1。因?yàn)槊總€(gè)機(jī)器周期采樣一次外部中斷輸入電平,所以,采用邊沿觸發(fā)方式時(shí),外部中斷源輸入的高電平和低電平必須保持一個(gè)機(jī)器周期(12個(gè)振蕩周期)以上,才能確保CPU檢測(cè)到由高到低的下降沿觸發(fā)。對(duì)于IT0,其對(duì)的影響同上,不再贅述。

2.?SCON(98H)中斷控制寄存器SCON的位定義格式如圖6-4所示。這里只定義了與中斷有關(guān)的兩個(gè)位。圖6-4中斷控制寄存器SCON

TI:串口發(fā)送數(shù)據(jù)中斷請(qǐng)求標(biāo)志位。當(dāng)單片機(jī)的串口發(fā)送完一個(gè)數(shù)據(jù)后,硬件置位TI,向CPU發(fā)出中斷請(qǐng)求。但CPU響應(yīng)中斷時(shí),并不自動(dòng)清零TI,必須由軟件清零。

RI:串口接收中斷標(biāo)志位。當(dāng)單片機(jī)的串口接收完一個(gè)數(shù)據(jù)后,硬件置位RI,向CPU發(fā)出中斷請(qǐng)求。但CPU響應(yīng)中斷后,并不自動(dòng)清零RI,必須由軟件清零。6.2.3中斷允許控制(IE)如圖6-2所示,IE是中斷允許寄存器,對(duì)51系列單片機(jī)的每一個(gè)中斷都有一個(gè)允許或者屏蔽的控制,分別對(duì)應(yīng)IE寄存器里面的一位。中斷允許寄存器IE的位定義格式如圖6-5所示。圖6-5中斷允許寄存器IE

EA:中斷允許總控制位。EA=0,CPU不響應(yīng)任何中斷,即所有中斷被屏蔽,稱為關(guān)中斷。EA=1,允許中斷,由每個(gè)中斷源對(duì)應(yīng)的控制位決定該中斷是否允許。如CLREA,關(guān)中斷;SETBEA,開(kāi)中斷。其他各位的使用方法相同。

ET2、ET1、ET0:定時(shí)/計(jì)數(shù)器Ti中斷允許位。1則允許,0則禁止。如ET1=1,則T1中斷允許;否則,中斷被屏蔽。

EX1、EX0:對(duì)應(yīng)外部中斷、允許位。1則允許,0則禁止。如EX0=1,則允許管腳上的中斷;否則,中斷被屏蔽。

ES:串口中斷允許位。ES=1,允許串行中斷;否則,禁止串行中斷。6.2.4中斷優(yōu)先級(jí)設(shè)定(IP)

MCS—51單片機(jī)具有兩個(gè)中斷優(yōu)先級(jí),由中斷優(yōu)先級(jí)寄存器IP控制,可以設(shè)定每個(gè)中斷源為高優(yōu)先級(jí)中斷或者為低優(yōu)先級(jí)中斷,從而控制中斷的嵌套。

1.中斷優(yōu)先級(jí)控制寄存器IP中斷優(yōu)先級(jí)控制寄存器IP的位定義格式如圖6-6所示。

PS:串口中斷優(yōu)先級(jí)控制位。1為高優(yōu)先級(jí),0為低優(yōu)先級(jí)。如SETBPS,則串口中斷為高優(yōu)先級(jí)。下面各位的使用方法相同。

PT2、PT1、PT0:對(duì)應(yīng)T2、T1、T0中斷優(yōu)先級(jí)控制位。1為高優(yōu)先級(jí),0為低優(yōu)先級(jí)。如PT1=1,則T1中斷源為高優(yōu)先級(jí)中斷。

PX1、PX0:外部中斷、中斷優(yōu)先級(jí)控制位。1為高優(yōu)先級(jí),0為低優(yōu)先級(jí)。圖6-6中斷優(yōu)先級(jí)控制寄存器IP

2.自然優(yōu)先級(jí)多個(gè)中斷源在同一個(gè)優(yōu)先級(jí)上時(shí)中斷源的內(nèi)部查詢順序,稱為自然優(yōu)先級(jí),先查詢到的被優(yōu)先響應(yīng)。8051中斷源的自然優(yōu)先級(jí)如圖6-7所示。

3.中斷嵌套高優(yōu)先級(jí)中斷可以中斷正在執(zhí)行的低優(yōu)先級(jí)的中斷,除非這個(gè)高優(yōu)先級(jí)中斷被屏蔽。同級(jí)或者低級(jí)的中斷源不能中斷正在執(zhí)行的中斷服務(wù)程序,只能等到當(dāng)前中斷服務(wù)結(jié)束后,由CPU響應(yīng)中斷,執(zhí)行中斷。這一點(diǎn)編程者一定要注意,特別是初學(xué)者。在中斷服務(wù)程序里要想到當(dāng)前程序是否會(huì)被高優(yōu)先級(jí)程序所嵌套中斷,并且在嵌套中是否會(huì)改變當(dāng)前使用的寄存器或者存儲(chǔ)單元的值,是否允許嵌套等。這些都要認(rèn)真考慮。圖6-7自然優(yōu)先級(jí)6.3中斷過(guò)程上文從硬件的角度講了與中斷響應(yīng)有關(guān)的控制寄存器的設(shè)置。下面從程序執(zhí)行的角度(即軟件的角度)分析中斷的處理過(guò)程,整體分為三個(gè)過(guò)程:中斷響應(yīng),中斷處理(中斷服務(wù)),中斷返回。這三者之間的層次關(guān)系已在圖6-1中進(jìn)行了描述。6.3.1中斷響應(yīng)當(dāng)中斷源發(fā)出中斷信號(hào)后,CPU不一定能夠立即響應(yīng)中斷。除了上面講的硬件中斷響應(yīng)條件外,程序當(dāng)前指令的執(zhí)行狀態(tài)也會(huì)暫時(shí)阻斷中斷響應(yīng)。下面系統(tǒng)介紹這兩個(gè)響應(yīng)條件。

1.響應(yīng)條件

(1)硬件設(shè)置條件:

中斷源有中斷申請(qǐng),如T0溢出。

中斷允許總控制位允許,即EA=1。

與中斷源對(duì)應(yīng)的中斷允許控制位允許,如ET0=1。

(2)指令執(zhí)行狀態(tài)條件:

CPU正在執(zhí)行同級(jí)或者高一級(jí)的中斷服務(wù)程序,則響應(yīng)等待。

當(dāng)前的機(jī)器周期不是正在執(zhí)行的指令的最后一個(gè)周期,則響應(yīng)等待。一條指令可能需要單周期、雙周期或者4個(gè)機(jī)器周期,但是中斷不能在一條指令的執(zhí)行周期內(nèi)響應(yīng)中斷,必須等到正在執(zhí)行的指令執(zhí)行完畢。

正在執(zhí)行的指令是中斷返回(RETI)指令或者是對(duì)專用寄存器IP、IE進(jìn)行讀寫(xiě)的指令,需要在該指令執(zhí)行完后再執(zhí)行一條其他指令,才有可能響應(yīng)中斷。如果上面的中斷條件已經(jīng)滿足,阻斷狀態(tài)已經(jīng)解除,那么CPU就可以響應(yīng)中斷。

2.響應(yīng)過(guò)程

置位相應(yīng)的優(yōu)先級(jí)狀態(tài)觸發(fā)器(CPU內(nèi)部使用,不對(duì)用戶開(kāi)放,不可尋址;該觸發(fā)器指出CPU開(kāi)始處理的中斷的優(yōu)先級(jí)別,會(huì)影響到是否允許再次中斷,并且屏蔽較低優(yōu)先級(jí)的中斷請(qǐng)求等)。

執(zhí)行一個(gè)由硬件自動(dòng)完成的子程序長(zhǎng)調(diào)用指令LCALL,去調(diào)用該中斷源入口地址。因此,中斷服務(wù)程序可以放在64KB的程序存儲(chǔ)器空間內(nèi)的任意位置。響應(yīng)應(yīng)完成以下工作:

硬件將當(dāng)前的斷點(diǎn)地址壓入堆棧。

將該中斷源對(duì)應(yīng)的中斷入口地址(中斷矢量)裝入程序計(jì)數(shù)器(PC)。

程序開(kāi)始執(zhí)行相應(yīng)的中斷服務(wù)(程序)。

有些中斷會(huì)由硬件自動(dòng)清除該中斷的中斷請(qǐng)求標(biāo)志位(T0、T1、T2,還有、的邊沿觸發(fā)方式)。上述條件判斷和執(zhí)行步驟如圖6-8所示。圖6-8中斷響應(yīng)的條件與過(guò)程

3.響應(yīng)時(shí)間

CPU對(duì)于中斷的響應(yīng)需要一定的時(shí)間,而且不同的中斷源、不同的指令、不同的優(yōu)先級(jí)等都會(huì)影響中斷的響應(yīng)時(shí)間。這個(gè)時(shí)間最短為3個(gè)機(jī)器周期,最長(zhǎng)為無(wú)限。當(dāng)然,優(yōu)良的程序設(shè)計(jì)不允許出現(xiàn)中斷響應(yīng)時(shí)間為無(wú)限的情況。一般的程序設(shè)計(jì)不用考慮中斷響應(yīng)時(shí)間的問(wèn)題。但是在精確定時(shí)或者實(shí)時(shí)控制要求較高的場(chǎng)合,就要認(rèn)真考量程序的每一步執(zhí)行和每一條指令的設(shè)計(jì)。詳細(xì)描述如下。在每個(gè)機(jī)器周期的S5P2狀態(tài)中,中斷源的中斷申請(qǐng)被鎖存到中斷標(biāo)志位,在下一個(gè)機(jī)器周期CPU才會(huì)查詢這些值。這里占用一個(gè)機(jī)器周期。如果滿足中斷響應(yīng)條件,則由硬件執(zhí)行長(zhǎng)調(diào)用指令LCALL,使程序轉(zhuǎn)入中斷服務(wù)程序執(zhí)行。這個(gè)調(diào)用需要兩個(gè)機(jī)器周期。這是最快的響應(yīng)時(shí)間,最少需要3個(gè)機(jī)器周期。下面看看如果有響應(yīng)受阻的情況發(fā)生。如果中斷源申請(qǐng)中斷時(shí),有一個(gè)優(yōu)先級(jí)更高的中斷正在發(fā)生(或執(zhí)行),那么中斷請(qǐng)求被擱置,進(jìn)入等待狀態(tài),一直要等到這個(gè)高優(yōu)先級(jí)的中斷執(zhí)行完畢以后,才有可能響應(yīng)。那么,這個(gè)等待時(shí)間就決定于這個(gè)高優(yōu)先級(jí)的中斷服務(wù)程序了。所以,上面提到?jīng)]有等待上限的問(wèn)題。但是,如果真的沒(méi)有上限,則是不良的程序設(shè)計(jì),甚至?xí)a(chǎn)生災(zāi)難。這里要特別提示,中斷服務(wù)程序要短小高效,以免影響其他中斷服務(wù)。6.3.2中斷處理中斷處理(中斷服務(wù))程序指的是,從中斷響應(yīng)后轉(zhuǎn)到中斷源對(duì)應(yīng)的中斷入口地址開(kāi)始執(zhí)行起,一直到執(zhí)行RETI指令開(kāi)始中斷返回止的這一段。這一段是由用戶來(lái)設(shè)計(jì)完成的,即軟件執(zhí)行部分。這部分主要有四個(gè)方面需要考慮。

1.程序跳轉(zhuǎn)每個(gè)中斷源的中斷入口地址是由硬件確定的,但是對(duì)應(yīng)的空間只有8個(gè)字節(jié),處理中斷服務(wù)有些困難。所以,一般在這里直接放置一個(gè)無(wú)條件跳轉(zhuǎn)指令,轉(zhuǎn)移到用戶的中斷服務(wù)程序去執(zhí)行。這里實(shí)際上已經(jīng)進(jìn)入了中斷服務(wù),但是習(xí)慣上說(shuō)的中斷服務(wù)常常是指跳轉(zhuǎn)后執(zhí)行的那個(gè)程序。關(guān)于跳轉(zhuǎn),在存儲(chǔ)單元結(jié)構(gòu)中有詳細(xì)的描述,見(jiàn)圖2-3(程序存儲(chǔ)器結(jié)構(gòu))。

2.現(xiàn)場(chǎng)保護(hù)與恢復(fù)在執(zhí)行中斷服務(wù)程序時(shí),有可能會(huì)影響PSW或者其他操作過(guò)的單元,如果這些操作單元在主程序中也被使用,就會(huì)產(chǎn)生兩種后果:

(1)傳遞結(jié)果或者參數(shù)。比如,在主程序中設(shè)置一個(gè)死循環(huán):

CLRA

JZ$然后在中斷服務(wù)中設(shè)置指令:

MOVA,#01H當(dāng)中斷服務(wù)執(zhí)行后,上面的死循環(huán)結(jié)束。為什么?問(wèn)題1:在死循環(huán)中還可以修改A中的值嗎?這就是中斷的特色和魅力。問(wèn)題2:修改了A的值死循環(huán)就結(jié)束了嗎?死循環(huán)是怎么形成的,如果A的值非零,就不是死循環(huán)了。這個(gè)例子是利用中斷來(lái)跳出死循環(huán)的。

(2)造成混亂,甚至導(dǎo)致程序的崩潰。舉個(gè)例子,在主程序中有:

MOVA,#02H MOVDPTR,#PROG_INDEX JMP@A+DPTR

PROG_INDEX: AJMPPROG1 AJMPPROG2 …中斷服務(wù)程序中設(shè)置指令:

MOVA,#01H如果這個(gè)中斷正好在主程序執(zhí)行完MOVA,#02H之后響應(yīng)中斷并且執(zhí)行中斷服務(wù),那么A中的值就會(huì)被修改為01H。AJMP指令是雙字節(jié)指令,這樣會(huì)有什么情況發(fā)生,程序跳轉(zhuǎn)到了一條指令的第二個(gè)字節(jié)執(zhí)行?!這就亂套了。(請(qǐng)查詢指令代碼,可以進(jìn)一步分析。)所以,要在中斷服務(wù)中對(duì)主程序中可能被影響的單元進(jìn)行保護(hù)。常用的方法就是入棧保護(hù)和出棧恢復(fù),這就是現(xiàn)場(chǎng)的保護(hù)和恢復(fù)。在進(jìn)入中斷服務(wù)程序后,首先將中斷服務(wù)中可能要用到的存儲(chǔ)器或者單元進(jìn)行保護(hù)(入棧處理,例如PUSHA);在中斷處理程序結(jié)束前,恢復(fù)這些單元的內(nèi)容(出棧處理,例如POPA)。

3.開(kāi)關(guān)中斷問(wèn)題

若在執(zhí)行當(dāng)前中斷時(shí)不想被更高級(jí)的中斷打斷,則進(jìn)入中斷服務(wù)程序后,首先要關(guān)中斷,或者屏蔽更高級(jí)中斷源的中斷。例如,執(zhí)行CLREA。通常采用的方式就是進(jìn)入中斷服務(wù)后關(guān)中斷,而在中斷返回前開(kāi)中斷。

在進(jìn)行現(xiàn)場(chǎng)的保護(hù)或操作時(shí),不能被高優(yōu)先級(jí)的中斷打斷,否則有可能會(huì)破壞現(xiàn)場(chǎng)數(shù)據(jù)或者造成混亂。通常采取的方法是保護(hù)現(xiàn)場(chǎng)前關(guān)中斷,保護(hù)后再開(kāi)中斷;恢復(fù)現(xiàn)場(chǎng)前關(guān)中斷,恢復(fù)結(jié)束后再開(kāi)中斷。這是一般意義的流程。如果在中斷服務(wù)中不希望發(fā)生中斷嵌套,則關(guān)中斷后中間就不用再開(kāi)了,直到返回前再開(kāi)中斷。一般意義的中斷處理流程如圖6-9所示。圖6-9中斷處理過(guò)程

4.處理中斷源請(qǐng)求(處理任務(wù))這是中斷響應(yīng)后程序要解決問(wèn)題的核心程序段,處理中斷任務(wù),完成該中斷的功能設(shè)計(jì)。比如,要對(duì)計(jì)數(shù)器的計(jì)數(shù)單元重新賦值,要處理外部的按鍵中斷等,這就相當(dāng)于一個(gè)子程序的設(shè)計(jì)。不再贅述。6.3.3中斷返回中斷返回是指從執(zhí)行RETI指令到程序回到主程序斷點(diǎn)處繼續(xù)執(zhí)行的這段過(guò)程。RETI是中斷返回專用指令。執(zhí)行這條指令后,可將主程序的斷點(diǎn)地址從堆棧中彈出,送回到PC中,讓程序回到主程序斷點(diǎn)處繼續(xù)向下執(zhí)行;還要通知中斷系統(tǒng)已經(jīng)處理完畢當(dāng)前中斷,清除優(yōu)先級(jí)狀態(tài)觸發(fā)器(也正是因?yàn)檫@樣,不能使用RET代替RETI;否則導(dǎo)致的后果是,不能再次響應(yīng)中斷)。這個(gè)過(guò)程的處理如圖6-10所示。圖6-10中斷返回示意圖6.4中斷的應(yīng)用及擴(kuò)展中斷系統(tǒng)是單片機(jī)的精髓,只有學(xué)會(huì)了中斷系統(tǒng),你才算真正了解了單片機(jī),并且可以嘗試進(jìn)行應(yīng)用設(shè)計(jì)了。比如說(shuō),前面我們已經(jīng)設(shè)計(jì)了按鍵系統(tǒng),但是它的工作方式是查詢,會(huì)消耗掉大量的CPU資源,在實(shí)踐中很難應(yīng)用,而實(shí)用的按鍵大多采用中斷方式設(shè)計(jì)。下面,我們把中斷應(yīng)用到具體的系統(tǒng)中,在領(lǐng)略中斷的魅力的同時(shí),來(lái)分析設(shè)計(jì)中斷服務(wù)的要領(lǐng)和注意事項(xiàng)。6.4.1鍵盤(pán)中斷與識(shí)別圖3-21(b)是獨(dú)立式按鍵的中斷設(shè)計(jì)方法,請(qǐng)讀者自己嘗試編程,完成中斷服務(wù)設(shè)計(jì)。這里講解比較實(shí)用的矩陣式按鍵設(shè)計(jì)。矩陣式按鍵中斷工作方式接口的電路如圖6-11所示。圖6-11矩陣式鍵盤(pán)中斷工作方式接口這個(gè)電路是在圖5-10(b)所示的電路原理基礎(chǔ)上增加了中斷。這個(gè)設(shè)計(jì)方法比較常用,而且由于增加了中斷,使該電路更為實(shí)用。對(duì)應(yīng)的電路圖如圖6-12所示。

(1)把行線全輸出0,而列線輸入為:當(dāng)無(wú)按鍵按下時(shí),列線全部為高電平;當(dāng)有按鍵按下時(shí),該按鍵對(duì)應(yīng)的列線為0。

(2)由圖6-12可知,只要有列線出現(xiàn)低電平,則4與門(mén)74LS21就輸出低電平,連接到CPU的,發(fā)出中斷請(qǐng)求。

(3)為了可以響應(yīng)按鍵中斷,需要在程序初始化時(shí)設(shè)置相應(yīng)的中斷允許:

SETBEX0 ;開(kāi)外部中斷0

SETBEA ;開(kāi)中斷,注意這個(gè)設(shè)置的先后順序(一般)或者直接執(zhí)行一條指令:

ORLIE,#81H圖6-12矩陣式鍵盤(pán)中斷方式設(shè)計(jì)電路圖

(4)響應(yīng)鍵盤(pán)中斷后,要在鍵盤(pán)中斷服務(wù)程序中完成鍵盤(pán)消抖和鍵盤(pán)識(shí)別及編碼工作,這個(gè)任務(wù)直接使用第5章講述的線反轉(zhuǎn)法。但需在這個(gè)功能程序段的前后做些工作,要保護(hù)在鍵盤(pán)識(shí)別和編碼過(guò)程中用到的寄存器和其他存儲(chǔ)單元(現(xiàn)場(chǎng)保護(hù)),以免回到主程序后影響運(yùn)行,甚至導(dǎo)致程序崩潰。中斷服務(wù)中用到的寄存器或存儲(chǔ)單元有R0、P1、A;消抖使用的10ms延時(shí)程序里的寄存器也要考慮在內(nèi),比如R1、R2、R3。另外,運(yùn)算會(huì)影響PSW相應(yīng)的位。不一定要對(duì)中斷服務(wù)中涉及到的所有寄存器或單元進(jìn)行保護(hù),保護(hù)的目的是不影響主程序的正確執(zhí)行。如果中斷服務(wù)中使用的寄存器或者單元在主程序的設(shè)計(jì)中沒(méi)有使用,或者就是用來(lái)和中斷服務(wù)程序進(jìn)行數(shù)據(jù)溝通(如參數(shù)傳遞)等,就沒(méi)有必要保護(hù)了。

(5)如果按照一般的設(shè)計(jì)方法,在鍵盤(pán)中斷服務(wù)期間不允許其他的中斷發(fā)生,則中斷服務(wù)程序設(shè)計(jì)如下:

CLREA ;關(guān)中斷

PUSHPSW ;保護(hù)程序狀態(tài)字

PUSHA ;保護(hù)累加器A鍵盤(pán)線反轉(zhuǎn)法掃描 ;就是第5章的線掃描法程序 ;建議不要采用調(diào)用方式

POPA ;恢復(fù)A

POPPSW ;恢復(fù)PSW

SETBEA ;開(kāi)中斷

RETI ;中斷返回

(6)還要考慮按鍵的重鍵問(wèn)題。當(dāng)按鍵已經(jīng)響應(yīng)并且中斷處理返回后,行線重新又恢復(fù)到輸出全0,列線為輸入的狀態(tài)。這個(gè)時(shí)間是非常短的(約幾十毫秒),但這個(gè)時(shí)候按鍵并沒(méi)有撤除,4與門(mén)仍然是輸出低電平,即端還是輸入低電平,就會(huì)再次產(chǎn)生中斷請(qǐng)求,CPU再次發(fā)生中斷,又再次執(zhí)行處理。這就產(chǎn)生了重鍵。實(shí)際上是一次按鍵,但程序把它當(dāng)成幾次按鍵動(dòng)作進(jìn)行處理。比如,你設(shè)計(jì)的是一個(gè)數(shù)字輸入鍵盤(pán),當(dāng)輸入一個(gè)1時(shí),程序卻連續(xù)輸入了3個(gè)、4個(gè)或者更多個(gè)1,應(yīng)該避免這種情況的發(fā)生。上面出現(xiàn)的問(wèn)題是,因?yàn)榘存I按下后會(huì)持續(xù)一段時(shí)間(幾百毫秒~幾秒),而在這段時(shí)間里按鍵是穩(wěn)定的(見(jiàn)圖3-18),特別是在中斷服務(wù)程序返回后,只要按鍵不重新抬起,就不會(huì)產(chǎn)生列線電平的變化。因此,可以把按鍵中斷的響應(yīng)條件改變?yōu)橄陆笛赜|發(fā),這樣一次按鍵只有一次觸發(fā)(不穩(wěn)定的觸發(fā)已被消抖處理,而在反轉(zhuǎn)掃描列線全部輸出為0時(shí),4輸入與門(mén)仍然輸出低電平,不會(huì)產(chǎn)生新的觸發(fā))。所以,在程序初始化時(shí),要設(shè)置:

SETB IT0 ;或者執(zhí)行:

ORL TCON,#01H ;

(7)完整的實(shí)例程序如下:

ORG0000H ;

LJMPSTART ;程序跳轉(zhuǎn)

ORG0003H ;按鍵中斷入口地址(中斷0入口地址) LJMPKEY_TEST ;跳轉(zhuǎn)到按鍵中斷服務(wù)

ORG0100H

START: ;主程序

MOVSP,#60H ;要給SP足夠的堆棧深度

MOVP1,#0F0H ;按鍵接口初始化,行輸出,列輸入

SETBIT0 ;中斷設(shè)置初始化,下降沿觸發(fā)

SETBEX0 ;開(kāi)外部中斷0 SETBEA ;開(kāi)中斷

MOVR0,#00H ;用R0作為按鍵鍵碼傳輸單元,

;這里初始化為0

LOOP:

CJNER0,#00H,FUNC ;如果有按鍵,則處理

SJMPLOOP ;重復(fù)檢測(cè)

FUNC: NOP ;這里的功能為空,請(qǐng)根據(jù)需要自己補(bǔ)充 MOVR0,#00H ;處理完畢后,重新設(shè)置R0為0 RET

DEL10: NOP ;這里的延時(shí)為空,請(qǐng)自己補(bǔ)充

RET

KEY_TEST: ;鍵盤(pán)檢測(cè)子程序的入口地址

CLREA PUSHPSW PUSHA MOVR0,#00H ;?R0存放按鍵編碼,初始化為0,表示無(wú)按鍵

MOVA,P1 ;行輸出,讀入列的狀態(tài)

ANLA,#0F0H ;屏蔽掉行線狀態(tài)

CJNEA,#0F0H,RE_TEST ;判斷列線狀態(tài)是否全為“1”,如果不是,

;去抖動(dòng)

SJMPRETU ;如果全部為“1”,則無(wú)按鍵,轉(zhuǎn)去返回處理

RE_TEST: ;去抖動(dòng)處理

LCALLDEL10 ;延時(shí)10ms MOVR0,A ;先保存剛才的列位置

MOVP1,#0FH ;交換,行輸入,列輸出

MOVA,P1 ;再讀入按鍵行狀態(tài)

ANLA,#0FH ;屏蔽掉列線狀態(tài)

CJNEA,#0FH,KEY_CODE ;是否仍有按鍵,如有,轉(zhuǎn)去得到鍵碼

MOVR0,#00H ;清除R0 SJMPRETU ;否則,說(shuō)明是抖動(dòng)或者干擾

KEY_CODE: ;在這里得到鍵盤(pán)編碼,確定按鍵

ORLA,R0 ;把行、列狀態(tài)合并,得到鍵碼

XCHA,R0 ;把鍵碼交換到R0

RETU: MOVP1,#0F0H ;恢復(fù)行輸出、列輸入的狀態(tài)

POPA POPPSW SETBEA RETI ;中斷返回主程序

END ;程序結(jié)束偽指令進(jìn)一步:

這個(gè)程序非常實(shí)用。

思考:R0的值是什么時(shí)候被改變的?主程序是怎樣檢測(cè)R0的值的變化的?

思考:延時(shí)去抖動(dòng)后驗(yàn)證是否仍有按鍵時(shí),不是采用原來(lái)的讀法,而是更換行、列輸出后再驗(yàn)證。這樣做的道理是什么?

思考:中斷響應(yīng)的觸發(fā)方式是什么?那么,中斷服務(wù)中的CLREA必需嗎?不使用會(huì)怎樣?

思考:在中斷返回前,為什么要有MOVP1,#0F0H這條指令?6.4.2編碼器中斷與識(shí)別在工程實(shí)踐中,常常需要測(cè)量位移或者轉(zhuǎn)速等,而編碼器是一種比較有效而穩(wěn)定的測(cè)量?jī)x器。其測(cè)量原理就是把位移的變化轉(zhuǎn)化為脈沖輸出的個(gè)數(shù)進(jìn)行測(cè)量,而把速度的變化轉(zhuǎn)化為脈沖輸出的頻率來(lái)進(jìn)行測(cè)量。其中光電式增量編碼器是較常用的一種編碼器。下面以EPC-755A光電式編碼器為例,來(lái)講解編碼器如何與單片機(jī)接口,并給出測(cè)量實(shí)例。

1.編碼器測(cè)量原理光電式編碼器是目前應(yīng)用較多的一種傳感器,測(cè)量原理如圖6-13所示。光電式編碼器是由光柵盤(pán)和光電檢測(cè)裝置組成的。光柵盤(pán)是在一定直徑的圓板上等分地開(kāi)通若干個(gè)長(zhǎng)方形孔。由于光電碼盤(pán)與電動(dòng)機(jī)同軸,電動(dòng)機(jī)旋轉(zhuǎn)時(shí),光柵盤(pán)與電動(dòng)機(jī)同速旋轉(zhuǎn),經(jīng)發(fā)光二極管等電子元件組成的檢測(cè)裝置檢測(cè)輸出若干脈沖信號(hào),通過(guò)計(jì)算每秒光電編碼器輸出脈沖的個(gè)數(shù)就能反映當(dāng)前電動(dòng)機(jī)的轉(zhuǎn)速。為判斷旋轉(zhuǎn)方向,碼盤(pán)提供相位相差90°的兩路脈沖信號(hào)OUT_A、OUT_B;另外還提供一個(gè)同步信號(hào)OUT_Z,編碼器每轉(zhuǎn)一圈輸出一個(gè)脈沖,可用于基準(zhǔn)點(diǎn)定位。圖6-13光電式編碼器測(cè)量原理

2.編碼器輸出信號(hào)分析編碼器提供的脈沖信號(hào)與方向的關(guān)系如圖6-14所示。可以看出,兩路信號(hào)總有90°的相位差,而且不同方向時(shí)相位差有正負(fù)區(qū)別。這個(gè)信號(hào)是集電極開(kāi)路輸出型,使用時(shí)需要接上拉電阻。如果選用OUT_A的下降沿作為脈沖的檢測(cè)條件,那么只要在脈沖到來(lái)后判斷OUT_B的電平信號(hào)就可以判斷當(dāng)前編碼器的旋轉(zhuǎn)方向。因?yàn)榫幋a器是外部設(shè)備,而且它的引線常常會(huì)比較長(zhǎng),為了避免給單片機(jī)帶來(lái)干擾,常采用光電耦合器件把編碼器和單片機(jī)控制部分進(jìn)行電磁隔離(見(jiàn)下面接口部分)。

3.編碼器與51單片機(jī)的接口編碼器與51單片機(jī)的接口電路如圖6-15所示。把PULSE_INT連接到相應(yīng)的中斷口,比如連接到,在中斷服務(wù)中需要判斷方向。把PULSE_DIR連接到P1.0,則可依據(jù)P1.0的電平狀態(tài)判斷編碼器的旋轉(zhuǎn)方向。圖6-14編碼器輸出信號(hào)與方向的關(guān)系圖6-15編碼器的接口電路

4.測(cè)量位移的例程按照?qǐng)D6-15所示的電路連接,設(shè)計(jì)一個(gè)測(cè)量位移的簡(jiǎn)短代碼:

ORG0000H LJMPSTART ORG0003H LJMPENCODER ORG0100H

COUNTERDATA40H

START:

MOVSP,#60H SETBEX0 ;中斷功能初始化

SETBIT0 SETBEA MOVCOUNTER,#00H ;初始化脈沖計(jì)數(shù)器為0 SJMP$ ;這個(gè)程序只用做編碼器接口測(cè)試

ENCODER: CLREA PUSHPSW PUSHA JBP1.0,ADD1 ;判斷中斷發(fā)生時(shí),如果P1.0是高電平,則是正向計(jì)數(shù)

DECCOUNTER ;否則,是反向計(jì)數(shù)

SJMPRETM

ADD1: INCCOUNTER

RETM: POPA ;恢復(fù)現(xiàn)場(chǎng)

POPPSW SETBEA RETI ;中斷返回

END進(jìn)一步:

如果這個(gè)程序只用于編碼器,在中斷服務(wù)中還用關(guān)中斷嗎?如果去掉SETBIT0,程序會(huì)怎樣?

這里的脈沖計(jì)數(shù)器只使用了單個(gè)字節(jié),嘗試使用兩個(gè)字節(jié)的計(jì)數(shù)器。6.4.3中斷的擴(kuò)展當(dāng)使用的外部中斷較多時(shí),可以采用如圖6-16所示的方法進(jìn)行中斷的擴(kuò)展。當(dāng)~任何一個(gè)有低電平時(shí),經(jīng)8輸入與門(mén)輸出低電平,向發(fā)出中斷請(qǐng)求。當(dāng)中斷響應(yīng)后,立刻查看P1口的各線狀態(tài)。采取逐位查詢的方式,先看P1.0,然后看P1.1,…,最后看P1.7,如果查詢到有位為低,則找到外部中斷擴(kuò)展源。當(dāng)然,在這個(gè)擴(kuò)展電路中,可以采用軟件設(shè)計(jì)的方式優(yōu)先查詢哪位或者哪幾位擴(kuò)展中斷源的狀態(tài)。這就是前面提到的中斷源的優(yōu)先級(jí)設(shè)置。比如,規(guī)定自然優(yōu)先級(jí)的順序是P1.0、P1.2、…、P1.7。在實(shí)際使用時(shí)會(huì)遇到元件選擇的問(wèn)題。這里使用的是8輸入與門(mén),市面上不常見(jiàn),但是8輸入與非門(mén)則比較常見(jiàn)。實(shí)際上,真有如此多的外部中斷源需要擴(kuò)展的時(shí)候,就應(yīng)該考慮使用CPLD或FPGA等器件了。這里使用8輸入與門(mén)的電路,如圖3-21(b)所示,把按鍵S0~S7換成外部擴(kuò)展中斷源~,得到如圖6-17所示的電路。(如果使用8輸入與非門(mén),則可以選擇74LS30,然后加一級(jí)74LS04反相器。)圖6-16中斷的擴(kuò)展原理圖6-17中斷擴(kuò)展電路程序代碼如下:

ORG0000H LJMPSTART ORG0003H ;擴(kuò)展中斷的入口地址

LJMPEX_INT0 ;跳轉(zhuǎn)到比較大的中斷空間中去

ORG0100H

START: MOVSP,#60H ;要給SP足夠的堆??臻g

MOVP1,#0FFH ;?P1輸入口打開(kāi)

SETBEX0 ;使能外部中斷

SETBIT0 ;設(shè)置為下降沿觸發(fā)

SETBEA ;中斷開(kāi)

SJMP$ ;主程序進(jìn)入循環(huán)

EX_INT0: ; CLREA ;關(guān)中斷

PUSHPSW ;程序狀態(tài)字入棧

PUSHA ;累加器入棧

MOVA,P1 ;按照順序依次判斷

CJNEA,#0FEH,EXINT1 ;是否擴(kuò)展中斷0 LJMPFUNC0

EXINT1:

CJNEA,#0FDH,EXINT2 ;是否擴(kuò)展中斷1 LJMPFUNC1

EXINT2: CJNEA,#0FBH,EXINT3 ;是否擴(kuò)展中斷2 LJMPFUNC2

EXINT3: CJNEA,#0F7H,EXINT4 ;是否擴(kuò)展中斷3 LJMPFUNC3

EXINT4: JBACC.4,EXINT5 ;是否擴(kuò)展中斷4 LJMPFUNC4

EXINT5: JBACC.5,EXINT6 ;是否擴(kuò)展中斷5 LJMPFUNC5

EXINT6: JBACC.6,EXINT7 ;是否擴(kuò)展中斷6 LJMPFUNC6

EXINT7:LJMPFUNC7 ;是否擴(kuò)展中斷7

FUNC0: ;具體響應(yīng)部分請(qǐng)自己補(bǔ)充

LJMPRET_M

FUNC1: ;具體響應(yīng)部分請(qǐng)自己補(bǔ)充

LJMPRET_M

FUNC2: ;具體響應(yīng)部分請(qǐng)自己補(bǔ)充

LJMPRET_M

FUNC3: ;具體響應(yīng)部分請(qǐng)自己補(bǔ)充

LJMPRET_M

FUNC4: ;具體響應(yīng)部分請(qǐng)自己補(bǔ)充

LJMPRET_M

FUNC5: ;具體響應(yīng)部分請(qǐng)自己補(bǔ)充

LJMPRET_M

FUNC6: ;具體響應(yīng)部分請(qǐng)自己補(bǔ)充

LJMPRET_M

FUNC7: ;具體響應(yīng)部分請(qǐng)自己補(bǔ)充

RET_M: POPA POPPSW SETBEA RETI END6.5系統(tǒng)化程序設(shè)計(jì)中的概念和方法程序設(shè)計(jì)的概念和方法已經(jīng)分散在前面各章學(xué)習(xí)指令和控制硬件的過(guò)程中了,這里集中總結(jié)一下,讓讀者對(duì)程序設(shè)計(jì)有一個(gè)系統(tǒng)的概念和印象。6.5.1匯編語(yǔ)言計(jì)算機(jī)的語(yǔ)言體系分為機(jī)器語(yǔ)言、匯編語(yǔ)言和高級(jí)語(yǔ)言。機(jī)器語(yǔ)言是能夠被機(jī)器直接識(shí)別和執(zhí)行的語(yǔ)言,是一系列的二進(jìn)制數(shù),就是前面講的指令代碼。對(duì)這些二進(jìn)制代碼進(jìn)行分析、編程、修改等是非常麻煩的事情。為了方便,就采用人們習(xí)慣的符號(hào)來(lái)表示指令的操作碼或操作數(shù),這些符號(hào)就是第1章講的助記符(如MOV、XOR等),這種符號(hào)語(yǔ)言就稱為匯編語(yǔ)言。用匯編語(yǔ)言編制的程序叫匯編程序,也叫源程序。匯編語(yǔ)言實(shí)際上是機(jī)器語(yǔ)言的符號(hào)化,只是采用助記符來(lái)描述。匯編語(yǔ)言只有翻譯成機(jī)器語(yǔ)言才可以被機(jī)器識(shí)別和執(zhí)行,這個(gè)翻譯過(guò)程稱為編譯?,F(xiàn)在,一般的系統(tǒng)開(kāi)發(fā)平臺(tái)提供集成的開(kāi)發(fā)環(huán)境:源程序的編輯和編譯,還有的同時(shí)也提供仿真等功能。μV3系統(tǒng)就可以完成這些任務(wù)。無(wú)論機(jī)器語(yǔ)言還是匯編語(yǔ)言,都是面向機(jī)器的設(shè)計(jì)方案,設(shè)計(jì)目標(biāo)直接針對(duì)硬件,離用戶的層次比較遠(yuǎn),所以把這種語(yǔ)言稱之為低級(jí)語(yǔ)言。其優(yōu)點(diǎn)是硬件控制能力強(qiáng),代碼執(zhí)行效率高,對(duì)指令的執(zhí)行時(shí)間控制能力高,特別適用于實(shí)時(shí)控制;缺點(diǎn)是沒(méi)有通用性,程序?qū)τ布蕾囆詮?qiáng),移植能力太差,編程工作量大。高級(jí)語(yǔ)言是一種面向過(guò)程或者面向?qū)ο蟮恼Z(yǔ)言,如C、VC、VB、PB等都是高級(jí)語(yǔ)言。在高級(jí)語(yǔ)言環(huán)境中,由系統(tǒng)來(lái)配置完成對(duì)不同硬件的支持,用戶使用時(shí)主要精力是掌握該語(yǔ)言的語(yǔ)法規(guī)則和程序的結(jié)構(gòu)設(shè)計(jì)等,這樣就可以提高用戶的編程效率。隨著單片機(jī)的發(fā)展,存儲(chǔ)器的價(jià)格非常便宜,空間已經(jīng)足夠,而且也具有足夠的運(yùn)行速度,所以程序設(shè)計(jì)的首要任務(wù)已不是節(jié)約空間和精簡(jiǎn)代碼,而是提高編程效率,增加程序的可讀性和可維護(hù)性。6.5.2程序結(jié)構(gòu)程序的基本結(jié)構(gòu)有三個(gè):順序、選擇和循環(huán)。任何復(fù)雜的程序都可由這三種基本結(jié)構(gòu)組合完成。6.5.3子程序與中斷服務(wù)程序這里重點(diǎn)強(qiáng)調(diào)一下二者執(zhí)行機(jī)制的不同。子程序是程序在固定的位置主動(dòng)去調(diào)用執(zhí)行的。而中斷服務(wù)程序則是在不確定的位置,由硬件去調(diào)用執(zhí)行的。在子程序中也有可能發(fā)生中斷調(diào)用;而在中斷服務(wù)中也可以安排子程序的調(diào)用。不過(guò),堆棧的深度要足夠,否則堆棧會(huì)溢出而導(dǎo)致程序崩潰。6.5.4查表、數(shù)據(jù)檢索與排序查表、數(shù)據(jù)檢索與排序是程序設(shè)計(jì)中比較重要的幾個(gè)算法。

1.查表專門(mén)的查表指令有兩條:MOVCA,@A+PC和MOVCA,@A+DPTR。二者的區(qū)別已在第2章介紹基址加變址指令時(shí)詳細(xì)介紹過(guò),請(qǐng)參閱。這里用第二條指令舉例說(shuō)明一下。

TABLE為首地址的表中依次存放了0~10的立方值,利用查表法求出R0中數(shù)的立方,結(jié)果放在R2R1中。程序如下:

ORG0000H LJMPSTART ORG0100H

START: MOVSP,#60H MOVR0,#08H ;給R0賦值

LCALLCUBE ;調(diào)用查找立方值

SJMP$ ;主程序循環(huán)

CUBE:

MOVDPTR,#TABLE ;?DPTR指向立方表

MOVA,R0 ;讀入R0里面的值

RLA ;雙字節(jié)存放,所以要乘2 PUSHA ;把A中的數(shù)據(jù)保存

MOVCA,@A+DPTR ;取出立方值的高8位

MOVR2,A ;放入R2中

POPA ;恢復(fù)剛才A中的原始值

INCA ;增加1指向低8位

MOVCA,#A+DPTR ;取出立方值的低8位

MOVR1,A ;放入到R1中

RET ;子程序返回

TABLE: DW0,1,8,27,64,125

;一共存放了11個(gè)字,對(duì)應(yīng)

DW216,343,512,648,1000;?0~10的立方值

END

2.檢索數(shù)據(jù)檢索是查找某個(gè)數(shù)據(jù)塊中是否存在某目標(biāo)值的程序。該目標(biāo)值常稱為檢索關(guān)鍵字。常用的數(shù)據(jù)檢索方法是順序檢索法,即將關(guān)鍵字與數(shù)據(jù)塊中的數(shù)據(jù)按前后順序依次比較是否相等,以此判斷是否找到目標(biāo)值。舉例如下:從30H開(kāi)始連續(xù)存放了10個(gè)數(shù),查看其中是否存在某個(gè)目標(biāo)值,如果存在,通過(guò)R0返回索引值,否則,返回0FFH。程序如下:

ORG0000H LJMPSTART ORG0100H

TARGET EQU 5AH ;定義目標(biāo)值

START: MOVSP,#60H ;定義堆棧

LCALLRETRIEVE ;調(diào)用檢索子程序

SJMP$ ;程序暫停(循環(huán))

RETRIEVE:

MOVR0,#00H ;?R0作為索引值

MOVR1,#30H ;?R1作為查尋的起始地址

LOOP: CJNE@R1,#TARGET,NEXT ;比較是否找到目標(biāo)值

SJMPRETU ;找到就返回索引值

NEXT: INCR0 ;修改索引值和地址

INCR1 CJNER0,#0AH,LOOP ;比較是否滿10個(gè)數(shù)

MOVR0,#0FFH ;沒(méi)有找到就返回0FFH

RETU: RET ;返回

END

3.排序在數(shù)據(jù)結(jié)構(gòu)中,排序有很多種算法,比如冒泡法、選擇法、插入法等。這里僅介紹冒泡法。冒泡法是一種常用的排序方法。在排序的比較過(guò)程中,總是讓較小的數(shù)向上“浮”,而較大的數(shù)向下“沉”,像水中的氣泡一樣向上“冒”,所以稱之為冒泡法(有時(shí)候也稱為沉底法)。下面給出冒泡法排序的一個(gè)實(shí)例。在30H開(kāi)始的存儲(chǔ)單元中,存放了6個(gè)數(shù)據(jù):1、5、2、8、6、9。現(xiàn)在要這些數(shù)據(jù)按照從小到大的順序給出排序,最小的數(shù)據(jù)對(duì)應(yīng)放在30H單元。分析操作過(guò)程如圖6-18所示。首先從頭開(kāi)始由上至下,相鄰的兩個(gè)數(shù)據(jù)依次比較,總是把大數(shù)往下交換。當(dāng)?shù)谝粋€(gè)輪次結(jié)束時(shí),最大數(shù)放在了最下面。然后進(jìn)行第二個(gè)輪次的比較,這個(gè)輪次結(jié)束的時(shí)候,次大數(shù)放到了倒數(shù)第二的位置上。因?yàn)榈谝粋€(gè)輪次找到的是最大數(shù),所以,第二個(gè)輪次再比較的時(shí)候就不用再和這個(gè)最大數(shù)比較了(就是比較也沒(méi)有交換發(fā)生,但是會(huì)浪費(fèi)資源)。后面的依此類推。因?yàn)槊恳粋€(gè)輪次的循環(huán)都可以找出本輪次參與比較的最大數(shù)并放在本輪次的最下面,所以如果有n個(gè)數(shù)的話,只要進(jìn)行n-1個(gè)輪次,就把數(shù)據(jù)全部按照既定的順序(這樣說(shuō)的意思是排序可以由大到小,亦可由小到大)排列完畢。分析幾個(gè)特殊的情況:如果這6個(gè)數(shù)的排序本來(lái)就是1、2、5、6、8、9,則第一個(gè)輪次循環(huán)比較結(jié)束后,發(fā)現(xiàn)沒(méi)有任何數(shù)據(jù)發(fā)生交換,就說(shuō)明全部數(shù)據(jù)已經(jīng)排序完畢,不用再繼續(xù)進(jìn)行下一個(gè)輪次的比較了。如果這些數(shù)據(jù)本來(lái)是2、1、5、6、8、9呢?第一個(gè)輪次發(fā)生了數(shù)據(jù)2和1的交換,進(jìn)行第二個(gè)輪次的比較時(shí)就沒(méi)有數(shù)據(jù)發(fā)生交換了,這時(shí)就可以判斷排序已經(jīng)完成。由此得到是否繼續(xù)循環(huán)的一個(gè)判斷依據(jù):當(dāng)前輪次的比較中如果沒(méi)有發(fā)生任何交換,就可以認(rèn)為排序已經(jīng)完成,排序可以提前結(jié)束。參與排序的數(shù)據(jù)個(gè)數(shù)為n,排序的輪次為i,每一輪次需要的比較次數(shù)為j,這些數(shù)據(jù)之間的關(guān)系在圖6-18中已經(jīng)注明。因?yàn)橐衖輪次和每一輪當(dāng)中的j次的比較,所以設(shè)計(jì)程序的時(shí)候要使用兩層循環(huán)。數(shù)據(jù)存放的首地址用R0表示;R1表示輔助地址,用來(lái)進(jìn)行比較和交換;數(shù)據(jù)個(gè)數(shù)用R2表示;輪次為外層循環(huán),使用R3控制;每一輪次內(nèi)相鄰數(shù)據(jù)的兩兩比較為內(nèi)層循環(huán),使用R4控制;當(dāng)前輪次是否有交換發(fā)生的標(biāo)志放在位20H.0中,用FLAG表示。圖6-18冒泡法排序程序設(shè)計(jì)如下:

ORG0000H LJMPSTART ORG0100H

FLAGBIT20H.0;定義一個(gè)是否發(fā)生交換標(biāo)志位

START: MOVSP,#60H MOVR0,#30H ;數(shù)據(jù)塊的起始地址

MOVR2,#06H ;數(shù)據(jù)塊的長(zhǎng)度

LCALLSORT ;調(diào)用排序子程序

SJMP$

SORT: MOVR3,#01H ;初始化R3,代表第幾個(gè)輪次

LOOP1: MOVA,R2 ;計(jì)算每個(gè)輪次的比較次數(shù)

SUBBA,R3 ;即:

MOVR4,A ;?R4=R2-R3(j=n-i) CLRFLAG ;清除交換標(biāo)志

PUSHR0 ;保護(hù)數(shù)據(jù)塊首地址

LOOP2: MOVA,@R0 ;開(kāi)始進(jìn)行一輪當(dāng)中的兩兩比較

INCR0 SUBBA,@R0 ;比較相鄰的兩個(gè)數(shù)大小

JCNEXT ;如果前面的大,則進(jìn)行交換

MOVA,@R0 ;把兩個(gè)數(shù)據(jù)交換

DECR0 XCHA,@R0

INCR0

XCHA,@R0 SETBFLAG ;這里發(fā)生過(guò)交換,置位交換標(biāo)志

NEXT: DJNZR4,LOOP2 ;判斷內(nèi)循環(huán)是否結(jié)束

INCR3 ;進(jìn)入下一個(gè)輪次

POPR0 ;恢復(fù)數(shù)據(jù)塊首地址

JBFLAG,LOOP1 ;不再發(fā)生交換時(shí),外圍的循環(huán)就結(jié)束

RET ;返回

END冒泡法排序子程序流程如圖6-19所示。圖6-19冒泡法排序流程6.5.5運(yùn)算類程序設(shè)計(jì)

MCS—51的指令系統(tǒng)只提供單字節(jié)和無(wú)符號(hào)數(shù)的算術(shù)運(yùn)算指令。但在實(shí)際的程序設(shè)計(jì)中,經(jīng)常處理帶符號(hào)數(shù)或者多字節(jié)數(shù)的運(yùn)算,這時(shí)就需要自己編寫(xiě)程序。這里給出幾個(gè)典型的運(yùn)算類子程序。

1.多字節(jié)加法多字節(jié)加法的關(guān)鍵是,從低字節(jié)相加,然后到高字節(jié)相加,逐字節(jié)順序操作,并且高字節(jié)相加時(shí)要考慮低字節(jié)的進(jìn)位(使用ADDC指令)。舉例:兩個(gè)10字節(jié)的無(wú)符號(hào)數(shù)分別存放在BLOCK1和BLOCK2為起始地址的存儲(chǔ)區(qū)中,求兩個(gè)數(shù)的和并把結(jié)果存放在BLOCK1為起始地址的存儲(chǔ)區(qū)中。分析:如果把第1個(gè)數(shù)據(jù)使用ADD指令對(duì)應(yīng)相加,后面的9個(gè)數(shù)據(jù)使用ADDC指令對(duì)應(yīng)相加,這就需要兩種加法指令。實(shí)際上,可以把所有數(shù)據(jù)的加法都使用ADDC指令,但是第一條指令執(zhí)行前應(yīng)當(dāng)清除進(jìn)位標(biāo)志位(即執(zhí)行CLRC)。解析結(jié)構(gòu)如圖6-20所示。程序如下:

ORG0000H LJMPSTART ORG0100H

START: MOVSP,#60H MOVR0,#BLOCK1 ;數(shù)據(jù)塊1首地址

MOVR1,#BLCOK2 ;數(shù)據(jù)塊2首地址

MOVR2,#10 ;數(shù)據(jù)塊長(zhǎng)度,這里作為循環(huán)次數(shù)控制

CLRC ;一定要先清除C

LOOP: MOVA,@R0 ;取數(shù)據(jù)塊1數(shù)據(jù)

ADDCA,@R1 ;加數(shù)據(jù)塊2數(shù)據(jù)

MOV@R0,A ;存結(jié)果到數(shù)據(jù)塊1對(duì)應(yīng)位置

INCR0 ;同時(shí)修改兩個(gè)數(shù)據(jù)塊的數(shù)據(jù)指針

INCR1 DJNZR2,LOOP ;循環(huán)次數(shù)判斷

CLRA ;把最后一個(gè)字節(jié)相加后的C保存

ADDCA,#00H ;采用的方法就是給累加器A加0 MOV@R0,A SJMP$

BLOCK1: DS10 ;這里放數(shù)據(jù)

BLOCK2: DS10 ;這里放數(shù)據(jù)

END思考:如果是要做BCD碼的多字節(jié)加法運(yùn)算呢?(提示:只要在加法指令后緊跟著DAA指令就可以了。)圖6-20多字節(jié)加法

2.單字節(jié)帶符號(hào)整數(shù)的乘法單字節(jié)帶符號(hào)整數(shù)的乘法可按照下面三步進(jìn)行操作:

(1)保存兩個(gè)乘數(shù)的符號(hào),計(jì)算乘積的符號(hào)。乘積符號(hào)與兩個(gè)相乘數(shù)符號(hào)之間的關(guān)系是:乘積符號(hào)位?=?被乘數(shù)符號(hào)位乘積符號(hào)位但51指令系統(tǒng)里面的位操作沒(méi)有異或指令,所以采用另一種形式:這樣就可以計(jì)算出乘積的符號(hào)位。

(2)兩個(gè)數(shù)取絕對(duì)值相乘。

(3)根據(jù)乘積符號(hào)位操作變換其絕對(duì)值乘積的結(jié)果。如果符號(hào)位為負(fù),則轉(zhuǎn)換為補(bǔ)碼。例如:R1、R0中對(duì)應(yīng)存放的是帶符號(hào)的乘數(shù)和被乘數(shù),求二者的乘積,并把結(jié)果存放在R3R2中。程序示例如下:

ORG0000H LJMPSTART ORG0100H

START: MOVSP,#60H MOVR1,#60H ;給R1賦值

MOVR0,#0B2H ;給R0賦值

LCALL PRODUCT ;調(diào)用乘積計(jì)算子程序

SJMP$

PRODUCT: MOVA,R1 ;取被乘數(shù)的符號(hào)位到00H位

RLCA MOV00H,C

MOVA,R0 ;取乘數(shù)的符號(hào)位到01H位

RLCA MOV01H,C ;開(kāi)始執(zhí)行求異或的運(yùn)算

ANLC,/00H MOV02H,C MOVC,00H ANLC,/01H ORLC,02H MOV02H,C ;求到的乘積的符號(hào)位保存到02H MOVA,R0 ;取乘數(shù),如果為負(fù)就求補(bǔ)碼

JNBACC.7,NEXT1

CPLA ;方法就是取反加1

INCA

NEXT1: MOVB,A ;把乘數(shù)保存到B MOVA,R1 ;取被乘數(shù),如果為負(fù)就求補(bǔ)碼

JNBACC.7,NEXT2 CPLA ;方法還是取反加1 INCA

NEXT2: MULAB ;取乘積,這是絕對(duì)值乘積

JNB02H,NEXT3 ;把結(jié)果進(jìn)行轉(zhuǎn)換

CPLA ;如果為負(fù),先把低8位取補(bǔ)碼

ADDA,#01H ;想想為什么使用ADD而不是INC

NEXT3: MO

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論