winnie 发表于 2009-5-5 17:32:32

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

4.23字节浮点数转换为定点整数
子程序的转换结果将采用补码表示。其转换数值范围:-32768~32767,入口条件和出口条件如下:
入口条件:ACCBHI、ACCBLO、EXPB
出口条件:ACCBHI、ACCBLO
    以下为子程序的清单。由于程序所需调用的子程序和所需通用寄存器单元地址和定点数转换为浮点数子程序相同,在此省略。使用时,将前面介绍的子程序拷入此处即可。
FtoD    CLRF         SIGN            ;清结果符号寄存器
    MOVF         ACCBHI,0
    BTFSS         ACCBHI,7    ;被转换数是否为负?
    GOTO         D1
    BSF             SIGN,7      ;是,SIGN.7置1
    CALL         NEG_B      ;被转换数取补
D1    BTFSS         EXPB,7      ;被转换数为正,再判阶码为负否?
    GOTO         D2
    CLRF         ACCBHI      ;为负,被转换数小于1,无法用定点数表示
    CLRF         ACCBLO
    RETLW         0
D2    MOVLW         .16            ;被转换数阶码减16(十进制数)
    SUBWF         EXPB,0
    BTFSS         STATUS,C    ;阶码小于16?
    GOTO         D3
      MOVLW         0XFF            ;阶码大于等于16,置ACCB为最大,返回
    MOVWF         ACCBHI
    MOVWF         ACCBLO
    RETLW         01
D3    CALL         FTOW3      ;调用子程序将浮点数转换为定点数
    BTFSC         SIGN,7      ;定点数为负?
    CALL         NEG_B      ;是,取补
    RETLW         0            ;否,返回
;****************************************
FTOW3    MOVLW         .15            ;EXPB=15(十进制数)?
    SUBWF         EXPB,0
    BTFSC         STATUS,Z
    RETLW         0            ;是,返回
    BCF             STATUS,C    ;否,ACCB继续右移,EXPB加1
    RRF             ACCBHI
    RRF             ACCBLO
    INCF         EXPB
    GOTO         FTOW3      ;重新判断EXPB=15?
【校验举例1】 19531(十进制)
化为十六进制数:4C4B0FH
结果:4C4BH
【校验举例2】 2622(十进制)
化为十六进制数:51F00CH
结果:0A3EH
【例程】
MAIN      MOVLW      0X4B      ;被转换数4C4BH送ACCB
    MOVWF      ACCBLO
    MOVLW      0X4C
    MOVWF      ACCBHI
    MOVLW      0X0F
    MOVWF      EXPB
      CALL      FtoD            ;调用定点数至浮点数转换子程序
    END
5码制转换程序设计
5.1   双字节定点数至5位BCD码转换程序
    入口条件:ACCBHI、ACCBLO
    出口条件:ACCCHI低半字节、ACCCLO、ACCDHI
以下为双字节定点数至5位BCD码转换程序清单。
    LIST            p=16f877
    INCLUDE      p16f877.inc
    ACCBLO         EQU   23      ;存放被转换的双字节整数低8位
    ACCBHI         EQU   24      ;存放被转换的双字节整数高8位
    ACCCLO         EQU   26      ;存放5位BCD码
    ACCCHI         EQU   27
    ACCDLO         EQU   28
    ACCDHI         EQU   29
    TEMP         EQU   2A      ;临时寄存器
    SIGN         EQU   2B      ;被转换数符号寄存器
    ORG            0X0000
START    GOTO      MAIN
    ORG            0X0100
;**********双字节数至BCD码子程序************
BtoBCD    CLRF      SIGN            ;初始化符号寄存器
    BTFSS      ACCBHI,7    ;被转换数为负?
    GOTO      LOOP1      ;否,转BtoBCD
    BSF            SIGN,7      ;是,存符号
    CALL      NEG_B      ;ACCB取补
LOOP1    BCF             STATUS,C    ;清进位位
    MOVLW         .16            ;移位计数器赋初值
    MOVWF         COUNT
    CLRF         ACCCHI      ;初始化出口寄存器
    CLRF         ACCCLO
    CLRF         ACCDHI
LOOP16    RLF             ACCBLO      ;ACCB左移一位至出口寄存器
    RLF             ACCBHI
    RLF             ACCDHI
    RLF             ACCCLO
    RLF             ACCCHI
    DECFSZ         COUNT         ;移位计数器=0?
    GOTO         ADJDEC      ;否,转ADJDEC
    RETLW         0            ;是,返回
