串口传递浮点数

原文网址:http://blog.tianya.cn/blogger/post_read.asp?BlogID=991984&PostID=23898227

前段时间应师兄要求,要通过单片机串口实现Modbus协议,在看了协议的内容后写好了程序的框架,然后根据不同的协议功能码分别实现不同的功能,比如对下位机分别读取或者写入线圈状态(位状态)、二进制数据以及浮点数等。其他的数据格式挺好实现,但怎样互相传递浮点数据却让我考虑了一番。

  串口通讯中传递的数据格式不外两种:ASCII码(即可见字符形式)和二进制数据格式(对应Modbus协议中有ASCII模式和RTU模式)。最初的想法是把浮点数的各位分别提取出来,保存成一个各元素都是ASCII码的数组,然后通过串口发送出去,对方接收到这个数组后再相应地组合成原来的浮点数。这是以前写过的一段代码:
  //################################################################
  // 函数名:void Float2Char(float Value,char *array)
  // 描 述:将浮点数的各个位的数值转换成字符串,通过串口发送至上位机显示
  // 参 数:float Value为欲转换的正数浮点数值,转换结果保存在字符数组*array里
  //################################################################
  
  void Float2Char(float Value,char *array) 
  {
   Uint16 IntegerPart;
   float DecimalPart;
   Uint16 i = 0;
   Uint16 j = 0;
   char temp;
  
   //分离整数部分与小数部分:
   //整数部分保存在IntegerPart中
   //小数部分保存在DecimalPart中
   if (Value>=1)
   {
   IntegerPart = (Uint16)Value;
   DecimalPart = Value-IntegerPart;
   }
   else 
   {
   IntegerPart = 0;
   DecimalPart = Value-IntegerPart;
   }
  
  
   //转换整数部分
   if (IntegerPart == 0)
   {
   array[0] = 0+48;
   array[1] = '.';
   i = 1;
   }
   else
   {
   while(IntegerPart>0)
   {
   array[i] = IntegerPart%10+48;
   IntegerPart = IntegerPart/10;
   i++;
   }
   i--;
  
   //修正转换结果的顺序
   for (j=0;j<i 2+1;j++)
   {
   temp = array[j];
   array[j] = array[i-j];
   array[i-j] = temp;
   }
   i++;
   array[i] = '.';
   }
  
  
   //转换小数部分,此处设置最多转换到第四位小数
   i++;
   array[i++] = (Uint16)(DecimalPart*10)%10+48;
   array[i++] = (Uint16)(DecimalPart*100)%10+48;
   array[i++] = (Uint16)(DecimalPart*1000)%10+48;
   if (5 == i)
   array[i++] = (Uint16)(DecimalPart*1000)%10+48;
  
   array[i] = '\0'; //结束符
  
  } 
  // End of line
  这段代码没有考虑负数的转换,要转换带符号数只需加入符号判断后将正(负)号标志放在数组的第一位即可。这段函数用起来挺好用,但是这种方法有很多不完善的地方,比如要预先设置字符数组*array的大小以足够存储转换后的各位,小数点位置不确定,给接收方还原数据带来了麻烦。
  
  硬件存储浮点数,统一的标准是IEEE754标准,因此更好的方法是通过这个统一的标准来实现串口传送浮点数据的转换和还原。嵌入式硬件使用的float型数据即单精度32位浮点数格式,这在一般应用中已经足够。IEEE754规定了32位数据的格式,分别规定1位符号位、23位尾数位和8位指数位(不知有没有记错?)。比如浮点数34.9,IEEE754标准十六进制显示是0x42 0x0B 0x99 0x9A,二进制显示则是 0 10000100 00010111001100110011010。我最初的想法是根据这个标准规定的各部分位数,写出转换和还原的代码来;但这样确实太麻烦了。因此何妨直接借助编译器来实现这个转换??这样多方便啊
  以下的代码我没有直接写,直接借用了这篇博客文章(http://blog.sina.com.cn/s/blog_4b94ff130100ejyb.html)里的程序:
  /*******************************************
  函数名称:Float2Byte
  功 能:浮点数转换成字节型数组
  参 数:入口参数floatNum,欲转换的浮点数
  返 回 值:byteArry,转换后的字节数组
  ********************************************/
  void Float2Byte(float floatNum,unsigned char* byteArry)
  {
   char* pchar=(char*)&floatNum;
   for(int i=0;i<sizeof(float);i++)
   {
   *byteArry=*pchar;
   pchar++;
   byteArry++;
   }
  }
  
  /*******************************************
  函数名称:Byte2Float
  功 能:字节型(16进制格式)转换成浮点数
  参 数:入口参数*byteArry,转换成的字节数组,每四个字节转换成一个单精度浮点数
  返 回 值:转换后的浮点数
  ********************************************/
  float Byte2Float(unsigned char* byteArry)
  {
   return *((float*)byteArry);
  }
  // End of line
  将以上的代码应用到MSP430单片机的串口通讯中,成功实现了430单片机与PC机通过串口进行浮点数据的传送。PC机的串口发送和接收代码,可直接根据上述程序修改。
  
  后来我想将Modbus协议移植到TMS320F28x的DSP上,但上述浮点数转换还原代码却不能正确运行。经调试后很快发现问题,MSP430单片机的开发环境IAR C430里规定的Char(Unsigned char )类型是1个字节(8位),而28x的开发环境CCS里规定的Char(Unsigned char )类型是双字节(16位)。知道这点后,改动起来也很容易:
  
  //定义一个unsigned char型的临时数组,用来保存接收到的十六进制字节
  unsigned char temp_char[2];
  float FloatNum;
  //将接收到的信号参数解码,按IEEE754浮点数标准还原
  //假设DSP的SCI接收到的4个字节依次保存在RxBuffer[1]~ RxBuffer[4]里
  temp_char[0] = RxBuffer[2]<<8 | RxBuffer[1];
  temp_char[1] = RxBuffer[4]<<8 | RxBuffer[3];
  //还原成原来的浮点数
  FloatNum = *((float*)temp_char);
  
  好了,问题解决了。
  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值