英锐恩单片机论坛,Microchip单片机,模拟器件,接口电路,麦肯单片机,单片机应用交流

标题: PIC单片机运算子程序(1) [打印本页]

作者: winnie    时间: 2009-5-5 17:33
标题: PIC单片机运算子程序(1)
PIC16F877单片机运算子程序
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         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




欢迎光临 英锐恩单片机论坛,Microchip单片机,模拟器件,接口电路,麦肯单片机,单片机应用交流 (http://enroobbs.com/) Powered by Discuz! X3.2