搜索
bottom↓
回复: 28

改造好方便keilC调用的最快16位2进制转压缩BCD 51库(关键字bin2BCD HEX int)

[复制链接]

出0入0汤圆

发表于 2009-11-27 20:12:22 | 显示全部楼层 |阅读模式
Hex2BCD的算法在http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3587651&bbs_page_no=1讨论时cowboy提到了16位2进制转压缩BCD的最快算法, 汇编的。当时没看懂,所以也没仔细研究。前两天翻出来看,突然来了精神,想改造下为不大用汇编的人民造福(改造下方便用C调用),下面就是成果了。是用C编译成src文件后改的。用了全局变量。本想用局部的,搞不好。不会传参数。
下面是完整的KeilC工程。
点击此处下载 bin2bcd0.1.rar(文件大小:19K) (原文件名:bin2bcd0.1.rar)

下面是cowboy贴出的DENGM的源代码。经我改造,在你的函数中加入bin2bcd.h,把要转换的uint放到IntBinBuf,调用Bin2BCD(),就可以在CharBCDBuf[3]中得到压缩BCD了。
输入:全局变量 unsigned int IntBinBuf;要转换的16位整数,<65536
输出:全局变量 unsigned char CharBCDBuf[3];        存放转换好的压缩BCD码
如果IntBinBuf=65535,则CharBCDBuf[0]=06 CharBCDBuf[0]=55 CharBCDBuf[0]=35
改造后的bin2bcd.asm中包含reg51.h的内容,不同的你可以改,直接复制reg52.h等的内容替换就行了。
工程调试运行可以在Keil的串口输出中看到。

=====================================
号称世上最快的16bit二进制数转5位压缩BCD码的程序,最长56周期(标准51)。原理还没弄懂。
原作者:DENGM
;R2R3-->R5R6R7 小端
BIN2BCD:
       MOV  A, R3        
       ANL  A, #0FCH
       RR   A
       RR   A
       MOV  R5,A
       ADD  A, R5
       ADD  A, R5
       MOV  R7,A
       MOV  A, R2
       ANL  A, #3
       MOV  R6,A
       XRL  A, R3
       ANL  A, #3
       XRL  A, R2
       RR   A
       RR   A
       ADD  A, R7
       JNC  L2
       INC  R5
       ADD  A, #6
L2:    ADD  A, R7
       MOV  B, #25
       JNC  L3
       INC  R5
       ADD  A, #6
       DIV  AB
       SJMP L4
L3:    DIV  AB
       CJNE A, #10, L4
       INC  R5
       CLR  A
L4:    MOV  R7,A
       MOV  A, #10
       XCH  A, B
       ADD  A, #(L5-$-3)
       MOVC A, @A+PC
       ADD  A, R6
       DA   A
       XCH  A, R5
       DIV  AB
       XCH  A, R7
       SWAP A
       ORL  A, B
       SWAP A
       MOV  R6,A
       RET
      
L5:    DB 00H, 04H, 08H, 12H, 16H
       DB 20H, 24H, 28H, 32H, 36H
       DB 40H, 44H, 48H, 52H, 56H
       DB 60H, 64H, 68H, 72H, 76H
       DB 80H, 84H, 88H, 92H, 96H
       END

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2009-11-28 10:02:43 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-11-28 10:18:07 | 显示全部楼层
支持楼主,我把原程序也简单的注释一下


BIN2BCD:
       MOV  A, R3      
       ANL  A, #0FCH  ;取高字节的高6位
       RR   A
       RR   A         ;除以4
       MOV  R5,A      ;有多少个1024,放入R5,
       ADD  A, R5
       ADD  A, R5     ;乘以3
       MOV  R7,A      ;1024的个数乘以3,放入R7
       MOV  A, R2
       ANL  A, #3     ;取低字节的低2位,高6位为0
       MOV  R6,A      ;低字节的低两位放入R6
       XRL  A, R3     ;高字节与低字节低2位想异或,高6位为高字节的
       ANL  A, #3     ;高字节与低字节低2位想异或,高6位为0
       XRL  A, R2     ;低2位为高字节的低2位,高6位为低字节的高6位
       RR   A         ;
       RR   A         ;两字节中从高字节低2位到低字节高6位的组成的一个字节
       ADD  A, R7     ;下面的步骤求出有多少个4,由于1024比1000多出24,1024的个数乘以6
       JNC  L2        ;也就可以求出这么多个1024中含有的4的个数,它可能大于256,所以分两次加
       INC  R5        ;逢256个4,超过1000,1000个数加1
       ADD  A, #6     ;由于250X4=1000,多出了6个,4的个数要加上6
