转自大虾网 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;
}
}
一周热门 更多>