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

在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;

}


显示如下:




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值