?? 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 + -