一种实用的单片机多字节除法算法 
一种实用的单片机多字节除法算法 在单片机的实际应用中,除法运算是比较常见的一种运算。
以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