📄 serial.c
字号:
return;
}
else if(ch=='\n'){PrintChar(10);PrintChar(13);}
else if(ch=='\t'){
for(j=0;j<TABNum;j++)
PrintChar(' ');
}
else PrintChar(ch);
}
ch=*fmt++;
switch(ch){
case 'c':
PrintChar(*((char *)p));
p=(char *)p+1;
break;
case 'd':
PrintN(*((int *)p),10);
p=(int *)p+1;
break;
case 'x':
PrintN(*((int *)p),16);
p=(int *)p+1;
break;
case 'o':
PrintUN(*((int *)p),8);
p=(int *)p+1;
break;
case 'b':
PrintUN(*((int *)p),2);
p=(int *)p+1;
break;
case 'l':
ch=*fmt++;
switch(ch){
case 'd':
PrintLN(*((long *)p),10);
p=(long *)p+1;
break;
case 'o':
PrintLUN(*((long *)p),8);
p=(long *)p+1;
break;
case 'u':
PrintLUN(*((unsigned long *)p),10);
p=(unsigned long *)p+1;
break;
case 'b':
PrintLUN(*((long *)p),2);
p=(long *)p+1;
break;
case 'x':
PrintLN(*((long *)p),16);
p=(long *)p+1;
break;
default:
//出临界区
#pragma ASM
POP IE;
#pragma ENDASM
return;
}
break;
case 'f':
DispF(*((float *)p));
p=(float *)p+1;
break;
case 'u':
PrintUN(*((unsigned int *)p),10);
p=(unsigned int *)p+1;
break;
case 's':
PrintStr(*((char **)p));
p=(char **)p+1;
break;
case '%':
PrintChar('%');
p=(char *)p+1;
break;
default:
//出临界区
#pragma ASM
POP IE;
#pragma ENDASM
return;
}
}
}
void PrintN(int n,int b) reentrant //十进制显示整形数
{
if(b==16){PrintWord(n);return;}
if(n<0){PrintChar('-');n=-n;}
if(n/b)
PrintN(n/b,b);
PrintChar(n%b+'0');
}
void PrintUN(unsigned int n,unsigned int b) reentrant //十进制显示无符号整形数
{
if(b==16){PrintWord(n);return;}
if(n/b)
PrintUN(n/b,b);
PrintChar(n%b+'0');
}
void PrintLN(long n,long b) reentrant //十进制显示长整形数
{
if(b==16){PrintLong(n);return;}
if(n<0){PrintChar('-');n=-n;}
if(n/b)
PrintLN(n/b,b);
PrintChar(n%b+'0');
}
void PrintLUN(unsigned long n,unsigned long b) reentrant //十进制显示无符号长整形数
{
if(b==16){PrintLong(n);return;}
if(n/b)
PrintLUN(n/b,b);
PrintChar(n%b+'0');
}
//============================================================================================
//KEIL C51的float类型采用IEEE-754标准存储,占4字节。
// S E E E E E E E E E (1) M M M M M M M M M M M M M M M M M M M M M M M
// S 1bit 正负标志位0=正;1=负
// E 8bit 二进制阶码=(EEEEEEEE)-127
// M 23bit 24bit尾数,只存储23位,最高位固定为1。此方法用最较少的位数实现了较高的有效数,提高了精度。
//
// 尾数为24bit,最高可表达的整数值为2^24-1=16777215,也就是说,小于等于16777215的整数可以被精确
//显示。这决定了十进制浮点数的有效位数为7位,10^7<16777215<10^8,10的7次方以内的数小于16777215,
//可以精确表示。使用科学记数法时,整数部分占1位,所以小数部分最大占7-1=6位,即最大有6位精度。
// 长整形数和浮点数都占4字节,但表示范围差别很大。浮点数的范围为+-1.175494E-38到+-3.402823E+38,
//无符号长整形数范围为0到4294967295。显示浮点数要用到长整形数保存数据,可他们范围差这么多,怎么办呢?
// 仔细观察十进制浮点数的显示,有一个尾数和一个阶码,由上面论证可知32位浮点数最大有效数字为7位十进制
//数,超出此范围的数字有截断误差,不必理会,因此,使浮点数尾数能够放在长整形数里保存。阶码为-38到38,
//一个char型变量就可以保存。
// 综上所述,以10^7的最大跨度为窗口(小于10^7也可以,如:10,100...10000等,但决不能大于它,那样会
//超出精度范围),定位浮点数的量级,然后取出7位尾数的整数值,再调整阶码,就可以精确显示此浮点数。
// 量级尺度如下:
// (-38)-(-35)-(-28)-(-21)-(-14)-(-7)-(0)-(7)-(14)-(21)-(28)-(35)-(38)
// 请严格按照KEIL手册给出的浮点数范围显示,因为数值空间没有完全使用,有些值用于错误指示和表示正负无穷。
//小于1.175494E-38的数仍可以显示一些,但最好不用,以免出错。我采用直接判断的方法,剔除此种情况。
// 在计算机里结合律不成立,(a*b)*c!=a*(b*c),原则是先让计算结果值动态范围小的两个数运算,请注意程序里
//的写法。
// 注:(1E38/b)*1E6不要写成1E44/b,因为无法在32位浮点数里保存1E44,切记!
// 计算机使用二进制数计算,能有效利用电子器件高速开关的特性,而人习惯于十进制数表示,二进制和十进制
//没有方便的方法转换,只能通过大量计算实现,浮点数的十进制科学记数法显示尤其需要大量的运算,可见,显示
//一个浮点数要经过若干次浮点运算,没有必要就不要显示,花在显示上的时间比计算的耗时都要多得多。
//============================================================================================
void DispF(float f) reentrant //用科学记数法显示浮点数,在float全范围内精确显示,超出范围给出提示。
{ //+-1.175494E-38到+-3.402823E+38
float tf,b;
unsigned long w;
char i,j;
if(f<0){
PrintChar('-');
f=-1.0*f;
}
if(f<1.175494E-38){
yyprintf("?.??????");//太小了,超出了最小范围。
return;
}
if(f>1E35){ //f>10^35
tf=f/1E35;
b=1000.0;
for(i=0,j=38;i<4;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f/(1E29*b); //1E35*b/1E6
PrintW(w,j);
}
else if(f>1E28){ //10^28<f<=10^35
tf=f/1E28;
b=1E7;
for(i=0,j=35;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f/(1E22*b); //1E28*b/1E6
PrintW(w,j);
}
else if(f>1E21){ //10^21<f<=10^28
tf=f/1E21;
b=1E7;
for(i=0,j=28;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f/(1E15*b); //1E21*b/1E6
PrintW(w,j);
}
else if(f>1E14){ //10^14<f<=10^21
tf=f/1E14;
b=1E7;
for(i=0,j=21;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f/(1E8*b); //1E14*b/1E6
PrintW(w,j);
}
else if(f>1E7){ //10^7<f<=10^14
tf=f/1E7;
b=1E7;
for(i=0,j=14;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f/(10.0*b); //1E28*b/1E6
PrintW(w,j);
}
else if(f>1){ //1<f<=10^7
tf=f;
b=1E7;
for(i=0,j=7;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f/(1E-6*b); //1E0*b/1E6
PrintW(w,j);
}
else if(f>1E-7){ //10^-7<f<=1
tf=f*1E7;
b=1E7;
for(i=0,j=0;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f*(1E13/b); //(1E7/b)*1E6
PrintW(w,j);
}
else if(f>1E-14){ //10^-14<f<=10^-7
tf=f*1E14;
b=1E7;
for(i=0,j=-7;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f*(1E20/b); //(1E14/b)*1E6
PrintW(w,j);
}
else if(f>1E-21){ //10^-21<f<=10^-14
tf=f*1E21;
b=1E7;
for(i=0,j=-14;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f*(1E27/b); //(1E21/b)*1E6
PrintW(w,j);
}
else if(f>1E-28){ //10^-28<f<=10^-21
tf=f*1E28;
b=1E7;
for(i=0,j=-21;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f*(1E34/b); //(1E28/b)*1E6
PrintW(w,j);
}
else if(f>1E-35){ //10^-35<f<=10^-28
tf=f*1E35;
b=1E7;
for(i=0,j=-28;i<8;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f*(1E35/b)*1E6; //(1E35/b)*1E6
PrintW(w,j);
}
else{ //f<=10^-35
tf=f*1E38;
b=1000.0;
for(i=0,j=-35;i<4;i++,j--)
if(tf/b<1) b=b/10.0;
else break;
w=f*(1E38/b)*1E6; //(1E38/b)*1E6
PrintW(w,j);
}
}
void PrintW(unsigned long w,char j) reentrant //科学记数法,显示十进制尾数和阶码。
{
char i;
unsigned long tw,b;
//if(j<-38){yyprintf("?.??????");return;}//太小了,超出最小表数范围。
//if(j>38){yyprintf("*.******");return;}此算法不会出现j>38的情况。
tw=w/1000000;
PrintChar(tw+'0');PrintChar('.');
w=w-tw*1000000;
b=100000;
for(i=0;i<6;i++){
tw=w/b;
PrintChar(tw+'0');
w=w-tw*b;
b=b/10;
}
yyprintf("E%d",(int)j);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -