You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

5.0 KiB

title author top cover toc mathjax summary tags categories reprintPolicy abbrlink date coverImg img password
通讯数据格式转换 TianZD true true true false modubusTCP在传输时,通过读写保持性寄存器位进行数据传输,一个保持性寄存器占有2个byte,16个bite,传输的数据常为float型(4个byte,32位),需要进行转换 [数据格式 modbus] [通信] cc_by fffca2d8 2022-04-29 13:47:36 <nil> <nil> <nil>

[toc]

通讯数据格式转换(float/real-word-byte)

前言

在上位机和下位机进行通讯的时候,通常要进行数据转换为字节(8位)或者word(16位)进行传输

modubusTCP在传输时,通过读写保持性寄存器位进行数据传输,一个保持性寄存器占有2个byte16个bite,传输的数据常为float型(4个byte,32位),需要进行转换

浮点数的表示通常采用IEEE 754浮点数标准,可以参考文章IEEE754标准的浮点数存储格式

IEEE754转换:在线转换网址

数据在内存中的存储格式

大端模式

大端模式是指数据的高字节保存在内存的低地址单元中,而数据的低字节保存在内存的高地址单元中,这样的存储模式有点类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。

小端模式

小端模式是指数据的高字节保存在内存的高地址单元中,而数据的低字节保存在内存的低地址单元中。

转换

其中float-byte、byte-float代码转自CSDN文章:float型数据与4字节之间的转换,作者tutu-hu

float-byte(32位浮点数转4个8位)

2进制,与运算,左移运算

/*将浮点数f转化为4个字节数据存放在byte[4]中*/
unsigned char* Float_to_Byte(float f)
{
	float float_data = 0;
	unsigned long longdata = 0;
	longdata = *(unsigned long*)&f;           //注意,会丢失精度
	byte[0] = (longdata & 0xFF000000) >> 24;
	byte[1] = (longdata & 0x00FF0000) >> 16;
	byte[2] = (longdata & 0x0000FF00) >> 8;
	byte[3] = (longdata & 0x000000FF);
	return byte;
}

float-word(32位浮点数转2个16位)

unsigned int* Float_to_word(float f)
{
    unsigned long longdata = 0;
    longdata = *(unsigned long*)&f;           //注意,会丢失精度
    word[0] = (longdata & 0xFFFF0000) >> 16;
    word[1] = (longdata & 0x0000FFFF);
    return word;
}

byte-float(4个8位转1个32位浮点数)

方法1

把四个字节存储好之后,再把这个存储区域的首地址强制转换为float指针类型,这样就可以提取出这个浮点数了。

/*将4个字节数据byte[4]转化为浮点数存放在*f中*/
float Byte_to_Float(unsigned char *p)
{
	float float_data=0;
	unsigned long longdata = 0;
	longdata = (*p<< 24) + (*(p+1) << 16) + (*(p + 2) << 8) + (*(p + 3) << 0);
	float_data = *(float*)&longdata;
	return float_data;
}

方法2

把四个字节存储好之后,再把这个存储区域的首地址强制转换为float指针类型,这样就可以提取出这个浮点数了。

这个和方法1类似

/**
 *作用:把u8四字节数组转为float
 *note:低地址放float的低字节
**/
float U8_to_Float(u8* str)  
{  
	float data;
	data = *((float*)str);
	return data;
}

方法3

定义一个float变量,然后定义u8类型指针数组指向float变量地址,Modbus协议解析的时候只管向地址指向的存储单元填充数据,需要用浮点数的时候直接拿过来用就可以了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)  
{  
    float freq;
    char recv[4] = {0x41, 0xbc, 0x00, 0x00}; //接收到的数据,高字节到低字节排列
    char *Modbus_HoldReg[4];				 //定义保持寄存器指针数组

    //第一步:指针初始化
    Modbus_HoldReg[0] = ((char*)(&freq)) + 3;	 //低地址指向高位
    Modbus_HoldReg[1] = ((char*)(&freq)) + 2;     
    Modbus_HoldReg[2] = ((char*)(&freq)) + 1;     
    Modbus_HoldReg[3] = ((char*)(&freq)) + 0;	 //高地址指向低位

    //第二步:给地址指定的内存单元赋值(对应Modbus协议中的数据解析)
    *Modbus_HoldReg[0] = recv[0];
    *Modbus_HoldReg[1] = recv[1];
    *Modbus_HoldReg[2] = recv[2];
    *Modbus_HoldReg[3] = recv[3];
    printf("%f\r\n", freq);
    
    return 0;
}

word-float(2个16位合成1个32位浮点数)

float Byte_to_Float(unsigned char *p)
{
	float float_data=0;
	unsigned long longdata = 0;
	longdata = (*p<< 16) + (*(p+1) << 0);
	float_data = *(float*)&longdata;
	return float_data;
}

byte-word(2个8位合成1个16位)

两个8位数如何转化为16位数?

int data = (a<<8) & b;
char a;//高位
char b;//低位
....
int data = (a<<8)&0xFF00;
data &= b;