在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_stackheap
ldr r0,=top_of_stacks
msr CPSR_c,#Mode_FIQ:OR:I_Bit:OR:F_Bit
sub sp,r0,#Offset_FIQ_Stack
msr CPSR_c,#Mode_IRQ:OR:I_Bit:OR:F_Bit
sub sp,r0,#Offset_IRQ_Stack
msr CPSR_c,#Mode_ABT:OR:I_Bit:OR:F_Bit
sub sp,r0,#Offset_ABT_Stack
msr CPSR_c,#Mode_UND:OR:I_Bit:OR:F_Bit
sub sp,r0,#Offset_UND_Stack
msr CPSR_c,#Mode_SVC:OR:I_Bit:OR:F_Bit
sub r1,r0,#Offset_SVC_Stack
;IMPORT |Image$$ZI$$Limit|
;LDR r0, =|Image$$ZI$$Limit|
ldr r0, =base_of_heap
mov r2,#0
mov r3,#0
mov pc,lr
AREA |C$$code|, CODE, READONLY
EXPORT __main
__main
bl __user_initial_stackheap
b __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); // 1001
LedDelay();
Led_Display(0x6); // 0110
LedDelay();
}
return 0;
}
显示如下:
![](https://img-my.csdn.net/uploads/201206/18/1340029485_4648.jpg)