📄 字节浮点数至5位压缩bcd码转换程序.txt
字号:
还少程序
;【校验举例1】 -5.8125(十进制)
;化为浮点数:A30003
;结果:058120(BCD),C_MUL=4,C_DIV=0,FPOL=A3
; 5.2 3字节浮点数至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 20H ;临时寄存器
ACCAHI EQU 21H
EXPA EQU 22H ;临时寄存器
ACCBLO EQU 23H ;存放被转换浮点数尾数
ACCBHI EQU 24H
EXPB EQU 25H ;存放被转换浮点数阶码
ACCCLO EQU 26H ;临时寄存器
ACCCHI EQU 27H ;临时寄存器
ACCDLO EQU 28H ;临时寄存器
ACCDHI EQU 29H ;临时寄存器
TEMP EQU 2AH ;临时寄存器
TEMP1 EQU 30H ;临时寄存器
TIMES EQU 31H ;临时寄存器
SIGN EQU 2BH ;临时寄存器
COUNT EQU 2FH ;临时寄存器
C_MUL EQU 2CH ;存放小数点位置
C_DIV EQU 2DH ;存放小数点位置
FPOL EQU 2EH ;存放被转换数的符号
FULL EQU 2FH ; 2F.0进位标志
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
SETUP MOVLW .15 ;初始化TEMP寄存器
MOVWF TEMP
MOVF ACCBHI,0 ;ACCB送ACCD
MOVWF ACCDHI
MOVF ACCBLO,0
MOVWF ACCDLO
CLRF ACCBHI ;清ACCB
CLRF ACCBLO
RETURN ;子程序返回
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?
;**********双字节数至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 0X03 ;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 ;返回
;***双字节加法子程序,入口地址ACCB+ACCA,出口地址ACCB***
D_add MOVF ACCALO,0 ;ACCB和ACCA低半字节相加
ADDWF ACCBLO
BTFSC STATUS,C ;有进位否?
goto $+6 ;有,
MOVF ACCAHI,0 ;ACCA、ACCB高半字节相加
ADDWF ACCBHI
BTFSC STATUS,C
BSF FULL,0
RETURN ;子程序返回
MOVFW ACCBHI ;ACCB高字节加1,再加ACCAHI
ADDLW 1h
BTFSC STATUS,C ;有进位否?
BSF FULL,0
MOVWF ACCBHI
GOTO $-D'10'
;***浮点乘法子程序,入口地址(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 ;乘法结束,子程序返回
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
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 ;返回
NEG_A COMF ACCALO ;ACCALO取反加1
INCF ACCALO
BTFSC STATUS,Z ;低8位有进位吗?
DECF ACCAHI ;有,ACCAHI减1,再取反
COMF ACCAHI ;否,ACCAHI直接取反
RETLW 0
MAIN MOVLW 0X00 ;将被转换数的尾数赋给ACCB
MOVWF ACCBLO
MOVLW 0XA3
MOVWF ACCBHI
MOVLW 0X03 ;将被转换数的阶码赋给EXPB
MOVWF EXPB
CALL FtoBCD ;调用子程序开始转换
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -