极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 15811|回复: 1

利用union传递不同类型数据

[复制链接]
发表于 2016-12-10 10:58:04 | 显示全部楼层 |阅读模式
本帖最后由 她叫小红 于 2016-12-10 15:50 编辑

        在下位机在与上位机进行通信的时候,通常遇到传输不同类型数据的情况,比如:“char”、“int”、“float”等等,而在用串口接收时,由于硬件限制,一次只能接收8bit,给传输造成不便。
        以前在学习6050时用到“匿名上位机”时,采用的是移位的方式,将一个长的数据右移8位并截取低8位的形式进行传输的,例如:
  1. void usart1_report_0x05(u16 a,u16 b,u16 c)
  2. {
  3.     u8 i,tbuf[6];
  4.     for(i=0;i<6;i++)tbuf=0;                   //清0
  5.     tbuf[0]=(a>>8)&0XFF;                        //横滚角
  6.     tbuf[1]=a&0XFF;
  7.     tbuf[2]=(b>>8)&0XFF;                        //俯仰角
  8.     tbuf[3]=b&0XFF;
  9.     tbuf[4]=(c>>8)&0XFF;                        //航向角
  10.     tbuf[5]=c&0XFF;                                  //上锁与否
  11.     usart1_niming_report(0X05,tbuf,6);    //功能字
  12. }
复制代码
而在mBlock固件中采用的是另一种方式,让我感到“要学习的东西真不少”了,先看两小段代码:                    代码一:
  1. //使用共用体数据结构实现short、float、double 向 char 转换,精妙!!学习了
  2. /*--------单精度浮点型--------*///Datatype for floating-point numbers, a number that has a decimal point.
  3. union{
  4.     byte byteVal[4];   //四字节数组
  5.     float floatVal;       //四个字节
  6.     long longVal;       //四个字节
  7. }val;
复制代码
      代码二:
  1. /*----------写float---------*/
  2. void sendFloat(float value){ //该函数的作用是发送一个单精度浮点型数据给上位机
  3.      writeSerial(2);                       // 2 float       //mBot固件协议:返回帧的功能字,2表示后面的数据是float型
  4.      val.floatVal = value;             //赋值
  5.      writeSerial(val.byteVal[0]);
  6.      writeSerial(val.byteVal[1]);
  7.      writeSerial(val.byteVal[2]);
  8.      writeSerial(val.byteVal[3]);
  9. }
复制代码
        在union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址,而一个union 只配置一个足够大的空间以来容纳最大长度的数据成员。

        代码一定义一个union类型的数据val,可以看出val中的各类数据长度都是一样的:4Byte。在代码二中当val.floatVal 被赋予初值是,由于val.floatVal与val.byteVal具有相同的起始地址,此时val.byteVal[0]表示的是val.floatVal在内存中存储的最低字节(小端模式),这里可以理解为byteVal数组中存储的是数据floatVal在内存中的存储数据。更多详细关于union的知识可以参考:http://c.biancheng.net/cpp/html/450.html
         下面看一段测试程序:
  1. #include <Arduino.h>
  2. union{
  3.     byte byteVal[4];
  4.     float floatVal;
  5. }val;
  6. void sendFloat(float value){
  7.      //Serial.write(2);                       // 2 float
  8.      val.floatVal = value;
  9.      Serial.write(val.byteVal[0]);
  10.      Serial.write(val.byteVal[1]);
  11.      Serial.write(val.byteVal[2]);
  12.      Serial.write(val.byteVal[3]);
  13. }
  14. void setup() {
  15.   // put your setup code here, to run once:
  16.   Serial.begin(9600);
  17.   sendFloat(-575);
  18. }
  19. void loop() {
  20.   // put your main code here, to run repeatedly:
  21. }
复制代码

        上面的代码实现的是:Arduino复位后将内存中存储的数据“-575”打印到串口,打印出的数据是:00 C0 0F C4

由于是小端模式,-575存储在内存中正确的顺序应该是:C4 0F C0 00(11000100 00001111 11000000 00000000)。

       这里涉及到数据在Arduino内存中的存储格式,以单精度浮点型为例:浮点在内存中的存储类似于科学记数法,一般形式为:

R = M * 2^ e

(R : real;M: 位数小数点前“1”被省略 ; e : 阶码,小数点移动位数,大于0右移,反之,左移)

其在内存中的表现形式为:

  x                                     x...x                             x...x...x...x  


                                                                  数符(1b)                      阶码(8b)                     尾码(23b)



则:-575                         =                             1                                 10001000          00011111 10000000 0000000


       -575                         =                          负数                              136-127= 9                    1.000 1111 11


       将1.000 1111 11小数点右移9位即可得到该数的绝对值,又因其数符为1,表示这是数为负,最后结果为:- 10 0011 1111 即 -575。更多详细关于float在内存中的存储格式的知识可以参考:http://www.cnblogs.com/dolphin0520/archive/2011/10/02/2198280.html

       学习mBot的固件还是挺有收获的,最后附上固件一份里面写了一些注释,但不是很全o,希望能帮到大家~


感谢无私奉献的网友们~









本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-27 11:36 , Processed in 0.063618 second(s), 19 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表