【例4.1】拆字程序。將一個(gè)字節(jié)的兩個(gè)BCD碼十進(jìn)制數(shù)拆開并變成相應(yīng)的ASCII碼,并存入兩個(gè)RAM單元中。
設(shè)兩個(gè)BCD碼(一個(gè)字節(jié))已存入在內(nèi)部RAM的30H單元中,變換后的ASCII 碼分別存放在31H和32H單元,且高位BCD碼的ASCII碼的ASCII碼存于31H單元。數(shù)字0~9的ASCII為30H~39H,完成拆字轉(zhuǎn)換只需將一個(gè)字節(jié)的兩個(gè)BCD碼拆開存放在另兩個(gè)單元的低4位,并在其高4位賦以0011即可。程序段清單如下:
MOV R0,#32H ;將32H單元地址送R0
MOV @R0,#00H ;32H單元清0
MOV A,30H ;將30H單元中的BCD送A
XCHD A,@R0 ;將低位BCD碼送32H單元
ORL 32H,#30H ;完成低位BCD碼轉(zhuǎn)換
SWAP A ;將高位BCD碼交換到低位
ORL A,#30H ;完成高位BCD碼轉(zhuǎn)換
MOV 31H,A ;將高位BCD的ASCII碼存入31H
上述程序段完成了將一個(gè)字節(jié)的BCD碼轉(zhuǎn)換成兩個(gè)ASCII碼的功能。共需占用15個(gè)程序存儲(chǔ)器字節(jié)單元,用9個(gè)機(jī)器周期執(zhí)行完畢。
【例4.2】 雙字節(jié)加法程序段
設(shè)被加數(shù)存放在內(nèi)部矛盾RAM的31H、32H單元,低位字節(jié)在前,加數(shù)存入于34H、35H單元(低字節(jié)在前),結(jié)果和存放于31H、32H、33H單元中。其程序段清單如下;
STRT:PUSH A ;將A內(nèi)容進(jìn)棧保護(hù)
MOV R0,#31H ;將地址碼送R0和R1
MOV R1,#34H
MOV 33H,#00H ;將33H單元清0,存放和的最高字節(jié)數(shù)
MOV A,R0 ;兩低字節(jié)數(shù)相加
ADD A,@R1
MOV @R0,A ;低字節(jié)和存于31H單元
INC R0 ;地址數(shù)分別加1
INC R1
MOV A,@R0 ;連用低位進(jìn)位進(jìn)行高字節(jié)數(shù)
ADDC A,@R1 ;相加
MOV @R0,A ;高字節(jié)和存于32H單元
INC R0 ;R0指針指向33H單元
MOV A,#00H ;清A為0
ADDC A,#00H ;求高字節(jié)和的進(jìn)位
MOV @R0,A ;將高字節(jié)進(jìn)位存于33H單元
POP A ;恢復(fù)A原內(nèi)容
【例4.3 】 求雙字節(jié)補(bǔ)碼程序段
設(shè):存于內(nèi)部RAM的addr1和addr1+1單元的雙字節(jié)數(shù)讀出取補(bǔ)后存入addr2和addr2+1單元中,其中高字節(jié)數(shù)存于高地址單元,圖4.7為雙字節(jié)數(shù)求補(bǔ)流程圖

