|
|
|
---
|
|
|
|
title: 通讯数据格式转换
|
|
|
|
author: TianZD
|
|
|
|
top: true
|
|
|
|
cover: true
|
|
|
|
toc: true
|
|
|
|
mathjax: false
|
|
|
|
summary: >-
|
|
|
|
modubusTCP在传输时,通过读写保持性寄存器位进行数据传输,一个保持性寄存器占有2个byte,16个bite,传输的数据常为float型(4个byte,32位),需要进行转换
|
|
|
|
tags:
|
|
|
|
- 数据格式
|
|
|
|
- modbus
|
|
|
|
categories:
|
|
|
|
- "通信"
|
|
|
|
reprintPolicy: cc_by
|
|
|
|
abbrlink: fffca2d8
|
|
|
|
date: 2022-04-29 13:47:36
|
|
|
|
coverImg:
|
|
|
|
img:
|
|
|
|
password:
|
|
|
|
---
|
|
|
|
|
|
|
|
\[toc\]
|
|
|
|
|
|
|
|
# 通讯数据格式转换(float/real-word-byte)
|
|
|
|
|
|
|
|
## 前言
|
|
|
|
|
|
|
|
在上位机和下位机进行通讯的时候,通常要进行数据转换为字节(8位)或者word(16位)进行传输
|
|
|
|
|
|
|
|
modubusTCP在传输时,通过**读写保持性寄存器**位进行数据传输,一个保持性寄存器占有**2个byte**,**16个bite**,传输的数据常为**float型(4个byte,32位)**,需要进行转换
|
|
|
|
|
|
|
|
浮点数的表示通常采用**IEEE 754浮点数标准**,可以参考文章[IEEE754标准的浮点数存储格式](https://www.cnblogs.com/MikeZhang/p/IEEE754FloatEncode20180117.html)
|
|
|
|
|
|
|
|
IEEE754转换:[在线转换网址](http://www.speedfly.cn/tools/hexconvert/)
|
|
|
|
|
|
|
|
## 数据在内存中的存储格式
|
|
|
|
|
|
|
|
### 大端模式
|
|
|
|
|
|
|
|
大端模式是指数据的高字节保存在内存的低地址单元中,而数据的低字节保存在内存的高地址单元中,这样的存储模式有点类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。
|
|
|
|
|
|
|
|
### 小端模式
|
|
|
|
|
|
|
|
小端模式是指数据的高字节保存在内存的高地址单元中,而数据的低字节保存在内存的低地址单元中。
|
|
|
|
|
|
|
|
## 转换
|
|
|
|
|
|
|
|
其中float-byte、byte-float代码转自CSDN文章:[float型数据与4字节之间的转换,作者tutu-hu](https://blog.csdn.net/weixin_42700740/article/details/103236885?share_token=7af34e32-1bce-4b09-9225-afa6e02006f6)
|
|
|
|
|
|
|
|
### float-byte(32位浮点数转4个8位)
|
|
|
|
|
|
|
|
**2进制,与运算,左移运算**
|
|
|
|
|
|
|
|
```c++
|
|
|
|
/*将浮点数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位)
|
|
|
|
|
|
|
|
```c++
|
|
|
|
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指针类型**,这样就可以提取出这个浮点数了。
|
|
|
|
|
|
|
|
```c
|
|
|
|
/*将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类似
|
|
|
|
|
|
|
|
```c
|
|
|
|
/**
|
|
|
|
*作用:把u8四字节数组转为float
|
|
|
|
*note:低地址放float的低字节
|
|
|
|
**/
|
|
|
|
float U8_to_Float(u8* str)
|
|
|
|
{
|
|
|
|
float data;
|
|
|
|
data = *((float*)str);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
#### 方法3
|
|
|
|
|
|
|
|
定义一个float变量,然后定义u8类型指针数组指向float变量地址,Modbus协议解析的时候只管向地址指向的存储单元填充数据,需要用浮点数的时候直接拿过来用就可以了。
|
|
|
|
|
|
|
|
```c
|
|
|
|
#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位浮点数)
|
|
|
|
|
|
|
|
```c
|
|
|
|
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位数?
|
|
|
|
|
|
|
|
```c
|
|
|
|
int data = (a<<8) & b;
|
|
|
|
```
|
|
|
|
|
|
|
|
```c
|
|
|
|
char a;//高位
|
|
|
|
char b;//低位
|
|
|
|
....
|
|
|
|
int data = (a<<8)&0xFF00;
|
|
|
|
data &= b;
|
|
|
|
```
|