Modbus 读写转换

1. 按ushort多字节写入

NModbus 写寄存器API:

C# 复制代码
    public void WriteSingleRegister(byte slaveAddress, ushort registerAddress, ushort value)
    {
        WriteSingleRegisterRequestResponse message = new WriteSingleRegisterRequestResponse(slaveAddress, registerAddress, value);
        base.Transport.UnicastMessage<WriteSingleRegisterRequestResponse>(message);
    }


    public void WriteMultipleRegisters(byte slaveAddress, ushort startAddress, ushort[] data)
    {
        ValidateData("data", data, 123);
        WriteMultipleRegistersRequest message = new WriteMultipleRegistersRequest(slaveAddress, startAddress, new RegisterCollection(data));
        base.Transport.UnicastMessage<WriteMultipleRegistersResponse>(message);
    }

根据不同的设备信号解析类型,大致可以分为:

C# 复制代码
   /// <summary>
   /// 浮点数解析字节序格式
   /// </summary>
   public enum ParseFormat
   {
       /// <summary>
       /// 标准32位:字节顺序 1 2 3 4 = AB CD
       /// </summary>
       ABCD,
       /// <summary>
       /// 字节反转:BA DC
       /// </summary>
       BADC,
       /// <summary>
       /// 高低字交换:CD AB
       /// </summary>
       CDAB,
       /// <summary>
       /// 完全反转:DC BA
       /// </summary>
       DCBA
   }

1.1 float 类型写入

这里主要是把一个 float 转换为对应的 ushort\[\].

C# 复制代码
        /// <summary>
        /// 将 float 按照指定字节序转换为两个 ushort
        /// </summary>
        /// <param name="value">float值</param>
        /// <param name="parseFormat">解析格式ABCD/BADC/CDAB/DCBA</param>
        /// <returns>[高16位, 低16位]</returns>
        private static ushort[] ConvertFloatToTwoUShorts(float value, ParseFormat parseFormat)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            ushort[] result = new ushort[2];

            switch (parseFormat)
            {
                case ParseFormat.ABCD:
                    // 标准:AB  CD
                    result[0] = BitConverter.ToUInt16(bytes, 2);
                    result[1] = BitConverter.ToUInt16(bytes, 0);
                    break;

                case ParseFormat.BADC:
                    // 低16位内部反转:BA  CD
                    result[0] = BitConverter.ToUInt16(bytes, 2);
                    result[1] = ReverseUShort(BitConverter.ToUInt16(bytes, 0));
                    break;

                case ParseFormat.CDAB:
                    // 高低16位互换:CD  AB
                    result[0] = BitConverter.ToUInt16(bytes, 0);
                    result[1] = BitConverter.ToUInt16(bytes, 2);
                    break;

                case ParseFormat.DCBA:
                    // 完全反转:DC  BA
                    result[0] = ReverseUShort(BitConverter.ToUInt16(bytes, 0));
                    result[1] = ReverseUShort(BitConverter.ToUInt16(bytes, 2));
                    break;
            }

            return result;
        }

        /// <summary>
        /// 反转 ushort 的高低字节(B A ↔ A B)
        /// </summary>
        private static ushort ReverseUShort(ushort value)
        {
            return (ushort)((value >> 8) | (value << 8));
        }

1.2 bool 类型写入

这里涉及一点思路转换,把ushort转换为16bits,每个bit对应一个bool状态,更改对应的bit后,得到更新后的ushort值,按照int转换为 ushort\[\]。

C# 复制代码
        private static ushort[] ConvertIntToTwoUShorts(int value)
        {
            byte[] bytes = BitConverter.GetBytes(value);
            return new ushort[]
            {
                BitConverter.ToUInt16(bytes, 0),  // 高16位
                BitConverter.ToUInt16(bytes, 2) // 低16位
            };
        }

2. 按ushort读取解析

NModbus 读寄存器API:

C# 复制代码
 ushort[] ReadHoldingRegisters(byte slaveAddress, ushort startAddress, ushort numberOfPoints);

