《單片機原理與實驗教程》課件第4章_第1頁
《單片機原理與實驗教程》課件第4章_第2頁
《單片機原理與實驗教程》課件第4章_第3頁
《單片機原理與實驗教程》課件第4章_第4頁
《單片機原理與實驗教程》課件第4章_第5頁
已閱讀5頁,還剩137頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

第4章MCS-51匯編語言程序設(shè)計

4.1簡單程序設(shè)計

4.2分支程序設(shè)計

4.3循環(huán)程序設(shè)計

4.4散轉(zhuǎn)程序設(shè)計4.5子程序和參數(shù)傳遞方法

4.6查表程序設(shè)計4.7數(shù)制轉(zhuǎn)換習(xí)題與思考題程序設(shè)計是為了解決某一個問題而將指令有序地組合在一起的過程。程序有簡有繁,但復(fù)雜程序往往是由簡單的基本程序所構(gòu)成的。本章將通過一些基本程序,介紹部分常用的程序設(shè)計方法。程序設(shè)計的過程大致可以分為以下幾個步驟:(1)編制要解決問題的程序框圖。(2)確定數(shù)據(jù)結(jié)構(gòu)、算法、工作單元、變量設(shè)定。(3)根據(jù)所用計算機的指令系統(tǒng),按照已編制的程序框圖用匯編語言編制出源程序。(4)將編制的程序在計算機上調(diào)試,直至實現(xiàn)預(yù)定的功能。4.1簡單程序設(shè)計

簡單程序又稱順序程序。計算機是按指令在存儲器中存放的先后次序來順序執(zhí)行程序的。

【例4-1】兩個8位的無符號數(shù)相加的和仍是8位。設(shè)內(nèi)部RAM的40H、41H單元中分別存放8位數(shù)N1、N2,兩數(shù)相加的結(jié)果送42H單元。程序如下:

AD1:MOV

R0,#40H;設(shè)R0為數(shù)據(jù)指針

MOVA,@R0;取N1

INCR0;修改指針

ADDA,@R0;N1+N2

INCR0

MOV@R0,A;存結(jié)果

END

【例4-2】將兩個半字節(jié)數(shù)合并成一個一字節(jié)數(shù)。設(shè)內(nèi)部RAM的40H、41H單元中分別存放著8位二進制數(shù),要求取出兩個單元中的低半字節(jié),并將其合并成一個字節(jié)后存放在42H單元。程序如下:START:MOV

R1,#40H

MOVA,@R1ANLA,#0FH;取第一個半字節(jié)

SWAPA;移至高4位

INCR1XCHA,@R1;取第二個字節(jié)

ANLA,#0FH;取第二個半字節(jié)

ORLA,@R1;拼字

INCR1MOV@R1,A;存放結(jié)果

END以上程序均采用了寄存器尋址方式,可以方便地取數(shù)、存數(shù)。例4-2中用XCHA,@R1指令,既取出了數(shù),又保存了中間結(jié)果。4.2分支程序設(shè)計

在處理實際事務(wù)中,只用簡單程序設(shè)計的方法是不夠的,因為大部分程序總包含有判斷、比較等情況,程序?qū)⒏鶕?jù)判斷、比較的結(jié)果轉(zhuǎn)向不同的分支。下面舉兩個分支程序的例子。

【例4-3】兩個無符號數(shù)比較大小。設(shè)存儲單元ST1和ST2中存放著兩個不帶符號的二進制數(shù),找出其中的大數(shù)存入ST3單元中。流程圖如圖4-1所示。圖4-1兩個無符號數(shù)的比較流程程序如下:

ST1:EQU8040H

ORG8000H

START1:CLRC;進位位清0

MOVDPTR,#ST1;設(shè)數(shù)據(jù)指針

MOVXA,@DPTR;取第一個數(shù)

MOVR2,A;暫存于R2

INCDPTR

MOVXA,@DPTR;取第二個數(shù)

SUBBA,R2;兩數(shù)比較

JNCBIG1

XCHA,R2;第一個數(shù)大BIG0:INCDPTR

MOVX@DPTR,A;存大數(shù)

RETBIG1:MOVXA,@DPTR;第二個數(shù)大

SJMPBIG0

END上面程序中,用減法指令SUBB來比較兩數(shù)的大小。由于這是一條帶借位的減法指令,因此在執(zhí)行該指令前,應(yīng)先把進位位清0。用減法指令通過借位(CY)的狀態(tài)判別兩數(shù)的大小,是兩個無符號數(shù)比較大小時常用的方法。設(shè)有兩數(shù)x,y,執(zhí)行x-y,當(dāng)x≥y時,結(jié)果無借位產(chǎn)生,則CY=0;反之,則CY=1,表示x<y。用減法指令比較大小,會破壞累加器中的內(nèi)容,故做減法前先保存累加器中的內(nèi)容。執(zhí)行JNC指令后,形成了分支。執(zhí)行SJMP指令后,實現(xiàn)了程序的轉(zhuǎn)移。

【例4-4】編制計算符號函數(shù)y=SGN(x)的程序。設(shè)自變量x已存入標(biāo)號為ARE的單元:-128≤x≤127。y存入標(biāo)號為BUF的單元。流程圖見圖4-2。圖4-2計算符號函數(shù)流程源程序如下:

ARE

EQU8050H

BUF

EQU8060H

NEG

EQU8070H

ORG

8000H

START2:MOVDPTR,#ARE

MOVXA,@DPTR

JZSUL;x=0,轉(zhuǎn)SUL

JBACC.7,NEG;判x的符號位

MOVA,#01;x>0,1→A

SUL:MOVDPTR,#BUF

MOVX@DPTR,A

END

NEG:MOVA,#FFH;x<0,-1→A

