在嵌入式系统中,无论是什么类型的数据,数据传输一般是以1个字节为单位(8位)。
比如读取某传感器的温度数据,假设该数据为32位,那么我们用u32来存放最终数据,但是由于一次是以一个字节发送的,所以需要用u8类型的变量作为中间变量,然后通过移位运算来拼接成最终的32位数据。如果发送过来的数据类型为浮点型,该如何正确接收数据呢?
我们先看一下简单的,非浮点型的例子,代码示意如如下:
u32 dat;
u8 temp;
for(int i=0;i<4;i++)//4个字节,一次8位
{
temp=get_u8_data(); //获取8位数据
dat=dat << 8; //左移8位
dat = dat | temp; //按位或运算
}
我们知道,温度数据一般都是小数形式,故此时需要根据温度传感器的数据手册进行换算即可。
此处的强制转换,是被传感器厂商所允许的(发过来的u32的数据也是这么设计的)
float temperature = dat *1.2
//被数据数据手册所允许的强制转换,强制转换数据会发生改变,但这样才是正确的温度数据
假设,传感器发来的数据直接就是float型温度的数据呢?此时不需要公式转换,比如发送过来的温度数据是 float 型的1.23,二进制为0111_0000_1010_0100
此时如果我们用上述方法,u32 dat 会等于二进制的0111_0000_1010_0100,
对应的十进制为28836
此时明显是不对的,假如我们使用强制转换的方法:
u32 dat=28836; //获取到的温度数十进制28836二进制0111_0000_1010_0100
float temperature=(float)dat;
此时temperature=28836.000,并没有得到1.23!!
为什么会这样呢,因为强制转换会改变内存数据!比如:
float a=1.23; //4字节
short unsigned int b; //4字节
b=a; //强制转换
//a为4字节,当a=1.23时在内存中为0111_0000_1010_0100
//十六进制为70A4,十进制为28836
//若直接强制转换,
//则b=1 ,对应内存为0000_0000_0000_0001
我们看到,float a=1.23转换成short unsigned int b之后,b=1;
二进制数据由0111_0000_1010_0100变为0000_0000_0000_0001
有什么办法将u32的二进制数据赋值给 folat 呢?首先,很容易想到的,位运算符:
u32 get_dat=28836;//代表了float型数据1.23,二进制0111_0000_1010_0100
float temperature ;
temperature = temperature | get_dat;
哈哈,这不就将get_dat的二进制数据赋值给float temperature了嘛,
此时的temperature=0111_0000_1010_0100
打印temperature得到的数就是1.23.
如果你这么想,编译器会将你打回现实,因为float型的数据不允许使用位运算符!
怎么办呢?我们可以用指针!既然数据强制转换会丢失,那我将数据地址强制转换呢?!
u32 get_dat=28836; //这是接收到的温度数据,二进制0111_0000_1010_0100
float *temperature;
temperature=(float *)&get_dat;
我们将u32 get_dat的地址强制转换成float *
此时就是temperature和get_dat共用一块内存,其二进制数据当然是一样的.
此时的*temperature=1.23
至此,大功告成!
但是需要注意的是,指针强制转换需要指针长度一致,本例中float和u32都是4个字节。如果不一致的话就需要再定义一个中间变量,避免发生严重错误。