Modbus字节序说明

Modbus字节序说明 用littly endine byte swap 解析寄存器

最近做ModBus TCP方面的测试有点多,尽管对于ModBus协议算是比较了解了,也经常知道字节传输序列的不同对工程师带来了很多不必要的麻烦,这不是一个技术难题,仅仅只是过去各家各户开发遗留下来的标准统一问题,所以这里写下这篇文章作为备忘。
在Modbus通信中,目前我们主要有16bit(AB)、32bit(AB CD)和最新的64bit(AB CD EF GH)三种数据长度。每个字母代表一个字节。
 针对16bit传输,只存在正序(AB)或反序(BA)两种方式,也就所谓的正序先传高位,以及反序先传低位,为什么会出现这样的现象,可以联系堆栈处理的方式,不过这个不重要。

更多的应用场景针对的是双字32位数据传输。那么同样的正序(ABCD)以及反序(DCBA)似乎就够用了,但是却还有字节交换这样的问题,所以你经常会看到SWAP函数,这样的我们衍生出了以下四种排序方式。

Big-endian :ABCD
Little-endian :DCBA
Big-endian byte swap :BADC
Little-endian byte swap :CDAB

对于32bit的Real类型:对应十六进制:ABCD。

1. Big-endian: 大端模式,正序。即:大端排序,先传递高位A依次传递到低位D。压入发送队列发送。

所以在通讯中,收发到的数据不对,先要做的就是确定确定数据类型,其次要确定数据传输时的字节序是如何的,这有确保了这两点的正确性,才可以正确的解析出数据。

2. Little-endian:小端模式,正序。即:依次从低位到高位。然后  依次压入发送队列,发送。

3. Big-endian byte swap: 大端模式,反序。先将寄存器内部字节交换,然后按照大端模式发送。 

4. Little-edian byte swap : 小端模式,反序。 先将寄存器内部字节交换顺序,然后  依次压入发送队列,发送。

float readModbusDataReal32bitBigMode(quint16 dataHighSectionABCDInD1, quint16 dataLowSectionDEFHInD2)
{
    //55.23    (??) 0xEB85,    (B\) 0x425C
    /*
    *   float: ABCD。 
        小端模式交换字节:先发送的是低字节, CD  AB
        就是:(向左看)是压入发送队列的顺序。 modbus 中D1位置就是:CD, D2寄存器就是:AB
        解析:字节数组char floatArray[4], 其中:3是高位,0是低位。
        因此:因为是小端模式
        则D1是floatArray中的[0,1]字节,且正序,D是0字节,C是1字节。
            D2是flaotArray中的[2,3]字节,正序,A是3字节,B是2字节。
    */ 

    QByteArray array0xABCDEFGH;//4字节
    array0xABCDEFGH.resize(4);
    array0xABCDEFGH[3] = (dataLowSectionDEFHInD2 & 0xFF00) >> 8; 
    array0xABCDEFGH[2] = (dataLowSectionDEFHInD2 & 0xFF);

    array0xABCDEFGH[1] = (dataHighSectionABCDInD1 & 0xFF00) >> 8;
    array0xABCDEFGH[0] = (dataHighSectionABCDInD1 & 0xFF);
    float tempFloat32;
    memcpy(&tempFloat32, array0xABCDEFGH.data(), array0xABCDEFGH.length());
    return tempFloat32;
}

 

void writeModbusDataReal32bitBigMode(float realData, quint16* dataHighSectionABCD, quint16* dataLowSectionDEFH)
{
    //一个float占4个字节 AB CD. D是低端字节。
    // 小端模式,交换字节:先发送的是低字节, CD  AB
    int leng4Byte = sizeof(realData);
    QByteArray array0xABCDEFGH;//4字节
    array0xABCDEFGH.resize(leng4Byte);
    memcpy(array0xABCDEFGH.data(), &realData, leng4Byte);
    //
    quint16 temp16;
    temp16 = array0xABCDEFGH[1] << 8 & 0xFF00;
    temp16 |= array0xABCDEFGH[0] ;
    *dataHighSectionABCD = temp16;
    temp16 = 0;
    temp16 = array0xABCDEFGH[3] << 8 & 0xFF00;
    temp16 |= array0xABCDEFGH[2];
    *dataLowSectionDEFH = temp16;
}

 C# 读取modbus rtu代码 

