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);
        }
相关推荐
唐青枫7 小时前
别只会看日志:C#.NET SOS 调试扩展从 Dump 到内存泄漏排查
c#·.net
yswenli14 小时前
基于C#开发网站视频嗅探下载工具——BrowserVideoGrabber
c#·videodownload·webvideodownload·videograbber
Lost of 程序猿14 小时前
M2 实战:询价与采购订单聚合落地——跨聚合一致性、领域事件与 Outbox
开发语言·c#·asp.net·.net
Polevne16 小时前
C# GRPC 一元与双向流
linux·算法·c#
XiaoZhenHua982 天前
C#工业机器视觉Recipe配方系统设计:多型号、多相机、多工位参数如何统一管理
c#·软件架构·机器视觉·工业自动化·工业软件·recipe
fujisheng6612 天前
FUI 导航实践:拆开 Layer、History、Coverage 与 Cache 的组合语义
c#·unity3d
淡海水2 天前
10-05-高级-模式匹配-CSharp如何改变与数据结构的交互方式
数据结构·算法·c#·模式匹配
XiaoZhenHua982 天前
C# WinForms + 西门子S7 + SQLite + EPPlus生产数据采集系统架构设计
系统架构·sqlite·c#
Lost of 程序猿2 天前
船岸数据同步链路实战:SendFlag、单调版本号与断网三天后的续传
后端·c#·asp.net
cjp5602 天前
012.UG二次开发,UG管道服务器与WPF管道通讯,传输JSON数据
c#