L2:    ADD  A, R7     ;A中存放的是4的个数,
       MOV  B, #25
       JNC  L3
       INC  R5        ;
       ADD  A, #6     ;与上次加法运算的原理相同
       DIV  AB
       SJMP L4
L3:    DIV  AB            ;至此A中存放的是4的个数,除以25,也就可以得出100的个数
       CJNE A, #10, L4
       INC  R5            ;如果超过25X10个4,R5需加1;至此R5中存放的是1000的个数
       CLR  A             ;剩余的个数不超过25
L4:    MOV  R7,A          ;100的个数入R7
       MOV  A, #10
       XCH  A, B          ;余数入A,前面求出1000和100的个数,剩余的4的个数用于求十位和个位。
       ADD  A, #(L5-$-3)  
       MOVC A, @A+PC      ;依据余数取数
       ADD  A, R6         ;加上低两位
       DA   A             ;十进制调整
       XCH  A, R5         ;十位个位放入R5,A中的是1000的个数
       DIV  AB            ;除以10,商也就是10000的个数,余数为1000的个数
       XCH  A, R7         ;10000的个数放入R7,A中为100的个数
       SWAP A             ;100个数放高半字节
       ORL  A, B          ;1000的个数低半字节
       SWAP A             ;交换
       MOV  R6,A          ;放入R6
       RET
     
L5:    DB 00H, 04H, 08H, 12H, 16H
       DB 20H, 24H, 28H, 32H, 36H
       DB 40H, 44H, 48H, 52H, 56H
       DB 60H, 64H, 68H, 72H, 76H
       DB 80H, 84H, 88H, 92H, 96H
       END

出0入0汤圆

 楼主| 发表于 2009-11-29 22:40:26 | 显示全部楼层
【2楼】 killin
注释很详细。谢谢!终于明白它的原理了。

出0入0汤圆

发表于 2009-11-30 01:39:38 | 显示全部楼层
我来捡个便宜,将程序写成可重定位的段的形式,修改入口参数与出口参数格式,制作成.LIB形式的库文件,可在C语言源文件中直接以“传递参数,取得返回值”的形式调用。
说明:
1、函数形式为“unsigned long bin2bcd(unsigned int)”,不再使用全局变量传递参数;
2、使用时将.H文件与.LIB文件复制到工程目录,包含.H文件并将.LIB文件添加进工程即可。
3、16位无符号整型参数通过R6、R7传递(C51采用大端格式,即R6中存高字节、R7中存低字节);
4、转成的压缩BCD码以“unsigned long int”32位无符号长整型的形式通过R4、R5、R6、R7返回(其中:R4中为随机
  值;R5高4位为0,低4位存BCD码的万位;R6高4位存千位,低4位存百位;R7高4位存十位,低4位存个位);
5、最多将花费57个机器周期,比原来的代码多了一个机器周期是因为入口参数与出口参数中的寄存器R6、R7重叠,原
  来代码中的倒数第二个XCH指令无法再使用,需要用两个MOV指令替代;
6、如果需要出口参数中的R4为0,可将源代码文件中的分号去掉,重新编译工程以得到合适的.LIB文件,代价为多使用
  2个字节的代码空间及2个额外的机器周期;
7、最后,附上Keil的完整工程及可用的.LIB库文件及.H头文件。

.LIB库文件、.H头文件、KEIL的整个工程ourdev_509015.rar(文件大小:4K) (原文件名:bin2bcd.rar)

出0入0汤圆

发表于 2009-11-30 01:46:22 | 显示全部楼层
其中的asm文件内容:

NAME    BIN2BCD

?PR?_bin2bcd?BIN2BCD    SEGMENT CODE INBLOCK
        PUBLIC  _bin2bcd

        RSEG    ?PR?_bin2bcd?BIN2BCD
_bin2bcd:
        USING   0
        MOV     A,      R6
        ANL     A,      #0xFC
        RR      A
        RR      A
        MOV     R5,     A
        ADD     A,      R5
        ADD     A,      R5
        MOV     R4,     A
        MOV     A,      R7
        ANL     A,      #0x03
        MOV     R3,     A
        XRL     A,      R6
        ANL     A,      #0x03
        XRL     A,      R7
        RR      A
        RR      A
        ADD     A,      R4
        JNC     ?C0001
        INC     R5
        ADD     A,      #0x06
