在單片機(jī)的實(shí)際應(yīng)用中,除法運(yùn)算是以比較常見的運(yùn)算。
以MCS-51單片機(jī)為例,雖然提供了除法指令,但只能進(jìn)行單字節(jié)的運(yùn)算。如果要進(jìn)行多字節(jié)的除法運(yùn)算,就得自己設(shè)計(jì)算法。目前,許多資料上都介紹了四字節(jié)除以二字節(jié)的算法,但它們主要有以下幾點(diǎn)不足:
1. 只能求出商,不能求出余數(shù);
2. 在被除數(shù)高二字節(jié)大于除數(shù)時(shí),不能進(jìn)行運(yùn)算;
3. 商只有兩個(gè)字節(jié)。 例如,被除數(shù)是0FFFFFFFFH,除數(shù)是0004H時(shí),商數(shù)應(yīng)該是3FFFFFFFH,余數(shù)是0003H。
但是,用以前的算法是無法進(jìn)行運(yùn)算的。 在實(shí)際運(yùn)用中,參與運(yùn)算的數(shù)是任意的,有時(shí)需要求出余數(shù),有時(shí)商數(shù)要求有四個(gè)字節(jié),因此,以前的算法在實(shí)際應(yīng)用中受到了很大的限制。 為了滿足實(shí)際運(yùn)用中的需要,有一套新的四字節(jié)除以二字節(jié)的算法,克服了上述算法中的缺點(diǎn),可以適合廣泛的實(shí)際需要。下面以MCS-51匯編語(yǔ)言為例進(jìn)行說明。 該算法增加了兩字節(jié)的余數(shù)單元,并把被除數(shù)單元用來存放商數(shù)。運(yùn)算時(shí),首先判斷除數(shù)是否為零,若為零時(shí),則設(shè)溢出標(biāo)志為1,然后退出。若除數(shù)不為零,則采用移位相減法進(jìn)行運(yùn)算。
首先,把進(jìn)位位和余數(shù)單元清零。再將進(jìn)位位、余數(shù)單元和被除數(shù)單元按順序首尾相連,逐位進(jìn)行向左循環(huán)移位,共移位32次。每移位一次,余數(shù)單元都和除數(shù)作一次減法運(yùn)算,若夠減,余數(shù)單元內(nèi)容更新為兩者之差,并且將被除數(shù)最末一位置為1;若不夠減,則余數(shù)單元內(nèi)容保持不變,且將被除數(shù)最末一位置為0。判斷是否夠減的方法是:在作減法之前,先保存進(jìn)位位,再看作完減法后的進(jìn)位位。僅在作減法之前進(jìn)位位為0,并且作減法之后進(jìn)位位為1時(shí)判為不夠減,其余情況均視為夠減。這樣,等到全部運(yùn)算結(jié)束時(shí),商數(shù)為四個(gè)字節(jié),存放在被除數(shù)單元中;余數(shù)為兩個(gè)字節(jié),存放在余數(shù)單元中。
例如,被除數(shù)是0FFFFFFFFH,除數(shù)是0004H時(shí),運(yùn)行新的算法,商數(shù)是3FFFFFFFH,存放在被除數(shù)單元中,余數(shù)是0003H,存放在余數(shù)單元中。 這個(gè)算法自然、流暢,運(yùn)算結(jié)果商數(shù)為四個(gè)字節(jié),余數(shù)為兩個(gè)字節(jié),尤其是在求除以某數(shù)的N次方時(shí),只需連續(xù)調(diào)用N次該算法子程序就可以了,省去了繁瑣的數(shù)據(jù)轉(zhuǎn)存語(yǔ)句。該算法還可以依實(shí)際需要擴(kuò)充為位數(shù)更高的多字節(jié)除數(shù)算法,也可以移植到其它的單片機(jī)平臺(tái)上。
本算法已在AT89C51單片機(jī)上調(diào)試通過。下面給出算法的程序代碼清單。
divdll data 20h ;定義被除數(shù)單元 divdlh data 21h divdhl data 22h dlvdhh data 23h divl data 24h ;定義除數(shù)單元 divh data 25h templ data 26h ;定義余數(shù)單元 temph data 27h divd: push acc push b mov a,divdh ;判除數(shù)是否為零 orl a,divl jnz divd0 setb ov ;除數(shù)為零,置溢出標(biāo)志 pop b pop acc ret divd0: mov templ,#00h ;除數(shù)不為零,進(jìn)行運(yùn)算 mov temph,#00h mov b,#20h ;置循環(huán)次數(shù) divd1:clr c ;進(jìn)位位、余數(shù)單元和 mov a,divdll ;被除數(shù)單元全體逐個(gè) rlc a ;向左循環(huán)移位 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 ;保存進(jìn)位位 clr c subb a,divl ;用余數(shù)減去除數(shù) mov r7,a mov a,temph subb a,divh jc divd2 mov templ,r7 ;夠減,刷新余數(shù)單元 mov temph,a inc divdll ;商上1 divd2: djnz b,divd1 clr ov pop b pop acc ret end 對(duì)于上述算法,其思想是正確的。但在DICE-51單片機(jī)仿真系統(tǒng)具體操作中還存在部分問題。下面我以DICE系列的DICE-51單片機(jī)仿真系統(tǒng)軟件為例,給出四除三字節(jié)的算法的程序代碼清單已在DICE-51單片機(jī)仿真系統(tǒng)軟件調(diào)試通過。首先,因?yàn)镈ICE-51單片機(jī)仿真系統(tǒng)軟件在做除法運(yùn)算時(shí),若產(chǎn)生借位,不能置位,所以要用CJNE比較指令進(jìn)行置位運(yùn)算。 ;定義被除數(shù)單元 DIVDLL EQU 40H DIVDLH EQU 41H DIVDHL EQU 42H DIVDHH EQU 43H ;定義除數(shù)單元 DIVDL EQU 44H DIVDM EQU 45H DIVDH EQU 46H ;定義余數(shù)單元 TEMPL EQU 50H TEMPM EQU 51H TEMPH EQU 52H ;定義輔助單元 FZ1 EQU 47H FZ2 EQU 48H DIV0: MOV A,DIVDH ;以下四行判斷除數(shù)是否為零 ORL A,DIVDM ORL A,DIVDL JNZ DIV1 ;如果(A)不等于0,則跳轉(zhuǎn);否則順序執(zhí)行 SETB OV ;除數(shù)為零,置溢出標(biāo)志位OV為1,程序結(jié)束 SJMP LOOP1 DIV1: MOV TEMPL,#00H ;余數(shù)單元清零 MOV TEMPM,#00H MOV TEMPH,#00H MOV B,#20H ;置循環(huán)次數(shù)32次 DIV2: CLR C ;進(jìn)位位清零 MOV A,DIVDLL ;以下三行被除數(shù)最低字節(jié)左移一位(帶進(jìn)位) RLC A MOV DIVDLL,A MOV A,DIVDLH ;以下三行被除數(shù)低16位高字節(jié)左移一位(帶進(jìn)位) RLC A MOV DIVDLH,A MOV A,DIVDHL ;以下三行被除數(shù)高16位低字節(jié)左移一位(帶進(jìn)位) RLC A MOV DIVDHL,A MOV A,DIVDHH ;以下三行被除數(shù)最高字節(jié)左移一位(帶進(jìn)位) RLC A MOV DIVDHH,A MOV A,TEMPL ;以下三行余數(shù)低字節(jié)左移一位(帶進(jìn)位) RLC A MOV TEMPL,A MOV A,TEMPM ;以下三行余數(shù)中間字節(jié)左移一位(帶進(jìn)位) RLC A MOV TEMPM,A MOV A,TEMPH ;以下三行余數(shù)高字節(jié)左移一位(帶進(jìn)位) RLC A MOV TEMPH,A MOV A,TEMPL ;把余數(shù)最低字節(jié)送到累加器A中 CLR C SUBB A,DIVDL ;用余數(shù)減去除數(shù) MOV R7,A ;低字節(jié)相減結(jié)果送R7保存 MOV A,TEMPL CJNE A,DIVDL,LP ;通過比較運(yùn)算實(shí)現(xiàn)因軟件設(shè)計(jì)原因相減不能借位 ;而產(chǎn)生的借位 LP1: MOV A,DIVDM ADDC A,#00H MOV FZ1,A ;計(jì)算除數(shù)中間字節(jié)與低字節(jié)相減產(chǎn)生的進(jìn)位位之和 ;將結(jié)果送FZ1保存 MOV A,TEMPM CJNE A,FZ1,LP2 ;通過比較運(yùn)算實(shí)現(xiàn)因軟件設(shè)計(jì)原因相減不能借位 ;而產(chǎn)生的借位 LP2: PUSH PSW ;對(duì)程序狀態(tài)字PSW壓棧保護(hù) MOV F0,C ;將C的值送給F0保存 CLR C MOV A,TEMPM SUBB A,FZ1 MOV R6,A ;中間字節(jié)帶進(jìn)位相減結(jié)果送R6保存 MOV C,F0 POP PSW ;程序狀態(tài)字PSW彈棧,恢復(fù)現(xiàn)場(chǎng) MOV A,DIVDH ADDC A,#00H MOV FZ2,A ;計(jì)算除數(shù)高字節(jié)與中間字節(jié)相減產(chǎn)生的進(jìn)位位之和 ;將結(jié)果送FZ2保存 MOV A,TEMPH CJNE A,FZ2,LP3 ;通過比較運(yùn)算實(shí)現(xiàn)因軟件設(shè)計(jì)原因相減不能借位 ;而產(chǎn)生的借位 LP3: PUSH PSW ;對(duì)程序狀態(tài)字PSW壓棧保護(hù) MOV F0,C CLR C MOV A,TEMPH SUBB A,FZ2 ;高字節(jié)帶進(jìn)位相減結(jié)果送R5保存 MOV R5,A MOV C,F0 POP PSW ;程序狀態(tài)字PSW彈棧,恢復(fù)現(xiàn)場(chǎng) JC DIV3 ;不夠減,則跳轉(zhuǎn)到DIV3 DIV4: MOV TEMPL,R7 ;夠減,刷新余數(shù)單元 MOV TEMPM,R6 MOV TEMPH,R5 MOV R0,#DIVDLL ;夠減,將被除數(shù)最低位置1 MOV A,@R0 INC A XCH A,@R0 DIV3: DJNZ B,DIV2 ;判斷B是否為零,若為零,循環(huán)結(jié)束;否則,跳轉(zhuǎn)繼續(xù)循環(huán) CLR F0 LOOP1:NOP RET