winnie 发表于 2009-5-5 17:33:25

PIC单片机运算子程序(1)

PIC16F877单片机运算子程序
1PIC16F877汇编语言程序主体框架
以下是一个典型的程序结构:
;***************程序说明区*******************
    LIST    p=16f877    ;指定微控制器型号和文件输出格式
    INCLUDE    p16f877.inc    ;读入MPLAB提供的定义文件P16F877.INC
;***片内RAM常用资源、变量定义和相应的说明*********
    ACCALO    EQU20    ;存放加数或减数低8位
    ACCAHI   EQU21    ;存放加数或减数高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.116×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.216×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.316×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
33字节浮点四则运算子程序
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
页: [1]
查看完整版本: PIC单片机运算子程序(1)