她叫小红 发表于 2016-12-10 10:58:04

利用union传递不同类型数据

本帖最后由 她叫小红 于 2016-12-10 15:50 编辑

      在下位机在与上位机进行通信的时候,通常遇到传输不同类型数据的情况,比如:“char”、“int”、“float”等等,而在用串口接收时,由于硬件限制,一次只能接收8bit,给传输造成不便。
      以前在学习6050时用到“匿名上位机”时,采用的是移位的方式,将一个长的数据右移8位并截取低8位的形式进行传输的,例如:
void usart1_report_0x05(u16 a,u16 b,u16 c)
{
    u8 i,tbuf;
    for(i=0;i<6;i++)tbuf=0;                   //清0
    tbuf=(a>>8)&0XFF;                        //横滚角
    tbuf=a&0XFF;
    tbuf=(b>>8)&0XFF;                        //俯仰角
    tbuf=b&0XFF;
    tbuf=(c>>8)&0XFF;                        //航向角
    tbuf=c&0XFF;                                  //上锁与否
    usart1_niming_report(0X05,tbuf,6);    //功能字
}而在mBlock固件中采用的是另一种方式,让我感到“要学习的东西真不少”了,先看两小段代码:                  代码一://使用共用体数据结构实现short、float、double 向 char 转换,精妙!!学习了
/*--------单精度浮点型--------*///Datatype for floating-point numbers, a number that has a decimal point.
union{
    byte byteVal;   //四字节数组
    float floatVal;       //四个字节
    long longVal;       //四个字节
}val;       代码二:/*----------写float---------*/
void sendFloat(float value){ //该函数的作用是发送一个单精度浮点型数据给上位机
   writeSerial(2);                     // 2 float       //mBot固件协议:返回帧的功能字,2表示后面的数据是float型
   val.floatVal = value;             //赋值
   writeSerial(val.byteVal);
   writeSerial(val.byteVal);
   writeSerial(val.byteVal);
   writeSerial(val.byteVal);
}      在union 中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址,而一个union 只配置一个足够大的空间以来容纳最大长度的数据成员。
      代码一定义一个union类型的数据val,可以看出val中的各类数据长度都是一样的:4Byte。在代码二中当val.floatVal 被赋予初值是,由于val.floatVal与val.byteVal具有相同的起始地址,此时val.byteVal表示的是val.floatVal在内存中存储的最低字节(小端模式),这里可以理解为byteVal数组中存储的是数据floatVal在内存中的存储数据。更多详细关于union的知识可以参考:http://c.biancheng.net/cpp/html/450.html         下面看一段测试程序:#include <Arduino.h>
union{
    byte byteVal;
    float floatVal;
}val;
void sendFloat(float value){
   //Serial.write(2);                     // 2 float
   val.floatVal = value;
   Serial.write(val.byteVal);
   Serial.write(val.byteVal);
   Serial.write(val.byteVal);
   Serial.write(val.byteVal);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
sendFloat(-575);
}
void loop() {
// put your main code here, to run repeatedly:
}

      上面的代码实现的是: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,希望能帮到大家~


感谢无私奉献的网友们~








页: [1]
查看完整版本: 利用union传递不同类型数据