圖4.7雙字節(jié)數(shù)取補(bǔ)流程圖
8位字長(zhǎng)的單片機(jī)對(duì)雙字節(jié)數(shù)取補(bǔ)需分兩次進(jìn)行,首先對(duì)低字節(jié)數(shù)取補(bǔ)后判其結(jié)果是否為0,若為全0,則要對(duì)高字節(jié)數(shù)取補(bǔ),否則取反即可。雙字節(jié)數(shù)取補(bǔ)程序估如下:
START:MOV R0,#addr1 ;原碼低字節(jié)數(shù)地址送R0
MOV R1,#addr2 ;補(bǔ)碼低字節(jié)數(shù)地址送R1
MOV A,@R0 ;原碼低字節(jié)數(shù)送A
CPL A ;對(duì)低字節(jié)數(shù)取補(bǔ)
INC A
MOV @R1,A ;低字節(jié)補(bǔ)碼存入addr2單元
INC R0 ;R0、R1內(nèi)容分別加1
INC R1
JZ ZERO ;判(A)=0?當(dāng)(A)=0,則轉(zhuǎn)ZERO
MOV A,@R0 ;原碼高字節(jié)數(shù)送A
CPL A ;對(duì)A內(nèi)容取反
MOV @R1,A ;高字節(jié)數(shù)補(bǔ)碼存addr2+1
SJMP LOOP1 ;轉(zhuǎn)結(jié)束
ZERO:MOV A,@R0 ;低字節(jié)取補(bǔ)后為0,則對(duì)高字節(jié)數(shù)取補(bǔ)
CPL A
INC A
MOV @R1,A ;將高字節(jié)補(bǔ)碼存addr2+2
LOOP1:END ;結(jié)束
所有條件判跳指令均屬相對(duì)尋址方式,其相對(duì)偏移量是一個(gè)帶符號(hào)的8位二進(jìn)制碼,常以補(bǔ)碼形式出現(xiàn)。其尋址范圍為-128~+127B。編程時(shí)應(yīng)多加注意。
【例4.4 】 由累加器A在動(dòng)態(tài)運(yùn)行中給出的結(jié)果值選擇對(duì)應(yīng)的轉(zhuǎn)移指令,其對(duì)應(yīng)關(guān)系為:
(A)=0,轉(zhuǎn)向分反處理程序0
(A)=1,轉(zhuǎn)向分支處理程序1
(A)=n,轉(zhuǎn)向分支處理程序n
一般轉(zhuǎn)移指令均為有條件轉(zhuǎn)移指令,而MCS-51單片機(jī)有兩條無條件轉(zhuǎn)移指令:AJMP和LJMP。前者為雙字節(jié)指令,后者為三字節(jié)指令,因此,需視選用何種跳轉(zhuǎn)指令而應(yīng)對(duì)A中值作相應(yīng)變換。如選用AJMP指令,則應(yīng)對(duì)A值變換成偶數(shù)值;如選用LJMP指令,則應(yīng)對(duì)A值乘3的變換。每個(gè)分支處理程序均為各自獨(dú)立的等程序段,分散在各自的程序存儲(chǔ)器區(qū)段。要皮,必須有一個(gè)中轉(zhuǎn)站,軒向各自的分支處理程序。這個(gè)無條件轉(zhuǎn)移指令串的首地址由DPTR指示?,F(xiàn)以AJMP為例,其程序段如下:
START:MOV DPTR,#addr16 ;跳轉(zhuǎn)指令串首址送DPTR
CLR C ;清C為0
RLC A ;將A值變換成偶數(shù)
JNC TABEL ;判(C)=0?不為0則轉(zhuǎn)
INC DPH ;(C)=1,則DPH內(nèi)容+1
TABEL:JMP @A+DPTR ;散轉(zhuǎn)
…
ADDR16:AJMP LOOP0 ;無條件轉(zhuǎn)移指令串
AJMP LOOP1
…
AJMP LOOPn
LOOP0:… ;分支程序段0
…
LOOP1:… ;分支程序段1
…
由于上例選用絕對(duì)值轉(zhuǎn)移指令A(yù)JMP是雙字節(jié)指令,因此,要求A中內(nèi)容必須換算成偶數(shù)。換算方式可以乘2,而這里采用左移一位的辦法來實(shí)現(xiàn)。如果n值等于或大于128,則左移一位將產(chǎn)生高位進(jìn)位,將進(jìn)位值加到DPH中去,等于將轉(zhuǎn)移指令串首址延伸256個(gè)存儲(chǔ)單元,所以在程序段中對(duì)C進(jìn)行測(cè)判。這樣,保證分支處理程序段可以在0-255個(gè)中任選。
如果選用長(zhǎng)調(diào)用LJMP,它是怎么樣三字節(jié)指令,在進(jìn)A值換算時(shí)應(yīng)乘3處理,將積的高字節(jié)值加到DPH中去。一般,DPTR+A的最終值應(yīng)不超過64KB范圍。
【例4.5】 采用循環(huán)程序?qū)崿F(xiàn)延時(shí),一般可達(dá)到任意延時(shí)要求,但需犧牲CPU的工作。
MOV 40H,#data ;設(shè)置計(jì)數(shù)初值
AGIN: NOP
NOP
DJNZ 40H,AGIN ;當(dāng)(40H)-1≠0則繼續(xù)循環(huán)
上例每循環(huán)一次共需4個(gè)機(jī)器周期,實(shí)際總延時(shí)由40H單元內(nèi)容和主頻(fosc)的頻率所設(shè)置決定。
【例4.6】 數(shù)據(jù)塊搜索
設(shè)外部RAM從BLOCK單元開始有一個(gè)無符號(hào)數(shù)據(jù)塊,其長(zhǎng)度(即數(shù)據(jù)塊個(gè)數(shù))存于LEN單元,試求出數(shù)據(jù)塊 最大值數(shù)據(jù),并存于MAX單元中。
尋找最大值的方法很多,最基本的方法是比較和交換依次進(jìn)行,即先讀取第一個(gè)數(shù)與第二個(gè)數(shù)相比較,并把前一個(gè)數(shù)作為基準(zhǔn)。比較結(jié)果:若基準(zhǔn)數(shù)在,則不作交換,再取下一個(gè)數(shù)進(jìn)行比較;若基準(zhǔn)數(shù)小,則將大數(shù)取代原基準(zhǔn)數(shù),即作一次交換,然后再以新的基準(zhǔn)數(shù)與下一個(gè)數(shù)作比較,直到全部比較完畢?;鶞?zhǔn)數(shù)始終保持為最大數(shù)值。圖7.6為數(shù)據(jù)塊搜索流程圖。
設(shè)R1中存放基準(zhǔn)數(shù),R3為數(shù)據(jù)長(zhǎng)度,R2中存放每次讀出的新的數(shù)據(jù)塊。
其循環(huán)程序段如下;
START:CLR A ;A清0
CLR R1 ;清R1為0
MOV R3,LEN ;數(shù)據(jù)塊長(zhǎng)度送R3作控制計(jì)數(shù)
LOOP:MOVX A,@DPTR ;讀數(shù)據(jù)塊
INC DPTR 指向下一個(gè)單元
MOV R2 ,A ;將讀出的靈敏據(jù)塊送R2
CLR C ;清C為0
MOV A ,R1 ;基準(zhǔn)值送A
SUBB A,R2 ;基準(zhǔn)數(shù)一讀出數(shù)
JNC NEXT ;(C)=0,即(A)≥(R2),跳轉(zhuǎn)
MOV R1,A
NEXT:DJNZ R3LOOP ;判搜索完否
MOV MAX,R1 ;最大數(shù)據(jù)存入MAX單元
END ;結(jié)束
【例4.7 】 工作單元清0
設(shè)R1中存放被清0單元首地址,R3中存放清0字節(jié)數(shù),則其循環(huán)程序如下:
START;MOV R1,#addr ;清0單元首地址送R1
MOV R3,#data ;清0字節(jié)數(shù)送R3
CLR A ;A清0
LOOP:、MOV @R1,A ;指定單元清0
INC R1工 ;指向下一個(gè)單元
DJNZ R3,LOOP ;(R3)-1≠0,繼續(xù)清0
END ;結(jié)束
【例4.8】 4位BCD碼整數(shù)轉(zhuǎn)換成二進(jìn)制整數(shù)
入口參數(shù):BCD碼字節(jié)地址指針R0,位數(shù)存于R2中。
出口參數(shù):二進(jìn)制數(shù)存于R3R4中。
算法:A=103a3+102a2+10a1+a0
程序流程如7.7所示。
子程序清單如下:
BCDA:PUSH PSW ;現(xiàn)場(chǎng)保護(hù)
PUSH A
PUSH B
MOV PSW,#08H
MOV R3,#00H
MOV R2,#3 ;BCD碼D的位數(shù)
MOV A,@R0 ;a0-R4
MOV R4,A
BCKB:MOV A,R3 ;(R3R4)×10
MOV B,#10 ;R4
MUL AB
MOV R4,A
XCH A,B
MOV B,#10
XCH A,R3
MUL AB
ADD A,R3
XCH A,R4
INC R0 ;(R0)+1-R0
ADD A,@R0 ;( R3R4)- ((R0))-RR3R4
XCH A,R4
ADDC A,#0
MOV R3,A
DJNZ R2,BCDB ;循環(huán)n-1次
POP B ;恢復(fù)現(xiàn)場(chǎng)
PIP A
POP PSW
RET ;返回
上例中的R2內(nèi)容是BCD碼的位數(shù)n,本例中n=4,即兩個(gè)字節(jié)4位BCD碼,在程序中作為循環(huán)控制寄存器的計(jì)數(shù)值為n-1=4-1=3,即本例循環(huán)3次即完成二次字節(jié)的BCD碼轉(zhuǎn)換。
本例采用乘10運(yùn)算,也可采用除2運(yùn)算進(jìn)行轉(zhuǎn)換。
【例4.9】 多字節(jié)十進(jìn)制數(shù)加法子程序
入口參數(shù):將R0指針的內(nèi)部RAM中N個(gè)字節(jié)的BCD碼被加數(shù),R1指針的內(nèi)產(chǎn)RAM中N個(gè)字節(jié)的BCD碼中數(shù)進(jìn)行相加。R2中存放字?jǐn)?shù)N。
出口參數(shù):相加結(jié)果的BCD碼和數(shù)存入R0指針的內(nèi)部RAM(原被加數(shù)單元)中。
圖4.8為多字節(jié)BCD碼加法子程序流程圖。子程序清單如下:

