转自大虾网 http://www.daxia.com/list_1683.shtml
有一个矛盾总是在困扰我们---那就是计算机喜欢2进制(16进制)而人类已经习惯了10进制
传统的HEX--BCD通常都按二进制定义按权展开,再付以10进制调整来实现,速度太慢,效率低
我的思路是这样的2的12次方=4096=4100-4=1000H及每一个1000H可以看着"4100"如果有误
差可以从余数中扣除,如双字节数最多扣除16*4=64个,如果有余数,够扣就扣,不够扣从4100
个中次高位减一当100已经够了!如果你问16是怎么来得我告诉65536/4096=16下面是程序
DPTR中是待转换的双字节16进制数,转换的数据保存在34H33H32H31H30H五个连续单元中34H
为高,同样的道理把100=60H+4 4096/96最多商42 4*42=168
16=4096/256 64和128因为都是单字节所以运算非常简单,经过仿真对比其运行速度比传统
方式快12倍!!!!!!!
HEXBCD:MOV A,DPH ;16进制高位送A
ANL A,#0F0H ;屏蔽A低四位
XRL DPH,A ;屏蔽DPH高四位
SWAP A ;A除以16 ( 注意这技巧)
MOV 32H,A ;把A个100放百位单元
RL A
RL A ;两次RL A相当于乘以4,这个4表示4A个千,也表示要扣除4A
;A*4096=A*(4000+100)-4A=4A*1000+A*100-4A
XCH A,DPL
SUBB A,DPL
XCH A,DPH
SUBB A,#00H ;以上四条指令完成4A的扣除,结果高位在A,低位在DPH
JNC "够扣"
DEC 32H ;不够扣32H减一当百
MOV A,#101 ;本来是100这里用101是考虑C=1这样就节省一条指令CLR C
SUBB A,DPL
ADD A,DPH ;A肯定小于64为什么?所以高位不计算了!
MOV B,#10
DIV AB
MOV 31H,A
MOV 30H,B
这是个简易的printf,一次只能带一个参数,printf代码在下面。
============================================================
这里是main.c
============================================================
#define _X
#include<myprintf.c> //mypr换成printf时,将此项注释掉
//mypr换成printf时,包含下面三项
//#include<regx52.h> //mypr换成printf时,包外含这三项,将上面一项注释掉
//#include<inituart.c>
//#include<stdio.h>
main()
{
unsigned int k=0x1234;
InitUart();
while(1)
{
mypr("Hello World!
K is %x",k);//定义_U时%x换成%u,用printf时用%u和%x各一次
}
}
void uart(void) interrupt 4 using 0
{
}
#define _X Program Size: data=15.0 xdata=0 code=256
#define _U Program Size: data=27.0 xdata=0 code=716
printf ...一样
%x Program Size: data=32.1 xdata=0 code=1131
%u Program Size: data=32.1 xdata=0 code=1131
============================================================
下面是myprintf.c
============================================================
#include<regx52.h>
#ifndef BaudRate
#define BaudRate 57600L
#endif
#ifndef OSC
#define OSC 22118400L //11.0592M
#endif
#include<inituarts.c>
#ifndef _X
#ifndef _U
#define _X
#define _U
#endif
#endif
unsigned char code hex2ascii[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46};
//putchar
void prc(unsigned char c)
{
while(!TI)
;
TI=0;
SBUF=c;
}
//xu=1 或2 说明包含输出%u功能
#ifdef _U
void Hex2BCD(unsigned char *p,unsigned int t)
{
unsigned char i=0;
unsigned char s;
if(t<10000) goto ca0;
if(t>=40000) {i =4;t-=40000;} //如果t<=9999,则这部分可不用。
if(t>=20000) {i+=2;t-=20000;}
if(t>=10000) {i++; t-=10000;}
*p++=i+48; //LCDascii
i=0;
ca0:
if(t>=8000) {i =8;t-=8000;goto ca1;}
else
if(t>=4000) {i=4;t-=4000;}
else ;
if(t>=2000) {i+=2;t-=2000;}
ca1:
if(t>=1000) {i++; t-=1000;}
*p++=i+48;
i=0;
if(t>=800) {i =8;t-=800;goto cb1;}
else
if(t>=400) {i=4;t-=400;}
else ;
if(t>=200) {i+=2;t-=200;}
cb1:
s=(unsigned char)t;
if(s>=100) {i++; s-=100;}
*p++=i+48;
i=0;
if(s>=80) {i=8;s-=80;goto cc1;}
else
if(s>=40) {i=4;s-=40;}
else ;
if(s>=20) {i+=2;s-=20;}
cc1:
if(s>=10) {i++; s-=10;}
*p++=i+48;
*p++=s+48;
*p=' ';
}
#endif
//miniprintf
void mypr(unsigned char code *p,unsigned int ap)
{
unsigned char* apbufp;
#ifdef _U
unsigned char apbuf[6];
#endif
for( ;(*p) != ' ';++p)
{
if(*p!='%')
{
prc(*p);
continue;
}
p++;
#ifdef _X
if(*p=='x')
{
prc('0');
prc('x');
apbufp=(unsigned char *)(&ap); //指向ap的高位,简化除法。(只用高位)
while(ap)
{
if(ap&0xf000) //说明ap>0x1000
prc(hex2ascii[(unsigned char)(*apbufp>>4)]); //提取高位,然后除8 ,如0x1234提出0x12,0x12>>4=0x01
else
prc('0');
ap<<=4; //向高位移4位,0x1234变成0x2340变成0x3400变成0x4000变成0x0000
}
}
continue;
#endif
#ifdef _U
if(*p=='u')
{
Hex2BCD(apbuf,ap); //变成BCD数组
apbufp=apbuf;
while(*apbufp)
{
prc(*apbufp);
apbufp++;
}
}
#endif
continue;
}
}
===============================================
快12倍表示有多快?能在100us内完成吗?(以标准12T的51运行于12MHz来算)
万位 千位 百位 十位 个位
2 5 6
+ 2 5 6
------------------------------
12 30 36
+ 10 25 30
4 10 12
------------------------------
4 20 49 60 36
+ 3 <-36->6
------------------------------
4 20 49 63 6
+ 6<-63->3
------------------------------
4 20 55 3 6
+ 5<-55->5
------------------------------
4 25 5 3 6
+ 2<-25->5
------------------------------
6 5 5 3 6
----------------------------------------------------------------------------
我不会汇编,所以只能写个类汇编出来了。等高手来改写优化。这个用在12MHz S51上,123周期(仅计算,没测)
WW EQU 30H;万位
QW EQU 31H;千位
BW EQU 32H;百位
SW EQU 33H;十位
GW EQU 34H;个位
MOV DPH,#FFH
MOV DPL,#FFH
;将DPH(ff)变成2.5.6
MOV A ,DPH
MOV B ,#100
DIV AB
MOV R0,A
MOV A,B;余数放A继续/10
MOV B,#10
DIV AB
MOV R1,A
MOV R2,B
;将DPL(ff)变成2.5.6
MOV A,DPL
MOV B,#100
DIV AB
MOV R3,A
MOV A,B
MOV B,#10
DIV AB
MOV R4,A
MOV R5,B
;开乘了256*6--6*6
MOV A,R5
MOV B,R2
MUL AB
MOV GW,A
;5*6
MOV A,R5
MOV B,R1;
MUL AB
MOV SW,A
;2*6
MOV A,R5
MOV B,R0
MUL AB
MOV BW,A
;256*5--6*5
MOV A,R4
MOV B,R2
MUL AB
ADD SW,A
;5*5
MOV A,R4
MOV B,R1
MUL AB
ADD BW,A
;2*5
MOV A,R4
MOV B,R0
MUL AB
MOV QW,A
;256*2---6*2
MOV A,R3
MOV B,R2
MUL AB
ADD BW,A
;5*2
MOV A,R3
MOV B,R1
MUL AB
ADD QW,A
;2*2
MOV A,R3
MOV B,R0
MUL AB
MOV WW,A
;开始合并--36/10=3(+QW) 余6(GW)
MOV A,GW
MOV B,#10
DIV AB
ADD SW,A
MOV GW,B
;sw
MOV A,SW
MOV B,#10
DIV AB
ADD BW,A
MOV SW,B
;bw
MOV A,BW
MOV B,#10
DIV AB
ADD QW,A
MOV BW,B
;qw ww
MOV A,QW
MOV B,#10
DIV AB
ADD WW,A
MOV QW,B
一周热门 更多>