ADJDEC    MOVLW         ACCDHI      ;指针指向ACCDHI
    MOVWF         FSR
    CALL         ADJBCD      ;调用BCD码校正子程序
    MOVLW         ACCCLO      ;指针指向ACCCLO
    MOVWF         FSR
    CALL         ADJBCD      ;调用BCD码校正子程序   
    MOVLW         ACCCHI      ;指针指向ACCCHI
    MOVWF         FSR
    CALL         ADJBCD      ;调用BCD码校正子程序
    GOTO         LOOP16      ;ACCB重新左移
;************* BCD码校正子程序**************
ADJBCD   MOVLW         00X03      ;LSD+3>7?
    ADDWF         INDF,0
    MOVWF         TEMP
    BTFSC         TEMP,3
    MOVWF         INDF         ;是,LSD=LSD+3
    MOVLW         0X30            ;否,MSD+3>7?
    ADDWF         INDF,0
    MOVWF         TEMP
    BTFSC         TEMP,7
    MOVWF         INDF            ;是,MSD=MSD+3
    RETLW         0            ;返回
【校验举例1】 -23808(十进制)
化为十六进制数:A300
结果:023808(BCD),SIGN=80
【校验举例2】 12306(十进制)
化为十六进制数: 3012
结果:012306(BCD),SIGN=00
【例程】
MAIN      MOVLW      0X00            ;双字节整数送ACCB
    MOVWF      ACCBLO
    MOVLW      0XA3
    MOVWF      ACCBHI
    CALL      BtoBCD      ;调子程序,将二进制数转换成BCD码
    END

5.23字节浮点数至5位压缩BCD码转换程序

图2.6浮点数至5位压缩BCD码转换程序
程序通过3个步骤将一个3字节浮点数转换成5位压缩BCD码(压缩BCD码是指将两个BCD码分别存放在一个8位字节的高半字节和低半字节中)。首先,判断浮点数的符号,如果是负数,存符号位,并将之取补。其次,调用浮点数乘法或除法子程序,对浮点数进行连续的乘以10或除以10的操作,把浮点的阶码控制在+12≤EXPB<+16之间,即使得浮点数转换成定点数后,数值在4095(FFFH)和32767(7FFFH)之间。再次,调用浮点数至定点数子程序,将浮点数转换成双字节定点数。最后,调用定点数至BCD码子程序,将双字节无符号数转换成5位压缩BCD码,从而完成浮点数至压缩BCD码的转换。此外,乘以10或除以10的次数可以用来确定小数点的位置。在子程序中,乘以10或除以10的次数分别存在C_MUL和C_DIV单元中,但二者不可能同时大于0(二者不可能同时小于0,但可以同时等于0)。其中,当C_MUL>0时(此时,C_DIV必然等于0),表示小数点从BCD码的最后往前移动C_MUL位;当C_DIV>0时(此时,C_MUL必为0),表示小数点由BCD码的最后往后移动C_DIV位。转换后的BCD码的符号存于FPOL单元的第7位。
在该子程序中要调用大量的子程序,如浮点数乘法子程序、浮点数除法子程序、浮点数至定点数转换子程序和定点数至BCD码转换子程序等。在此由于篇幅的原因都予以省略,需要这些子程序的读者,请参阅前面相关章节。
浮点数至压缩BCD码转换程序的入口条件和出口条件如下:
入口条件:ACCBHI、ACCBLO、EXPB
出口条件:5位压缩BCD码存于ACCCHI低半字节、ACCCLO和ACCDHI中,符号保存于FPOL寄存器的第7位,小数点位置存于C_MUL和C_DIV中。
以下为本子程序的程序清单。

    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      ;临时寄存器
    C_MUL         EQU   2C      ;存放小数点位置
    C_DIV         EQU   2D      ;存放小数点位置
    FPOL         EQU   2E      ;存放被转换数的符号
    ORG            0X0000
START    GOTO      MAIN
    ORG            0X0100
;*************浮点数到BCD码子程序****************
FtoBCD    CLRF         C_MUL      ;清小数点位数寄存器
    CLRF         C_DIV
    CLRF         ACCAHI      ;求取结果符号,存于FPOL.7
    CALL         S_SIGN
    MOVF         SIGN ,0
    MOVWF      FPOL
    MOVLW         50            ;ACCA赋初值,ACCA=10(十进制)
    MOVWF         ACCAHI
    CLRF         ACCALO
    MOVLW         04
    MOVWF         EXPA