SJMPSUL這是一個二次判斷的程序,它與例4-3不同。例4-3程序只有一次判斷,所以是單分支程序,本例則是二分支程序。分支程序在實際使用中用處很大,除了用于比較數(shù)的大小之外,常用于控制子程序的轉(zhuǎn)移。在4.4節(jié)中將詳細(xì)介紹分支程序的使用。4.3循環(huán)程序設(shè)計在程序設(shè)計中,只有簡單程序和分支程序是不夠的。因為簡單程序每條指令只執(zhí)行一次,而分支程序則根據(jù)條件的不同,會跳過一些指令,執(zhí)行另一些指令。它們的特點是,每一條指令至多執(zhí)行一次。在處理實際事務(wù)時,有時會遇到多次重復(fù)處理的問題,用循環(huán)程序的方法來解決就比較合適。循環(huán)程序中的某些指令可以反復(fù)執(zhí)行多次。采用循環(huán)程序,可以縮短程序,節(jié)省存儲單元。當(dāng)重復(fù)次數(shù)越多時,循環(huán)程序的優(yōu)越性就越明顯。但是程序的執(zhí)行時間并不節(jié)省。由于要有循環(huán)準(zhǔn)備、結(jié)束判斷等指令,速度要比簡單程序稍慢些。循環(huán)程序一般由五部分組成:(1)初始化部分:為循環(huán)程序做準(zhǔn)備。如設(shè)置循環(huán)次數(shù)計數(shù)器的初值、地址指針置初值、為循環(huán)變量賦初值等。

(2)處理部分:為反復(fù)執(zhí)行的程序段,是循環(huán)程序的實體。(3)修改部分:每執(zhí)行一次循環(huán)體后,對指針作一次修改,使指針指向下一數(shù)據(jù)所在位置,為進入下一輪處理做準(zhǔn)備。(4)控制部分:根據(jù)循環(huán)次數(shù)、計數(shù)器的狀態(tài)或循環(huán)條件等檢查循環(huán)是否能繼續(xù)進行,若循環(huán)次數(shù)到或循環(huán)條件不滿足時,應(yīng)退出循環(huán),否則繼續(xù)循環(huán)。通常(2)、(3)、(4)部分又稱為循環(huán)體。(5)結(jié)束部分:分析及存放執(zhí)行結(jié)果。循環(huán)程序的結(jié)構(gòu)一般有兩種形式:(1)先進入處理部分,再控制循環(huán),即至少執(zhí)行一次循環(huán)體,如圖4-3(a)所示。(2)先控制循環(huán),后進入處理部分,即根據(jù)判斷結(jié)果控制循環(huán)的執(zhí)行與否,有時可以不進入循環(huán)體就退出循環(huán)程序,如圖4-3(b)所示。圖4-3循環(huán)程序的結(jié)構(gòu)形式循環(huán)結(jié)構(gòu)的程序,不論是先處理后判斷,還是先判斷后處理,其關(guān)鍵是控制循環(huán)的次數(shù)。根據(jù)需解決問題的實際情況,對循環(huán)次數(shù)的控制有多種:循環(huán)次數(shù)已知的,用計數(shù)器控制循環(huán);循環(huán)次數(shù)未知的,可以按條件控制循環(huán),也可以用邏輯尺控制循環(huán)。循環(huán)程序又分單循環(huán)程序和多重循環(huán)程序。下面舉例說明循環(huán)程序的使用。

1.單循環(huán)程序

1)循環(huán)次數(shù)已知的循環(huán)程序下面舉幾個循環(huán)次數(shù)已知的循環(huán)程序例子。

【例4-5】工作單元清0。在程序設(shè)計時,有時需要將存儲器中的部分地址作為工作單元,存放程序執(zhí)行的中間值和結(jié)果。工作單元清0工作常常放在程序的初始化部分中。設(shè)有50個工作單元,其首址存放在DPTR中,循環(huán)次數(shù)存放在R2寄存器中,每執(zhí)行一次循環(huán),R2的內(nèi)容減1,直至R2=0時,循環(huán)程序結(jié)束。流程圖見圖4-4圖4-4工作單元清0流程圖

CLEAR:CLR

A[KG8]

MOVR2,#32H;置計數(shù)值

LOOP:MOVX@DPTR,A

INCDPTR;修改地址指針

DJNZR2,LOOP;控制循環(huán)

END本例中循環(huán)次數(shù)是已知的。用R2作循環(huán)次數(shù)計數(shù)器,用DJNZ指令修改計數(shù)器值,控制循環(huán)的結(jié)束與否。

【例4-6】多個單字節(jié)數(shù)據(jù)求和。已知有n個單字節(jié)數(shù)據(jù),依次存放在內(nèi)部RAM的40H單元開始的連續(xù)單元中,要求把計算結(jié)果存入R2、R3中(高位存R2,低位存R3)。流程圖見圖4-5。圖4-5多個單字節(jié)數(shù)據(jù)求和流程圖程序如下:

NUMEQU0AH

ORG8000H

SAD:MOVR0,#40H;設(shè)數(shù)據(jù)指針

MOVR5,#NUN;計數(shù)值0AH→R5

SAD1:MOVR2,#0;和的高8位清0

MOVR3,#0;和的低8位清0

LOOP:MOVA,@R3;取加數(shù)

ADDA,@R0

MOVR3,A;存和的低8位

JNCLOP1

INCR2;有進位,和的高8位+1

LOP1:INCR0;指向下一數(shù)據(jù)地址

DJNZR5,LOOP

END上述程序中,用R0作間址寄存器,每做一次加法,R0加1,數(shù)據(jù)指針指向下一數(shù)據(jù)地址,R5為循環(huán)次數(shù)計數(shù)器,控制循環(huán)的次數(shù)。