圖4.8多字節(jié)BCD碼加法子程序流程圖
BCDADD:PUSH PSW
PUSH A
MOV PSW,#08H
MOV A,R0
ADD A,R2
MOV R0,A
DEC R0
MOV A,R1
ADD A,R2
MOV R1,A
DEC R1
CLR C
ADDA:MOV A,@R0
ADDC A,@R1
DA A
MOV @R0,A
DEC R1
DEC R0
DJNZ R2,ADDA ;判加完否
JNC ADDB ;若(C)=0則轉(zhuǎn)ADDB
MOV A,#00H ;清A為0
ADDC A,#00H ;若(C)=1,則為最高位進(jìn)位
MOV @R0,A
ADDB:POP A ;現(xiàn)場(chǎng)恢復(fù)
POP PSW
RET ;返回
本例中兩數(shù)均按高位字節(jié)數(shù)存放于低地址單元,而相國(guó)運(yùn)算則從低位字節(jié)數(shù)開始,R0、R1指針在運(yùn)算前均指向最高字節(jié)數(shù)的地址,故需轉(zhuǎn)換成指向最低字節(jié)數(shù)的地址,然后進(jìn)行相加運(yùn)算。
【例4.10】 應(yīng)用系統(tǒng)采用LED七段顯示,可將BCD碼或十六進(jìn)制碼以及某些符號(hào)通過查找LED顯示編碼進(jìn)行顯示輸出。
七段LED顯示器有共陰極和共陽極之分,其顯示編碼是不同的,共陽極是低電平為有效輸入;共陰極則是高電平輸入有效,LED的編碼不是序碼,即表格無規(guī)律可尋,可根據(jù)各自方便排列。例如BCD碼顯示,同是其顯示碼可按0~9的順序排列。假如顯示器是共陽極的,則BCD碼與顯示器編碼的對(duì)應(yīng)關(guān)系為:0的顯示編碼為0100 0000,即40H,1的編碼為0111 1001,即79H;2的編碼為24H,3的編碼為30H,…,對(duì)于這類問題,通過查表來實(shí)現(xiàn)比較方便。具體程序段如下:
MOV DPTR,#LEDA ;表格首址送DPTR
MOV A,@A+DPTR ;變址寄存器A中內(nèi)容為查表主序號(hào), 即要顯示的內(nèi)容,如0,1,2,…,9
MOVC A,@A+DPTR ;讀出要顯示的內(nèi)容
;進(jìn)行LED顯示
LEDA:DB 40H,79H,24H,30H,12H
DB 20H,78H,00H,18H,…
對(duì)于這類問題,一般均選用DPTR作為基址指針的查表指令為宜。這樣,表格串可設(shè)置在64KB的任何地址段,可實(shí)現(xiàn)任意次查表。