MUl5    BTFSS      EXPB,7      ;阶码EXPB<0?
    GOTO      MUl2      ;否,转MU12
MUl1    CALL         F_mpy      ;是,ACCA×10
    INCF         C_MUL      ;小数点左移寄存器加1
    GOTO         MUl5      ;重新判断阶码是否小于零
MUl2    MOVLW         .12            ;阶码EXPB<12?
    SUBWF         EXPB,0
    BTFSC         STATUS,C
    GOTO         MUl4      ;否,转MU14
MUl3    CALL         F_mpy      ;是,ACCA×10
    INCF         C_MUL      ;小数点左移寄存器加1
    GOTO         MUL2      ;重判阶码值
MUl4    MOVLW         .16            ;阶码EXPB>16?
    SUBWF         EXPB,0
    BTFSS      STATUS,C
    GOTO         NEXT      ;否,表示阶码12≤EXPB<16,求取BCD码值
DIV1    CALL         FDIV            ;是,EXPB÷10
    INCF         C_DIV      ;小数点右移寄存器加1
    GOTO         MUl4      ;重新判断阶码值
NEXT    CALL         FTOW3      ;调子程序,将浮点数转换为定点数
    CALL         BtoBCD      ;调双字节数到BCD码子程序,求BCD码
    MOVF         ACCCHI      ;ACCCHI=0?
    BTFSS         STATUS,Z
    RETLW         0            ;否,返回
    MOVLW         04            ;是,结果左移4次,保证ACCCHI不为零
    MOVWF         TIMES
    BCF             STATUS,C
MUl6    RLF             ACCDHI
    RLF            ACCCLO
    RLF             ACCCHI
    DECFSZ         TIMES
    GOTO         MUl6
    MOVF         C_DIV      ;C_DIV=0?
    BTFSC         STATUS,Z
    GOTO         TEMUL      ;是,转判断C_MUL
    DECF         C_DIV      ;否,小数点右移寄存器减1
    RETLW         0
TEMUL    INCF         C_MUL      ;小数点左移寄存器加1
    RETLW         0   
【校验举例1】 -5.8125(十进制)
化为浮点数:A30003
结果:058120(BCD),C_MUL=4,C_DIV=0,FPOL=A3
【校验举例2】 0.00048881(十进制)
化为浮点数:4012F6
结果:048870(BCD),C_MUL=08,C_DIV=0,FPOL=40
【例程】
MAIN    MOVLW      0X00            ;将被转换数的尾数赋给ACCB
    MOVWF      ACCBLO
    MOVLW      0XA3
    MOVWF      ACCBHI
    MOVLW      0X03            ;将被转换数的阶码赋给EXPB
    MOVWF      EXPB
    CALL      FtoBCD      ;调用子程序开始转换
    END
6定点数开方子程序
    从数值计算方法可知,方程G(X)=0可以由牛顿迭代法来求解。牛顿迭代法的一个重要应用就是开平方,就是通过对以下方程求解得到M的平方根:

函数G(X)在X0点用一阶泰勒级数展开可得:

如果Y是方程G(X)=0的根,那么G(Y)=0,即:

忽略高阶项,而只取前两项,就可以得到根Y的近似值,即

把此方程写成离散形式的迭代方程为:


又因为: ,所以 ,代入迭代方程可得:

这里M的平方根初值取M/2。如果在此之前知道M的平方根的范围,则可以取一个比M/2更好的初值开始迭代,可以减少迭代的次数。
如果被开方数是定点数格式,代入的迭代初值也是定点数格式,并且用定点除法(定点数的除2操作可以由右移一位得到)和定点加法进行迭代运算,则就是定点数开方。
定点数开方只能得到结果的整数部分,如代入FFFFH和FF10H的开方结果都是一样的,为FFH。如果想要得到比较精确的结果,可以先对被开方数乘以一个系数,待得到结果后,再除以相应的系数。如果被开方数太大,则不能使用此法,若想得到比较精确的结果,可以采用后面介绍的“浮点数开方”。
以下为定点数开方的程序清单(其中包含校验程序部分)。该程序中包含定点数加法程序和定点数除法程序。

    LIST            p=16f877
    INCLUDE      p16f877.inc