using Modbus.Device;
using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfAppModbusTest.View
{
    public class MainView : BindableBase
    {
        public SerialPort serialPort = new SerialPort();
        public IModbusMaster modbusMaster;
        private ObservableCollection<double> _Values = new ObservableCollection<double>();

        public ObservableCollection<double> Values
        {
            get { return _Values; }

            set { SetProperty(ref _Values, value); }
        }

        public MainView()

        {
            serialPort.PortName = "COM20";
            serialPort.BaudRate = 9600;
            serialPort.DataBits = 8;
            serialPort.Parity = Parity.Even;
            serialPort.StopBits = StopBits.One;
            serialPort.Open();
            modbusMaster = ModbusSerialMaster.CreateRtu(serialPort);
            //打开串口
            if (!serialPort.IsOpen) serialPort.Open();

            Task.Run(() =>
            {
                while (true)
                {
                    //1 litter-endian-swap CDAB 排序后 小端压入发送队列 CD AB
                    //ushort[] vals = modbusMaster.ReadHoldingRegisters(1, 0, 2);//CD AB 接收的顺序
                    //var buff0 = vals[0] & 0xff; //d
                    //var buff1 = vals[0] >> 8 & 0xff;//c
                    //var buff2 = vals[1] & 0xff; //b
                    //var buff3 = vals[1] >> 8 & 0xff;//a
                    //还原成0x abcd
                    //List<byte> bufferlist = new List<byte>();
                    //bufferlist.Add((byte)buff0);//d
                    //bufferlist.Add((byte)buff1);//c
                    //bufferlist.Add((byte)buff2);//b
                    //bufferlist.Add((byte)buff3);//a

                    //2 litter-endian DCBA 排序后 小端发送
                    //ushort[] vals = modbusMaster.ReadHoldingRegisters(1, 0, 2);//DC BA 接收的顺序
                    //var buff0 = vals[0] & 0xff; //C
                    //var buff1 = vals[0] >> 8 & 0xff;//D
                    //var buff2 = vals[1] & 0xff; //B
                    //var buff3 = vals[1] >> 8 & 0xff;//A
                    ////还原成0x abcd
                    //List<byte> bufferlist = new List<byte>();
                    //bufferlist.Add((byte)buff1);//D
                    //bufferlist.Add((byte)buff0);//C
                    //bufferlist.Add((byte)buff3);//B
                    //bufferlist.Add((byte)buff2);//A

                    //3 big-endian-swap BADC 排序后 大端发送
                    //ushort[] vals = modbusMaster.ReadHoldingRegisters(1, 0, 2);//BA DC 接收的顺序
                    //var buff0 = vals[0] & 0xff; //A
                    //var buff1 = vals[0] >> 8 & 0xff;//B
                    //var buff2 = vals[1] & 0xff; //C
                    //var buff3 = vals[1] >> 8 & 0xff;//D
                    ////还原成0x abcd
                    //List<byte> bufferlist = new List<byte>();
                    //bufferlist.Add((byte)buff3);//D
                    //bufferlist.Add((byte)buff2);//C
                    //bufferlist.Add((byte)buff1);//B
                    //bufferlist.Add((byte)buff0);//A

                    //4 big-endian  ABCD 排序后 大端发送
                    ushort[] vals = modbusMaster.ReadHoldingRegisters(1, 0, 2);//AB CD接收的顺序
                    var buff0 = vals[0] & 0xff; //B
                    var buff1 = vals[0] >> 8 & 0xff;//A
                    var buff2 = vals[1] & 0xff; //D
                    var buff3 = vals[1] >> 8 & 0xff;//C
                    //还原成0x abcd
                    List<byte> bufferlist = new List<byte>();
                    bufferlist.Add((byte)buff2);//D
                    bufferlist.Add((byte)buff3);//C
                    bufferlist.Add((byte)buff0);//B
                    bufferlist.Add((byte)buff1);//A

                    double val = BitConverter.ToSingle(bufferlist.ToArray(), 0);
                    Values = new ObservableCollection<double>(new double[] { val });
                    Thread.Sleep(500);
                }
            });
        }
    }
}

 

 

 

 

posted @ 2025-06-13 15:08  未风  阅读(258)  评论(0)    收藏  举报