2)循環(huán)次數(shù)未知的循環(huán)程序以上介紹的幾個循環(huán)程序例子,它們的循環(huán)次數(shù)是已知的,適合用計數(shù)器置初值的方法。而有些循環(huán)程序事先不知道循環(huán)次數(shù),不能用以上方法。這時需要根據(jù)判斷循環(huán)條件的成立與否,或用建立標(biāo)志的方式控制循環(huán)程序的結(jié)束。

【例4-7】測試字符串長度。設(shè)有一串字符依次存放在內(nèi)部RAM的從50H單元開始的連續(xù)單元中。該字符串以回車符為結(jié)束標(biāo)志。測字符串長度程序,即將該字符串中的每一個字符依次與回車符相比;若比較不相等,則統(tǒng)計字符串長度的計數(shù)器加1;若比較相等,則表示該字符串結(jié)束,計數(shù)器中的值就是字符串的長度。程序如下:

CONT:MOVR2,#0FFH

MOVR0,#4FH;數(shù)據(jù)指針R0置初值

LOOP:INCR0

INCR2

CJNE@R0,#0DH,LOOP

END

待測字符以ASCII碼形式存放在RAM中,回車符的ASCII碼為0DH,程序中用一條CJNZ@R0,#0DH,LOOP指令實現(xiàn)字符比較及控制循環(huán)的任務(wù),當(dāng)循環(huán)結(jié)束時,R2的內(nèi)容為字符串長度。

3)用邏輯尺控制循環(huán)次數(shù)的循環(huán)程序在實際應(yīng)用中,有時并不要求按一定的固有順序執(zhí)行循環(huán)處理,而要求處理部分是不規(guī)則的循環(huán)過程。如調(diào)用處理部分的子程序PRG0、PRG1共8次。調(diào)用順序為:第1、3、4、7次是調(diào)用PRG1;其余是調(diào)用PRG0。程序的設(shè)計方法是:設(shè)總的調(diào)用次數(shù)為循環(huán)次數(shù),并且另設(shè)一個標(biāo)志,用來識別調(diào)用哪個子程序。兩個子程序可以用0和1兩種邏輯狀態(tài)識別,如用0狀態(tài)表示調(diào)用PRG0,用1狀態(tài)表示調(diào)用PRG1。由于總共調(diào)用8次,因此用一個寄存器的8位作為8個標(biāo)志位,按調(diào)用子程序的順序,把0、1存放在寄存器的不同位上。當(dāng)執(zhí)行程序時,由寄存器的第0位或第7位起逐位測試,根據(jù)此位的狀態(tài)決定調(diào)用哪個子程序。因此該寄存器好像一把“尺”,它的內(nèi)容猶如“尺”的“刻度”,作為識別調(diào)用子程序的標(biāo)志,人們稱它為“邏輯尺”。“邏輯尺”的長寬視需要而定,一個字節(jié)不夠用,可以把相鄰的字節(jié)串聯(lián)起來,或者設(shè)定n把“邏輯尺”。

【例4-8】邏輯尺使用。設(shè)R0為原始數(shù)首地址,R1存放結(jié)果首地址,R3為邏輯尺,流程圖如圖4-6所示。圖4-6邏輯尺程序流程圖程序如下:

PRG0EQU

8360H

PRG1EQU

8200H

ORG8000HTEST:MOVR2,#08H;邏輯尺長度

MOVR3,#10110010B;設(shè)定邏輯尺

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

XCHA,R3RLCA;左移,讀尺刻度

XCHA,R3JCLOOP1;轉(zhuǎn)調(diào)用PRG1LCALLPRG0;是0,調(diào)用PRG0SJMPRELT

LOOP1:LCALLPRG1RELT:MOV@R1,A;存結(jié)果

INCR0

INCR1

DJNZR2,LOOP;R2≠0,繼續(xù)循環(huán)END

2.多重循環(huán)程序

如果在一個循環(huán)體中又包含了其他的循環(huán)程序,即循環(huán)中還套著循環(huán),則這種程序稱為多重循環(huán)程序。

【例4-9】

10s延時程序。延時程序與MCS-51執(zhí)行指令的時間有關(guān),如果使用6MHz晶振,則一個機器周期為2μs,計算出執(zhí)行一條指令以及一個循環(huán)所需要的時間,給出相應(yīng)的循環(huán)次數(shù),便能達(dá)到延時的目的。程序如下:

DEL:MOVR5,#100

DEL0:MOVR6,#200

DEL1:MOVR7,#248

DEL2:DJNZR7,DEL2;248*2+4

DJNZR6,DEL1;(248*2+4)*200+4DJNZR5,DEL0;((248*2+4)*200+4)*100+4

RET上例延時程序?qū)嶋H延時為10.000406s。它是一個三重循環(huán)程序,利用程序嵌套的方法對時間實行延遲是程序設(shè)計中常用的方法。使用多重循環(huán)程序時,必須注意以下幾點:(1)循環(huán)嵌套必須層次分明,不允許產(chǎn)生內(nèi)外層循環(huán)交叉。(2)外循環(huán)可一層層向內(nèi)循環(huán)進入,結(jié)束時由里往外一層層退出。(3)內(nèi)循環(huán)體可以直接轉(zhuǎn)入外循環(huán)體,實現(xiàn)一個循環(huán)由多個條件控制的循環(huán)結(jié)構(gòu)方式。