;****************************************
;此子程序是求16位二进制数平方根的子程序,需要调用16/16位除法子程序和
;加法子程序,虽然前面有了,但标号有些不同,为了易于阅读和理解,也把它列在后面。
;入口条件:16位二进制数存放在NUMHI和NUMLO单元中。
;出口条件:8位二进制数存放在SQRTLO单元中。
;迭代次数由LUPCNT的地址值决定。
;用指令CALL      SQRT实现定点数开方程序调用
;****************************************
   ACCALO      EQU      0X20
    ACCAHI      EQU      ACCALO+1
    EXPA      EQU      ACCALO+2
    ACCBLO      EQU      ACCALO+3
    ACCBHI      EQU      ACCALO+4
    EXPB      EQU      ACCALO+5   
    ACCCLO      EQU      ACCALO+6
    ACCCHI      EQU      ACCALO+7
    ACCDLO      EQU      ACCALO+8
    ACCDHI      EQU      ACCALO+9
    TEMP      EQU      ACCDHI+1
    SIGN            EQU      ACCDHI+2
    SQRTLO      EQU      ACCALO
    SQRTHI      EQU      ACCAHI
    NUMLO      EQU      ACCDHI+4
    NUMHI      EQU      ACCDHI+5
    COUNT    EQU    ACCDHI+6    ;此方法定义的数据块为连续层断,只要
                ;将第一行改变,就可以将数据整块搬动到
                ;新的地方,为调试带来方便,是比较推
                ;崇的一种寄存器定义方法
    LUPCNT    EQU    .10   
;****************************************
      ORG            0X00
      GOTO      MAIN
      ORG            0X10
;****************************************
INIT      MOVLW      LUPCNT
    MOVWF      COUNT
    MOVF      NUMHI,0
    MOVWF         SQRTHI
    MOVF      NUMLO,0
    MOVWF      SQRTLO
    BCF            STATUS,C
    RRF            SQRTHI,1
    RRF            SQRTLO,1
    RETLW      0
;***************16×16位定点数右移子程序***************
DIV2      BCF            STATUS,C
    RRF            ACCBHI,0
    MOVWF      SQRTHI
    RRF            ACCBLO,0
    MOVWF      SQRTLO
    RETLW      0
;*********16×16位定点数开方子程序**********
SQRT    CALL      INIT
SLOOP    MOVF      NUMLO,0
    MOVWF      ACCBLO
    MOVF      NUMHI,0
    MOVWF      ACCBHI
    CALL      D_DIVS
    CALL      D_ADD
    CALL      DIV2
    DECFSZ      COUNT,1
    GOTO      SLOOP
    RETURN
;***********16×16位定点整数除法子程序*********
D_DIVS    CALL      SETUP
      CLRF      ACCCHI
      CLRF      ACCCLO
DLOOP    BCF            STATUS,C
    RLF            ACCDLO
    RLF            ACCDHI
    RLF            ACCCLO
    RLF            ACCCHI
    MOVF      ACCAHI,0
    SUBWF      ACCCHI,0
    BTFSS      STATUS,Z
    GOTO      NOCHK
    MOVF      ACCALO,0
    SUBWF      ACCCLO,0
NOCHK    BTFSS      STATUS,C
      GOTO         NOGO
    MOVF      ACCALO,0
    SUBWF      ACCCLO,1
    BTFSS      STATUS,C
    DECF      ACCCHI,1
    MOVF      ACCAHI,0
    SUBWF      ACCCHI,1
    BSF            STATUS,C
NOGO    RLF            ACCBLO
    RLF            ACCBHI
    DECFSZ      TEMP
    GOTO      DLOOP
    RETLW      0
;****************************************
SETUP    MOVLW      .16
    MOVWF      TEMP
    MOVF      ACCBHI,0
    MOVWF      ACCDHI
    MOVF      ACCBLO,0
    MOVWF      ACCDLO
    CLRF      ACCBHI
    CLRF      ACCBLO
    RETLW      0
;**********16×16位定点数取补子程序**************
NEG_A    COMF      ACCALO,1
    INCF            ACCALO,1
    BTFSC      STATUS,Z
    DECF      ACCAHI,1
    COMF      ACCAHI,1
    RETLW      0
;*************16×16位定点数加法子程序**************
D_ADD    MOVF      ACCALO,0
    ADDWF      ACCBLO,1
    BTFSC      STATUS,C
    INCF            ACCBHI,1
    MOVF      ACCAHI,0
    ADDWF      ACCBHI,1
    RETLW      0