?C0001: ADD     A,      R4
        MOV     B,      #0x19
        JNC     ?C0002
        INC     R5
        ADD     A,      #0x06
        DIV     AB
        SJMP    ?C0003
?C0002: DIV     AB
        CJNE    A,      #0x0A,  ?C0003
        INC     R5
        CLR     A
?C0003: MOV     R6,     A
        MOV     A,      #0x0A
        XCH     A,      B
        ADD     A,      #(?C0004-$-3)
        MOVC    A,      @A+PC
        ADD     A,      R3
        DA      A
        MOV     R7,     A
        MOV     A,      R5
        DIV     AB
        MOV     R5,     A
        MOV     A,      B
        SWAP    A
        ORL     A,      R6
        MOV     R6,     A
        ;CLR    A
        ;MOV    R4,     A
        RET
?C0004: DB      0x00,   0x04,   0x08,   0x12,   0x16
        DB      0x20,   0x24,   0x28,   0x32,   0x36
        DB      0x40,   0x44,   0x48,   0x52,   0x56
        DB      0x60,   0x64,   0x68,   0x72,   0x76
        DB      0x80,   0x84,   0x88,   0x92,   0x96
        END

出0入0汤圆

发表于 2009-11-30 08:24:16 | 显示全部楼层
高手真不少,学习了。

出0入0汤圆

发表于 2009-11-30 08:57:14 | 显示全部楼层
学习了。

出0入0汤圆

 楼主| 发表于 2009-12-8 15:37:29 | 显示全部楼层
我又改了下。现在可以直接输入Int和一个idata数组的地址,出口就在这个idata的数组中。
这里说明下。keil中没有说明类型的指针都是通用指针,占3byte,而用unsigned char idata说明,就是指向unsigned char idata的指针了,只占1byte。



下面是完整的Keil工程
第一个是没有用lib的。第二个用了编译好的lib。进入调试,运行可以在串口1中看到输出。
点击此处下载 ourdev_511999.rar(文件大小:19K) (原文件名:bin2bcd2.rar)
点击此处下载 ourdev_512000.rar(文件大小:13K) (原文件名:bin2bcdlibtest.rar)

asm中 R4R5 分别是int的高低位,高位在前为R4. 压缩BCD在R1R2R3中。也是高位在前。
R4=0xff,R5=0xff  出来 R1=0x06 R2=0x55 R3=0x35
buf[0]=0x06 buf[1]=0x055 buf[2]=0x35

asm内容如下:

我用bin2bcd.c生成SRC然后改的。呵呵。比较笨。
; .\bin2bcd.SRC generated from: bin2bcd.c
; COMPILER INVOKED BY:
;        D:\Program Files\keil C 8.05\C51\BIN\C51.EXE bin2bcd.c ROM(SMALL) BROWSE DEBUG OBJECTEXTEND SRC(.\bin2bcd.SRC)

$NOMOD51

NAME        BIN2BCD
下面是reg51.h的内容,被我删掉了。你可以看上面的工程里的源文件,里面是全的。   
下面是bin2bcd的函数内容了  
?PR?_bin2bcd?BIN2BCD SEGMENT CODE INBLOCK
        PUBLIC        _bin2bcd
; #include<reg51.h>
; #include<bin2bcd.h>
; void bin2bcd(unsigned char idata *bcd,unsigned int bin)

        RSEG  ?PR?_bin2bcd?BIN2BCD
_bin2bcd:
        USING        0

BIN2BCD:
        MOV  A, R4         
        ANL  A, #0FCH  
        RR   A  
        RR   A  
        MOV  R3,A  
        ADD  A, R3  
        ADD  A, R3  
        MOV  R1,A  
        MOV  A, R5  
        ANL  A, #3  
        MOV  R2,A  
        XRL  A, R4  
        ANL  A, #3  
        XRL  A, R5  
        RR   A  
        RR   A  
        ADD  A, R1  
        JNC  L2  
        INC  R3  
        ADD  A, #6  
L2:      ADD  A, R1  
        MOV  B, #25  
        JNC  L3  
        INC  R3  
        ADD  A, #6  
        DIV  AB  
        SJMP L4  
