转自大虾网 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;
}
}
#define _X
#include<myprintf2.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(" K is %x, K is %u",k,k);//定义_U时%x换成%u,用printf时用%u和%x各一次
}
}
void uart(void) interrupt 4 using 0
{
}
#define _X %x%x Program Size: data=31.0 xdata=0 code=369
#define _U %u%u Program Size: data=45.0 xdata=0 code=835
#define _XU %x%u Program Size: data=48.0 xdata=0 code=922
printf ...一样
%x%x Program Size: data=32.1 xdata=0 code=1146
%u%u Program Size: data=32.1 xdata=0 code=1146
%x%u Program Size: data=32.1 xdata=0 code=1146
看来是在Hex2BCD上花了太多资源。高手来指点。!
==================================================================
下面是myprintf2.c inituarts.c在最本贴最下面。
==================================================================
#include<regx52.h>
#include <stdarg.h>
#ifndef BaudRate
#define BaudRate 57600L
#endif
#ifndef OSC
#define OSC 22118400L //11.0592M
#endif
#include<inituarts.c>
//#define _XU
#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;
}
#ifdef _U
void Hex2BCD(unsigned char *fmt,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;}
*fmt++=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;}
*fmt++=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;}
*fmt++=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;}
*fmt++=i+48;
*fmt++=s+48;
*fmt=' ';
}
#endif
//miniprintf
void mypr(unsigned char code *fmt,...)
{
unsigned char * apbufp;
#ifdef _U
unsigned char apbuf[6];
#endif
va_list pp;
va_start(pp,fmt); /* 用最后一个具有参数的类型的参数去初始化ap */
for( ;(*fmt) != ' ';++fmt)
{
if(*fmt!='%')
{
prc(*fmt);
continue;
}
fmt++;
if(*fmt=='%')
{
prc('%');
continue;
}
if(*fmt==' ') //错误,格式符不完整
{
prc(16); //输出一个小方框...表示错误
return ;}
{
unsigned int ap =va_arg(pp,unsigned int); //作用范围{}内
if(*fmt=='x')
{
#ifdef _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
}
#else
goto error;
#endif
continue;
}
if(*fmt=='u')
{
#ifdef _U
Hex2BCD(apbuf,ap); //变成BCD数组
apbufp=apbuf;
while(*apbufp)
{
prc(*apbufp);
apbufp++;
}
#else
goto error;
#endif
continue;
}
}
#ifndef _XU
error:
prc(15); //定义时未包含此格式,例如定义了_U,却用了%x
continue;
#endif
}
}
=======================================
下面是inituarts.c
=======================================
//22.1184M Hz 晶振
//#define BaudRate 57600L //波特率
//#define OSC 22118400L //晶振频率//22.1184M
#ifndef BaudRate //波特率
#error BaudRate undefined! Now BaudRate is Defaut(115200)!
#define BaudRate 115200L //晶振频率
#endif
#ifndef OSC
#error OSC undefined! Now OSC is Defaut(11059200)!
#define OSC 11059200L //11.0592M
#endif
#define TimerInitNum (256 - (OSC/192L)/BaudRate) // 255 //定时器1初值
//定时器1为波特率发生器
#if (BaudRate==2400)||(BaudRate==4800)||(BaudRate==9600)||(BaudRate==14400)||(BaudRate==19200)||(BaudRate==28800)||(BaudRate==38400)||(BaudRate==57600)||(BaudRate==115200)
void InitUart(void)
{
SCON=0x50; //串口方式1,允许接收
TMOD=0x20; //定时器1定时方式2
PCON=0x80; //设定SMOD为1
TH1=TimerInitNum; //0xfe 22.1184M-57600bps
TL1=TimerInitNum;
TR1=1; //启动定时器 //设定时器1开始计数
ET1=1;TI=1;
EA=1;
ES=1;
}
#else
#error "BaudRate" defination do not match,must be one of (19200,57600,115200)!
#endif
一周热门 更多>