;****************************************
【校验举例】 被开方数2910H(十六进制)
                  10512(十进制)
    求得平方根:66H(十六进制)
                  102(十进制)
MAIN    NOP
    MOVLW      0X29   
    MOVWF      NUMHI
    MOVL7W      0X10
    MOVWF      NUMLO                ;被开方数赋值
    CALL      SQRT                ;调用开方子程序      
    NOP                              ;开方完毕
    END
7浮点数开方程序
    如果被开方数是浮点数格式,代入的迭代初值也是浮点数格式,并且用浮点除法(浮点数的除以2操作可以由阶码减1得到)和浮点加法进行迭代运算,就是浮点数开方的基本思路。
以下为浮点数开方的程序清单(其中包含校验程序部分)。该程序中包含浮点数加法程序和浮点数除法程序,这些程序与前面章节列出的程序完全相同,不再列出。

      LIST            P=16f877
      INCLUDE      p16f877.inc
;****************************************
;此子程序是16尾数,8位阶码开方程序
;入口条件:浮点数存放在ACCBHI和ACCBLO   EXPB单元中.
;出口条件:结果放在ACCBHI和ACCBLO EXPB单元中.
;迭代次数由LUPCNT的地址值决定
;用CALLSQRTF指令调用,
;内含浮点除程序,浮点加减程序
;****************************************
      ACCALO         EQU         20H
      ACCAHI         EQU         ACCALO +1
      EXPA         EQU         ACCALO +2
      ACCBLO         EQU         ACCALO +3
      ACCBHI      EQU         ACCALO +4
      EXPB         EQU         ACCALO +5
      ACCCLO         EQU         ACCALO +6
      ACCCHI         EQU         ACCALO +7
      ACCDLO         EQU         ACCALO +8
      ACCDHI         EQU         ACCALO +9
      TEMP         EQU         ACCALO +0A
      TEMP1         EQU         ACCALO +0B
      TIMES         EQU         ACCALO +0C
      SIGN         EQU         ACCALO +0D
      COUNT         EQU         ACCALO +0E
      C_MUL         EQU         ACCALO +0F
    C_DIV         EQU         ACCALO +10
      FPOL         EQU         ACCALO +11      ;符号放置位
      NUMLO      EQU      FPOL+1
      NUMHI      EQU      FPOL+2
      NUMM      EQU      FPOL+4
         LUPCNT      EQU      .10
      CONSTANT   C=0
      CONSTANT   Z=2
      CONSTANT   MODEL16=1
      CONSTANT   FALSE=0
;****************************************
      ORG            0X0000
      NOP
      GOTO      MAIN
      ORG            0X0010
;****************************************
INIT1    DECF      EXPB            ;假设迭代根的初始值为其原值的一半
    MOVF      ACCBHI,W
    MOVWF      ACCAHI
    MOVF      ACCBLO,W
    MOVWF      ACCALO
    MOVF      EXPB,W
    MOVWF      EXPA
    RETLW      0
SQRTF    MOVLW      LUPCNT
    MOVWF      COUNT
    MOVF      ACCBHI,W
    MOVWF      NUMHI
    MOVF      ACCBLO,W
    MOVWF      NUMLO
    MOVF      EXPB,W
    MOVWF      NUMM            ;存储被开方的数
    BTFSC      ACCBHI,7
    GOTO      TIQIAN            ;如果被开方数是个负数,则返回一极小数
    CALL      INIT1
SLOOP1    MOVF      NUMLO,0
      MOVWF      ACCBLO
      MOVF      NUMHI,0
    MOVWF      ACCBHI
    MOVF      NUMM,0
    MOVWF      EXPB
    CALL      FDIV
    CALL      F_add
    CALL      INIT1
    DECFSZ      COUNT,1
    GOTO      SLOOP1
    RETURN
TIQIAN    MOVLW      0X40
    MOVWF      ACCBHI
    CLRF      ACCBLO
    MOVLW      0X80
    MOVWF      EXPB      ;如果被开方数是一个负数,返回一个极小的浮点数
    RETURN      
;***浮点加子程序F_add详细的程序语句请参考前面章节***
;***浮点数除法子程序FDIV详细的程序语句请参考前面章节***
【校验举例】被开方数55AAH,02H(浮点数)
    求得平方根:68B6H,01H(浮点数)
