搜索
bottom↓
回复: 9

【分享】浮点数转压缩BCD码源代码 for IAR_AVR

[复制链接]

出0入0汤圆

发表于 2008-2-3 14:42:11 | 显示全部楼层 |阅读模式
本程序是根据 陈远征的浮点数变为压缩BCD码 FOR 51 源代码移植过来的,并做了修正。
全部是用汇编写,可提供C函数调用,有了这个函数,浮点数转字符串就可以不用sprintf了,无论占用空间或时间都优于sprintf甚多。

功能:将符合IEEE574标准的浮点数变为压缩BCD码,保存在以数组 CYZ 中
      第1字节的位7:0正,1负.位6:0(位5--0代表小数点前的位数),1(位5--0代表小数点后0的位数)
      2--4字节为压缩BCD码,有效位为7位,3个半字节,最后半个字节请使用者自行放弃
      SP深度6,RAM 5个放数据

调用了两个数学库函数:1、浮点数乘法 2、无符号字节除法(AVR没有除法指令啊)

IAR中的浮点数形参传递规则:
                                      R19      R18      R17       R16
参数传递在R19--R16中,浮点数IEEE标准seeeeeee emmmmmmm mmmmmmmm mmmmmmmm

主要思路:
   把IEEE574标准的浮点数进行放大10^10(10的10次方)倍(浮点运算),使其≤10^10和≥10^0(即 1),再查表找出他的数量级,再除以数量级(浮点运算)得到二进制的纯小数(还是IEEE574标准),再进行规格化变为二进制纯小数,尾数乘以100得到整数部分就是十分位和百分位,再十分位和百分位得到整数部分就是千分位和万分位....,再每次乘以100得到整数转换为BCD码,最后进行四舍五入,存档即可。

用到的知识:
1、浮点数IEEE标准
2、浮点数比较
3、查表
4、浮点数标准化
5、多字节乘法
6、BCD码加法
7、IAR的参数传递规则

主要修正:在陈远征的51程序中,多字节乘法没有考虑字节间进位(乘以100时),因此,有个别数转换误差较大,比如1.002,他转换为1.001609
我的这个版本中已经修复了这个问题。

欢迎测试和使用。

源代码:

;------------------------------------FloatToBCD.s90文件-----------------------

NAME   FloatToBCD

#include  <ioavr.h>

PUBLIC   FloatToBCD
EXTERN   ?F_MUL_L04
EXTERN   ?UC_DIVMOD_L01
EXTERN   CYZ

RSEG    CODE:CODE

;程序说明:浮点数变为压缩BCD码,保存在以数组 CYZ 中
;         第1字节的位7:0正,1负.位6:0(位5--0代表小数点前的位数),1(位5--0代表小数点后0的位数)
;         2--4字节为压缩BCD码,有效位为7位,3个半字节,最后半个字节请使用者自行放弃
;         SP深度6,RAM 5个放数据

;参数传递在R19--R16中,浮点数IEEE标准seeeeeee emmmmmmm mmmmmmmm mmmmmmmm

FloatToBCD:
    ;保存符号位
    MOV     R24, R19  
    ANDI    R24, 0x80       ;CYZ.7
    STS     CYZ, R24
    ;取绝对值
    MOV     R24, R19
    ANDI    R24, 0x7F
    MOV     R19, R24
    OR      R24, R18        ;判断是否为0
    TST     R24
    BRNE    FCMP_1E10       ;不为0,跳转
    ;待转换浮点数为0时
    LDI     R24, 0
    STS     CYZ, R24
    LDI     R24, 0
    STS     (CYZ+1), R24
    LDI     R24, 0
    STS     (CYZ+2), R24
    LDI     R24, 0
    STS     (CYZ+3), R24
    LDI     R24, 0
    STS     (CYZ+4), R24
    ;转换完成,程序返回
    RET
   