【例4-10】冒泡程序。設(shè)有N個數(shù),它們依次存放于LIST地址開始的存儲區(qū)域中,將N個數(shù)比較大小之后,使它們按由小到大(或由大到?。┑拇涡蚺帕?,存放在原存儲區(qū)域中。編制該程序的方法:依次將相鄰兩個單元的內(nèi)容作比較,即第一個數(shù)和第二個數(shù)比較,第二個數(shù)和第三個數(shù)比較……如果符合從小到大的順序則不改變它們在內(nèi)存中的位置,否則交換它們之間的位置。如此反復(fù)比較,直至數(shù)列排序完成為止。由于在比較過程中將小數(shù)(或大數(shù))向上“冒”,因此這種算法稱為“冒泡法”或稱為排序法。下列表格可以說明冒泡法的比較過程。第一輪經(jīng)過6次兩兩比較后,得到一個最大數(shù)。第二輪經(jīng)過5次兩兩比較后,得到一個次大數(shù)。

……每輪比較后均得到本輪最大數(shù)(或最小數(shù)),該數(shù)就不再參加下一輪的兩兩比較,故進入下一輪時,兩兩比較次數(shù)減1。為了加快數(shù)列排序速度,程序中設(shè)置一個標(biāo)志位,只要在比較過程中兩數(shù)之間沒有發(fā)生過交換,就表示數(shù)列已按大小順序排列了,可以結(jié)束比較。根據(jù)以上分析,可畫出流程圖如圖4-7所示。圖4-7冒泡程序流程圖設(shè)數(shù)列首地址在R0寄存器中,R2為外循環(huán)次數(shù)計數(shù)器,R3為內(nèi)循環(huán)次數(shù)計數(shù)器,R1為交換標(biāo)志。程序如下:

CONTEQU07H

LIST

DB0,13,3,90,27,32,11

ORG8000H

MOVR2,#CNT-1;數(shù)列個數(shù)-1

LOOP1:MOVA,R2;外循環(huán)計數(shù)值

MOVR3,A;內(nèi)循環(huán)計數(shù)值

MOVR1,#01;交換標(biāo)志置1LOOP2:MOVA,@R0;限數(shù)據(jù)

MOV

B,A;暫存B

INC

R0

CLR

C

SUBB

A,@R0;兩數(shù)比較

JC

LESS;Xi<Xi+1,轉(zhuǎn)LESS

MOV

A,B;取大數(shù)

XCH

A,@R0;兩數(shù)交換位置

DEC

R0

MOV@R0,A

INC

R0;恢復(fù)數(shù)據(jù)指針

MOV

R1,#02;置交換標(biāo)志為2LESS:DJNZR3,LOOP2;內(nèi)循環(huán)計數(shù)減1,判一遍是否查完

DJNZR2,LOOP3;外循環(huán)計數(shù)減1,判排序是否結(jié)束STOP:RETLOOP3:R1,LOOP1;交換轉(zhuǎn)移

SJMP

STOP

ORG

50H;(內(nèi)部RAM)

END

3.循環(huán)程序應(yīng)用舉例

1)不帶符號數(shù)的多字節(jié)加法在處理多字節(jié)運算時,應(yīng)注意低字節(jié)向高字節(jié)的進位(或借位)(用進位CY判別,當(dāng)CY=0時,表示無進位或借位,反之則表示有進位或借位)。在進行不帶符號的單字節(jié)二進制數(shù)加減運算時,用進位CY判別數(shù)的溢出與否。

【例4-11】兩個多字節(jié)數(shù)P、Q均以低字節(jié)在前,高字節(jié)在后的次序,分別存放在由R0、R1指出的內(nèi)部RAM中,相加后存入P數(shù)據(jù)區(qū),見圖4-8。圖4-8

RAM數(shù)據(jù)存儲示意程序如下:

N1

EQU0AH

ORG

8000H

START1:CLR

C;清進位

MOV

R2,#N1;取字節(jié)數(shù)

MADD:MOV

A,@R0;取加數(shù)(一個字節(jié))

ADDC

A,@R1;兩數(shù)相加(由低字節(jié)開始)MOV@R0,A

INC

R0

INC

R1

DJNZ

R2,MADD;兩數(shù)加完?JC

ERR;和字節(jié)數(shù)大于n,則溢出錯RET

ERR:…

END上例中若將ADDCA,@R1指令改為SUBBA,@R1指令,則該程序就是多字節(jié)減法程序。無符號數(shù)的減法運算,被減數(shù)必須大于減數(shù)。不帶符號的十進制數(shù)加法程序的設(shè)計思想與上例相同。

MCS-51指令系統(tǒng)中沒有直接的十進制數(shù)加法指令,要做十進制BCD碼加減運算,只要在加、減指令后跟一條DAA指令,即可使運算結(jié)果成為十進制數(shù)的形式。

2)帶符號數(shù)的加減運算帶符號的定點二進制數(shù)加減運算程序和無符號的定點二進制數(shù)加減運算程序基本相同,只是判斷溢出的條件不同。帶符號的兩個定點二進制數(shù)參加運算時,應(yīng)先判斷兩數(shù)符號,然后決定其加減運算。即首先應(yīng)判兩數(shù)符號是否相同。若兩運算數(shù)符號相同,則數(shù)值部分相加。加法結(jié)果有溢出時,轉(zhuǎn)溢出處理;加法結(jié)果無溢出時,最后結(jié)果的符號與被加數(shù)的符號相同。如兩運算數(shù)符號不同,則執(zhí)行減法。如夠減,則結(jié)果符號為被減數(shù)符號;不夠減則應(yīng)將差取補,結(jié)果符號為減數(shù)符號。對減法運算,可以先把減數(shù)符號取反,再進行加法運算。根據(jù)上述算法,可畫出原碼加減運算的流程圖,見圖4-9。圖4-9原碼加減運算流程圖

【例4-12】雙字節(jié)原碼加減法程序。

R2R3±R4R5→R6R7已知:R2R3、R4R5分別存放16位帶符號二進制數(shù);R2、R4的最高位分別是兩數(shù)的符號位,0代表正數(shù),1代表負(fù)數(shù);結(jié)束時CY=1表示溢出,CY=0表示無溢出。

