将浮点型数据转化成字符输出

      在调试中,常常需要把数据发送到PC端,而串口通常以字节为单位传送数据,这就需要将各种不同类型的数据转化成字符串的形式。我在调试485程序时,遇到几个问题。

      我打算将一个浮点型数据传送到PC,用串口助手观察其数值,所以我定义了一个字符数组:长度为8(我的数据取值有限,精确度要求也不高);前4元素为整数部分(千位、百位、十位、个位);第五个元素为小数点;后三个元素是小数。这样,调用RS485_Write函数就可以将这个数组发送到485。这个函数定义如下:

void RS485_Write(u8* data,u16 len)
{
	u16 i;
	DIR485_H ;

	for (i=0; i<len; i++)
	{
		RS485_SendByte(data[i]);
	}

	DIR485_L;		
}


问题1:发送数据的长度问题

     在调用RS485_Write函数时,我的字符数组长度是8,所以想到形参len的值应为8,但是,这么做经常会出错,最后一个字节总是不能显示出来,很郁闷。后来经俞老师点播:字符串的结尾有一个空字符作为结束,正是对这个空字符的处理,造成了错误。

     事实上,像RS485_Write((u8*)"abc",sizeof("abc"));这样的应用是没有错的,但字符串的size是包含末尾的空字符的,所以这个函数将发送‘a’、‘b’、‘c’和‘\0’共4个字节,在PC接收端,也是这么默认的,在显示的时候,最后一个字符是舍弃的(实际上他也不可显示)。这就解释了我的千分位为什么消失了。将AsciiBuff数组的长度初始化为9,并给AsciiBuff[8]赋值为‘\0’,RS485_Write((u8*)AsciiBuff,9);就能解决问题。

     但是,即使是原方法,我的串口也确实是完整发送了八个字符的,只不过是串口助手将我最后一个字节舍弃,这个做法应该是有点不妥的,我要不要为这个特性修改代码,还要看我所服务的上位机的程序到底怎么理解从串口上接收的字符。

问题2:数据的转换

    之前,我的代码为:

u8 AsciiBuff[9];
int HexToASCII(float data)
{
	AsciiBuff[0] =( u8 )(data/1000)%10 + 0x30;
	AsciiBuff[1] =( u8 )(data/100)%10 + 0x30;
	AsciiBuff[2] =( u8 )(data/10)%10 + 0x30;
	AsciiBuff[3] =( u8 )((int)(data)%10) + 0x30;
	AsciiBuff[4] = 46;		 //小数点
	AsciiBuff[5] = ( u8 )(data*10)%10 + 0x30;
	AsciiBuff[6] = (( u8 )(data*100))%10 + 0x30;
	AsciiBuff[7] = ((u8)(data*1000.0))%10 + 0x30;
	AsciiBuff[8] = (u8)'\0';

	if(AsciiBuff[0]==48 && AsciiBuff[1]==48 && AsciiBuff[2]==48)		
    		{
		AsciiBuff[0] =32;		
		AsciiBuff[1] =32;
		AsciiBuff[2] =32;
		}
	if(AsciiBuff[0]==48 && AsciiBuff[1]==48 )
		{
		AsciiBuff[0] =32;		
		AsciiBuff[1] =32;
		}
	if(AsciiBuff[0]==48)
    		{
		AsciiBuff[0] =32;		
		}
}

    关键在于这两句:

AsciiBuff[6] = ( u8 )(data*100)%10 + 0x30;

AsciiBuff[7] = ( u8 )((u8)(data*1000)%10) + 0x30;

     之前总是出错,症状是小数最后两位(百分位、千分位)不准。想了很多可能性,包括考虑data*1000是不是超过了u8类型的最大值(确实可能超过255,但是c语言不会直接对字符数据进行运算,都是转换为整型处理,所以不会出问题)。都没有效果

     后来改为:

	AsciiBuff[0] =( u8 )(data/1000)%10 + 0x30;
	AsciiBuff[1] =( u8 )(data/100)%10 + 0x30;
	AsciiBuff[2] =( u8 )(data/10)%10 + 0x30;
	AsciiBuff[3] =( u8 )((int)(data)%10) + 0x30;
	AsciiBuff[4] = 46;		 
	AsciiBuff[5] = ( int )(data*10)%10 + 0x30;
	AsciiBuff[6] = (( int )(data*100))%10 + 0x30;
	AsciiBuff[7] = ((int)(data*1000.0))%10 + 0x30;
	AsciiBuff[8] = (u8)'\0';

     这才实现。

     也就是说,我u8必须改为int,这是为什么?难道u8的数据不能做取余的运算?不是有自动转化为整型么。我猜想可能是强制指派的类型,不会再自动变化,所以指派为u8后,不能再进行取余运算,但是编译器为什么不报错呢?

这仍是个疑问

问题3:二进制的精度

     我要显示1121.553,显示出来的总是1121.552,这是二进制的精度问题,没有简单的办法解决,我的处理方法是不管他。

     具体是这样的,AsciiBuff[7] = ((int)(data*1000))%10 + 0x30;就可以正确显示1152.553,问题出在1000.0上。汗一个

问题4:PC机的串口设置

     之前传输485数据,波特率设为115200,但是接收总出问题,在发送数据之间需要很大的延时,需要5ms左右,这太长了。后来更改了串口的设置(设备管理器-端口),可以将延时缩小到500us。(这个延时对485是必要的)

总结

在发生问题后, 要全局考虑问题,判断问题出在哪,第一个、第四个问题就是这么定位原因的

要分析症状,将问题分解,比如数值转换的问题,那个赋值语句很长,将其分解为多条语句,一步一步观察其运行,最后得到解

写代码的时候,不要去刻意省略括号,一些运算符的优先级可能对计算产生很大影响,加上括号可以使代码意图很明显,也不会出错。整理好并不会显得繁复。

posted on 2012-07-29 20:27  lxjsailor  阅读(768)  评论(1编辑  收藏  举报

导航