FCMP_1E10:   
    LDI     ZL, LOW(DE10)
    LDI     ZH, HIGH(DE10)   
    CALL    FR0DPTR         ;数值 10^10 装入R23--R20
    CALL    FCMP            ;与 10^10 比较
    BRCC    FCMP_1E0        ;判断C,如C=0,则数值小于等于 10^10,跳转
    LDI     ZL, LOW(DE_10)
    LDI     ZH, HIGH(DE_10) ;数值大于 10^10,X=X*(10^-10)使数值缩小 10^10 倍
    CALL    FR0DPTR         ;将数值 10^10 装入 R23--R20
    CALL    ?F_MUL_L04      ;浮点数乘法,结果在 R19--R16
    LDS     R24, CYZ
    CBR     R24, 0x40       ;CYZ.6=0,不为纯小数
    SUBI    R24, 246        ;加10
    STS     CYZ, R24
    JMP     FCMP_1E10

FCMP_1E0:
    LDI     ZL, LOW(DE0)
    LDI     ZH, HIGH(DE0)
    CALL    FR0DPTR         ;数值 10^0 装入R23--R20
    CALL    FCMP            ;与 10^0 比较   
    BRCS    FCMP_1E0_10     ;判断C,如C=1,则数值大于 10^0,跳转
    BREQ    FCMP_1E0_10     ;判断Z,如Z=1,则数值等于 10^0, 跳转
    LDI     ZL, LOW(DE10)
    LDI     ZH, HIGH(DE10)  ;数值小于 10^0, X=X*(10^10)使数值放大 10^10 倍
    CALL    FR0DPTR         ;数值10^10装入 R23--R20
    CALL    ?F_MUL_L04      ;浮点数乘法,结果在 R19--R16
    LDS     R24, CYZ
    SBR     R24, 0x40       ;CYZ.6=1,为纯小数
    SUBI    R24, 246        ;加10
    STS     CYZ, R24
    JMP     FCMP_1E10
   
FCMP_1E0_10:                ;转换为纯小数
    LDI     ZL, LOW(DE0)
    LDI     ZH, HIGH(DE0)
FCMP_FIND:   
    CALL    FR0DPTR
    CALL    FCMP
    BRNE    FCMP_UNEQU      ;不相等,跳转
    LDI     R24, 0x10       ;正好是表格中的数,尾数为0.10000000
    STS     (CYZ+1), R24
    LDI     R24, 0
    STS     (CYZ+2), R24
    LDI     R24, 0
    STS     (CYZ+3), R24
    LDI     R24, 0
    STS     (CYZ+4), R24
    CALL    CYZDEAL_JIE     ;调整幂值调整
    ;转换完成,程序返回
    RET
   
FCMP_UNEQU:
    BRCS    FCMP_NEXT       ;待转换浮点数大,跳转
    ;查表,找到一个比待转换浮点数大的整数幂 10^+e ,再将比待转换浮点数乘以 10^-e 得到纯小数
    ;地址计算:A(10^-e)=A(10^0)-[A(10^+e)-A(10^0)],注:A(..)意为..的地址
    ;          ZH:ZL-(R27:R26-ZH:ZL),完成后,Z 还有加 4 才能得到 10^-e 的首地址
    MOVW    R26, ZL   
    LDI     ZL, LOW(DE0)
    LDI     ZH, HIGH(DE0)
    CLC
    SUB     R26, ZL
    SBC     R27, ZH
    CLC
    SUB     ZL, R26
    SBC     ZH, R27
   
    ADIW    ZL, 4           ;Z=Z+4
    CALL    FR0DPTR         ;数值 10^-e 装入R23--R20
    CALL    ?F_MUL_L04      ;浮点数乘法,结果在 R19--R16
    JMP     YUANZHENG_FBCD  ;得到一个二进制浮点数的纯小数。
   
FCMP_NEXT:
    LDS     R24, CYZ        ;幂值调整
    BST     R24, 6
    BRTS    FCMP_NEXT1      ;CYZ.6为1,跳转
    LDS     R24, CYZ
    INC     R24             ;加1
    STS     CYZ, R24
    JMP     FCMP_FIND
FCMP_NEXT1:
    LDS     R24, CYZ
    DEC     R24             ;减1
    STS     CYZ, R24
    JMP     FCMP_FIND

YUANZHENG_FBCD:
    MOV     R24, R18        ;恢复阶码
    ROL     R24             ;取R18的最高位放到C中
    ROL     R19             ;R19循环左移,把C放到R19的最低位
    SUBI    R19, 126        ;-126   
        
    ORI     R18, 0x80       ;恢复尾数

CYZFTB0:
    TST     R19             ;取阶码
    BREQ    CYZFTB1         ;为零,跳转
    CLC
    CALL    RR1             ;右规。
    RJMP    CYZFTB0

CYZFTB1:
    CALL    HB2             ;转换尾数的十分位和百分位
    STS     (CYZ+1), R24
    CALL    HB2             ;转换尾数的千分位和万分位
    STS     (CYZ+2), R24
    CALL    HB2             ;转换尾数的十万分位和百万分位
    STS     (CYZ+3), R24
    CALL    HB2             ;转换尾数的千万分位和亿分位
    STS     (CYZ+4), R24
   
    CLC

    LDI     R24, 0x05       ;此处后半字节(BCD码的第8位)的值不保证
    LDS     R26, CYZ+4
    CALL    ADDAA           ;BCD码相加后调整
    STS     CYZ+4, R24
    CLR     R24
    LDS     R26, CYZ+3
    CALL    ADDAA
    STS     CYZ+3, R24
    CLR     R24
    LDS     R26, CYZ+2
    CALL    ADDAA
    STS     CYZ+2, R24
    CLR     R24
    LDS     R26, CYZ+1
    CALL    ADDAA
    STS     CYZ+1, R24
    BRCC    CYZFTB2
    LDI     R25, 0x10
    STS     CYZ+1, R25   
    CALL    CYZDEAL_JIE     ;幂值调整      
CYZFTB2:                    ;转换完成,程序返回
    RET
   
CYZDEAL_JIE:
    LDS     R24, CYZ        ;幂值调整
    BST     R24, 6
    BRTC    CYZDEAL_JIE1
    DEC     R24
    STS     CYZ, R24
    RET
CYZDEAL_JIE1:
    INC     R24
    STS     CYZ, R24   
    RET

RR1:
    MOV     R24, R18        ;第一操作数右规一次
    ROR     R24             ;尾数缩小一半
    MOV     R18, R24
    MOV     R24, R17
    ROR     R24
    MOV     R17, R24
    MOV     R24, R16
    ROR     R24
    MOV     R16, R24
    INC     R19             ;阶码加一
    CLV                     ;清溢出标志
    CPI     R19, 0x80
    BRNE    RR1E            ;阶码上溢否?
    LDI     R19, 0x7F       ;阶码溢出
    SEV
RR1E:
    RET

HB2:
    ;尾数扩大100倍
    LDI     R25, 100
    MUL     R16, R25        ;R16*100
    MOV     R16, R0         ;(R16*100)L -> R16
    MOV     R24, R17        
    MOV     R17, R1         ;(R16*100)H -> R17
    MUL     R24, R25        ;R17*100
    ADD     R17, R0         ;(R17*100)L + (R16*100)H -> R17,进位放到 C 中
    MOV     R24, R18
    CLR     R18
    ADC     R18, R1         ;(R17*100)H + C -> R18,加上进位
    MUL     R24, R25        ;R18*100  
    ADD     R18, R0         ;(R18*100)L + (R17*100)H + C -> R18,进位放到 C 中   

    MOV     R25, R16        ;备份R16
    CLR     R16
    ADC     R16, R1         ;(R18*100)H + C -> R16,加上进位,R16为整数部分
    ;将整数部分转换成BCD码
    LDI     R20, 10         
    CALL    ?UC_DIVMOD_L01  ;无符号字节除法,R16/R20,商放到 R16,余数放到 R20
    SWAP    R16
    OR      R16, R20
    MOV     R24, R16        ;结果 -> R24
    MOV     R16, R25        ;恢复R16
    RET
   
ADDAA:
    ADC     R24, R26        ;BCD码加法子程序
    IN      R26, SREG       ;先保存相加后的SREG
    LDI     R27, 0x66       ;
    ADD     R24, R27        ;将和预加立即数0x66
    IN      R27, SREG       ;输入相加后的SREG
    OR      R26, R27        ;新旧状态相或
    SBRS    R26, 0          ;相或后进位置位则跳行
    SUBI    R24, 0x60       ;否则减去$60(十位bcd不满足调整条件)
    SBRS    R26, 5          ;半进位置位则跳行
    SUBI    R24, 6          ;否则减去$06(个位bcd不满足调整条件)
    RET
  
FR0DPTR:                    ;装入R23--R20   
    LPM     R23, Z+
    LPM     R22, Z+
    LPM     R21, Z+
    LPM     R20, Z+
    RET
   
FCMP:                       ;比较两个正的浮点数
    CLC
    MOV     R24, R23
    SUB     R24, R19
    BRNE    FCMP1           ;不相等跳转,再通过判断C标志,便可分出大小
    MOV     R24, R22
    SUB     R24, R18
    BRNE    FCMP1
    MOV     R24, R21
    SUB     R24, R17
    BRNE    FCMP1
    MOV     R24, R20
    SBC     R24, R16
FCMP1:
    RET
   
   
RSEG    CODE:CODE
DE_10:
    DB 02EH,0DBH,0E6H,0FFH ;10^-10
    DB 030H,089H,070H,05FH ;10^-9
    DB 032H,02BH,0CCH,077H ;10^-8
    DB 033H,0D6H,0BFH,095H ;10^-7
    DB 035H,086H,037H,0BDH ;10^-6
    DB 037H,027H,0C5H,0ACH ;10^-5
    DB 038H,0D1H,0B7H,017H ;10^-4
    DB 03AH,083H,012H,06FH ;10^-3
    DB 03CH,023H,0D7H,00AH ;10^-2
    DB 03DH,0CCH,0CCH,0CDH ;10^-1
DE0:
    DB 03FH,080H,000H,000H ;10^0
    DB 041H,020H,000H,000H ;10^1
    DB 042H,0C8H,000H,000H ;10^2
    DB 044H,07AH,000H,000H ;10^3
    DB 046H,01CH,040H,000H ;10^4
    DB 047H,0C3H,050H,000H ;10^5
    DB 049H,074H,024H,000H ;10^6
    DB 04BH,018H,096H,080H ;10^7
    DB 04CH,0BEH,0BCH,020H ;10^8
    DB 04EH,06EH,06BH,028H ;10^9
DE10:
    DB 050H,015H,002H,0F9H ;10^10
   
END


//--------------------main.c-------------------------------------

#include  <ioavr.h>
#include  <ina90.h>

extern void FloatToBCD(float i);//声明为外部函数

unsigned char CYZ[5];    //定义接收数组

void main()
{
    while(1)
    {
        FloatToBCD(1.3992928);
    }
}

//1.3992928 的结果 01 13 99 29 28  //第1字节 01 第7和6位均为0,5到0为的数值1,表示为正数,小数点前有1位整数
//1.002     的结果 01 10 02 00 04
//-0.00123  的结果 C2 12 30 00 01  //第1字节 C2 第7和6位均为1,5到0为的数值2,表示为负数,纯小数点后有2个0

点击此处下载ourdev_211017.rar(文件大小:12K)

出0入0汤圆

发表于 2008-2-4 02:33:58 | 显示全部楼层
好,收藏

出0入0汤圆

 楼主| 发表于 2008-4-14 09:01:41 | 显示全部楼层
更新:
1、不再使用R24、R25、R26和R27这4个需保护的寄存器。第1版本使用了这些寄存器,但没有进行保护操作,因而存在安全隐患。
2、修正了在末尾的四舍五入问题

上传的示例中还包括一个专用数码管的浮点数显示函数。
点击此处下载 ourdev_251342.rar(文件大小:124K) (原文件名:Float2BCD_IARAVR1.1.rar)

出0入0汤圆

发表于 2008-4-14 09:13:44 | 显示全部楼层
mark...

出0入0汤圆

发表于 2008-4-14 09:34:35 | 显示全部楼层
怎么应用在C上?

出0入0汤圆

发表于 2008-4-14 10:04:27 | 显示全部楼层
记号

出0入0汤圆

 楼主| 发表于 2008-4-14 15:33:00 | 显示全部楼层
使用很简单:
在工程里添加 FloatToBCD.s90 文件

然后,在需要调用 FloatToBCD 的C文件里添加以下代码就可以了:

extern void FloatToBCD(float i);//声明为外部函数
unsigned char CYZ[5];    //定义接收数组

以后就可以像C函数一样调用了,如
FloatToBCD(1.3992928);

出0入0汤圆

发表于 2008-4-24 22:57:47 | 显示全部楼层
mack

出0入0汤圆

发表于 2010-3-2 16:25:15 | 显示全部楼层
mark

出0入0汤圆

发表于 2012-5-24 16:28:22 | 显示全部楼层
学习学习
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-8 08:13

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表