PIC16F877單片機運算子程序
更新時間: 2007-05-25 16:51:03來源: 粵嵌教育瀏覽量:867
1 PIC16F877匯編語言程序主體框架
以下是一個典型的程序結構:
;***************程序說明區*******************
LIST p=16f877 ;指定微控制器型號和文件輸出格式
INCLUDE p16f877.inc ;讀入MPLAB提供的定義文件P16F877.INC
;***片內RAM常用資源、變量定義和相應的說明*********
ACCALO EQU 20 ;存放加數或減數低8位
ACCAHI EQU 21 ;存放加數或減數高8位
ACCBLO EQU 23 ;存放被加數或被減數低8位
ACCBHI EQU 24 ;存放被加數或被減數高8位
S_W EQU 25 ;棧存W寄存器值
S_STATUS EQU 26 ;棧存STATUS寄存器值
;****************芯片復位矢量*******************
ORG 0X0000 ;由于PIC16F877芯片復位矢量在0000h單
;元,所以常在0000h單元處放置一條跳轉
;指令,使單片機復位后能跳過中斷矢量,
;直接執行主程序
START GOTO MAIN
;******************中斷矢量**********************
ORG 0X0004 ;由于PIC16F877的中斷矢量為0004h,所以
;當中斷開放時, 需在此處加入中斷程序,
;使單片機能在中斷到來時及時進入相應的
;中斷服務程序。為了可靠起見,如果單片
;機不使用中斷,則常常在該中斷矢量處放
;置RETFIE指令,可以使單片機不會因
;干擾產生誤中斷而導致程序跑飛
CALL PUSH ;調用保護現場子程序
BTFSS PIR1,ADIF
CALL AD ;若AD中斷到,則執行中斷服務程序
…….. ;此處可放多個中斷子程序,并以軟件安排
;中斷優先級
CALL POP ;恢復中斷現場
RETFIE ;中斷返回
;****************主程序區*****************
ORG 0X0100 ;將主程序、子程序和中斷服務程序等存放
;在0100h單元之后,在中斷矢量和主程序
;區之間預留一些存儲單元,以便寫入判
;跳指令和一些必要的現場保護程序。此外
;用戶也可以根據實際需要,使主程序從其
;它地址開始存放
MAIN BSF STATUS,RP0 ;選擇存儲體1
MOVLW 0XFF ;定義RA口為輸入端口
MOVWF TRISA
BCF STATUS,RP0 ;選擇存儲體0
MOVLW 0X04 ;初值化ACCALO
MOVWF ACCALO
CALL DX ;調用DX子程序
LOOP1 …… ;任務1
…… ;任務2
:
:
:
GOTO LOOP1 ;反復執行任務一和任務二等
;***************子程序區*********************
DX MOVF ACCALO,0 ;ACCB和ACCA低半字節相加
ADDWF ACCBLO
RETURN ;子程序返回
;****************************************
PUSH MOVWF S_W ;保護W寄存器
MOVF STATUS,0 ;保護STATUS寄存器
MOVWF S_STATUS
RETURN ;子程序返回
;****************************************
POP MOVF S_STATUS,0 ;恢復STATUS寄存器
MOVWF STATUS
MOVF S_W,0 ;恢復W寄存器
RETURN ;子程序返回
;****************中斷服務子程序區************************
AD BCF PIR1,ADIF ;清AD中斷標志
…… ;中斷服務主體程序
RETURN ;子程序返回
END
2 四則運算子程序
2.1 16×16位定點數加、減法子程序
以下子程序實現2個16×16位有符號數加、減運算,其和或差用一個16位數表示。在子程序中,減法是通過對減數求補后再與被減數相加來實現的。因此,當程序從D_sub進入子程序時為減法,當從D_add進入子程序時為加法。
子程序的入口條件和出口條件如下:
入口條件:16位被加數/被減數存放在ACCBHI、ACCBLO中;
16位加數/減數存放在ACCAHI、ACCALO中;
出口條件:16位和/差存放在ACCBHI和ACCBLO中。
以下為16×16位有符號數加、減法子程序。
注意:在以下注釋程序中均以ACCA代替ACCAHI、ACCALO兩個字節,以ACCB代替ACCBHI、ACCBLO兩個字節。
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放加數或減數低8位
ACCAHI EQU 21 ;存放加數或減數高8位
ACCBLO EQU 23 ;存放被加數或被減數低8位
ACCBHI EQU 24 ;存放被加數或被減數高8位
ORG 0X0000
START GOTO MAIN
;***雙字節減法子程序,入口地址ACCB-ACCA,出口地址ACCB***
D_sub CALL NEG_A ;求ACCA的補碼
;***雙字節加法子程序,入口地址ACCB+ACCA,出口地址ACCB***
D_add MOVF ACCALO,0 ;ACCB和ACCA低半字節相加
ADDWF ACCBLO
BTFSC STATUS,C ;有進位否?
INCF ACCBHI ;有,ACCB高字節加1,再加ACCAHI
MOVF ACCAHI,0 ;ACCA、ACCB高半字節相加
ADDWF ACCBHI
RETURN ;子程序返回
;************** ACCA取補子程序*****************
NEG_A COMF ACCALO ;ACCALO取反加1
INCF ACCALO
BTFSC STATUS,Z ;低8位有進位嗎?
DECF ACCAHI ;有,ACCAHI減1,再取反
COMF ACCAHI ;否則ACCAHI直接取反
RETURN ;子程序返回
【校驗舉例1】 19531+(-16594)=2937(十進制)
化為十六進制數:4C46H+BF2EH
結果:0B79H(十六進制)
【校驗舉例2】 26222+3000=29222(十進制)
化為十六進制數: 666EH+0BB8H
結果:7226H(十六進制)
【例程】
MAIN MOVLW 0X6E ;被加數666EH送ACCB
MOVWF ACCBLO
MOVLW 0X66
MOVWF ACCBHI
MOVLW 0XB8 ;加數BB8H送ACCA
MOVWF ACCALO
MOVLW 0X0B
MOVWF ACCAHI
CALL D_add ;調用雙字節加法子程序,求和
END
2.2 16×16位定點數乘法子程序
子程序采用部分積右移加法實現乘法運算。乘數和被乘數分別為16位二進制有符號數(均采用補碼表示,第16位為符號位),積為32位二進制有符號數,第32位為符號位。子程序的入口條件和出口條件如下:
入口條件:被乘數存放在ACCBHI和ACCBLO單元中,
乘數存放在ACCAHI和ACCALO單元中。
出口條件:積存放在ACCBHI、ACCBLO、ACCCHI和ACCCLO單元中,ACCB為高16位,ACCC為低16位。
以下為本子程序的程序清單:
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放乘數低8位
ACCAHI EQU 21 ;存放乘數高8位
ACCBLO EQU 23 ;存放被乘數低8位和乘積第16~23位
ACCBHI EQU 24 ;存放被乘數高8位和乘積第24~31位
ACCCLO EQU 26 ;存放乘積低8位
ACCCHI EQU 27 ;存放乘積高8位
ACCDLO EQU 28 ;臨時寄存器
ACCDHI EQU 29 ;臨時寄存器
TEMP EQU 2A ;臨時寄存器
SIGN EQU 2B ;存放乘積的符號
ORG 0X0000
START GOTO MAIN
;***16×16位乘法子程序,入口地址ACCB×ACCA,出口地址ACCB和ACCC ***
ORG 0X0100
D_mpy CALL S_SIGN ;求取乘積的符號,并對負數取補
CALL SETUP ;調用子程序,將ACCB的值送ACCD
INCF TEMP
CLRF ACCCHI ;清ACCC
CLRF ACCCLO
MLOOP BCF STATUS,C ;清進位位
RRF ACCDHI ;ACCD右移
RRF ACCDLO
BTFSC STATUS,C ;判斷是否需要相加
CALL D_add ;加乘數至ACCB,見加法程序
BCF STATUS,C ;清進位位
RRF ACCBHI ;右移部分乘積
RRF ACCBLO
RRF ACCCHI
RRF ACCCLO
DECFSZ TEMP ;乘法完成否?
GOTO MLOOP ;否,繼續求乘積
BTFSS SIGN,7 ;是,確定乘積的符號
GOTO OVER ;為正,乘法結束
COMF ACCCLO ;為負,乘積取補
INCF ACCCLO
BTFSC STATUS,Z
DECF ACCCHI
COMF ACCCHI
BTFSC STATUS,Z
NEG_B DECF ACCBLO ;
COMF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
OVER RETURN ;子程序返回
;****************************************
SETUP MOVLW .15 ;初始化TEMP寄存器
MOVWF TEMP
MOVF ACCBHI,0 ;ACCB送ACCD
MOVWF ACCDHI
MOVF ACCBLO,0
MOVWF ACCDLO
CLRF ACCBHI ;清ACCB
CLRF ACCBLO
RETURN ;子程序返回
;*******乘法運算確定結果符號判斷子程序******
S_SIGN MOVF ACCAHI,0 ;ACCAHI異或ACCBHI,結果送SIGN單元
XORWF ACCBHI,0
MOVWF SIGN
BTFSS ACCBHI,7 ;ACCB為負嗎?
GOTO CHEK_A ;否,檢查ACCA
CALL NEG_B ;是,求取ACCB值
CHEK_A BTFSC ACCAHI,7 ;ACCA為負嗎?
CALL NEG_A ;ACCA為負,求取ACCA值,
;見雙字節加法程序
RETURN ;ACCA和ACCB均為正,返回
【校驗舉例1】:-24555×(-7391)=181486005(十進制)
化為十六進制數:A015H×E321H
結果:0AD141B5H(十六進制)
【校驗舉例2】 16405×13089=214725045(十進制)
化為十六進制數:4015H×3321H
結果:0CCC71B5H(十六進制)
【例程】
MAIN MOVLW 0X15 ;被乘數4015H送ACCB
MOVWF ACCBLO
MOVLW 0X40
MOVWF ACCBHI
MOVLW 0X21 ;乘數3321H送ACCA
MOVWF ACCALO
MOVLW 0X33
MOVWF ACCAHI
CALL D_mpy ;調用雙字節乘法子程序,求積
END
2.3 16×16位定點數除法子程序
子程序采用反復的減法算法,除數和被除數分別為16位二進制有符號數(均采用補碼表示,第16位為符號位),商為16位二進制有符號數,第16位為符號位。子程序的入口條件和出口條件如下:
入口條件:被除數存放在ACCBHI、ACCBLO單元中;
除數存放在ACCAHI、ACCALO單元中。
出口條件:商存放在ACCBHI、ACCBLO單元中;
余數存放在ACCCHI、ACCCLO單元中。
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放除數低8位
ACCAHI EQU 21 ;存放除數高8位
ACCBLO EQU 22 ;存放被除數和商的低8位
ACCBHI EQU 23 ;存放被除數和商的高8位
ACCCLO EQU 24 ;存放余數低8位
ACCCHI EQU 25 ;存放余數高8位
ACCDLO EQU 26 ;臨時寄存器
ACCDHI EQU 27 ;臨時寄存器
TEMP EQU 28 ;臨時寄存器
SIGN EQU 29 ;存放商的符號
ORG 0X0000
START GOTO MAIN
;***16×16位數除法子程序,入口地址ACCB /ACCA,出口地址ACCB ***
ORG 0X0100
D_div CALL S_SIGN ;確定商的符號,并將負數取補
CALL SETUP ;初始化TEMP,將被除數移至ACCD,
;(SETUP子程序請參見16×16位定點數
;乘法子程序SETUP)
INCF TEMP
CLRF ACCCHI ;清余數寄存器
CLRF ACCCLO
DLOOP BCF STATUS,C ;清進位位
RLF ACCDLO ;被除數、余數左移1位
RLF ACCDHI
RLF ACCCLO
RLF ACCCHI
MOVF ACCAHI,0 ;ACCCHI-ACCAHI
SUBWF ACCCHI,0
BTFSS STATUS,Z ;ACCCHI=ACCAHI?
GOTO NOCHK
MOVF ACCALO,0 ;是,ACCCLO-ACCALO
SUBWF ACCCLO,0
NOCHK BTFSS STATUS,C ;ACCC>ACCA?
GOTO NOGO
MOVF ACCALO,0 ;是,余數減除數
SUBWF ACCCLO
BTFSS STATUS,C
DECF ACCCHI
MOVF ACCAHI,0
SUBWF ACCCHI
BSF STATUS,C ;置進位位
NOGO RLF ACCBLO ;商左移1位
RLF ACCBHI
DECFSZ TEMP ;循環完畢?
GOTO DLOOP
BTFSS SIGN,7 ;是,確定商的符號
GOTO DIVOVER ;為正,除法結束,跳轉到結束行
COMF ACCCLO ;為負,商和余數分別取補
INCF ACCCLO
BTFSC STATUS,Z
DECF ACCCHI
COMF ACCCHI
CALL NEG_B ;見乘法程序中間NEG_B
DIVOVER RETURN ;子程序返回
;************除法運算確定結果符號子程序*******************
S_SIGN MOVF ACCAHI,0 ;ACCAHI異或ACCBHI,結果送SIGN單元
XORWF ACCBHI,0
MOVWF SIGN
BTFSS ACCBHI,7 ;ACCB為負?
GOTO CHEK_A ;否,檢查ACCA
COMF ACCBLO ;是,ACCB取補
INCF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
CHEK_A BTFSC ACCAHI,7 ;ACCA為負?
CALL NEG_A ;ACCA為負,取補(NEG_A子程序請參見
;16×16位定點數乘法子程序NEG_A)
RETURN ;ACCA和ACCB均為負,返回
【校驗舉例1】 -23775÷(-240)=99.0625(十進制)
化為十六進制數:A321H÷FF10H;
結果:(商)0063H,(余數)000FH(十六進制)。
【校驗舉例2】 769÷3856=0.199429(十進制)
化為十六進制數:0301H÷0F10H;
結果:(商)0000H,(余數)0301H(十六進制)。
【例程】
MAIN MOVLW 0X01 ;被除數0301H送ACCB
MOVWF ACCBLO
MOVLW 0X03
MOVWF ACCBHI
MOVLW 0X10 ;除數0F10H送ACCA
MOVWF ACCALO
MOVLW 0X0F
MOVWF ACCAHI
CALL D_div ;調用雙字節除法子程序,求商
END
3 3字節浮點四則運算子程序
3.1 浮點數加(減)法子程序
以下為浮點加(減)運算例程:
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放加數或減數的尾數
ACCAHI EQU 21
EXPA EQU 22 ;存放加數或減數階碼
ACCBLO EQU 23 ;存放被加數或被減數尾數以及和或差
ACCBHI EQU 24
EXPB EQU 25 ;存放被加數或被減數階碼
ACCCLO EQU 26 ;臨時寄存器
ACCCHI EQU 27 ;臨時寄存器
ACCDLO EQU 28 ;臨時寄存器
ACCDHI EQU 29 ;臨時寄存器
TEMP EQU 2A ;臨時寄存器
TEMP1 EQU 30 ;臨時寄存器
TIMES EQU 31 ;臨時寄存器
ORG 0X000
START GOTO MAIN
ORG 0X0100
;**************浮點減法子程序****************
F_sub CALL NEG_A ;求ACCA的補碼,將減法轉換為補碼加法
;***********浮點加法子程序**************
F_add CALL SUBADJ ;調子程序判斷EXPB和EXPA的大小
BTFSC STATUS,Z ;參與運算的兩個數階碼相等?
GOTO PADD ;是,求尾數的和
BTFSC STATUS,C ;EXPB>EXPA?
CALL F_swap ;是,ACCB與ACCA互換
MOVF EXPA,0 ;否,求取兩者的差值
SUBWF EXPB
SCLOOP CALL SHFTSR ;ACCB右移規格化
INCFSZ EXPB ;EXPB=EXPA?
GOTO SCLOOP ;否,繼續右移
MOVF EXPA,0 ;是,存和(差)的階碼
MOVWF EXPB
PADD MOVF ACCAHI,0 ;ACCAHI或ACCBHI
IORWF ACCBHI,0
MOVWF SIGN ;存于SIGN寄存器
MOVF ACCBHI,0 ;暫存ACCBHI
MOVWF EXPA
CALL D_add ;尾數相加
BTFSS SIGN,7 ;ACCA和ACCB有負數?
BTFSC ACCBHI,7 ;否,把和的位和次高位同時進位?
GOTO ADD2 ;否,轉ADD2
BTFSS ACCAHI,7 ;ACCA為負嗎?
GOTO ADD3 ;ACCA和ACCB不同時為負,轉ADD3
BTFSS EXPA,7 ;是,ACCB為負嗎?
GOTO ADD3
BSF STATUS,C ;ACCA和ACCB同為負,帶負號右移
RRF ACCBHI
RRF ACCBLO
INCF EXPB
ADD3 CLRF ACCCHI ;和(差)規格化
CLRF ACCCLO
CALL F_norm
RETURN ;子程序返回
ADD2 BCF STATUS,C ;位次高位不同時進位,ACCB右移
INCF EXPB
GOTO SHFTR
SHFTSR BCF STATUS,C ;ACCB帶符號右移子程序
BTFSC ACCBHI,7
BSF STATUS,C
SHFTR RRF ACCBHI
RRF ACCBLO
RETURN ;子程序返回
;********* ACCB、ACCA互換子程序************
F_swap MOVF ACCAHI,0 ;ACCAHI、ACCBHI互換
MOVWF TEMP
MOVF ACCBHI,0
MOVWF ACCAHI
MOVF TEMP,0
MOVWF ACCBHI
MOVF ACCALO,0 ;ACCALO、ACCBLO互換
MOVWF TEMP
MOVF ACCBLO,0
MOVWF ACCALO
MOVF TEMP,0
MOVWF ACCBLO
MOVF EXPA,0 ;EXPA、EXPB互換
MOVWF TEMP
MOVF EXPB,0
MOVWF EXPA
MOVF TEMP,0
MOVWF EXPB
RETURN
;*************比較EXPB、EXPA大小子程序*************
SUBADJ MOVF EXPA,0 ;EXPA異或EXPB,結果送C_DIV
XORWF EXPB,0
MOVWF C_DIV
MOVF EXPA,0 ;EXPB-EXPA
SUBWF EXPB,0
BTFSS C_DIV,7 ;EXPA和EXPB同號?
RETURN ;是,進位位的值真確反映兩者的大小,返回
BTFSS STATUS,C ;否,進位位的值取反
GOTO CHANGEC
BCF STATUS,C
RETURN
CHANGEC BSF STATUS,C
RETURN
;***********浮點數規格化子程序****************
F_norm MOVF ACCBHI ;ACCB=0?
BTFSS STATUS,Z
GOTO C_norm
MOVF ACCBLO
BTFSC STATUS,Z
RETURN ;是,不需規格化,返回
C_norm BTFSC ACCBHI,7 ;否。ACCB為負?
GOTO C_norm2
C_norm1 BTFSC ACCBHI,6 ;為正。規格化完畢?
RETURN ;ACCBHI.6=1,規格化結束
CALL SHFTSL ;否。ACCB左移
DECF EXPB ;EXPB減1
GOTO C_norm1 ;重新判斷規格化完畢否?
C_norm2 BTFSS ACCBHI,6 ;ACCB為負。規格化完畢否?
RETURN ;ACCBHI.6=0,規格化結束
BCF STATUS,C
CALL SHFTSL ;否,ACCB左移
BSF ACCBHI,7 ;加符號
DECF EXPB ;EXPB減1
GOTO C_norm2 ;重新判斷規格化完畢否?
SHFTSL BCF STATUS ,C ;ACCB左移子程序
RLF ACCCLO
RLF ACCCHI
RLF ACCBLO
RLF ACCBHI
RETURN
【校驗舉例1】 0.0019531+(-0.00016594)=0.00178716
化為十六進制數:4000F8+A900F4
結果:7520F7
【校驗舉例2】 0.26222+3.5025=3.76478
化為十六進制數: 4321FF+701502
結果:787902
【例程】
MAIN MOVLW 0X21 ;被加數的尾數4321H送ACCB
MOVWF ACCBLO
MOVLW 0X43
MOVWF ACCBHI
MOVLW 0XFF ;被加數的階碼FFH送EXPB
MOVWF EXPB
MOVLW 0X15 ;加數尾數7015H送ACCA
MOVWF ACCALO
MOVLW 0X70
MOVWF ACCAHI
MOVLW 0X02 ;加數階碼送EXPA
MOVWF EXPA
CALL F_add ;調用浮點數加法子程序,求和
END
3.2 浮點數乘法子程序
以下為浮點數乘法的程序清單。
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放乘數尾數
ACCAHI EQU 21
EXPA EQU 22 ;存放乘數階碼
ACCBLO EQU 23 ;存放被乘數尾數和乘積高16位
ACCBHI EQU 24
EXPB EQU 25 ;存放被乘數階碼
ACCCLO EQU 26 ;存放乘積低16位
ACCCHI EQU 27
ACCDLO EQU 28 ;臨時寄存器
ACCDHI EQU 29 ;臨時寄存器
TEMP EQU 2A ;臨時寄存器
TEMP1 EQU 30 ;臨時寄存器
TIMES EQU 31 ;臨時寄存器
SIGN EQU 2B ;存放乘積符號
COUNT EQU 2F ;臨時寄存器
ACCEHI EQU 30 ;臨時寄存器
ACCELO EQU 31 ;臨時寄存器
ORG 0X0000
START GOTO MAIN
ORG 0X0100
;***浮點乘法子程序,入口地址(ACCB、EXPB)×(ACCA、EXPA),出口地址ACCB、EXPB ***
F_mpy CALL S_SIGN ;求取乘積的符號,并對負數取補
CALL SETUP ;調用子程序將ACCB的值送ACCD
CLRF ACCCHI ;清ACCC
CLRF ACCCLO
MLOOP BCF STATUS,C ;清進位位
RRF ACCDHI ;ACCD右移
RRF ACCDLO
BTFSC STATUS,C ;判斷是否需要相加
CALL D_add ;加乘數至ACCB
BCF STATUS,C ;清進位位
RRF ACCBHI ;右移部分乘積
RRF ACCBLO
RRF ACCCHI
RRF ACCCLO
DECFSZ TEMP ;乘法完成否?
GOTO MLOOP ;否,繼續循環
MOVF EXPA,0 ;是,乘數與被乘數階碼相加,得積的階碼
ADDWF EXPB
MOVF ACCBHI ;ACCBHI=0?
BTFSS STATUS,Z
GOTO FINUP ;否,轉FINUP
MOVF ACCBLO ;ACCB=0?
BTFSS STATUS ,Z
GOTO SHFT08 ;否,只有ACCBHI=0,轉SHFT08
MOVF &nbs, p; ACCCHI,0 ;ACCB=0,將乘積左移15位
MOVWF ACCBHI
MOVF ACCCLO,0
MOVWF ACCBLO
BCF STATUS,C
RRF ACCBHI
RRF ACCBLO
MOVLW .15 ;乘積階碼減15(十進制數)
SUBWF EXPB
GOTO FINUP
SHFT08 MOVF ACCBLO,0 ;只有ACCBHI=0,乘積左移7位
MOVWF ACCBHI
MOVF ACCCHI,0
MOVWF ACCBLO
BCF STATUS,C
RRF ACCBHI
RRF ACCBLO
MOVLW .7 ;乘積階碼減7
SUBWF EXPB
FINUP CALL F_norm ;對乘積進行規格化
BTFSS SIGN,7 ;確定乘積的符號
GOTO OVER ;為正,乘法結束
COMF ACCCLO ;為負,乘積取補
INCF ACCCLO
BTFSC STATUS,Z
DECF ACCCHI
COMF ACCCHI
BTFSC STATUS,Z
NEG_B DECF ACCBLO
COMF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
OVER RETURN ;乘法結束,子程序返回
;********浮點乘除法運算確定結果符號子程序***********
S_SIGN MOVF ACCAHI,0 ;ACCAHI異或ACCBHI,結果送SIGN
XORWF ACCBHI,0
MOVWF SIGN
BTFSS ACCBHI,7 ;ACCB為負?
GOTO CHEK_A ;否,檢查ACCA
COMF ACCBLO ;是,ACCB取補
INCF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
CHEK_A BTFSC ACCAHI,7 ;ACCA為負?
CALL NEG_A ;ACCA取補
RETURN ;返回
;*********浮點運算結果規格化子程序*************
F_norm MOVF ACCBHI ;ACCB=0?
BTFSS STATUS,Z
GOTO C_norm
MOVF ACCBLO
BTFSC STATUS,Z
RETURN ;是,不需規格化,返回
C_norm BTFSC ACCBHI,7 ;否。ACCB為負?
GOTO C_norm2
C_norm1 BTFSC ACCBHI,6 ;為正。規格化完畢?
RETURN ;ACCBHI.6=1,規格化結束
CALL SHFTSL ;否。ACCB左移
DECF EXPB ;EXPB減1
GOTO C_norm1 ;重新判斷規格化完畢否?
C_norm2 BTFSS ACCBHI,6 ;ACCB為負。規格化完畢否?
RETURN ;ACCBHI.6=0,規格化結束
BCF STATUS,C
CALL SHFTSL ;否,ACCB左移
BSF ACCBHI,7 ;加符號
DECF EXPB ;EXPB減1
GOTO C_norm2 ;重新判斷規格化完畢否?
SHFTSL BCF STATUS ,C ;ACCB左移子程序
RLF ACCCLO
RLF ACCCHI
RLF ACCBLO
RLF ACCBHI
RETURN
【校驗舉例1】 0.0019531×(-0.00016594)=-0.000000324
化為十六進制數:4000F8×A900F4
結果:A900EB
【校驗舉例2】 0.26222×3.5025=0.91842
化為十六進制數: 4321FF×701502
結果: 758F00
【例程】
MAIN MOVLW 0X21 ;被乘數的尾數4321H送ACCB
MOVWF ACCBLO
MOVLW 0X43
MOVWF ACCBHI
MOVLW 0XFF ;被乘數的階碼FFH送EXPB
MOVWF EXPB
MOVLW 0X15 ;乘數尾數7015H送ACCA
MOVWF ACCALO
MOVLW 0X70
MOVWF ACCAHI
MOVLW 0X02 ;乘數階碼送EXPA
MOVWF EXPA
CALL F_mpy ;調用浮點數乘法子程序,求積
END
3.3 浮點數除法子程序
以下為浮點數除法子程序清單。
LIST p=16f877
INCLUDE p16f877.inc
ACCALO EQU 20 ;存放除數的尾數
ACCAHI EQU 21
EXPA EQU 22 ;存放除數的階碼
ACCBLO EQU 23 ;存放被除數的尾數和商的尾數
ACCBHI EQU 24
EXPB EQU 25 ;存放被除數和商的階碼
ACCCLO EQU 26 ;存放余數
ACCCHI EQU 27
ACCDLO EQU 28 ;臨時寄存器
ACCDHI EQU 29 ;臨時寄存器
TEMP EQU 2A ;臨時寄存器
TEMP1 EQU 30 ;臨時寄存器
TIMES EQU 31 ;臨時寄存器
SIGN EQU 2B ;存放商的符號
COUNT EQU 2F ;臨時寄存器
ACCEHI EQU 30 ;臨時寄存器
ACCELO EQU 31 ;臨時寄存器
ORG 0X0000
START GOTO MAIN
ORG 0X0100
;***浮點數除法子程序,入口地址(ACCB、EXPB)/(ACCA、EXPA),出口地址ACCB、EXPB***
F_div CALL S_SIGN ;確定商的符號,并將負數取補
CLRF ACCCHI ;初始化ACCC寄存器
CLRF ACCCLO
CALL F_norm ;規格化ACCB
CLRF ACCCLO
CLRF ACCCHI
CLRF TIMES
MOVF ACCAHI ;除數為零?
BTFSS STATUS,Z
GOTO FD0 ;否,求商
MOVF ACCALO
BTFSC STATUS,Z
RETLW 01 ;是,返回
FD0 CALL NEG_A ;除數取補
FD1 MOVF ACCBHI,0 ;ACCBHI送ACCDLO
MOVWF ACCDLO
CALL D_add1 ;被除數尾數大于除數尾數?
BTFSS STATUS,C
GOTO FD2
RRF1 BCF STATUS,C ;是,被除數右移規格化,直到小于除數為止
RRF ACCBHI
RRF ACCBLO
INCF TIMES
RRF ACCCHI
BCF STATUS,C
GOTO FD1
FD2 CALL DDIV ;否,調用雙字節除法子程序,求商的尾數
MOVF TIMES,0 ;根據右移規格化次數調整ACCB階碼
ADDWF EXPB
MOVF EXPA,0 ;求商的階碼
SUBWF EXPB
CALL F_norm ;商規格化
BTFSC SIGN,7 ;商為負?
CALL NEG_B ;是,取補
CALL NEG_A ;除數還原
RETURN ;浮點數除法完成,返回
;***********雙字節純小數除法子程序***************
DDIV MOVLW 0X0F ;初始化ACCDHI
MOVWF ACCDHI
DV1 BCF STATUS,C
RLF ACCCLO ;左移商
RLF ACCCHI
RLF ACCBLO ;左移余數
RLF ACCBHI
MOVF STATUS,0 ;暫存STATUS寄存器
MOVWF ACCDLO
MOVF ACCBHI,0 ;ACCBHI送TEMP1
MOVWF TEMP1
MOVF ACCALO,0 ;ACCB-ACCA
ADDWF ACCBLO,0
MOVWF TEMP
BTFSC STATUS,C
INCF TEMP1
MOVF ACCAHI,0
ADDWF TEMP1,0
BTFSC ACCDLO,0 ;左移余數時移出來的數為1?
GOTO DV2
TESTC BTFSS STATUS,C ;是,再判斷ACCB尾數是否大于ACCA
GOTO DV3
DV2 MOVWF ACCBHI ;是,余數送ACCB
MOVF TEMP,0
MOVWF ACCBLO
INCF ACCCLO ;商加1
DV3 DECFSZ ACCDHI ;商求取完畢?
GOTO DV1
MOVF ACCCHI,0 ;是,將商送ACCB
MOVWF ACCBHI
MOVF ACCCLO,0
MOVWF ACCBLO
RETLW 00
;**********本子程序用于判斷比較ACCB與ACCA的大小**********
D_add1 MOVF ACCALO,0 ;加數、被加數低半字節相加
ADDWF ACCBLO,0
BTFSC STATUS,C ;有進位?
INCF ACCDLO ;ACCD低半字節加1
MOVF ACCAHI,0 ;ACCAHI+ACCDLO
ADDWF ACCDLO
RETLW 0 ;子程序返回
;****************************************
SETUP MOVLW .15
MOVWF TEMP
MOVF ACCBHI,0
MOVWF ACCDHI
MOVF ACCBLO,0
MOVWF ACCDLO
CLRF ACCBHI
CLRF ACCBLO
RETLW 0
;*************** ACCA取補子程序*************
NEG_A COMF ACCALO ;ACCALO取反加1
INCF ACCALO
BTFSC STATUS,Z ;低8位有進位嗎?
DECF ACCAHI ;有,ACCAHI減1,再取反
COMF ACCAHI ;否,ACCAHI直接取反
RETLW 0
;********* ACCB取補子程序*************
NEG_B DECF ACCBLO ;ACCBLO取反加1
COMF ACCBLO
BTFSC STATUS,Z ;低8位有進位嗎?
DECF ACCBHI ;有,ACCBHI減1,再取反
COMF ACCBHI ;否,ACCBHI直接取反
RETLW 0
;*********浮點乘除法運算確定結果符號子程序**********
S_SIGN MOVF ACCAHI,0 ;ACCAHI異或ACCBHI,結果送SIGN單元
XORWF ACCBHI,0
MOVWF SIGN
BTFSS ACCBHI,7 ;ACCB為負?
GOTO CHEK_A ;否,檢查ACCA
COMF ACCBLO ;是,ACCB取補
INCF ACCBLO
BTFSC STATUS,Z
DECF ACCBHI
COMF ACCBHI
CHEK_A BTFSC ACCAHI,7 ;ACCA為負?
CALL NEG_A ;ACCA為負,取補
RETLW 0 ;ACCA和ACCB均為負,返回
;************浮點運算結果規格化子程序***************
F_norm MOVF ACCBHI ;ACCB=0?
BTFSS STATUS,Z
GOTO C_norm
MOVF ACCBLO
BTFSC STATUS,Z
RETLW 0 ;是,不需規格化,返回
C_norm BTFSC ACCBHI,7 ;否。ACCB為負?
GOTO C_norm2
C_norm1 BTFSC ACCBHI,6 ;為正。規格化完畢?
RETLW 0 ;ACCBHI.6=1,規格化結束
CALL SHFTSL ;否。ACCB左移
DECF EXPB ;EXPB減1
GOTO C_norm1 ;重新判斷規格化完畢否?
C_norm2 BTFSS ACCBHI,6 ;ACCB為負。規格化完畢否?
RETLW 0 ;ACCBHI.6=0,規格化結束
BCF STATUS,C
CALL SHFTSL ;否,ACCB左移
BSF ACCBHI,7 ;加符號
DECF EXPB ;EXPB減1
GOTO C_norm2 ;重新判斷規格化完畢否?
SHFTSL BCF STATUS ,C ;ACCB左移子程序
RLF ACCCLO
RLF ACCCHI
RLF ACCBLO
RLF ACCBHI
RETLW 0
【校驗舉例1】 0.0019531÷(-0.00016594)=-12.7699
化為十六進制數:4000F8÷A900F4
結果:A1D704
【校驗舉例2】 0.26222÷3.5025=0.074867
化為十六進制數: 4321FF÷701502
結果:4CA9FD
【例程】
MAIN MOVLW 0X21 ;被除數的尾數4321H送ACCB
MOVWF ACCBLO
MOVLW 0X43
MOVWF ACCBHI
MOVLW 0XFF ;被除數的階碼FFH送EXPB
MOVWF EXPB
MOVLW 0X15 ;除數尾數7015H送ACCA
MOVWF ACCALO
MOVLW 0X70
MOVWF ACCAHI
MOVLW 0X02 ;除數階碼送EXPA
MOVWF EXPA
CALL F_div ;調用浮點數除法子程序,求商
END
4 定點數與浮點數轉換程序
4.1 定點數轉換成浮點數
本子程序的功能是將雙字節定點整數(十六進制)轉換為3字節浮點數,其轉換數值范圍:-32768~32767,入口條件和出口條件如下:
入口條件:ACCBHI、ACCBLO
出口條件:ACCBHI、ACCBLO、EXPB
以下為定點整數轉換成浮點數的程序清單。
LIST p=16f877
INCLUDE p16f877.inc
ACCBLO EQU 23 ;存放定點整數和轉換后浮點數的尾數
ACCBHI EQU 24
EXPB EQU 25 ;存放轉換后浮點數的階碼
ACCCLO EQU 26 ;臨時寄存器
ACCCHI EQU 27 ;臨時寄存器
ACCDLO EQU 28 ;臨時寄存器
ACCDHI EQU 29 ;臨時寄存器
SIGN EQU 2B ;存放被轉換數的符號
ORG 0X0000
START GOTO MAIN
ORG 0X0100
;*********雙字節定點整數到浮點數轉換子程序***********
DtoF CLRF SIGN ;根據被轉換數確定結果的符號,對負數取補
BTFSS ACCBHI,7
GOTO INTF1
BSF SIGN,7
CALL NEG_B
INTF1 MOVLW .15 ;初始化EXPB
MOVWF EXPB
CLRF ACCCHI
CLRF ACCCLO
CALL F_norm ;對ACCB進行規格化
BTFSS SIGN,7 ;結果為負?
GOTO DtoF1
CALL NEG_B ;是,求補
DtoF1 RETURN
;**************浮點數規格化子程序**************
F_norm MOVF ACCBHI ;ACCB=0?
BTFSS STATUS,Z
GOTO C_norm
MOVF ACCBLO
BTFSC STATUS,Z
RETLW 0 ;是,不需規格化,返回
C_norm BTFSC ACCBHI,7 ;否。ACCB為負?
GOTO C_norm2
C_norm1 BTFSC ACCBHI,6 ;為正。規格化完畢?
RETLW 0 ;ACCBHI.6=1,規格化結束
CALL SHFTSL ;否。ACCB左移
DECF EXPB ;EXPB減1
GOTO C_norm1 ;重新判斷規格化完畢否?
C_norm2 BTFSS ACCBHI,6 ;ACCB為負。規格化完畢否?
RETLW 0 ;ACCBHI.6=0,規格化結束
BCF STATUS,C
CALL SHFTSL ;否,ACCB左移
BSF ACCBHI,7 ;加符號
DECF EXPB ;EXPB減1
GOTO C_norm2 ;重新判斷規格化完畢否?
SHFTSL BCF STATUS ,C ;ACCB左移子程序
RLF ACCCLO
RLF ACCCHI
RLF ACCBLO
RLF ACCBHI
RETLW 0
【校驗舉例1】 19531(十進制)
化為十六進制數:4C4BH
結果:4C4B0FH
【校驗舉例2】 2622(十進制)
化為十六進制數: 0A3EH
結果:51F00CH
【例程】
MAIN MOVLW 0X4B ;被轉換數4C4BH送ACCB
MOVWF ACCBLO
MOVLW 0X4C
MOVWF ACCBHI
CALL DtoF ;調用定點數至浮點數轉換子程序
END