BSUB為原碼減法程序入口;BADD為原碼加法程序入口。程序如下:

F0

EQU

20H

ORG

8000HBSUB:MOV

A,R4

CPL

ACC.7;減數(shù)符號位取反

MOV

R4,ABADD:MOV

A,R2

MOV

C,ACC.7

MOVF0,C;保存被加數(shù)符號位

XRL

A,R4MOV

C,ACC.7;兩數(shù)同號,CY=0;兩數(shù)異號,CY=1MOV

A,R2

CLR

ACC.7;符號位清0

MOV

R2,A;取數(shù)值部分

MOV

A,R4

CLR

ACC.7;符號位清0

MOV

R4,A;取數(shù)值部分

JC

BX2ADD1:MOVA,R3;同號,兩個雙字節(jié)數(shù)相加ADDA,R5;低位相加MOVR7,A;存低位和MOVA,R2ADDCA,R4;高位相加MOVR4,A;存高低和JB

ACC.7,BERR

BX1:

MOV

C,F(xiàn)0;恢復(fù)結(jié)果符號MOV

ACC.7,CMOV

R4,ARETBERR:SETB

CRETBX2:MOVA,R3;異號,兩個雙字節(jié)數(shù)相減

CLRCSUBBA,R5;低位相減

MOVR7,A;存低位結(jié)果MOVA,R2SUBBA,R4;高位相減MOVR6,A;存高位結(jié)果

JNBACC.7,BX1;判結(jié)果符號,為正則轉(zhuǎn)

BX1BMP:MOVA,R7;符號為負(fù),則對差求補

CPLAADDA,#1MOVR7,AMOVA,R6CPLAADDCA,#0MOVR6,ACPLF0;保存在用戶標(biāo)志位F0中的符號取反SJMP

BX1

END本例分為四個部分處理,其中第一部分是符號處理,這是為了使數(shù)值以正整數(shù)形式參加運算;第二部分是加法運算;第三部分是減法運算;第四部分是結(jié)果取補運算。

3)乘法運算在MCS-51指令系統(tǒng)中有專門的單字節(jié)乘法指令MULAB,該指令功能為A*B→BA。下面將用這條乘法指令實現(xiàn)無符號雙字節(jié)數(shù)的乘法運算。兩個單字節(jié)數(shù)相乘,結(jié)果為雙字節(jié),可以用字節(jié)為單位的豎式乘法擴展其為雙字節(jié)數(shù)的乘法。采用乘法和加法結(jié)合實現(xiàn)乘法運算的示意圖見圖4-10,其執(zhí)行速度比移位相加方法要快得多。圖4-10采用乘法和加法結(jié)合實現(xiàn)乘法運算

【例4-13】

R2R3*R6R7→R4R5R6R7。雙字節(jié)被乘數(shù)在R2、R3中,雙字節(jié)乘數(shù)在R6、R7中,R3*R7→R3R7、R2*R7→R2R7;同理,R3*R6→R3R6,R2*R6→R2R6。執(zhí)行四次乘法后,每次乘積經(jīng)累加器,最后R4R5R6R7中。程序如下:

F0

EQU20

ORG8000HDBMU1:MOVA,R3MOVB,R7MULAB;R3*R7XCHA,R7;乘積低位→R7,R7→A準(zhǔn)備乘數(shù)MOVR5,B;乘積高位暫存R5MOV

B,R2MUL

AB;R7*R2ADD

A,R5;乘積低位加上一次的乘積高位暫存R4MOV

R4,ACLR

A;清累加器ADDCA,B;高位加從低位來的進位后暫存R5MOV

R5,AMOV

A,R6MOV

B,R3MUL

AB;R6*R3ADD

A,R4;第三次乘積低位加R5暫存R6XCH

A,R6XCH

A,BADDC

A,R5;第三次乘積高位加R5暫存R5MOV

R5,AMOV

F0,C;保存進位位MOV

A,R2MUL

AB;R2*R6ADD

A,R5;第4次乘積低位加R5暫存R5MOV

R5,ACLR

AMOVACC.0,CMOVC,F(xiàn)0ADDCA,B;第4次乘積高位加低位來的進位后存于R4MOVR4,ARETEND

4)除法運算除法是乘法的逆運算,用移位、相減的方法完成。根據(jù)手算除法的原則,上商前先比較被除數(shù)與除數(shù),如果被除數(shù)大于除數(shù),商上1,然后做減法,否則商上0,說明不夠減,不執(zhí)行減法。在計算機中,判斷夠減不夠減的方法是做一次減法,由余數(shù)的符號決定,如果余數(shù)為正說明夠減,商為1,否則商為0。根據(jù)上述算法思想,畫出除法程序的流程圖,如圖4-11所示。圖4-11除法流程圖

【例4-14】無符號雙字節(jié)數(shù)的除法:

R4R5R6R7÷R2R3→R6R7,余數(shù)→R4R5已知:被除數(shù)存放在R4R5R6R7中,除數(shù)存放在R2R3中,商送R6R7中。由商送R6R7可知,本題中商為16位,若商大于16位則稱為溢出。在進行除法前,先比較R4R5和R3R2的內(nèi)容,如被除數(shù)高字節(jié)(兩個字節(jié))大于等于除數(shù),則溢出,不執(zhí)行除法,F(xiàn)0置1,表示出錯直接返回;否則執(zhí)行除法,這時F0=0。用減法實現(xiàn)被除數(shù)和除數(shù)比較,結(jié)果保存在累加器A和寄存器R1中,如果夠減,商上1,回送減法結(jié)果,否則不回送。商上1用加1的方法實現(xiàn),商上0不加1。程序如下:

F0

EQU20H

ORG8000HBDIV:MOVA,R5;判商是否產(chǎn)生溢出

CLRC

SUBBA,R3

MOVA,R4

