版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
第4章單片機匯編語言程序設(shè)計4.1匯編語言程序的設(shè)計基礎(chǔ)4.2匯編語言程序的基本結(jié)構(gòu)形式4.3常用程序設(shè)計舉例思考與練習(xí)
4.1匯編語言程序的設(shè)計基礎(chǔ)
程序?qū)嶋H上是一系列計算機指令的有序集合。程序設(shè)計是單片機應(yīng)用系統(tǒng)設(shè)計的重要組成部分,單片機的全部動作都是在程序的控制下進行的。隨著芯片技術(shù)的發(fā)展,很多標(biāo)準(zhǔn)的或功能型的硬件電路都集成到了芯片中。所以,程序設(shè)計在單片機應(yīng)用系統(tǒng)開發(fā)中占的比重越來越大,這一點在有駐留系統(tǒng)程序的高級嵌入式系統(tǒng)中更加明顯。
4.1.1匯編語言的語句格式
匯編語言的語句有兩種基本類型:指令語句和偽指令語句。
1.指令語句
指令語句是引發(fā)單片機操作的命令。每一條指令語句在匯編時都產(chǎn)生一個指令代碼
(也稱機器代碼),執(zhí)行該指令代碼對應(yīng)著單片機的一種操作。
2.偽指令語句
偽指令語句是控制匯編(翻譯)過程的一些控制命令。在匯編時沒有機器代碼與偽指令語句對應(yīng)。
4.1.2偽指令
匯編時為了便于匯編器(某些情況下,也可以稱為編譯器)的操作,匯編程序提供了一些本身的操作命令,比如匯編器匯編時需要知道匯編語言源程序中哪些是數(shù)據(jù)、數(shù)據(jù)的狀態(tài)、程序的起始和終止等。這些匯編器本身的操作指令可以出現(xiàn)在匯編語言源程序中,但它不控制單片機操作,而是控制匯編器的指令。這些指令稱為偽指令。
偽指令是程序員發(fā)給匯編器的命令,也稱為匯編命令或匯編程序控制指令。
MCS51匯編語言程序中常用的偽指令有以下幾個。
(1)ORG(ORiGin)匯編起始地址指令:其中,“<地址>”是4位十六進制數(shù),這個十六進制數(shù)前不用加“#”,這點與匯編指令中的立即數(shù)前加“#”不同,需要注意。
ORG指令的功能是通知匯編器在把程序“翻譯”成機器碼的過程中,將ORG后面這段程序的起始地址設(shè)定在ORG規(guī)定的地址上。MCS51系列單片機執(zhí)行的機器碼是放在程
序存儲器中的,執(zhí)行是從首地址開始的。
(2)END(ENDofassembly)匯編終止指令:
END指令的功能是通知匯編器在把程序“翻譯”成機器碼的過程中,遇到END就停止“翻譯”。這條語句是給匯編器的指令,而不是給單片機的指令,不表示程序運行到這里就結(jié)束。
END指令是單指令,一般沒有標(biāo)號和表達式。
(3)EQU(EQUate)賦值指令:
EQU指令用于將一個數(shù)值或寄存器名賦給一個指定符號名。經(jīng)過EQU指令賦值的符號可在程序的其他地方使用,以代替其賦值。
(4)DB(DefineByte)定義數(shù)據(jù)字節(jié)指令:
DB指令的功能是給定表達式的值以字節(jié)形式初始化代碼空間。通常是在程序存儲器的某個位置預(yù)置一個字節(jié)數(shù)(
8位二進制數(shù)),可以和ORG配合使用;“<8位二進制數(shù)表>”前不加“#”,一般用2位十六進制數(shù)表示。
(5)DW(DefineWord)定義數(shù)據(jù)字指令:
DW指令的功能是給定表達式的值以字形式(雙字節(jié))初始化代碼空間。通常是在程序存儲器的某個位置預(yù)置兩個字節(jié)數(shù)(16位二進制數(shù)),可以和ORG配合使用;“<16位二進制數(shù)表>”前不加“#”,一般用4位十六進制數(shù)表示。DW的使用方法和DB類似。
(6)DATA數(shù)據(jù)地址賦值指令:
DATA指令用于將一個內(nèi)部RAM的地址賦給指定的符號名。數(shù)值表達式的值應(yīng)在00H~FFH(0~255)之間。
DATA偽指令的使用與EQU相似,不同之處是:
·EQU定義的標(biāo)識符必須先定義后使用,DATA定義的符號名可以先使用后定義;
·EQU可以把匯編符號賦予標(biāo)識符,而DATA則不可以。
(7)BIT位定義指令:
BIT指令用于將一個位地址賦給指定的符號名。經(jīng)BIT指令定義過的位符號名不能更改。
(8)DS(DefineStonage)定義存儲區(qū)指令:
DS指令的功能是以字節(jié)為單位在內(nèi)部和外部存儲器保留存儲空間,標(biāo)號值將是保留區(qū)的第一個字節(jié)地址。
4.1.3匯編語言程序的結(jié)構(gòu)
完成控制任務(wù)的匯編語言源程序基本上由主程序、子程序、中斷服務(wù)程序等組成。單片機程序存儲器的某些單元被保留作為特定的程序入口地址,0000H是單片機的啟動地址。由于系統(tǒng)復(fù)位后的PC(程序計數(shù)器)的內(nèi)容是0000H,所以系統(tǒng)從0000H開始取指令,執(zhí)行程序。如果程序需要用到中斷功能,則程序必須在0000H開始的第一條指令放入一個無條件轉(zhuǎn)移指令,將主程序引到別處。程序段的起始定位可由偽指令ORG來規(guī)定,主程序的開始地址最好設(shè)在0030H以后。
0003H、000BH、0013H、001BH、0023H分別是五個中斷服務(wù)程序的入口地址。當(dāng)中斷產(chǎn)生時,PC會自動指向這里,即程序可以從這五個地址的某一個開始運行。由于每一入口的地址空間較小,一般只有幾個字節(jié),通常在入口地址存放一條無條件轉(zhuǎn)移指令,將中斷服務(wù)程序引到別處。
單片機標(biāo)準(zhǔn)匯編程序結(jié)構(gòu)如圖4-1所示。圖4-1標(biāo)準(zhǔn)匯編程序結(jié)構(gòu)
注意事項:
①必須有主程序,程序入口地址是0000H。如果有中斷服務(wù)程序,主程序必須是一個跳轉(zhuǎn)指令,將主程序引出中斷向量區(qū),一般可以從0030H開始。
②必須用偽指令來規(guī)定程序的開始地址。除了主程序,其他一些程序段也可以用偽指令來規(guī)定開始地址,可能會形成一些不連續(xù)的代碼區(qū),尤其要注意后面的代碼區(qū)不能覆蓋前面的代碼區(qū)。
③用戶可以根據(jù)功能要求設(shè)計子程序。
④如果使用中斷、定時器、串口等功能,則單片機相關(guān)寄存器必須要初始化。
⑤主程序必須是閉環(huán)結(jié)構(gòu),即是一個閉環(huán)循環(huán),采用LOOP:…LJMPLOOP(類似C語言例程中的while(1){…})表示單片機的執(zhí)行代碼有一部分是循環(huán)執(zhí)行。實際應(yīng)用中,單片機程序先進行一次初始化操作,然后使用循環(huán)執(zhí)行其執(zhí)行代碼部分。后面的例程由于部分主程序沒有實際功能,本書的例題中一般用一條“LJMP$”來代替循環(huán)執(zhí)行代碼。
⑥注釋部分可以用“;注釋內(nèi)容”或“//注釋內(nèi)容”來分割。
4.1.4匯編語言程序的編輯與匯編
匯編語言源程序的編寫要在一個編輯工具上進行,例如,“寫字板”、“Keil集成開發(fā)環(huán)境”(見第9章)等。編寫好的程序,單片機是不“認識”的,單片機能夠認識的就是由“0”和“1”組成的機器碼。匯編指令編寫的匯編語言源程序,需轉(zhuǎn)換成二進制代碼表示的機器語言程序,單片機才能識別和執(zhí)行,通常把這一轉(zhuǎn)換(翻譯)工作稱為“匯編”。
完成“翻譯”工作的專用程序稱為匯編程序軟件(即匯編器),經(jīng)匯編程序“匯編”得到的以0、1代碼形式表示的機器語言程序稱為目標(biāo)程序,這一過程通常是在微機上進行的。
匯編程序從編寫到生成可執(zhí)行機器碼的過程如圖4-2所示。其中,HEX文件(十六進制文件)是由Intel公司定義的一種格式,包括地址、數(shù)據(jù)和校驗碼,用ASCII碼存儲,可以顯示和打印,通常用于仿真器的集成調(diào)試環(huán)境界面顯示(詳見第9章)。還有一種是BIN(二進制)格式的文件,它完全是由編譯器生成的二進制文件,是程序的機器碼。兩種格式都支持寫入單片機或仿真器調(diào)試的目標(biāo)程序。圖4-2匯編程序從編寫到生成可執(zhí)行機器碼的過程
4.1.5匯編語言程序的設(shè)計方法
用匯編語言進行程序設(shè)計的過程和用高級語言進行程序設(shè)計相類似。在進行程序設(shè)計時,要按照實際問題的要求和單片機的特點,決定所采用的設(shè)計方法、邏輯關(guān)系、計算公
式和步驟,也就是通常所說的算法。合適的算法常??梢云鸬绞掳牍Ρ兜男Ч?然后根據(jù)單片機的指令系統(tǒng)來編制程序。
1.任務(wù)析(硬件、軟件系統(tǒng)分析)
根據(jù)單片機系統(tǒng)需要完成的控制任務(wù),在確定好的單片機的硬件體系、外圍電路條件下,結(jié)合軟件的功能分配,明確軟件應(yīng)該完成的任務(wù)。
2.確定算法和工作步驟
對一些復(fù)雜的任務(wù),需要提煉數(shù)學(xué)算法,提高編程質(zhì)量,當(dāng)然這些還要和硬件完全配合。也可以說,不同的硬件也許有不同的算法。但對于一些簡單的功能(多數(shù)情況),則不需要復(fù)雜算法,只要把邏輯關(guān)系弄明白即可。編程前,還需考慮整個程序的功能模塊劃分。
3.制定程序流程圖
流程圖也稱為程序框圖,就是用各種符號、圖形、箭頭把程序的流向及過程用圖形表示出來,使程序清晰、結(jié)構(gòu)合理、便于調(diào)試。繪制流程圖是編寫單片機程序前最重要的工
作,通常程序就是根據(jù)流程圖的指向采用適當(dāng)?shù)闹噶顏砭帉懙?。流程圖一般可以用繪圖工具繪制,常用工具有Visio、AutoCAD等,流程圖也可以手工繪制,但不便于保存和修改。
圖4-3是流程圖的常用格式。圖4-3程序流程圖的常用格式
4.分配內(nèi)存,確定程序與數(shù)據(jù)區(qū)存放地址
分配內(nèi)存工作要根據(jù)程序區(qū)、數(shù)據(jù)區(qū)、堆棧區(qū)等預(yù)計所占空間大小,對片內(nèi)外存儲區(qū)進行合理分配并確定每個區(qū)域的首地址,便于編程使用。
5.編寫源程序
根據(jù)任務(wù)要求和程序流程圖編寫程序代碼。盡可能按照節(jié)省數(shù)據(jù)存放單元、縮短程序長度和減少運算時間三個原則來編制程序。
6.調(diào)試、修改,最終確定程序
通過仿真器或用直接方法進行調(diào)試,即發(fā)現(xiàn)錯誤和修改錯誤的過程。程序錯誤分為兩類:一類是語法錯誤,比較容易發(fā)現(xiàn),一般編譯時就可以發(fā)現(xiàn);另一類是邏輯錯誤,如指令使用錯誤、指令缺失、算法錯誤、順序安排錯誤等,很難發(fā)現(xiàn),需要在調(diào)試過程中根據(jù)中間結(jié)果或其他現(xiàn)象來判斷,有時甚至需要利用仿真器的單步執(zhí)行方法去調(diào)試(詳見9.2.5節(jié))。
4.2匯編語言程序的基本結(jié)構(gòu)形式
匯編語言程序設(shè)計一般采用模塊化編程,基本程序結(jié)構(gòu)有三種:順序結(jié)構(gòu)、分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)。這三種結(jié)構(gòu)組合起來,可以解決任何復(fù)雜問題。
4.2.1順序程序
順序結(jié)構(gòu)是最簡單、最基本的程序結(jié)構(gòu),其特點是按指令的排列順序一條一條地執(zhí)行,直到全部指令執(zhí)行完畢為止。不管多么復(fù)雜的程序,總是由若干順序程序段所組成的,如果某一個需要解決的問題可以分解成若干個簡單的操作步驟,并且可以由這些操作按一定的順序構(gòu)成一種解決問題的算法,則可用簡單的順序結(jié)構(gòu)來進行程序設(shè)計。
【例4-1】三字節(jié)無符號數(shù)相加,其中被加數(shù)在內(nèi)部RAM的50H、51H和52H單元中(低位在后),加數(shù)在內(nèi)部RAM的53H、54H和55H單元中(低位在后);要求把相加之和存放在50H、51H和52H單元中(低位在后),進位存放在位尋址區(qū)的00H位中。
分析1:單片機累加器A是8位的,本例是3字節(jié)24位的加法,這就需要分成三次從低到高使用加法指令進行加法運算。需要注意的是:最低8位相加時,無需考慮進位,可以采用ADD指令,其他部分因為需要考慮進位位,所以采用ADDC指令。
這里采用被加數(shù)放到累加器A中,再直接和內(nèi)存單元中的加數(shù)之間求和,比較直接,但程序?qū)淼臄U展性不好。
分析2:可以考慮采用寄存器間接尋址來獲取操作數(shù),這樣程序?qū)肀阌谵D(zhuǎn)化成循環(huán)方式(見例4-7),需要統(tǒng)一使用ADDC指令,因此在進行最低8位相加之前,先清除進位(進位清“0”)。
4.2.2分支程序
在實際程序設(shè)計過程中,會有很多復(fù)雜狀態(tài)和條件,需要根據(jù)這些條件進行不同的選擇,這時就必須對某一變量的狀態(tài)進行判斷,根據(jù)判斷結(jié)果選擇不同的程序流向,這就是分支程序。分支程序有單分支程序、雙分支程序、多分支(散轉(zhuǎn))程序。
在MCS-51單片機指令系統(tǒng)中,有JZ(JNZ)、CJNE、JC(JNC)及JB(JNB)等豐富的控制轉(zhuǎn)移指令,它們是分支結(jié)構(gòu)程序設(shè)計的基礎(chǔ),可以完成各種各樣的條件判斷,控制轉(zhuǎn)移方向。
1.單分支程序
有一個控制轉(zhuǎn)移方向的程序是單分支程序。
【例4-2】兩個無符號數(shù)比較(單分支)。內(nèi)部RAM
的30H單元和40H單元各存放了一個8位無符號數(shù),比較這兩個數(shù)的大小。若(30H)≥(40H),則將地址為20的內(nèi)存單
元置0;否則,將地址為20H的內(nèi)存單元置1。
分析:程序比較很簡單,流程圖如圖4-4所示。圖4-4例4-2的程序流程圖
2.多分支程序
有兩個或兩個以上控制轉(zhuǎn)移方向的程序是多分支程序。
【例4-3】變量X存放在UNIT1單元內(nèi),函數(shù)值Y
存放在UNIT2單元中,試按下式的要求給Y賦值。
分析1:該例涉及正數(shù)、負數(shù)和0的判斷,符號位在最高位ACC.7??梢园凑杖缦滤悸愤M行編程:
將存放在UNIT1單元的X傳送到累加器A,再利用JZ或者JNZ指令判斷該數(shù)是否為0。如果(A)=0,則將0送入Y中(即UNIT2單元);如果(A)≠0,則需要提取符號位進一步判斷A的正負性。根據(jù)“邏輯與”操作的性質(zhì),只要將A與10000000B進行邏輯與操作,即可保留最高位(符號位),屏蔽低7位,然后再根據(jù)A的值進行判斷:執(zhí)行上述邏輯與操作后,(A)≠0,則最高位為1,代表該數(shù)為負數(shù),此時將-1以補碼形式送入Y中,-1的補碼是FFH;否則(A)=0,即最高位為0,代表該數(shù)為正數(shù),此時將+1送入Y中。
圖4-5(a)實際是三分支而歸一的流程圖,至少要用兩個轉(zhuǎn)移指令。
分析2:這個程序也可以按圖4-5(b)所示的流程圖來編寫,其特征是先賦值,再比較判斷,然后修改賦值并結(jié)束。
在參考程序1中,使用偽指令EQU定義UNIT1和NIT2,在參考程序2中使用偽指令DATA定義UNIT1和UNIT2,最后執(zhí)行結(jié)果相同,說明在本例中兩種偽指令都可以使用。圖4-5例4-3的分支流程圖
3.散轉(zhuǎn)程序
散轉(zhuǎn)程序是一種并行分支程序,它可根據(jù)運算結(jié)果或輸入數(shù)據(jù)將程序轉(zhuǎn)入不同的分支。MCS51指令系統(tǒng)中有一條散轉(zhuǎn)指令“JMP@A+DPTR”,用它可以很容易地實現(xiàn)散轉(zhuǎn)功能。該指令把累加器的8位無符號數(shù)與16位數(shù)據(jù)指針的內(nèi)容相加,并把相加的結(jié)果裝入程序計數(shù)器PC,控制程序轉(zhuǎn)向目標(biāo)地址去執(zhí)行。此指令的特點在于:轉(zhuǎn)移的目標(biāo)地址不是在編程或匯編時預(yù)先確定的,而是在程序運行過程中動態(tài)地確定的,目標(biāo)地址是以數(shù)據(jù)指針DPTR的內(nèi)容為起始的256個字節(jié)范圍內(nèi)的指定地址,即由DPTR的內(nèi)容決定分支轉(zhuǎn)移程序的首地址,由累加器A的內(nèi)容來動態(tài)選擇其中的某一個分支轉(zhuǎn)移程序,如圖4-6所示。散轉(zhuǎn)程序適合在鍵盤控制程序中使用。圖4-6散轉(zhuǎn)程序轉(zhuǎn)移
實現(xiàn)程序散轉(zhuǎn)常用指令表法,即在程序存儲器中建立一個轉(zhuǎn)移指令表,將表的首地址送DPTR,將特定單元的內(nèi)容送A,再通過散轉(zhuǎn)指令就可以根據(jù)A值轉(zhuǎn)向轉(zhuǎn)移指令表中的某條LJMP指令,然后再執(zhí)行“LJMPPRGi”,把程序轉(zhuǎn)移到指定的分支程序入口PRGi。這種方法實際上是通過2次轉(zhuǎn)移(1次執(zhí)行散轉(zhuǎn)指令,1次執(zhí)行無條件轉(zhuǎn)移指令)實現(xiàn)的
【例4-4】已知累加器A中存放著控制程序轉(zhuǎn)向的編號0~n(n<10),ROM中存有起始地址為TABLE的三字節(jié)長轉(zhuǎn)移指令表,試編程使單片機能按照累加器A中的編號轉(zhuǎn)去執(zhí)行相應(yīng)的命令程序,即當(dāng)(A)=0時,執(zhí)行PR0分支程序;當(dāng)(A)=1時,執(zhí)行PR1分支程序;當(dāng)(A)=2時,執(zhí)行PR2分支程序;當(dāng)(A)=n時,執(zhí)行PRn分支程序。
分析:考慮用散轉(zhuǎn)指令“JMP@A+DPTR”來實現(xiàn),定義散轉(zhuǎn)表首地址是TAB,需注意“LJMP<標(biāo)號>”是三個字節(jié),(A)=0對應(yīng)分支程序標(biāo)號PR0,地址是TAB+0;(A)=1對應(yīng)分支程序標(biāo)號PR1,地址是TAB+3;(A)=n對應(yīng)分支程序標(biāo)號PRn,地址是TAB+3×n,所以用A求地址偏移量時需將A中的數(shù)值“乘以”3。有多種方法能夠獲取偏移量A×3的功能。程序流程圖如圖4-7所示。圖4-7例4-4的程序流程圖
4.2.3循環(huán)程序
在程序設(shè)計過程中,經(jīng)常會遇到需要重復(fù)執(zhí)行某一段程序的情況,這時使用循環(huán)程序結(jié)構(gòu),可以節(jié)省程序存儲空間,提高程序的質(zhì)量。從本質(zhì)上看,循環(huán)程序結(jié)構(gòu)只是分支程序中的一個特殊形式而已。
循環(huán)程序一般由4部分組成:
(1)設(shè)置循環(huán)初值,即確立循環(huán)開始時的狀態(tài)。
(2)循環(huán)體(工作部分),要求重復(fù)執(zhí)行的部分。
(3)循環(huán)修改,循環(huán)程序必須在一定條件下結(jié)束,否則就要變成死循環(huán)。
(4)循環(huán)控制部分,根據(jù)循環(huán)結(jié)束條件,判斷是否結(jié)束循環(huán)。
循環(huán)控制的一般方法有:
①循環(huán)次數(shù)已知,利用循環(huán)次數(shù)控制。
②循環(huán)次數(shù)未知,利用關(guān)鍵字控制。
以上4個部分可以有兩種組織方式,一種是先循環(huán)后判斷,另一種是先判斷后循環(huán),如圖4-8所示。
循環(huán)程序體中不再包含其他循環(huán)程序,即為單循環(huán)程序。如果在循環(huán)體中還有循環(huán),則為循環(huán)嵌套,或多重循環(huán)。在多重循環(huán)中,只允許外重循環(huán)嵌套內(nèi)重循環(huán),不允許循環(huán)相互交叉,也不允許從循環(huán)程序外部跳到循環(huán)程序內(nèi)部。圖4-8循環(huán)程序流程圖
【例4-5】從BLOCK單元開始存放一組無符號數(shù),一般稱為一個數(shù)據(jù)塊。數(shù)據(jù)塊長度放在LEN單元,編寫一個求和程序,將和存入SUM單元。假設(shè)和不超過8位二進制數(shù)。
分析:在設(shè)置初值時,將數(shù)據(jù)塊長度置入一個工作寄存器,將數(shù)據(jù)塊首地址送入另一個工作寄存器,一般稱它為數(shù)據(jù)塊地址指針。每做一次加法之后,修改地址指針,以便取出下一個數(shù)來相加,并且使計數(shù)器減1。到計數(shù)器減到0時,求和結(jié)束,把和存入SUM即可。程序流程圖如圖4-9所示。
假設(shè)數(shù)據(jù)塊長度存在內(nèi)存單元20H中,數(shù)據(jù)塊起始地址為22H,結(jié)果存入內(nèi)存單元21H中。圖4-9例4-5的程序流程圖
【例4-6】將內(nèi)部RAM中起始地址為data的數(shù)據(jù)串送到外部RAM中起始地址為buffer的存儲區(qū)域中,直到發(fā)現(xiàn)“$”字符,傳送停止。
分析:這是一個不定循環(huán)次數(shù)的數(shù)據(jù)轉(zhuǎn)移程序。循環(huán)次數(shù)事先不知道,需要先判斷,后執(zhí)行。以特殊字符“$”作為結(jié)束,編程時,在循環(huán)體內(nèi)部開始就進行特殊字符判斷,遇到后立即轉(zhuǎn)出循環(huán);否則,完成操作后,進行無條件轉(zhuǎn)移,繼續(xù)循環(huán)。程序流程圖如圖4-10所示。圖4-10例4-6的程序流程圖
【例4-7】把例4-1三字節(jié)無符號數(shù)相加的程序改寫成循環(huán)方式。
分析:針對例4-1的“參考程序2”,就可以把程序改成循環(huán)方式。因為是三個字節(jié)相加,故循環(huán)次數(shù)為3;因為循環(huán)體內(nèi)統(tǒng)一用ADDC,故要在循環(huán)前把進位位C置成“0”。用這種方法還可以實現(xiàn)更多位的加法或減法。
4.2.4子程序
在程序設(shè)計中,經(jīng)常會遇到通用問題,同一個程序的不同地方要求執(zhí)行同樣的操作或運算,例如求各種函數(shù)和加減乘除運算、代碼轉(zhuǎn)換以及延時程序等,通常將這些能完成某種基本操作并具有相同操作的程序段單獨編制成子程序,以供不同程序或同一程序反復(fù)調(diào)用。這樣,一方面,程序結(jié)構(gòu)簡單,程序模塊化、通用化,便于閱讀;另一方面,節(jié)省了程序存儲空間,還利于按照某種功能進行調(diào)試。在程序中需要執(zhí)行這種操作的地方執(zhí)行一條調(diào)用指令,轉(zhuǎn)到子程序中完成規(guī)定操作,并返回原來程序中繼續(xù)執(zhí)行下去,這就是所謂的子程序結(jié)構(gòu)。
調(diào)用子程序時應(yīng)注意以下幾點:
(1)子程序調(diào)用由LCALL指令或ACALL指令產(chǎn)生,子程序中執(zhí)行RET返回。
(2)在子程序中,一般應(yīng)包括現(xiàn)場保護和現(xiàn)場恢復(fù),可通過堆棧實現(xiàn)保護和恢復(fù)現(xiàn)場。
(3)如果需要從主程序傳遞參數(shù)到子程序,可以約定交換數(shù)據(jù)的地址單元、寄存器,或者采用堆棧方法。
(4)一個子程序可以被另一個子程序調(diào)用,稱之為子程序嵌套。
(5)在子程序調(diào)用過程中,若使用堆棧,應(yīng)注意給堆棧指針SP賦棧底初值,設(shè)置合適大小的棧區(qū)空間,也可以默認初始值,這時(SP)=07H。程序中使用堆棧指令時,PUSH和POP一般要配對使用。
【例4-8】設(shè)a、b是個位數(shù),分別存于內(nèi)部RAM
的A1、A2兩個單元中,編程計算平方和c=a2+b2,并將計算結(jié)果存入內(nèi)部RAM的A3單元中。
分析:考慮到a、b是個位數(shù),我們可以設(shè)定一個個位數(shù)平方的表格,利用“MOVCA,@A+DPTR”語句,通過查表的方法來計算a和b的平方。因為c是兩個數(shù)的平方和,所以兩次求平方可以采用子程序。在子程序中用累加器A來傳遞參數(shù)。
【例4-9】將內(nèi)部RAM從30H開始的8個單元的十六進制數(shù)轉(zhuǎn)換成ASCII碼,并存在內(nèi)部RAM從40H開始的單元中,轉(zhuǎn)換結(jié)果的高位存在前,低位存在后。
因為8個單元中,每個字節(jié)有兩個十六進制數(shù),可以編寫單一字節(jié)的轉(zhuǎn)換子程序,然后循環(huán)調(diào)用8次。轉(zhuǎn)換子程序在例410中已編好,待轉(zhuǎn)換數(shù)需傳入A中,直接調(diào)用子程序HEXASC,轉(zhuǎn)換完成的結(jié)果:高位ASCII碼在B中,低位ASCII碼在A中。我們可以根據(jù)約定好的入口和出口參數(shù)直接調(diào)用。
4.3常用程序設(shè)計舉例
子程序給定了入口名稱和入口參數(shù),運算結(jié)果在出口參數(shù)里。因為已規(guī)定了程序入口標(biāo)號,任務(wù)也是子程序結(jié)構(gòu),最后的結(jié)束語句是RET,所以不再用ORG規(guī)定程序的起始地址。在子程序的設(shè)計過程中,需要考慮保護所有用到的SFR、工作寄存器和內(nèi)存單元,除了入口參數(shù)和出口參數(shù)所涉及的以外,有的是隱含在程序里的,比如:指令若影響了進位C,就需要保護程序狀態(tài)字PSW。
4.3.1數(shù)制轉(zhuǎn)換子程序
單片機能識別和處理的是二進制碼,而輸入/輸出設(shè)備(如:LED顯示器、微型打印機等)則常使用ASCII碼或十六進制數(shù)。為此,在單片機應(yīng)用系統(tǒng)中經(jīng)常需要通過程序進行二進制與BCD碼或ASCII碼的相互轉(zhuǎn)換。
【例4-10】編寫將累加器A中存放的十六進制數(shù)轉(zhuǎn)換成兩位ASCII碼的子程序。入口名稱:HEXASC。入口參數(shù):A=二位十六進制數(shù)。出口參數(shù):B=高位ASCII碼,A=
低位ASCII碼。
分析1:此例適用嵌套子程序,先編寫一個低四位轉(zhuǎn)換的子程序HEASC,再由HEXASC子程序調(diào)用。
對于十六進制數(shù)0~9,其ASCII碼是30H~39H;對于十六進制數(shù)A~F,其ASCII碼是41H~46H??梢岳谩癕OVCA,@A+DPTR”指令、查表方法,編寫子程序。這種方法更容易理解。
程中的NOP語句主要用于功能模塊的分割,沒有其他意義。.
分析2:通過判斷十六進制數(shù)是0~9還是A~F來進行轉(zhuǎn)換。判斷方法最好用指令CJNE,然后分別加上30H或37H,編寫子程序。也可以用減法指令SUBB,由于減法指令得到的是差值,原來的數(shù)據(jù)被破壞,所以必須預(yù)先加以保護。
分析3:利用“DAA”指令進行轉(zhuǎn)換。
對于0~9,其BCD碼是#00H~#09H,加上BCD碼#90H,則分別是BCD碼#90H~#99H。執(zhí)行“DAA”指令后,原數(shù)不變,再加BCD碼#40H,則應(yīng)等于#0C0H~#0C9H;再執(zhí)行“DAA”指令后,變?yōu)?30H~#39H,恰好是0~9的ASCII碼。
對于A~F,其BCD碼是#10H~#15H,加上BCD碼#90H,則分別是BCD碼#0A0H~#0A5H,進位位為1。執(zhí)行“DAA”指令后,變?yōu)?00H~#05H,再加BCD碼#40H和進位位,則應(yīng)等于#41H~#46H;再執(zhí)行“DAA”指令后,仍為#41H~#46H,恰好是A~F的ASCII碼。
【例4-11】編寫將單字節(jié)二進制數(shù)轉(zhuǎn)換為BCD碼的子程序。入口名稱:BBCD。入口參數(shù):A=待轉(zhuǎn)換8位二進制數(shù)。出口參數(shù):B=百位BCD碼,A=十位、個位BCD碼。
分析1:由于單字節(jié)二進制數(shù)最大是255,所以最多是三位BCD碼,可以采用除法指令編程,即先除以100,余數(shù)再除以10。
分析2:采用減法方法,先減100,判斷是否有借位。沒有借位時,B+1,循環(huán);有借位時,多減了100,需再加100。其余類似。
4.3.2延時子程序
單片機工作時有時需要一些時間的延時,但不用十分精確。比如:控制一個指示燈的亮滅用于提示,或A/D轉(zhuǎn)換器啟動后的等待時間等。這種情況下,用指令運行時間的累積
來做延時比較便捷。
【例4-12】已知單片機的fosc=12MHz,設(shè)計延時1ms的子程序。入口名稱:DELAY。入口參數(shù):無。出口參數(shù):無。
分析:單片機指令在執(zhí)行時需要一定的時間,這樣我們就可以利用運行若干條指令的方式(一般是循環(huán)執(zhí)行),來獲取一段延時,但這樣的延時準(zhǔn)確性和靈活性稍差。我們可以利用單片機內(nèi)部的定時器/計數(shù)器,來獲取精確的時間,具體方法見第5章的有關(guān)內(nèi)容。
這里采用運行指令延時的方法。晶振頻率為fosc=12MHz時,一個機器周期為12/fosc=1μs,因此延時1ms的子程序的執(zhí)行時間是1000個機器周期(1000μs)。
需要執(zhí)行的時間為(2+1+(1+1+2)×248+2+2)μs=999μs≈1ms,循環(huán)次數(shù)為248。
通常,為了簡單起見,我們只考慮循環(huán)體內(nèi)的執(zhí)行時間:(
1+1+2)×250≈1ms,循環(huán)次數(shù)為250。
4.3.3均值濾波子程序
在應(yīng)用系統(tǒng)中有時需要對數(shù)據(jù)進行采樣(比如:測溫),為了克服偶然因素引起的波動,一般需要采集N個值,求算術(shù)平均,這就是算術(shù)平均值濾波法。
【例4-13】已知采樣值為單字節(jié),連續(xù)采樣n次,編寫對采樣值進行算術(shù)平均值濾波的子程序。入口名稱:FILTER。入口參數(shù):R0=采樣首地址,R7=采樣次數(shù)n(
n只能取1、2、4、8、16)。出口參數(shù):A=平均值。
分析1:先實現(xiàn)n次數(shù)據(jù)求和,和的值可能會大于255,因此需用兩個存儲器保存。然后再將和除以n,由于n的取值是1、2、4、8、16,為2的整數(shù)冪,因此通過右移位代替除法,可簡化算法,提高運行效率。
分析2:當(dāng)n為任意數(shù)時,如果還用先求和再除的方法,編程比較困難,因為匯編指令只提供了單字節(jié)除法。我們可以考慮采用先除以n,再求和的方法。所有商數(shù)直接相加作為平均值,余數(shù)在相加過程中減n,沒有借位,則平均值+1,循環(huán)得到結(jié)果。也可以在余數(shù)相加過程中除以n。
4.3.4數(shù)據(jù)極值查找子程序
【例4-14】編寫外部存儲器中最大數(shù)查找子程序。入口名稱:MAXIM。入口參數(shù):DPTR=數(shù)據(jù)塊首地址,R7=數(shù)據(jù)塊長度。出口參數(shù):A=最大數(shù)。
分析:極值查找操作的主要內(nèi)容是進行數(shù)值大小的比較。假定在比較過程中,以B單元存放比較出來的最大數(shù),與之逐個比較的另一個數(shù)隨時取出放在A中。比較結(jié)束后,把查找到的最大數(shù)放在A中。
采用循環(huán)程序結(jié)構(gòu),必須先設(shè)一個“0”,放到B中,數(shù)據(jù)區(qū)長度計數(shù)器是R7,其他取數(shù)過程在循環(huán)體內(nèi)。程序流程圖如圖4-11所示。圖4-11極值查找程序流程圖
4.3.5算術(shù)運算子程序
MCS-51單片機指令集里只提供了簡單的8位無符號數(shù)二進制加、減、乘、除指令,
在實際的數(shù)據(jù)采集和控制系統(tǒng)中還需要更復(fù)雜的算術(shù)運算。
【例4-15】編寫帶符號雙字節(jié)二進制數(shù)的加減法運算子程序。入口名稱:BSUB為減法程序入口,BADD為加法程序入口。入口參數(shù):R2R3=(被加數(shù)或被減數(shù)),R4R5=(加數(shù)或減數(shù)),其中R2和R4的最高位為兩數(shù)的符號位。出口參數(shù):R6R7=(和或差),R6的最高位是符號位。
分析:有符號數(shù)的加減運算比較復(fù)雜,首先把減法轉(zhuǎn)換成加法,即如果是減法,就把減數(shù)的符號位取反;其次,判斷兩數(shù)的符號位
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 《常見病食療》課件
- 七年級道德與法治上冊第四單元生命的思考第九課珍視生命第2課時增強生命的韌性教案新人教版
- 初中音樂教學(xué)課件走進京劇
- 三年級數(shù)學(xué)下冊專項復(fù)習(xí)統(tǒng)計與可能性第一組統(tǒng)計新人教版
- 三年級科學(xué)上冊第三單元生命之源-水2觀察水教案蘇教版
- 小學(xué)生贊美別人課件
- 2021一建考試《建設(shè)工程項目管理》題庫試卷考前押題考點題庫合集及答案解析五
- 三月份安全教育課件
- 暑假小學(xué)生視頻課件下載
- 開學(xué)安全第一課課件
- 編譯原理考試題及答案匯總
- 【蘇州市軌道交通安全管理現(xiàn)狀、問題及優(yōu)化建議分析4300字(論文)】
- 國家開放大學(xué)2023年7月期末統(tǒng)一試《11132衛(wèi)生管理》試題及答案-開放本科
- 咽喉癌病歷書寫
- 2023年自然資源部所屬事業(yè)單位招聘(208人)筆試參考題庫(共500題)答案詳解版
- 自身免疫性肝炎診斷和治療指南(2021版)解讀
- 淺析小班幼兒角色游戲的年齡特點及游戲指導(dǎo)
- 全州疫苗接種與免疫規(guī)劃培訓(xùn)班講話稿
- 詩化小說示范課
- 有機合成化學(xué)3-基團的保護與基團的反應(yīng)性轉(zhuǎn)換
- 康復(fù)醫(yī)學(xué)治療技術(shù)(士)《基礎(chǔ)知識》測試題(含答案)
評論
0/150
提交評論