串口发送接收浮点型数据

转自:https://blog.csdn.net/liangwei88624/article/details/6885803

转自:https://blog.csdn.net/newstoy/article/details/25726127

在做下位机通信时往往会用到串口,包括下位机将数据传输给上位机,或者是下位机与下位机之间进行数据传输,这时候就会遇到发送数据的问题,单片机通过串口发送数据时往往是一次一个字节(8位),如果传输char(8位)型数据则很好办,只需要直接发送就可以了,但是在发送int型数据和float型数据时就会稍微有些复杂。

   当发送float型数据时稍微有些复杂。下面简单介绍下float型数据在内存中的存储方式(double类似,以下部分参考了别人的博客)。

    float遵从的是IEEE R32.24 在存储中都分为三个部分:
1.符号位(Sign) : 0代表正,1代表为负
2.指数位(Exponent):用于存储科学计数法中的指数数据,并且采用移位存储
3.尾数部分(Mantissa):尾数部分

float的存储方式如下图所示:

   R32.24和R64.53的存储方式都是用科学计数法来存储数据的,比如8.25用十进制的科学计数法表示就为:8.25*clip_image0021,而120.5可以表示为:1.205*clip_image0022

    而计算机根本不认识十进制的数据,他只认识0,1,所以在计算机存储中,首先要将上面的数更改为二进制的科学计数法表示,8.25用二进制表示可表示为1000.01,120.5用二进制表示为:1110110.1。用二进制的科学计数法表示1000.01可以表示为1.00001*clip_image002[2],1110110.1可以表示为1.1101101*clip_image002[3],任何一个数都的科学计数法表示都为1.xxx*clip_image002[1],尾数部分就可以表示为xxxx,第一位都是1,所以可以将小数点前面的1省略,所以23bit的尾数部分,可以表示的精度却变成了24bit,道理就是在这里,那24bit能精确到小数点后几位呢,我们知道9的二进制表示为1001,所以4bit能精确十进制中的1位小数点,24bit就能使float能精确到小数点后6位,而对于指数部分,因为指数可正可负,8位的指数位能表示的指数范围就应该为:-127-128了,所以指数部分的存储采用移位存储,存储的数据为元数据 127,下面就看看8.25和120.5在内存中真正的存储方式。

     首先看下8.25,用二进制的科学计数法表示为:1.00001*clip_image002[2]

按照上面的存储方式,符号位为:0,表示为正,指数位为:3 127=130 ,位数部分为,故8.25的存储方式如下图所示:

而单精度浮点数120.5的存储方式如下图所示:

 

那么如果给出内存中一段数据,并且告诉你是单精度存储的话,你如何知道该数据的十进制数值呢?其实就是对上面的反推过程,比如给出如下内存数据:0100001011101101000000000000,首先我们现将该数据分段,0 10000 0101 110 1101 0000 0000 0000 0000,在内存中的存储就为下图所示:

根据我们的计算方式,可以计算出,这样一组数据表示为:1.1101101*clip_image002[3]=120.5而双精度浮点数的存储和单精度的存储大同小异,不同的是指数部分和尾数部分的位数。

    介绍完了float型数据在内存中的存储方式后能够知道如何发送float型数据了,直接按照int型类似的发送肯定是不行的,这就需要采用指针的方法(在keil中数据的排放格式是大端模式):

    最近正在调试nrf24L01无线通行模块,由于要fpga与PC机相互通信,PC机没spi,所以要个开发板转发,数据传输流程如下:

上位机 <-> 串口 <-> ARM开发板 <-> spi<->nrf24L01<->另一个nrf24L01<->spi<->fpga开发板。

其中遇到一个头疼的问题是传输的都是浮点型数,但发送接受的是unsigned char型。

float,占4字节,包括符号位(1位,第31位),指数为(8位,-126~128,22~30位),尾数位(23位,0~22位)

当时想出了两种方案

(1)其实精度要求不高的话,直接把浮点数X100转化成16位或32位整数,在拆分为unsigned char类型发过去,在接收后合并,并强制转化为float在除以100.(不太好放弃)

(2)直接把float数据拆分为4个unsigned char,发过去,再合并为float。

我使用方案(2),其中有两点要注意。

(1)大端存储,小端存储;如果搞错读取数据就不是你接收的数据地址(我主要使用了fpga,arm以及PC机,很有可能存储方式不同,一般可能不需要考虑)

 (2)字对齐。不然就合并不成float(我先前没注意直接一个很怪异的数据)

方法如下:

(1)发送端

    void package_frame(const void *data)
    {
    	int i;
    	for(i=0; i<4; i++)
    	{
    		send_frame[i] = ((uchar *)data)[i];
    	}
    }

 

将float data数据拆分成uchar后存储在数组send_frame[]发送。

(2)接收端

    float exchange_data(uchar *data)
    {
     
    	float float_data;
    	float_data = *((float*)data);
    	return float_data;
    }

 

将uchar *data首地址付给float_data来合并成float型数据(记得字对齐和大小端存储,不然数据不对)

其实发整数等大于1字节的数据也一样。

  • 18
    点赞
  • 129
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
要在MicroPython中使用串口发送浮点数和整数,需要使用串口通信库,如pyserial。以下是一个示例代码,该代码使用pyserial库将浮点数和整数发送串口: ```python import serial ser = serial.Serial('/dev/ttyUSB0', 9600) # 串口初始化,根据具体情况修改端口号和波特率 # 发送浮点数 f = 3.14 ser.write(str(f).encode()) # 将浮点数转换为字符串并发送串口 # 发送整数 i = 123 ser.write(str(i).encode()) # 将整数转换为字符串并发送串口 ``` 在上述代码中,我们首先使用pyserial库初始化了串口,然后将浮点数和整数转换为字符串,并通过串口发送。请注意,发送的字符串必须使用encode()方法进行编码,以便正确发送串口。 另外,如果接收方需要以相同的格式解析接收到的数据,可以在发送时在字符串中添加标识符,例如在浮点数前添加字符F,在整数前添加字符I,以便接收方正确解析数据。例如: ```python # 发送带有标识符的浮点数 f = 3.14 ser.write(('F'+str(f)).encode()) # 将带有标识符的浮点数转换为字符串并发送串口 # 发送带有标识符的整数 i = 123 ser.write(('I'+str(i)).encode()) # 将带有标识符的整数转换为字符串并发送串口 ``` 在接收方,可以使用相应的标识符来解析接收到的数据。例如: ```python data = ser.readline().decode().strip() # 读取串口接收到的数据并解码为字符串 if data.startswith('F'): f = float(data[1:]) # 解析浮点数 elif data.startswith('I'): i = int(data[1:]) # 解析整数 ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值