一種實用的單片機多字節除法算法
一種實用的單片機多字節除法算法 在單片機的實際應用中,除法運算是比較常見的一種運算。
以MCS-51單片機為例,雖然它提供了除法指令,但只能進行單字節除以單字節的運算,如果要進行多字節的除法運算,就得自己設計算法。目前,許多資料上都介紹了四字節除以二字節的算法,但它們主要有以下幾點不足:
1. 只能求出商,不能求出余數;
2. 在被除數高二位大于除數時,不能進行運算;
3. 商只有兩個字節。 例如,被除數是0FFFFFFFFH,除數是0004H時,商數應該是3FFFFFFFH,余數是0003H。
但是,用以前的算法是無法進行運算的。 在實際運用中,參與運算的數是任意的,有時需要求出余數,有時商數要求有四個字節,因此,以前的算法在實際應用中受到了很大的限制。 為了滿足實際運用中的需要,我設計了一套新的四字節除以二字節的算法,克服了上述算法中的缺點,可以適合廣泛的實際需要。下面以MCS-51匯編語言為例進行說明。 該算法增加了兩字節的余數單元,并把被除數單元用來存放商數。運算時,首先判斷除數是否為零,若為零時,則設溢出標志為1,然后退出。若除數不為零,則采用移位相減法進行運算。
首先,把進位位和余數單元清零。再將進位位、余數單元和被除數單元按順序首尾相連,逐位進行向左循環移位(如圖示),共移位32次。每移位一次,余數單元都 C (H L)(HH HL LH LL) 進位位 余 數 單 元 被 除 數 單 元 和除數作一次減法運算,若夠減,余數單元內容更新為兩者之差,并且將被除數最末一位置為1;若不夠減,則余數單元內容保持不變,且將被除數最末一位置為0。判斷是否夠減的方法是:在作減法之前,先保存進位位,再看作完減法后的進位位。僅在作減法之前進位位為0,并且作減法之后進位位為1時判為不夠減,其余情況均視為夠減。這樣,等到全部運算結束時,商數為四個字節,存放在被除數單元中;余數為兩個字節,存放在余數單元中。
例如,被除數是0FFFFFFFFH,除數是0004H時,運行新的算法,商數是3FFFFFFFH,存放在被除數單元中,余數是0003H,存放在余數單元中。 這個算法自然、流暢,運算結果商數為四個字節,余數為兩個字節,尤其是在求除以某數的N次方時,只需連續調用N次該算法子程序就可以了,省去了繁瑣的數據轉存語句。該算法還可以依實際需要擴充為位數更高的多字節除數算法,也可以移植到其它的單片機平臺上。
本算法已在AT89C51單片機上調試通過。下面給出算法的程序代碼清單。
divdll data 20h ;定義被除數單元
divdlh data 21h
divdhl data 22h
dlvdhh data 23h
divl data 24h ;定義除數單元
divh data 25h
templ data 26h ;定義余數單元
temph data 27h
divd: push acc
push b
mov a,divdh ;判除數是否為零
orl a,divl
jnz divd0
setb ov ;除數為零,置溢出標志
pop b
pop acc
ret
divd0: mov templ,#00h ;除數不為零,進行運算
mov temph,#00h
mov b,#20h ;置循環次數
divd1:clr c ;進位位、余數單元和
mov a,divdll ;被除數單元全體逐個
rlc a ;向左循環移位
mov divdll,a
mov a,divdlh
rlc a
mov divdlh,a
mov a,divdhl
rlc a
mov divdhl,a
mov a,divdhh
rlc a
mov divdhh,a
mov a,templ
rlc a
mov templ,a
xch a,temph
rlc a
xch a,temph
mov f0,c ;保存進位位
clr c
subb a,divl ;用余數減去除數
mov r7,a
mov a,temph
subb a,divh
anl c,/f0 ;判斷是否夠減
jc divd2 ;不夠減,移下一位
mov templ,r7 ;夠減,刷新余數單元
mov temph,a
inc divdll ;商上1
divd2: djnz b,divd1
clr ov
pop b
pop acc
ret
end
真正實用的任意字節加減乘除子程序
大家都用C估計它的作用已不大了。 這是本人初學單片機時從一種自己熟悉的產品反匯編出來的,本人還據此做了一套用于EMC單片機的子程序(不舍得貼)。
這套程序的作者是在用手工編譯再敲進仿真機的年代做出來的,估計新一輩的單片機工程師沒有幾個會這么認真的去做一段代碼。
這套程序通用性極強,用它做四則混算方便程度跟C有得一比,但代碼比用C的短多了,本程序缺點執行時間長了點,不太適合做較高速的實時運算。
除法子程序的算法原理跟樓主的是一個樣的。
;===================================================
;乘法子程序: ;
;R3放被乘數起始地址,R4放乘數起始地址 ;積放入R7所指向RAM中,R5表示相乘位數, 高位表示R3位數,低位表示R4位數;地址高存放高位;
mov r3,#dbuf03 ;
mov r4,#dbuf06 ;
mov r7,#dbuf08 ;
mov r5,#22h ;
lcall mulstart
MULSTART: MOV A,R5 ;存放乘積地址清零
ANL A,#0F0H ;
SWAP A ;
MOV R6,A ;R6:表示R3位數,
ANL 05H,#0FH ;R5:表示R4位數
ADD A,R5 ; MOV R2,A ;R2:乘積位數,
MOV 00H,R7 ;
CLR A ;
PRODCLR: MOV @R0,A ;
INC R0 ;
DJNZ R2,PRODCLR ;
MULLOOP: MOV 00H,R7 ;
MOV 02H,R6 ;
MOV 01H,R4 ;
MOV A,@R1 ;
JZ MULLOOP4 ;
MULLOOP1: MOV 01H,R3 ;
MOV A,@R1 ;
JZ MULLOOP5 ;
MOV 01H,R4 ;
MOV B,@R1 ;
MUL AB ;
ADD A,@R0 ;
MOV @R0,A ;
MOV A,B ;
INC R0 ;
ADDC A,@R0 ;
MOV @R0,A ;
JNC MULLOOP3 ;
MOV 01H,R0 ;
MULLOOP2:
INC R1 ;
CLR A ;
ADDC A,@R1 ;
MOV @R1,A ;
JC MULLOOP2 ;
MULLOOP3: INC R3 ;
DJNZ R2,MULLOOP1 ;
MOV A,R3 ;
SUBB A,R6 ;
MOV R3,A ;
MULLOOP4: INC R4 ;
INC R7 ;
DJNZ R5,MULLOOP ;
RET ;
MULLOOP5: INC R0 ;
SJMP MULLOOP3 ;
;============================================
;除法子程序: ;R3:存放被除數指針,R4:存放除數指針 ;商放入R3所指向RAM中,余數放入以DBUF10開始的連續RAM中,R5表示相乘位數, 高位表示被除數位數,低位 表示除數位數. ;地址高存放高位 ;
MOV R3,#DBUF08 ;
MOV R4,#DBUF06 ;
MOV R5,#42H ;
LCALL DIVSTART
DIVSTART: MOV A,R5 ; 除法子程序
ANL A,#0F0H ;
MOV B,A ;
SWAP A ;
MOV R6,A ;R6:表示R3位數,
ANL 05H,#0FH ;R5:表示R4位數
DEC A ;
ADD A,R3 ;
MOV R3,A ;
MOV R0,A ;
DIVLOOP1: MOV A,@R0 ;
JNZ DIVLOOP2 ;
DEC R0 ;
DJNZ R6,DIVLOOP1 ;
RET ;
DIVLOOP2: MOV 03H,R0 ;
MOV A,R4 ;
DEC A ;
ADD A,R5 ;
MOV R1,A ;
DIVLOOP3 : MOV A,@R1 ;
JNZ DIVLOOP4 ;
DEC R1 ;
DJNZ R5,DIVLOOP3 ;高位為零屏去
RET ;
DIVLOOP4: MOV 02H,R5 ;
INC R2 ;
MOV R1,#DBUF10 ;
CLR A ; DIVLOOP5:
MOV @R1,A ;
INC R1 ;
DJNZ R2,DIVLOOP5 ;
NOP ;
NOP ;
NOP ;
NOP ;
NOP ;
MOV A,R5 ;
INC A ;
SWAP A ; ;
ORL 05H,A ;
DIVLOOP6: MOV R7,#08H ;
DIVLOOP7: MOV 00H,R3 ;
MOV R1,#DBUF10 ;
MOV A,R5 ;
ANL A,#0FH ;
INC A ;
MOV R2,A ;
CLR C ;
MOV A,@R0 ;
RLC A ;
MOV @R0,A ;
DIVLOOP8: MOV A,@R1 ;
RLC A ;
MOV @R1,A ;
INC R1 ;
DJNZ R2,DIVLOOP8 ;
MOV A,R4 ;
MOV R1,A ;
MOV R0,#DBUF10 ;
MOV 02H,R5 ;
LCALL SUBSTART ;
JNC DIVLOOP9 ;
MOV 01H,R4 ;
MOV R0,#DBUF10 ;
MOV 02H,R5 ;
LCALL ADDSTART ;
SJMP DIVLOOP0 ;
DIVLOOP9: MOV 00H,R3 ;
INC @R0 ;
DIVLOOP0: DJNZ R7,DIVLOOP7 ;
DEC R3 ;
DJNZ R6,DIVLOOP6 ;
NOP ; ;================== ;以下運算為四舍五收
MOV R0,#DBUF10 ;
MOV R1,#DBUF10 ;
MOV 02H,R5 ;
NOP ;
LCALL ADDSTART ;
MOV R0,#DBUF10 ;
MOV 01H,R4 ;
MOV 02H,R5 ;
NOP ;
LCALL SUBSTART ;
JC DIVRETURN ;
MOV A,B ;
MOV R2,A ;
MOV 00H,R3 ;
INC R0 ;
INC R2 ;
MOV R1,#01H ;
NOP ;
LCALL ADDSTART ;
DIVRETURN:
RET ;
;========================================
;加法子程序 ;@R0+@R1 to @R0,R2 表示相加位數, 高位表示@R0位數,低位表示R1位數 ;@r0 @@r1 地址高存放高位 ;
MOV R0,#DBUF06 ;
MOV R1,#DBUF03 ;
MOV R2,#22H ;
call ADDSTART ADDSTART:
CLR C
ADDLOOP: MOV A,@R0 ;
ADDC A,@R1 ;
MOV @R0,A ;
INC R0 ;
INC R1 ;
DEC R2 ;
MOV A,R2 ;
ANL A,#0FH ;
JZ ADLBITZ ;
XCH A,R2 ;
ANL A,#0F0H ;
DEC A ;
ANL A,#0F0H ;
ORL 02H,A ;
SJMP ADDLOOP ;
ADLBITZ: MOV A,R2 ;
SWAP A ;
DEC A ;
JZ ADHBITZ ;
MOV R2,A ;
ADHBITNZ: CLR A ;
ADDC A,@R0 ;
MOV @R0,A ;
INC R0 ;
DJNZ R2,ADHBITNZ ;
ADHBITZ:
RET ;
;======================================= ;
減法子程序: ;@R0-@R1放入@R0中,R2 表示相加位數, 高位表示@R0位數,低位表示@R1位數 ;@r0 ,@r1 地址高存放高位 ;
MOV R0,#DBUF00 ;
MOV R1,#DBUF03 ;
MOV R2,#22H ;
call SUBSTART SUBSTART:
CLR C SUBLOOP :
MOV A,@R0 ;
SUBB A,@R1 ;
MOV @R0,A ;
INC R0 ;
INC R1 ;
DEC R2 ;
MOV A,R2 ;
ANL A,#0FH ;
JZ SUBLOOP1 ;
XCH A,R2 ;
ANL A,#0F0H ;
DEC A ;
ANL A,#0F0H ;
ORL 02H,A ;
SJMP SUBLOOP ;
SUBLOOP1:
MOV A,R2 ;
SWAP A ;
DEC A ;
JZ SUBLOOP3 ;
MOV R2,A ;
SUBLOOP2:
MOV A,@R0 ;
SUBB A,#00H ;
MOV @R0,A ;
INC R0 ;
DJNZ R2,SUBLOOP2 ;
SUBLOOP3 :
RET ;/ end