在做嵌入式系统通信时往往会用到串口,包括嵌入式系统将数据传输给PC,或者是嵌入式系统之间进行数据传输,这时候就会遇到发送数据的问题。
我们知道单片机通过串口发送数据时往往是一次一个字节(8位),如果传输char(8位)型数据则很好办,只需要直接发送就可以了,但是在发送int型数据和float型数据时就会稍微有些复杂。
下面就以常用的8位单片机89c51为例来进行说明。
当发送int型或long型数据时比较简单,一个int型数据是16位,long是32位,把int型/long型数据变成2/4个char型数据发送出去就可以了,程序如下
void long_char(unsigned long l,unsigned char *s)
{
*s = l>>24;
*(s+1) = l>>16;
*(s+2) = l>>8;
*(s+3) = l;
}
在串口助手上就可以接收到相应的long型数据了。
当发送float型数据时稍微有些复杂。首先简单介绍下float型数据在内存中的存储方式:
float遵从的是IEEE R32.24 在存储中都分为三个部分:
1.符号位(Sign) : 0代表正,1代表为负
2.指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储
3.尾数部分(Mantissa):尾数部分
如下图所示:
以8.25和120.5这两个数字来举例:
8.25用二进制表示为:1000.01。1000.01可以表示为1.00001*23
120.5用二进制表示为:1110110.1。1110110.1可以表示为1.1101101*26
十进制小数点转换成二进制,可以上网查一下相关资料,“小数转二进制”,不在本篇讨论的范围内。
下面就看看8.25和120.5在内存中真正的存储方式。
8.25,用二进制的科学计数法表示为: 1.00001*23
120.5,用二进制的科学计数法表示为: 1.1101101*26
介绍完了float型数据在内存中的存储方式,能够知道如何发送float型数据了:直接按照int型类似的发送肯定是不行的,这就需要采用指针的方法(在keil中数据的排放格式是大端模式):
void float_char(float f,unsigned char *s)
{
unsigned char *p;
p = (unsigned char *)&f;
*s = *p;
*(s+1) = *(p+1);
*(s+2) = *(p+2);
*(s+3) = *(p+3);
}
通过这种方法把数组s发送出去,在接受端接受到的就是标准的IEEE754结构的原始数据,也就是float型数据在内存中存放的值,这种方法比较简单明了,这时候的串口接收端可以用现成的,不需要自己编写。
还可以采用共用体的方法,如果采用共用体时串口的接收端软件需要自己编写:
我们知道共用体可以使不同的数据类型来共享相同的地址空间,所以程序如下:
void float_char(float f,unsigned char *s)
{
union change
{
float d;
unsigned char dat[4];
}r1;
r1.d = f;
*s = r1.dat[0];
*(s+1) = r1.dat[1];
*(s+2) = r1.dat[2];
*(s+3) = r1.dat[3];
}
接收端采用同样的程序编写就可以得到float型数据的值了,不再需要其他的转换。
类似的,传输long型或int型时也可以采用共用体的方法:
void long_char(unsigned long l,unsigned char *s)
{
union change
{
long d;
unsigned char dat[4];
}r1;
r1.d = l;
*s = r1.dat[0];
*(s+1) = r1.dat[1];
*(s+2) = r1.dat[2];
*(s+3) = r1.dat[3];
}
以上就是串口通信中传输int/float型数据的方式了,有什么疑问一起讨论。