6410 浮点与printf处理(基于RVDS)

来源:互联网 发布:php gtk 完全中文手册 编辑:程序博客网 时间:2024/05/16 09:32

在RVDS环境下,使用直接使用printf不可以显示浮点,即使用如下代码:

#include <stdarg.h>void Printf(const char *fmt,...){    va_list ap;    char string[256];int i;    va_start(ap, fmt);    vsprintf(string, fmt, ap);    for (i = 0; string[i]; i++)UART_Putc(string[i]);    va_end(ap);}

要想正常显示浮点,必须使用arm库,并且使用软件浮点库,即不能使用硬浮点VFP。在初始化代码中添加如下代码调用arm库,可以正常使用浮点了:
EXPORT__user_initial_stackheap__user_initial_stackheapldrr0,=top_of_stacksmsrCPSR_c,#Mode_FIQ:OR:I_Bit:OR:F_Bitsubsp,r0,#Offset_FIQ_StackmsrCPSR_c,#Mode_IRQ:OR:I_Bit:OR:F_Bitsub     sp,r0,#Offset_IRQ_StackmsrCPSR_c,#Mode_ABT:OR:I_Bit:OR:F_Bitsubsp,r0,#Offset_ABT_StackmsrCPSR_c,#Mode_UND:OR:I_Bit:OR:F_Bitsubsp,r0,#Offset_UND_StackmsrCPSR_c,#Mode_SVC:OR:I_Bit:OR:F_Bitsubr1,r0,#Offset_SVC_Stack;IMPORT  |Image$$ZI$$Limit|;LDRr0, =|Image$$ZI$$Limit|ldrr0, =base_of_heapmovr2,#0movr3,#0movpc,lr

AREA|C$$code|, CODE, READONLYEXPORT__main__mainbl__user_initial_stackheapb__rt_entry

这样 在执行_rt_entry时,就会调用main()函数。把用户程序写在main()里面就可以了。

想在使用VFP的情况下,显示浮点,必须重新完成可变参数的printf函数了。
由于堆栈是8字节对齐,所以不能使用头文件#include <stdarg.h>。必须重新完成几个重要的宏:
改后的宏如下:
typedef char *  va_list;#define _INTSIZEOF(n) ((sizeof(n) + sizeof(n) - 1) & ~(sizeof(n) - 1) )#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )#define va_arg(ap,t)   (*(t *)(((unsigned int)ap=(((unsigned int)ap+sizeof(t)+sizeof(t)-1)&(~(sizeof(t)-1))))-sizeof(t)))#define va_end(ap)      ( ap = (va_list)0 )

上面重新完成的宏一方面要符合堆栈(函数参数传递)的8字节对齐,还要符合double或者long long类型的8字节对齐。使用可变参数传递的浮点都会被转化成双精度的double型,并且是8字节对齐的。这里要注意,在stdarg.h库里面,我经过测试发现这几个宏都不能是64位类型8字节对齐,造成浮点显示错误,所以这是第一步就应该完成的。
浮点的存储格式可以参考IEEE 754 standard和ARM1176JZF-S™ Technical Reference Manual手册
我在处理浮点时,没有直接显示,而是先显示整数部分,然后把小数部分转化成整数,再显示出现。代码如下:
void output_int(int num, const int base,int precision){const char *digit = "0123456789ABCDEF";unsigned int buf[32];int i = 0;char ch;if(base){if(precision){for(i=0;i<precision;i++){buf[i] = num%base;num = num/base;}}else{do{buf[i] = num%base;num = num/base;i++;}while(num > 0);}}if(i != 0)if(num < 0){UART_Putc('-');}while(--i >= 0){ch = digit[buf[i]];UART_Putc(ch);}}void output_double(double num,int precision){const char *digit = "0123456789ABCDEF";unsigned int buf[32]={0};int i = 0,j = 0;int value_i=0;int value_f=0;char ch;double temp=0;value_i=(int)num;temp=num;if(value_i<0){UART_Putc('-');temp=0-temp;value_i=0-value_i;}do{buf[i] = value_i%10;value_i = value_i/10;i++;}while(value_i > 0);while(--i >= 0){ch = digit[buf[i]];UART_Putc(ch);} UART_Putc('.'); i=1; if(precision) { for(j=0;j<precision;j++){i=i*10;}}else i=10000;  switch(i) { case 10: value_f=(int)(temp*10)-((int)temp)*10; output_int(value_f,10,0); break;   case 100: value_f=(int)(temp*100)-((int)temp)*100; output_int(value_f,10,0); break; case 1000: value_f=(int)(temp*1000)-((int)temp)*1000; output_int(value_f,10,0); break; case 10000: value_f=(int)(temp*10000)-((int)temp)*10000; output_int(value_f,10,0); break; case 100000: value_f=(int)(temp*100000)-((int)temp)*100000; output_int(value_f,10,0); break; case 1000000: value_f=(int)(temp*1000000)-((int)temp)*1000000; output_int(value_f,10,0); break; case 10000000: value_f=(int)(temp*10000000)-((int)temp)*10000000; output_int(value_f,10,0); break; case 100000000: value_f=(int)(temp*100000000)-((int)temp)*100000000; output_int(value_f,10,0); break; case 1000000000: value_f=(int)(temp*1000000000)-((int)temp)*1000000000; output_int(value_f,10,0); break;  }  }int uart0_printf(char *format, ...){va_list unnamed_p;char *p, *sval;int value_i;long long value_t;int precision=0;double ff=0;va_start(unnamed_p, format);for(p = (char *)format; *p != '\0'; p++){if(*p != '%'){UART_Putc(*p);continue;}++p;if (is_digit(*p)){precision = skip_atoi(&p);}else precision=0;if (*p == '.') {++p;if (is_digit(*p))precision = skip_atoi(&p); }{switch(*p){case 'd':value_i = va_arg(unnamed_p, int);output_int(value_i, 10,precision);break;case 's':for(sval = va_arg(unnamed_p, char *); *sval; sval++)UART_Putc(*sval);break;case 'x':value_i = va_arg(unnamed_p, int);output_int(value_i, 16,precision);break;case 'o':value_i = va_arg(unnamed_p, int);output_int(value_i, 8,precision);break;case 'f':ff=va_arg(unnamed_p,double);output_double(ff,precision);break;default:UART_Putc(*p);break;}}}va_end(unnamed_p);return 0;}

这样就可以避免使用arm库函数,解决硬件浮点的显示了。

比如:

int main(void){ Port_Init();    Uart_Init();uart0_printf("abcdefg:%d,%f\n",1,(float)1/3);uart0_printf("abcdefg:%d,%6f\n",1,-12.567891);         for(;;) {    Led_Display(0x9); // 1001LedDelay();    Led_Display(0x6); // 0110LedDelay();    }    return 0;}


显示如下:




原创粉丝点击