SUBBA,R2

JNCDIV1;被除數(shù)高位字節(jié)大于除數(shù),轉(zhuǎn)溢出處理

MOV

B,#16;無溢出則執(zhí)行除法,置循環(huán)次數(shù)DIV2:CLR

C;被除數(shù)向左移一位,低位送0

MOV

A,R7

RLC

A

MOV

R7,A

MOV

A,R6

RLC

A

MOV

R6,A

MOV

A,R5

RLC

A

MOV

R5,AXCH

A,R4RLC

AXCH

A,R4MOV

F0,C;保護移出的最高位CLR

CSUBB

A,R3;被除數(shù)與除數(shù)比較MOV

R1,AMOV

A,R4SUBB

A,R2JB

F0,DV2;高位移出位為1,夠減轉(zhuǎn)DV2JC

DV3

DV2:MOV

R4,A;回送減法結(jié)果MOV

A,R1MOV

R5,AINC

R7;商上1DV3:DJNZ

R1,DIV2;不夠減,循環(huán)次數(shù)-1CLR

F0;正常執(zhí)行無溢出,F(xiàn)0=0RETDIV1:SETB

F0;置溢出標(biāo)志RETEND

【例4-15】帶符號二進制數(shù)的除法。

R4R5R6R7÷R2R3→R6R7,余數(shù)→R4R5被除數(shù)和除數(shù)以原碼表示,符號位在最高位。帶符號的原碼除法,對符號位的處理方法與帶符號的原碼乘法對符號位的處理方法是相同的,即將兩數(shù)符號位作異或運算后的結(jié)果設(shè)為結(jié)果的符號。除法運算時,先確定商的符號,然后把被除數(shù)、除數(shù)作無符號除法運算,最后把符號送商的符號位。程序如下:

F0

EQU20H

ORG8000HDDIV:MOVA,R2;被除數(shù)符號異或除數(shù)符號XRLA,R2

MOVC,ACC.7;商的符號通過進位送(20H)保存

MOVF0,C

MOVA,R4;被除數(shù)轉(zhuǎn)換成無符號數(shù)形式CLRACC.7

MOVR4,A

MOVA,R2;除數(shù)轉(zhuǎn)換成無符號數(shù)形式

CLRACC.7

MOVR2,A

ACALLDDIV;調(diào)用無符號雙字節(jié)除法子程序MOVA,R6

JBACC.7,DDIV1;溢出,轉(zhuǎn)出錯處理MOV

C,F(xiàn)0;回送商的符號

MOV

ACC.7,C

MOV

R6,ADDIV1:SETB

F0;出錯F0=1

RET

END4.4散轉(zhuǎn)程序設(shè)計

散轉(zhuǎn)程序是分支程序的一種,它由輸入條件或運算結(jié)果來確定轉(zhuǎn)入何種處理程序。有多種方法能實現(xiàn)散轉(zhuǎn)程序,但通常用逐次比較法,即把所有情況逐一進行比較,若有符合條件便轉(zhuǎn)向?qū)?yīng)的處理程序。由于每一種情況都有判斷和轉(zhuǎn)移,如對n種情況,需要n次判斷和轉(zhuǎn)移,因此它的缺點是程序比較長。MCS-51指令系統(tǒng)中有一條跳轉(zhuǎn)指令JMP@A+DPTR,用它可以很容易地實現(xiàn)散轉(zhuǎn)功能。該指令把累加器作為轉(zhuǎn)移指令的地址。執(zhí)行該指令后,累加器和16位數(shù)據(jù)指針的內(nèi)容均不受影響。

1.用轉(zhuǎn)移指令表實現(xiàn)散轉(zhuǎn)

在許多場合中,要根據(jù)某一單元的值(0,1,2,…,n)分別轉(zhuǎn)向相應(yīng)處理程序(處理程序0,處理程序1……處理程序n),這時可以用轉(zhuǎn)移指令A(yù)JMP(或LJMP)組成一個轉(zhuǎn)移表。

【例4-16】根據(jù)R6的內(nèi)容(R6=0,轉(zhuǎn)PRGM0;R6=1,轉(zhuǎn)PRGM1……R6=n,轉(zhuǎn)PRGMn),轉(zhuǎn)向各個處理程序。把轉(zhuǎn)移標(biāo)志送累加器A,轉(zhuǎn)移表首地址送DPTR,利用JMP@A+DPTR指令實現(xiàn)轉(zhuǎn)移。程序如下:

PJD:MOV

DPTR,#TAB1

MOV

A,R6

ADD

A,R6;R6*2→A

JNC

PAD

INC

DPH;R6*2>256,16位數(shù)據(jù)指針高8位加1

PAD:JMP@A+DPTR

TAB1:AJMP

PRGM0;轉(zhuǎn)處理程序0的首地址

AJMP

PRGM1;轉(zhuǎn)處理程序1的首地址

AJMP

PRGMn;轉(zhuǎn)處理程序n的首地址本例適用于散轉(zhuǎn)表首地址TAB1和處理程序入口地址PRGM0、PRGM1……PRGMn在同一個2KB范圍存儲區(qū)內(nèi)的情形。如一個2KB范圍的存儲區(qū)內(nèi)放不下所有的處理程序時,則把一些較長的處理程序放在其他存儲區(qū)域,只要在該處理程序的入口地址內(nèi)調(diào)用LJMP指令即可。方法有兩種:(1)例如處理程序PRGM0、PRGM3比較長,要把兩個程序轉(zhuǎn)至其他區(qū)域,則分別把它們的入口地址用符號PPRGM0、PPRGM3表示,以實現(xiàn)程序的轉(zhuǎn)移。

PRGM0:LJMPPPRGM0

PRGM3:LJMPPPRGM3(2)可以直接用LJMP指令組成轉(zhuǎn)移表。由于LJMP是3字節(jié)的指令,因此在組成指令轉(zhuǎn)移表后,當(dāng)執(zhí)行JMP@A+DPTR指令時,可能出現(xiàn)DPTR低8位向高8位進位的情況,所以必須先用加法指令調(diào)整DPTR的值后才能用JMP@A+DPTR指令實現(xiàn)跳轉(zhuǎn)。程序如下:PJ2:MOV

DPTR,#TAB2

CLR

C

MOV

R5,#0

MOV

A,R6

RLC

A;R6*2

JNC

P1

INC

R5;有進位,高8位加1P1:ADD

A,R6;R3*3

JNC

P2

INC

R5;有進位,高8位加1P2:MOV

A,R5

ADD

A,DPH;DPTR高8位調(diào)整MOV

A,R6

JMP@A+DPTR;得散轉(zhuǎn)地址TAB2:LJMP

PRGM0LJMP

PRGM1

LJMP

PRGMn用AJMP組成的散轉(zhuǎn)表為2字節(jié)一項,而用LJMP組成的散轉(zhuǎn)表則為3字節(jié)一項,根據(jù)R6中的內(nèi)容或乘2,或乘3,得每一處理程序的入口地址表指針。

2.用轉(zhuǎn)移地址表實現(xiàn)散轉(zhuǎn)當(dāng)轉(zhuǎn)向范圍比較大時,可直接使用轉(zhuǎn)向地址表方法,即把每個處理程序的入口地址直接置于地址內(nèi)。用查表指令,找到對應(yīng)的轉(zhuǎn)向地址,把它裝入DPTR中。將累加器清0后用JMP@A+DPTR直接轉(zhuǎn)向各個處理程序的入口。

【例4-17】根據(jù)R3的內(nèi)容轉(zhuǎn)向?qū)?yīng)處理程序。處理程序的入口分別為PR0~PRn。程序如下:PJ3:MOV

DPTR,#TAB3

MOV

A,R3

ADD

A,R3;R3*2

JNC

CAD

INC

DPH;有進位,DPTR高位加1CAD:MOV

R2,A;暫存R2

MOVCA,@A+DPTR

XCHA,R2;處理程序入口地址高8位暫存R2

INC

A

MOVC

A,@A+DPTR

MOV

DPL,A;處理程序入口地址低8位暫存DPL

MOV

DPH,R2

CLR

A

JMP@A+DPTR

TAB3:DW

PR0

DW

PR1

DW

PRn本例可實現(xiàn)64KB范圍內(nèi)的轉(zhuǎn)移,但散轉(zhuǎn)數(shù)n應(yīng)小于256。如大于256時,應(yīng)采用雙字節(jié)數(shù)加法運算修改DPTR。

3.用RET指令實現(xiàn)散轉(zhuǎn)以上介紹的兩種方法均采用JMP@A+DPTR指令實現(xiàn)散轉(zhuǎn)功能。這里要介紹的散轉(zhuǎn)方法不是把轉(zhuǎn)向地址裝入DPTR,而是將它壓入堆棧,然后通過RET指令把轉(zhuǎn)向地址退棧到PC中,使棧指針恢復(fù)原值。

【例4-18】根據(jù)R5R6內(nèi)容,轉(zhuǎn)向不同的處理程序。程序如下:PJ4:MOV

DPTR,#TAB4

MOV

A,R6

CLR

C

RLC

A

XCH

A,R5

RLC

A

ADD

A,DPH

MOV

DPH,A;R5R6*2高8位加到DPH

MOV

DPH,A;R5R6*2低8位存A

MOV

A,R5;從表中得到處理程序入口地址高8位

MOVCA,@A+DPTR

XCHA,R5

INC

DPTR

MOVCA,@A+DPTR;從表中得到處理程序入口地址低8位

PUSH

ACC;地址低8位進棧

MOV

A,R5

PUSH

ACC;地址高8位進棧

RET;轉(zhuǎn)向地址退棧裝入PC中TAB4:DW

PR0

DW

PR1

DW

PRn4.5子程序和參數(shù)傳遞方法

在實際程序中,常常會多次進行一些相同的計算和操作,如數(shù)制轉(zhuǎn)換、函數(shù)式計算等等。如果每次都從頭開始編制一段程序,不僅麻煩,而且浪費存儲空間。因而將一些常用的程序段以子程序的形式,事先存放在存儲器的某一個區(qū)域,當(dāng)主程序在運行中需要用子程序時,只要執(zhí)行調(diào)用子程序的指令,使程序轉(zhuǎn)至子程序即可。當(dāng)子程序處理完畢后,返回主程序,繼續(xù)進行以后的操作。調(diào)用子程序有幾個優(yōu)點:(1)避免了對相同程序段的重復(fù)編制。(2)簡化程序的邏輯結(jié)構(gòu),同時也便于子程序調(diào)試。(3)節(jié)省存儲器空間。

MCS-51指令系統(tǒng)中,提供了兩條調(diào)用子程序指令:ACALL及LCALL,并提供了一條返回主程序的指令RET。對于子程序的調(diào)用,一般包含兩個部分:保護現(xiàn)場和恢復(fù)現(xiàn)場。由于主程序每次調(diào)用子程序的工作是事先安排的,因此根據(jù)實際情況,有時可以省去保護現(xiàn)場的工作。調(diào)用子程序時,主程序應(yīng)先把有關(guān)的參數(shù)存放在約定的位置,子程序在執(zhí)行時,可以從約定的位置取得參數(shù);當(dāng)子程序執(zhí)行完后,將得到的結(jié)果存入約定的位置,返回主程序后,主程序可以從這些約定的位置上取到需要的結(jié)果,這就是參數(shù)的傳遞。下面結(jié)合MCS-51單片機的特點,介紹幾種參數(shù)傳遞方法。