MAIN    NOP
    MOVLW      0X55
    MOVWF      ACCBHI               
    MOVLW      0XAA
    MOVWF      ACCBLO      ;被开方数的尾数55AAH赋值
    MOVLW      0X02
    MOVWF      EXPB      ;被开方数的阶码02H赋值
    CALL      SQRTF      ;调用浮点开方子程序
    NOP                        ;开方完毕,结果在ACCBHI、ACCBLO、EXPB
      END   
8小数点显示位置确定子程序
在实际应用中,往往需要将一个浮点数表示的十进制数用数码管显示出来。当用户调用浮点数至BCD码子程序FtoBCD将这个浮点数转换成BCD码后,除了可以得到5位BCD码外,C_MUL和C_DIV寄存器中还有一个值用于确定哪个数码管该显示小数点。例如,设某浮点数调用译码子程序后,得到以下数值:012345(BCD),C_MUL=07,C_DIV=0,那么数码管显示的值应该为:0.0012345,1号数码管除了要显示0外,还要将小数点显示出来。以下子程序将完成这一功能。此外,一般而言,工程应用和实验中,多数要求显示4位有效数字,其显示范围在0.001~9999(符号没显示,如有需要,请读者自己添上)。如果要求显示数据超过9999,则4个LED显示“1111”;如果要求显示数据小于“0.001”,则4个LED显示“0000”(如果实际要求显示多于4位有效数字,则读者可以对本程序作相应的修改,就可以满足要求)。本子程序入口条件和出口条件分别如下:
    入口条件:ACCCHI1、ACCCLO1、ACCDHI1、ZUO、YOU;
    出口条件:DISP1、DISP2、DISP3、DISP4、LEDDOT(DISP1、DISP2、DISP3、DISP4用于存放显示的数字,LEDDOT用于存放小数点的位置)。
    注意,该子程序的入口条件和FtoBCD子程序的出口条件有如下对应关系:
ACCCHI1与ACCCHI对应,ACCCLO1与ACCCLO对应,ACCDHI1与ACCDHI对应,ZUO与C_MUL对应,YOU与C_DIV对应
用户在调用FtoBCD子程序后,可以用下面一段语句与该程序实现接口。
    CALL      FtoBCD
    MOVF      ACCCHI,W
    MOVWF      ACCCHI1
    MOVF      ACCCLO,W
    MOVWF      ACCCLO1
    MOVF      ACCDHI,W
    MOVWF      ACCDHI1
    MOVF      C_MUL,W
    MOVWF      ZUO
    MOVF      C_DIV,W
    MOVWF      YOU
    CALL      TESTDOT
本子程序的程序清单如下:
;**********小数点位置及显示寄存器值确定子程序************
TESTDOT      BANKSEL      LEDDOT
    CLRF      LEDDOT      ;清除小数点位置寄存器   
    MOVF      ZUO,W
    MOVWF      C_MUL1   
    MOVF      YOU,W
    BTFSS      STATUS,Z
    GOTO      CHAOCHU1
    MOVF      ZUO,W
    BTFSC      STATUS,Z
    GOTO      CHAOCHU1   ;C_DIV>0或C_MUL=0,表示浮点数超出显示
;范围上限,转移到过量程处理
    MOVF      ZUO,W
    SUBLW      0X07
    BTFSS      STATUS,C
    GOTO      TAIXIAO      ;C_MUL>7,超出显示范围下限,转移处理(改
;变与C_MUL比较的立即数的大小,可以改变
;下限)
    MOVF      ZUO,W
    SUBLW      0X01
    BTFSC      STATUS,Z
    GOTO      ZHUANG1      ;C_MUL=1,表示小数点左移1位,能够显示前
   ;4位(ACCCHI低半字节中始终有1位),转移处理
    MOVF      ZUO,W      ;同理可以对左移2~7位处理
    SUBLW      0X02
    BTFSC      STATUS,Z
    GOTO      ZHUANG2
    MOVF      ZUO,W
    SUBLW      0X03
    BTFSC      STATUS,Z
    GOTO      ZHUANG3
    MOVF      ZUO,W
    SUBLW      0X04
    BTFSC      STATUS,Z
    GOTO      ZHUANG4
    MOVF      ZUO,W
    SUBLW      0X05
    BTFSC      STATUS,Z
    GOTO      ZHUANG5
    MOVF      ZUO,W
    SUBLW      0X06
    BTFSC      STATUS,Z
    GOTO      ZHUANG6
    MOVF      ZUO,W
    SUBLW      0X07
    BTFSC      STATUS,Z
    GOTO      ZHUANG7