L3:      DIV  AB  
        CJNE A, #10, L4  
        INC  R3  
        CLR  A  
L4:      MOV  R1,A  
        MOV  A, #10  
        XCH  A, B  
        ADD  A, #(L5-$-3)  
        MOVC A, @A+PC  
        ADD  A, R2  
        DA   A  
        XCH  A, R3  
        DIV  AB  
        XCH  A, R1  
        SWAP A  
        ORL  A, B  
        SWAP A  
        MOV  R2,A  
下面这几句是我加的了,其实可以跟上面的最后几句合并下,这样可以挤出几个周期来,但我改了一回,改不好。等高手来吧。      
        MOV  R0,AR7          
        MOV  @R0,AR1
        INC  R0
        MOV  @R0,AR2
        INC  R0
        MOV  @R0,AR3
        RET
L5:    DB 00H, 04H, 08H, 12H, 16H  
       DB 20H, 24H, 28H, 32H, 36H  
       DB 40H, 44H, 48H, 52H, 56H  
       DB 60H, 64H, 68H, 72H, 76H  
       DB 80H, 84H, 88H, 92H, 96H  
       END

出0入0汤圆

发表于 2010-3-2 15:07:26 | 显示全部楼层
强悍,学习了

出0入0汤圆

发表于 2010-5-27 12:29:32 | 显示全部楼层
MARK

出0入0汤圆

发表于 2010-5-27 12:51:11 | 显示全部楼层
喜欢这类帖。

出0入0汤圆

发表于 2010-7-22 11:20:10 | 显示全部楼层
追加C51版本,82周期,个别数据需86或90周期,比汇编慢一些,但仍比传统算法快N++倍。
程序也很简洁,比汇编容易看。

#include <reg51.h>
unsigned char dig[5];
  
bin2bcd(unsigned int x)
{
    unsigned char i,j,k;
    k = x;
    i = x>>10;
    if (i > 41)        i++;
    j = (i+i+i)*2 + (x>>8<<6 | k>>2);
    if (CY == 1) {i++; j += 6;}
    if (j > 249) {i++; j += 6;}

    dig[0] = i / 10;            //万位
    dig[1] = B;                 //千位
    dig[2] = j / 25;            //百位
    dig[3] = (B*4 | k%4) / 10;  //十位
    dig[4] = B;                 //个位
}

出0入0汤圆

发表于 2010-7-22 11:52:28 | 显示全部楼层
回复【12楼】cowboy
追加c51版本,82周期,个别数据需86或90周期,比汇编慢一些,但仍比传统算法快n++倍。
程序也很简洁,比汇编容易看。
......
-----------------------------------------------------------------------

顶牛仔一下。

出0入0汤圆

发表于 2010-7-22 11:55:25 | 显示全部楼层
很不错。

出0入0汤圆

发表于 2010-11-28 15:14:42 | 显示全部楼层
都是牛人啊

出0入0汤圆

发表于 2011-1-6 22:46:24 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-2-4 01:51:25 | 显示全部楼层
厉害,牛人。

出0入0汤圆

发表于 2011-2-4 08:40:19 | 显示全部楼层
厉害,记号下

出0入8汤圆

发表于 2011-2-4 08:47:20 | 显示全部楼层
牛人,谢谢!!

出0入0汤圆

发表于 2011-2-4 09:44:05 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-2-4 10:40:22 | 显示全部楼层
晕了。51支持乘除法?为何不直接%10?
o……51应该不支持16位乘法吧呵又范迷糊了……

出0入0汤圆

发表于 2011-2-4 10:58:59 | 显示全部楼层
mark..........

出0入0汤圆

发表于 2011-2-4 12:19:28 | 显示全部楼层
MARK

出0入0汤圆

发表于 2011-10-26 10:03:31 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-7-14 11:37:45 | 显示全部楼层
cowboy 发表于 2010-7-22 11:20
追加C51版本,82周期,个别数据需86或90周期,比汇编慢一些,但仍比传统算法快N++倍。
程序也很简洁,比汇 ...

SIR:

What is the C code for 32Bits?

Thank you.

出0入12汤圆

发表于 2013-7-17 05:16:11 来自手机 | 显示全部楼层
记号备用谢谢分享

出0入0汤圆

发表于 2013-7-20 23:24:27 | 显示全部楼层
没看懂。。。

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-8-26 10:00

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

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