以下为双字节定点数至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
3字节浮点数至5位压缩BCD码转换程序
浮点数至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&pide;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