2.1 解析float类型

一个float占用4个bytes,也就是两个ushort,所以将两个ushort转换为一个float

C# 复制代码
        /// <summary>
        /// 【反向】将两个 ushort 根据指定格式 还原为 float
        /// </summary>
        /// <param name="values">两个ushort:[高16位, 低16位]</param>
        /// <param name="parseFormat">解析格式 ABCD/BADC/CDAB/DCBA</param>
        /// <returns>还原后的float</returns>
        private static float ConvertTwoUShortsToFloat(ushort[] values, ParseFormat parseFormat)
        {
            if (values == null || values.Length != 2)
                throw new ArgumentException("必须传入长度为2的ushort数组");

            ushort high = values[0];
            ushort low = values[1];
            byte[] bytes = new byte[4];

            switch (parseFormat)
            {
                case ParseFormat.ABCD:
                    // AB  CD → 字节顺序 [CD][AB]
                    Buffer.BlockCopy(BitConverter.GetBytes(low), 0, bytes, 0, 2);
                    Buffer.BlockCopy(BitConverter.GetBytes(high), 0, bytes, 2, 2);
                    break;

                case ParseFormat.BADC:
                    // BA  CD → 低字反转,高字不变
                    Buffer.BlockCopy(BitConverter.GetBytes(ReverseUShort(low)), 0, bytes, 0, 2);
                    Buffer.BlockCopy(BitConverter.GetBytes(high), 0, bytes, 2, 2);
                    break;

                case ParseFormat.CDAB:
                    // CD  AB → 高低字互换
                    Buffer.BlockCopy(BitConverter.GetBytes(high), 0, bytes, 0, 2);
                    Buffer.BlockCopy(BitConverter.GetBytes(low), 0, bytes, 2, 2);
                    break;

                case ParseFormat.DCBA:
                    // DC  BA → 高低字都反转
                    Buffer.BlockCopy(BitConverter.GetBytes(ReverseUShort(low)), 0, bytes, 0, 2);
                    Buffer.BlockCopy(BitConverter.GetBytes(ReverseUShort(high)), 0, bytes, 2, 2);
                    break;

                default:
                    throw new NotSupportedException("不支持的解析格式");
            }

            return BitConverter.ToSingle(bytes, 0);
        }

2.2 解析bool类型

这里拿到的依然是一个ushort,然后看该bool量对应的bit在第几位。下面仅列出ushort对应到int的逆向转换。

C# 复制代码
        private static int ConvertTwoUShortsToInt(ushort[] values)
        {
            if (values == null || values.Length != 2)
                throw new ArgumentException("必须传入长度为2的ushort数组");

            byte[] bytes = new byte[4];

            Buffer.BlockCopy(BitConverter.GetBytes(values[0]), 0, bytes, 0, 2);
            Buffer.BlockCopy(BitConverter.GetBytes(values[1]), 0, bytes, 2, 2);

            return BitConverter.ToInt32(bytes, 0);
        }
相关推荐
逝水无殇11 小时前
C# 异常处理详解
开发语言·后端·c#
玖玥拾13 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
逝水无殇14 小时前
C# 文件的输入与输出详解
开发语言·数据库·后端·c#
唐青枫19 小时前
看懂 IL 的关键:C#.NET 栈机执行模型实战拆解
c#·.net
我才是银古19 小时前
从零构建 Windows 桌面 RPA 框架:Go 与 .NET 的跨语言协奏
c#·go·rpa
逝水无殇21 小时前
C# 正则表达式详解
开发语言·后端·正则表达式·c#
朱永博21 小时前
使用Onnruntime实现Padim/Patchcore推理
开发语言·c#
吴可可1231 天前
C# CAD二次开发添加带按钮的窗口
c#
铅笔侠_小龙虾1 天前
Rust 学习(8)-切片类型
学习·rust·c#
习明然1 天前
我的本地化AI项目(三)
人工智能·python·electron·c#·avalonia