号称世上最快的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
KEIL建了个工程,运行后发现,速度真的是很快,50几个周期,只是因为是汇编,调用有点麻烦,后来又看了一个关于此贴的
地址如下:
改造好方便keilC调用的最快16位2进制转压缩BCD 51库(关键字bin2BCD HEX int)
这其中的 eduhf_123 兄,在5楼将此段代码做了LIB,方便C语言的调用,很方便,原文如下:
我来捡个便宜,将程序写成可重定位的段的形式,修改入口参数与出口参数格式,制作成.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)
经过建工程测试,速度确实很快, 帖子往下看,看到 cowboy 兄贴出了C源码,根据上面的汇编写的,经过测试,速度稍微慢了一点,80多个指令周期,但是他输出的不是压缩的BCD码,所以很实用,不用再转换,原文如下:
追加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; //个位
}
因为我个人的应用需要将BCD码进行前缀0去掉,这里函数返回的是数字的有效位数,ps指向存放BCD码的缓冲区,x是需要转换的16数,经过测试,调用函数,执行完大约花掉180几个指令周期,还算不错。这其中直接调用了51的内部寄存器,所以无法移植到其他平台,如下代码:
unsigned char bin2bcd2(unsigned int x, unsigned char *ps)
{
unsigned char i,j,k,len,flag;
unsigned char *p = ps;
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;}
*p = i / 10; //万位
if(*p!=0) {p++; len++; flag = 1;}
else if(*p!=0) { p++; len++; flag = 1; }
*p = B; //千位
if(flag) { p++; len++; }
else if(*p!=0) { p++; len++; flag = 1; }
*p = j / 25; //百位
if(flag) { p++; len++; }
else if(*p!=0) { p++; len++; flag = 1; }
*p = (B*4 | k%4) / 10; //十位
if(flag) { p++; len++; }
else if(*p!=0) { p++; len++; flag = 1; }
*p = B; //个位
len++;
return len;
}