1.用累加器或寄存器進行參數(shù)的傳遞

用累加器和寄存器存放輸入?yún)?shù)及結(jié)果參數(shù),可以提高程序的運算速度,而且程序也很簡單。如本章例4-15的帶符號的原碼除法子程序就是采用此方法。它的不足之處是參數(shù)不能傳遞得很多,因為寄存器的數(shù)量有限;主程序在調(diào)用子程序前必須將參數(shù)先送入寄存器;由于子程序參數(shù)的個數(shù)是固定的,因此主程序不能任意設(shè)定參數(shù)的多少。

2.用指針寄存器進行參數(shù)的傳遞

當(dāng)程序中所需處理的數(shù)據(jù)量比較大時,常常用存儲器存放數(shù)據(jù),而不用寄存器。用指針指示數(shù)據(jù)在存儲器中所處的位置,可以大大節(jié)省參數(shù)傳遞中的工作量。使用指針的方法能實現(xiàn)數(shù)據(jù)長度可變的運算。MCS-51指令系統(tǒng)中提供的由R0、R1作間址寄存器的指令很多,當(dāng)參數(shù)存放在內(nèi)部RAM時,用R0、R1作指針使參數(shù)的傳遞十分方便。如例4-6的多個單字節(jié)數(shù)據(jù)求和程序,調(diào)用時R0作為存放參數(shù)的地址指針,R5存放參數(shù)長度,R2R3存放運算結(jié)果,作為子程序被調(diào)用時,其入口地址為SAD。當(dāng)參數(shù)在外部RAM或在程序存儲器時,可用DPTR作指針。對可變長度的數(shù)據(jù)做運算時,數(shù)據(jù)長度可由寄存器指出,也可采用在數(shù)據(jù)后設(shè)置標(biāo)志的方法。

3.用堆棧進行參數(shù)傳遞堆??梢杂糜谥鞒绦蛘{(diào)用子程序時相互之間的參數(shù)傳遞。調(diào)用前,主程序用PUSH指令把參數(shù)壓入堆棧,子程序在執(zhí)行中按堆棧指針間接訪問棧中參數(shù),并且把運算結(jié)果送回堆棧。返回主程序后,主程序用POP指令得到堆棧中的結(jié)果參數(shù)。利用堆棧傳遞參數(shù)的方法比較簡單,而且傳遞參數(shù)量比用寄存器來傳遞參數(shù)多得多,也不必為特定的參數(shù)分配存儲單元。下面舉幾個例子介紹用堆棧進行參數(shù)傳遞的方法。

【例4-19】一位十六進制數(shù)轉(zhuǎn)換成ASCII碼。程序如下:

HEASC:MOVR0,SP;借用R0為堆棧指針

DECR0

DECR0;R0指向被轉(zhuǎn)換參數(shù)地址

XCHA,@R0;保護累加器,取被轉(zhuǎn)換參數(shù)

ANLA,#0FH

ADDA,#2;PC表首地址

MOVCA,@A+PC;查表

XCH

A,@R0;結(jié)果送回堆棧

RETATAB:DB

30H,31H,32H,33H,34H,

35H,36H,37H,38H,39H

DB

41H,42H,43H,44H,45H,46HEND調(diào)用上述子程序后,后一位十六進制數(shù)轉(zhuǎn)換成對應(yīng)的ASCII碼。輸入?yún)?shù)位于棧頂,進入子程序時,堆棧中又壓入了兩個字節(jié)的返回地址,將原來的輸入?yún)?shù)變成新棧頂起的第三個字節(jié)。R0的內(nèi)容經(jīng)兩次減1后,指向原來的輸入?yún)?shù)。利用兩條XCH指令實現(xiàn)了兩個操作:被轉(zhuǎn)換輸入?yún)?shù)的提取及轉(zhuǎn)換后的結(jié)果參數(shù)送回原堆棧中的操作,而A的內(nèi)容沒有破壞。

【例4-20】把內(nèi)部RAM中40H單元1字節(jié)的十六進制數(shù)轉(zhuǎn)換成2位ASCII碼,存放在R1指出的兩個單元中,調(diào)用HEASC子程序。程序如下:

ORG

8000HMAIN:MOV

A,40H;直接尋址,(40H)→A

SWAPA;2位十六進制數(shù)半字節(jié)交換

PUSH

ACC

ACALLHEASC

POP

ACC

MOV@R1,A;高半字節(jié)轉(zhuǎn)換成ASCII碼,存結(jié)果

INC

R1

PUSH40H

ACALLHEASC

POP

ACC

MOV@R1,A;低半字節(jié)轉(zhuǎn)換成ASCII碼,存結(jié)果

END由于HEASC子程序每次只能完成1位十六進制數(shù)對ASCII碼的轉(zhuǎn)換,因此對于1字節(jié)的十六進制數(shù)轉(zhuǎn)換,需要在主程序中兩次調(diào)用HEASC。如果被轉(zhuǎn)換的十六進制數(shù)是多字節(jié)時,則調(diào)用程序?qū)⒄既ズ芏啻鎯臻g。下面仍采用堆棧傳遞參數(shù)法,介紹1字節(jié)的2位十六進制數(shù)轉(zhuǎn)換成ASCII碼的子程序。

【例4-21】被轉(zhuǎn)換數(shù)據(jù)存放在R0指出的堆棧地址中,結(jié)果送原單元及其下一單元。程序如下:

HEAS2:MOVR0,SP;借用R0為堆棧指針

DECR0

DECR0;R0指向被轉(zhuǎn)換參數(shù)地址

PUSHACC;保護累加器

MOVA,@R0;取出參數(shù)

ANLA,#0FH;取右半字節(jié)

ADDA,#14;得

溫馨提示

  • 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)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論