# NModbusX **Repository Path**: clever_student/nmodbus-x ## Basic Information - **Project Name**: NModbusX - **Description**: 基于NModbus写的一个Modbus通信库,使用 C# 7.3 语法。支持通信交换消息订阅、大小端处理、返回原始数据、同步与异步读写、数据格式转换等功能。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-04 - **Last Updated**: 2026-08-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: NModbus, modbus ## README # NModbusX 基于 [NModbus](https://github.com/NModbus/NModbus)(3.0.83)的 Modbus 通信库,面向 WinForms / .NET 桌面应用,使用 C# 7.3 语法、面向对象方式封装。 ## 功能特性 - **三种传输**:Modbus TCP / RTU / ASCII,统一连接配置 `ModbusConnectionOptions`; - **同步与异步读写**:读线圈(0x01)、读离散输入(0x02)、读保持寄存器(0x03)、读输入寄存器(0x04)、写单个/多个线圈与寄存器(0x05/0x06/0x0F/0x10)、读写多寄存器(0x17)、读设备标识(0x2B); - **返回原始数据**:`ReadHoldingRegistersRaw` 等直接返回寄存器原始字节(大端,Modbus 线上字节序),线圈返回按位打包字节; - **大小端处理**:`EndianHelper` 提供整体反转、字内字节交换、32 位字交换、按元素宽度转换字节序; - **数据格式转换**:`DataConvert` 支持 `short/ushort/int/uint/float/double/string` 与字节数组、寄存器数组互转,支持大端/小端(`ByteOrder`)以及 Modbus 32 位数据的四种寄存器排列(`RegisterOrder`:ABCD / CDAB / BADC / DCBA); - **通信交换消息订阅**:通过 `MessageTraced` 事件订阅每次请求/响应交换,事件参数 `ModbusMessageLogEntry` 包含时间、方向、从站地址、功能码、事务 ID、完整原始帧(TCP 含 MBAP 头、RTU 含 CRC)、PDU 及可读描述,可直接用于通信日志显示。 ## 项目结构 ``` NModbusX/ # 解决方案根(VS2022 打开 NModbusX.sln) ├── NModbusX.sln ├── NModbusX/ # 类库(.NET Framework 4.7.2,C# 7.3,packages.config) │ ├── NModbusX.csproj │ ├── Core/ │ │ ├── ModbusMasterX.cs # 主类:连接 + 同步/异步读写 + 原始数据 + 事件 │ │ ├── ModbusTraceTransport.cs # IModbusTransport 装饰器:消息订阅核心 │ │ ├── ModbusMessageLogEntry.cs # 通信日志条目 │ │ ├── ModbusConnectionOptions.cs │ │ └── ... # 功能码/异常码名称映射等 │ ├── Data/ │ │ ├── DataConvert.cs # 数据格式转换(含大小端) │ │ ├── EndianHelper.cs # 原始数据大小端处理 │ │ └── ByteOrder.cs / RegisterOrder.cs │ ├── IO/SerialPortStreamResource.cs # 串口适配 │ └── packages.config ├── NModbusXDemo/ # WinForms 演示(.NET Framework 4.7.2,引用 NModbusX 类库) ├── tools/EndToEndTest/ # 端到端自检(net48,起 TCP 从站模拟器验证) └── packages/ # NuGet 包(NModbus 3.0.83) ``` ## 快速开始 ### 1. 连接 ```csharp // TCP var options = ModbusConnectionOptions.CreateTcp("192.168.1.10", 502, slaveAddress: 1); // 串口 RTU var options = ModbusConnectionOptions.CreateSerial("COM3", ModbusConnectionMode.Rtu, baudRate: 9600, parity: Parity.None, dataBits: 8, stopBits: StopBits.One, slaveAddress: 1); var master = new ModbusMasterX(options); master.Connect(); ``` ### 2. 同步 / 异步读写 ```csharp // 同步 ushort[] regs = master.ReadHoldingRegisters(slave: 1, startAddress: 0, numberOfPoints: 10); bool[] coils = master.ReadCoils(1, 0, 8); master.WriteSingleRegister(1, 0, 0x1234); master.WriteMultipleRegistersRaw(1, 10, new byte[] { 0x12, 0x34, 0x56, 0x78 }); // 异步 ushort[] regs2 = await master.ReadHoldingRegistersAsync(1, 0, 10); byte[] raw = await master.ReadHoldingRegistersRawAsync(1, 0, 10); ``` ### 3. 原始数据与大小端 ```csharp // 返回寄存器原始字节(大端) byte[] raw = master.ReadHoldingRegistersRaw(1, 0, 4); // 例如 [3F 80 00 00 12 34 56 78] // 整体反转(小端视图) byte[] le = EndianHelper.Reverse(raw); // 字内字节交换(BADC) byte[] badc = EndianHelper.SwapBytesInWords(raw); // 32 位字交换(CDAB) byte[] cdab = EndianHelper.SwapWords(raw, wordBytes: 4); ``` ### 4. 数据格式转换 ```csharp // 按大小端解析 float f = DataConvert.ToSingle(raw, offset: 0, ByteOrder.BigEndian); int i = DataConvert.ToInt32(raw, 0, ByteOrder.LittleEndian); // 按 Modbus 32 位寄存器排列解析(不同厂商设备差异) float f2 = DataConvert.ToSingle(raw, 0, RegisterOrder.CDAB); // AB PLC 常用 // 便捷读:直接从设备读取并按排列解析 float value = master.ReadSingle(1, 0, RegisterOrder.ABCD); // 2 个寄存器 double d = master.ReadDouble(1, 0, ByteOrder.BigEndian); // 4 个寄存器 string s = master.ReadString(1, 0, 10, ByteOrder.BigEndian); // 10 个寄存器 -> ASCII ``` ### 5. 通信交换消息订阅(通信日志) ```csharp var master = new ModbusMasterX(options); master.MessageTraced += OnMessageTraced; // 订阅:主站每次请求 / 从站每次响应都会触发 master.Connect(); private void OnMessageTraced(object sender, ModbusMessageLogEntry e) { // e.Direction 方向:Request(主站->从站) / Response(从站->主站) // e.SlaveAddress 从站地址 // e.FunctionCode 功能码 // e.FunctionName 功能码名称,如"读保持寄存器 (Read Holding Registers)" // e.TransactionId 事务 ID // e.RawFrame 完整原始帧(TCP 含 MBAP 头 / RTU 含 CRC) // e.HexFrame 原始帧十六进制 // e.ProtocolDataUnit / e.HexPdu PDU 及十六进制 // e.Description 可读描述,如"起始=0,数量=10" // e.Timestamp 时间 Console.WriteLine(e); } ``` 日志示例(TCP): ``` [10:01:17.584] --> 从站=1 读保持寄存器 (Read Holding Registers) 起始=0,数量=4 00 00 00 00 00 06 01 03 00 00 00 04 [10:01:17.601] <-- 从站=1 读保持寄存器 (Read Holding Registers) 返回 8 字节数据 00 01 00 00 00 0B 01 03 08 3F 80 00 00 12 34 56 78 ``` > 说明:请求方向日志的 TransactionId 字段显示为消息构造时的默认值(NModbus 在真正发送时才分配事务 ID),PDU 内容与实际线上完全一致;响应方向包含完整准确的事务 ID。 ## 构建 ```bash # 方式一:VS2022 直接打开 NModbusX.sln 构建(库 + Demo) # 方式二:命令行 MSBuild MSBuild.exe NModbusX.sln /restore /p:Configuration=Release # 端到端自检(SDK 风格 net48;会启动 TCP 从站模拟器并断言全部功能) MSBuild.exe tools/EndToEndTest/EndToEndTest.csproj /restore /p:Configuration=Debug tools/EndToEndTest/bin/Debug/net48/EndToEndTest.exe ``` ## WinForms 示例 `NModbusXDemo` 演示了: - TCP / RTU / ASCII 连接; - 同步读保持寄存器(同时展示寄存器值、原始字节、整体反转、字内交换、字交换); - 异步读保持寄存器; - 读输入寄存器、读线圈(含位打包原始字节); - 按 4 种 32 位寄存器排列读 Float; - 写单个寄存器、写多个寄存器(hex 原始字节输入); - `MessageTraced` 订阅的通信日志实时显示(ListView,时间/方向/从站/功能码/描述/原始帧)。 默认 TFM 为 `net472`(VS2022 直接打开即用);如需 .NET 8/9 环境,将 `TargetFramework` 改为 `net8.0-windows`(或 `net9.0-windows`)即可。 ## 注意事项 - 主站对象非线程安全,多线程并发读写需自行加锁; - 串口(RTU/ASCII)路径代码与 TCP 一致,但建议在真实设备/虚拟串口上做硬件联调; - 库目标 `.NET Framework 4.7.2`(传统 csproj + packages.config,与 WinForms 环境一致);核心代码兼容 netstandard2.0,如需跨平台可改用 SDK 风格项目。