CHAOCHU1    MOVLW      0X01
      MOVWF      DISP1
      MOVWF      DISP2
      MOVWF      DISP3
      MOVWF      DISP4
      MOVLW      0XFF
      MOVWF      LEDDOT      ;不显示小数点
      RETURN                  ;超出上限时,DSP1、 DSP2、 DSP3、 DSP4中赋
;1,显示“1111”
TAIXIAO      MOVLW      0X00
      MOVWF      DISP1
      MOVWF      DISP2
      MOVWF      DISP3
      MOVWF      DISP4
      MOVLW      0X01
      MOVWF      LEDDOT      ;小数点的位置在第一位   
      RETURN                  ;超出下限,显示"0.000"
ZHUANG1      CALL      BIAO      ;C_MUL=1~4时,可调用标准赋值模块对
                              ;DSP1、 DSP2、DSP3、 DSP4赋值
      MOVLW      0X04
      MOVWF      LEDDOT      ;C_MUL=1时,小数点的位置在第4位
      RETURN
ZHUANG2      CALL      BIAO
      MOVLW      0X03
      MOVWF      LEDDOT      ;C_MUL=2时,小数点的位置在第3位
      RETURN
ZHUANG3      CALL      BIAO
      MOVLW      0X02
      MOVWF      LEDDOT      ;C_MUL=3时,小数点的位置在第2位
      RETURN
ZHUANG4      CALL      BIAO
      MOVLW      0X01
      MOVWF      LEDDOT      ;C_MUL=4时,小数点的位置在第1位
      RETURN
ZHUANG5      CLRF      DISP1      ;C_MUL=5时,DSP1=0
      MOVF      ACCCHI1,W   ;DSP2=ACCHI1低字节,DSP3和DSP4分别对
                                 ;应ACCCLO1的高低字节,ACCDHI1不显示(太小),
      MOVWF      DISP2         ;ACCDHI1的低字节一直没有显示
      MOVF      ACCCLO1,0
      MOVWF      C_MUL1
      SWAPF      ACCCLO1
      MOVLW      0X0F
      ANDWF      ACCCLO1,0
      MOVWF      DISP3
      MOVLW      0X0F
      ANDWF      C_MUL1,0
      MOVWF      DISP4
      MOVLW      0X01
      MOVWF      LEDDOT      ;小数点的位置在第1位      
      RETURN
ZHUANG6      CLRF      DISP1      ;C_MUL=6时,DSP1=0
      CLRF      DISP2      ;DSP2=0,DSP3=ACCCHI1的低字节,
                              ; DSP4=ACCCLO1的高字节,ACCCLO1低字
                              ;节和ACCDHI1不显示
      MOVF      ACCCHI1,W
      MOVWF      DISP3
      SWAPF      ACCCLO1
      MOVLW      0X0F
      ANDWF      ACCCLO1,0
      MOVWF      DISP4
      MOVLW      0X01
      MOVWF      LEDDOT      ;小数点的位置在第1位   
      RETURN
ZHUANG7      CLRF      DISP1      ;C_MUL=7时,DSP1=DSP2=DSP3=0,
                              ; DSP4=ACCCHI1低半字节,其它不显示
      CLRF      DISP2
      CLRF      DISP3
      MOVF      ACCCHI1,W
      MOVWF      DISP4
      MOVLW      0X01
      MOVWF      LEDDOT      ;小数点的位置在第1位   
      RETURN
BIAO      MOVF      ACCCHI1,W    ;C_MUL=1~4时的标准赋值模块
      MOVWF      DISP1
      SWAPF      ACCDHI1
      MOVLW      0X0F
      ANDWF      ACCDHI1,0
      MOVWF      DISP4
      MOVF      ACCCLO1,0
      MOVWF      C_MUL1
      SWAPF      ACCCLO1
      MOVLW      0X0F
      ANDWF      ACCCLO1,0
      MOVWF      DISP2
      MOVLW      0X0F
      ANDWF      C_MUL1,0
      MOVWF      DISP3
      RETURN
   执行完该程序后,通过调用适合的子程序,就可以方便地实现小数点位置的浮动显示(即若被显示的数突然从99.99变化到999.9,则程序自动实现小数点位置的调整。)
页: [1]
查看完整版本: PIC单片机运算子程序(2)