基于Modbus协议的TCP服务器-客户端源码(C#)

付费 ¥4.99付费 ¥4.99

该内容已接入现有会员/付费系统,解锁后可查看完整资料或下载附件。

查看解锁方式
基于Modbus协议的TCP服务器-客户端源码(C#)缩略图
本文目录
  1. 1. 一、项目结构与依赖
  2. 2. 二、Modbus TCP服务器实现
  3. 3. 三、Modbus TCP客户端实现
  4. 4. 四、完整使用示例
  5. 5. 五、关键技术说明
  6. 6. 六、测试与验证
  7. 7. 七、扩展建议
  8. 8. 基于Modbus协议的TCP服务器-客户端源码(C#)¥4.99

C#是Windows平台工业软件开发的主流语言,广泛应用于上位机、SCADA系统、数据采集软件等领域。本文提供完整的C# Modbus TCP服务器和客户端实现代码,包括TCP监听、多客户端管理、Modbus协议解析、寄存器映射、客户端读写操作以及完整的使用示例。代码基于.NET Framework 4.5+,可直接在Visual Studio中编译运行。

一、项目结构与依赖

1.1 开发环境

项目要求
开发工具Visual Studio 2017+ / Visual Studio Code
.NET版本.NET Framework 4.5+ 或 .NET Core 2.0+
语言C# 7.0+
NuGet包无需第三方库,使用System.Net.Sockets
项目类型控制台应用 / Windows Forms / WPF

1.2 寄存器映射

地址范围类型说明
0x0000-0x03FF线圈(Coil)1024个可读写布尔量
0x0000-0x03FF离散输入1024个只读布尔量
0x0000-0x03FF保持寄存器1024个可读写16位整数
0x0000-0x03FF输入寄存器1024个只读16位整数

二、Modbus TCP服务器实现

2.1 数据存储类(ModbusDataStore.cs)

using System;

namespace ModbusTcpServer
{
    /// <summary>
    /// Modbus数据存储,线程安全
    /// </summary>
    public class ModbusDataStore
    {
        private readonly object _lock = new object();
        
        // 线圈(可读写布尔量)
        private readonly bool[] _coils = new bool[1024];
        // 离散输入(只读布尔量)
        private readonly bool[] _inputs = new bool[1024];
        // 保持寄存器(可读写16位)
        private readonly ushort[] _holdingRegs = new ushort[1024];
        // 输入寄存器(只读16位)
        private readonly ushort[] _inputRegs = new ushort[1024];

        // 线圈操作
        public bool GetCoil(ushort address)
        {
            lock (_lock) { return _coils[address]; }
        }
        
        public void SetCoil(ushort address, bool value)
        {
            lock (_lock) { _coils[address] = value; }
        }
        
        public bool[] GetCoils(ushort startAddr, ushort count)
        {
            lock (_lock)
            {
                bool[] result = new bool[count];
                Array.Copy(_coils, startAddr, result, 0, count);
                return result;
            }
        }
        
        public void SetCoils(ushort startAddr, bool[] values)
        {
            lock (_lock)
            {
                Array.Copy(values, 0, _coils, startAddr, values.Length);
            }
        }

        // 离散输入操作
        public bool[] GetInputs(ushort startAddr, ushort count)
        {
            lock (_lock)
            {
                bool[] result = new bool[count];
                Array.Copy(_inputs, startAddr, result, 0, count);
                return result;
            }
        }
        
        public void SetInput(ushort address, bool value)
        {
            lock (_lock) { _inputs[address] = value; }
        }

        // 保持寄存器操作
        public ushort GetHoldingReg(ushort address)
        {
            lock (_lock) { return _holdingRegs[address]; }
        }
        
        public void SetHoldingReg(ushort address, ushort value)
        {
            lock (_lock) { _holdingRegs[address] = value; }
        }
        
        public ushort[] GetHoldingRegs(ushort startAddr, ushort count)
        {
            lock (_lock)
            {
                ushort[] result = new ushort[count];
                Array.Copy(_holdingRegs, startAddr, result, 0, count);
                return result;
            }
        }
        
        public void SetHoldingRegs(ushort startAddr, ushort[] values)
        {
            lock (_lock)
            {
                Array.Copy(values, 0, _holdingRegs, startAddr, values.Length);
            }
        }

        // 输入寄存器操作
        public ushort[] GetInputRegs(ushort startAddr, ushort count)
        {
            lock (_lock)
            {
                ushort[] result = new ushort[count];
                Array.Copy(_inputRegs, startAddr, result, 0, count);
                return result;
            }
        }
        
        public void SetInputReg(ushort address, ushort value)
        {
            lock (_lock) { _inputRegs[address] = value; }
        }
    }
}

2.2 Modbus TCP服务器类(ModbusTcpServer.cs)

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace ModbusTcpServer
{
    public class ModbusTcpServer
    {
        private TcpListener _listener;
        private Thread _listenThread;
        private bool _isRunning;
        private readonly ModbusDataStore _dataStore;
        private readonly List<TcpClient> _clients = new List<TcpClient>();
        private ushort _transactionId = 0;

        public int Port { get; } = 502;
        public ModbusDataStore DataStore => _dataStore;

        public ModbusTcpServer(int port = 502)
        {
            Port = port;
            _dataStore = new ModbusDataStore();
        }

        public void Start()
        {
            _listener = new TcpListener(IPAddress.Any, Port);
            _listener.Start();
            _isRunning = true;
            
            _listenThread = new Thread(ListenForClients)
            {
                IsBackground = true
            };
            _listenThread.Start();
            
            Console.WriteLine($"Modbus TCP服务器已启动,监听端口:{Port}");
        }

        public void Stop()
        {
            _isRunning = false;
            _listener?.Stop();
            lock (_clients)
            {
                foreach (var client in _clients)
                    client.Close();
                _clients.Clear();
            }
            Console.WriteLine("Modbus TCP服务器已停止");
        }

        private void ListenForClients()
        {
            while (_isRunning)
            {
                try
                {
                    TcpClient client = _listener.AcceptTcpClient();
                    lock (_clients) { _clients.Add(client); }
                    
                    Thread clientThread = new Thread(HandleClient)
                    {
                        IsBackground = true
                    };
                    clientThread.Start(client);
                    
                    Console.WriteLine($"客户端连接:{client.Client.RemoteEndPoint}");
                }
                catch (SocketException)
                {
                    // 服务器停止时会触发
                    break;
                }
            }
        }

        private void HandleClient(object obj)
        {
            TcpClient client = (TcpClient)obj;
            NetworkStream stream = client.GetStream();
            byte[] buffer = new byte[260]; // Modbus TCP最大ADU长度

            try
            {
                while (_isRunning && client.Connected)
                {
                    int bytesRead = stream.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0) break; // 客户端断开

                    // 解析MBAP头
                    ushort transId = (ushort)((buffer[0] << 8) | buffer[1]);
                    ushort protoId = (ushort)((buffer[2] << 8) | buffer[3]);
                    ushort length = (ushort)((buffer[4] << 8) | buffer[5]);
                    byte unitId = buffer[6];
                    byte funcCode = buffer[7];

                    // 处理请求并生成响应
                    byte[] response = ProcessRequest(buffer, bytesRead, transId, unitId, funcCode);
                    
                    // 发送响应
                    stream.Write(response, 0, response.Length);
                    stream.Flush();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"客户端异常:{ex.Message}");
            }
            finally
            {
                client.Close();
                lock (_clients) { _clients.Remove(client); }
                Console.WriteLine($"客户端断开:{client.Client.RemoteEndPoint}");
            }
        }

        private byte[] ProcessRequest(byte[] request, int length, 
            ushort transId, byte unitId, byte funcCode)
        {
            try
            {
                switch (funcCode)
                {
                    case 0x01: return ReadCoils(request, transId, unitId);
                    case 0x02: return ReadDiscreteInputs(request, transId, unitId);
                    case 0x03: return ReadHoldingRegisters(request, transId, unitId);
                    case 0x04: return ReadInputRegisters(request, transId, unitId);
                    case 0x05: return WriteSingleCoil(request, transId, unitId);
                    case 0x06: return WriteSingleRegister(request, transId, unitId);
                    case 0x0F: return WriteMultipleCoils(request, transId, unitId);
                    case 0x10: return WriteMultipleRegisters(request, transId, unitId);
                    default:
                        return BuildExceptionResponse(transId, unitId, funcCode, 0x01);
                }
            }
            catch (IndexOutOfRangeException)
            {
                return BuildExceptionResponse(transId, unitId, funcCode, 0x02);
            }
            catch (Exception)
            {
                return BuildExceptionResponse(transId, unitId, funcCode, 0x04);
            }
        }

        // 功能码01:读线圈
        private byte[] ReadCoils(byte[] req, ushort transId, byte unitId)
        {
            ushort startAddr = (ushort)((req[8] << 8) | req[9]);
            ushort quantity = (ushort)((req[10] << 8) | req[11]);
            
            bool[] coils = _dataStore.GetCoils(startAddr, quantity);
            byte byteCount = (byte)((quantity + 7) / 8);
            
            byte[] response = new byte[9 + byteCount];
            BuildMBAPHeader(response, transId, unitId, (ushort)(3 + byteCount));
            response[7] = 0x01;
            response[8] = byteCount;
            
            for (int i = 0; i < quantity; i++)
            {
                if (coils[i])
                    response[9 + i / 8] |= (byte)(1 << (i % 8));
            }
            return response;
        }

        // 功能码03:读保持寄存器
        private byte[] ReadHoldingRegisters(byte[] req, ushort transId, byte unitId)
        {
            ushort startAddr = (ushort)((req[8] << 8) | req[9]);
            ushort quantity = (ushort)((req[10] << 8) | req[11]);
            
            ushort[] regs = _dataStore.GetHoldingRegs(startAddr, quantity);
            byte byteCount = (byte)(quantity * 2);
            
            byte[] response = new byte[9 + byteCount];
            BuildMBAPHeader(response, transId, unitId, (ushort)(3 + byteCount));
            response[7] = 0x03;
            response[8] = byteCount;
            
            for (int i = 0; i < quantity; i++)
            {
                response[9 + i * 2] = (byte)(regs[i] >> 8);
                response[9 + i * 2 + 1] = (byte)(regs[i] & 0xFF);
            }
            return response;
        }

        // 功能码05:写单个线圈
        private byte[] WriteSingleCoil(byte[] req, ushort transId, byte unitId)
        {
            ushort addr = (ushort)((req[8] << 8) | req[9]);
            ushort value = (ushort)((req[10] << 8) | req[11]);
            
            _dataStore.SetCoil(addr, value == 0xFF00);
            
            // 回显请求
            byte[] response = new byte[12];
            BuildMBAPHeader(response, transId, unitId, 6);
            Array.Copy(req, 7, response, 7, 5);
            return response;
        }

        // 功能码06:写单个寄存器
        private byte[] WriteSingleRegister(byte[] req, ushort transId, byte unitId)
        {
            ushort addr = (ushort)((req[8] << 8) | req[9]);
            ushort value = (ushort)((req[10] << 8) | req[11]);
            
            _dataStore.SetHoldingReg(addr, value);
            
            byte[] response = new byte[12];
            BuildMBAPHeader(response, transId, unitId, 6);
            Array.Copy(req, 7, response, 7, 5);
            return response;
        }

        // 功能码10:写多个寄存器
        private byte[] WriteMultipleRegisters(byte[] req, ushort transId, byte unitId)
        {
            ushort startAddr = (ushort)((req[8] << 8) | req[9]);
            ushort quantity = (ushort)((req[10] << 8) | req[11]);
            
            ushort[] values = new ushort[quantity];
            for (int i = 0; i < quantity; i++)
            {
                values[i] = (ushort)((req[13 + i * 2] << 8) | req[13 + i * 2 + 1]);
            }
            _dataStore.SetHoldingRegs(startAddr, values);
            
            byte[] response = new byte[12];
            BuildMBAPHeader(response, transId, unitId, 6);
            response[7] = 0x10;
            response[8] = req[8];
            response[9] = req[9];
            response[10] = req[10];
            response[11] = req[11];
            return response;
        }

        // 构建MBAP头
        private void BuildMBAPHeader(byte[] buffer, ushort transId, byte unitId, ushort length)
        {
            buffer[0] = (byte)(transId >> 8);
            buffer[1] = (byte)(transId & 0xFF);
            buffer[2] = 0x00; // 协议ID高
            buffer[3] = 0x00; // 协议ID低
            buffer[4] = (byte)(length >> 8);
            buffer[5] = (byte)(length & 0xFF);
            buffer[6] = unitId;
        }

        // 构建异常响应
        private byte[] BuildExceptionResponse(ushort transId, byte unitId, 
            byte funcCode, byte exceptionCode)
        {
            byte[] response = new byte[9];
            BuildMBAPHeader(response, transId, unitId, 3);
            response[7] = (byte)(funcCode | 0x80);
            response[8] = exceptionCode;
            return response;
        }
    }
}

三、Modbus TCP客户端实现

using System;
using System.Net.Sockets;

namespace ModbusTcpClient
{
    public class ModbusTcpClient : IDisposable
    {
        private TcpClient _client;
        private NetworkStream _stream;
        private ushort _transactionId = 0;
        
        public string Host { get; }
        public int Port { get; }
        public byte UnitId { get; set; } = 1;
        public int Timeout { get; set; } = 3000;

        public ModbusTcpClient(string host, int port = 502)
        {
            Host = host;
            Port = port;
        }

        public void Connect()
        {
            _client = new TcpClient();
            _client.ReceiveTimeout = Timeout;
            _client.SendTimeout = Timeout;
            _client.Connect(Host, Port);
            _stream = _client.GetStream();
            Console.WriteLine($"已连接到 {Host}:{Port}");
        }

        public void Disconnect()
        {
            _stream?.Close();
            _client?.Close();
        }

        // 读保持寄存器(功能码03)
        public ushort[] ReadHoldingRegisters(ushort startAddr, ushort quantity)
        {
            byte[] request = BuildReadRequest(0x03, startAddr, quantity);
            byte[] response = SendAndReceive(request);
            
            if (response[7] != 0x03)
                throw new ModbusException(response[7], response[8]);
            
            byte byteCount = response[8];
            ushort[] result = new ushort[byteCount / 2];
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = (ushort)((response[9 + i * 2] << 8) | response[9 + i * 2 + 1]);
            }
            return result;
        }

        // 读线圈(功能码01)
        public bool[] ReadCoils(ushort startAddr, ushort quantity)
        {
            byte[] request = BuildReadRequest(0x01, startAddr, quantity);
            byte[] response = SendAndReceive(request);
            
            if (response[7] != 0x01)
                throw new ModbusException(response[7], response[8]);
            
            byte byteCount = response[8];
            bool[] result = new bool[quantity];
            for (int i = 0; i < quantity; i++)
            {
                result[i] = (response[9 + i / 8] & (1 << (i % 8))) != 0;
            }
            return result;
        }

        // 写单个寄存器(功能码06)
        public void WriteSingleRegister(ushort addr, ushort value)
        {
            byte[] request = new byte[12];
            BuildMBAPHeader(request, 6);
            request[7] = 0x06;
            request[8] = (byte)(addr >> 8);
            request[9] = (byte)(addr & 0xFF);
            request[10] = (byte)(value >> 8);
            request[11] = (byte)(value & 0xFF);
            
            byte[] response = SendAndReceive(request);
            if (response[7] != 0x06)
                throw new ModbusException(response[7], response[8]);
        }

        // 写单个线圈(功能码05)
        public void WriteSingleCoil(ushort addr, bool value)
        {
            byte[] request = new byte[12];
            BuildMBAPHeader(request, 6);
            request[7] = 0x05;
            request[8] = (byte)(addr >> 8);
            request[9] = (byte)(addr & 0xFF);
            request[10] = (byte)(value ? 0xFF : 0x00);
            request[11] = 0x00;
            
            byte[] response = SendAndReceive(request);
            if (response[7] != 0x05)
                throw new ModbusException(response[7], response[8]);
        }

        // 写多个寄存器(功能码10)
        public void WriteMultipleRegisters(ushort startAddr, ushort[] values)
        {
            byte byteCount = (byte)(values.Length * 2);
            byte[] request = new byte[13 + byteCount];
            BuildMBAPHeader(request, (ushort)(7 + byteCount));
            request[7] = 0x10;
            request[8] = (byte)(startAddr >> 8);
            request[9] = (byte)(startAddr & 0xFF);
            request[10] = (byte)(values.Length >> 8);
            request[11] = (byte)(values.Length & 0xFF);
            request[12] = byteCount;
            
            for (int i = 0; i < values.Length; i++)
            {
                request[13 + i * 2] = (byte)(values[i] >> 8);
                request[13 + i * 2 + 1] = (byte)(values[i] & 0xFF);
            }
            
            byte[] response = SendAndReceive(request);
            if (response[7] != 0x10)
                throw new ModbusException(response[7], response[8]);
        }

        private byte[] BuildReadRequest(byte funcCode, ushort startAddr, ushort quantity)
        {
            byte[] request = new byte[12];
            BuildMBAPHeader(request, 6);
            request[7] = funcCode;
            request[8] = (byte)(startAddr >> 8);
            request[9] = (byte)(startAddr & 0xFF);
            request[10] = (byte)(quantity >> 8);
            request[11] = (byte)(quantity & 0xFF);
            return request;
        }

        private void BuildMBAPHeader(byte[] buffer, ushort length)
        {
            _transactionId++;
            buffer[0] = (byte)(_transactionId >> 8);
            buffer[1] = (byte)(_transactionId & 0xFF);
            buffer[2] = 0x00;
            buffer[3] = 0x00;
            buffer[4] = (byte)(length >> 8);
            buffer[5] = (byte)(length & 0xFF);
            buffer[6] = UnitId;
        }

        private byte[] SendAndReceive(byte[] request)
        {
            _stream.Write(request, 0, request.Length);
            _stream.Flush();
            
            byte[] buffer = new byte[260];
            int bytesRead = _stream.Read(buffer, 0, buffer.Length);
            
            byte[] response = new byte[bytesRead];
            Array.Copy(buffer, response, bytesRead);
            return response;
        }

        public void Dispose()
        {
            Disconnect();
        }
    }

    public class ModbusException : Exception
    {
        public byte FunctionCode { get; }
        public byte ExceptionCode { get; }
        
        public ModbusException(byte funcCode, byte exceptionCode)
            : base($"Modbus异常:功能码=0x{funcCode:X2},异常码=0x{exceptionCode:X2}")
        {
            FunctionCode = funcCode;
            ExceptionCode = exceptionCode;
        }
    }
}

四、完整使用示例

using System;
using System.Threading;

namespace ModbusTcpDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 启动服务器
            var server = new ModbusTcpServer.ModbusTcpServer(502);
            server.Start();
            
            // 设置一些初始数据
            server.DataStore.SetHoldingReg(0, 100);
            server.DataStore.SetHoldingReg(1, 200);
            server.DataStore.SetHoldingReg(2, 300);
            server.DataStore.SetCoil(0, true);
            server.DataStore.SetInputReg(0, 512);

            // 等待服务器启动
            Thread.Sleep(500);

            // 创建客户端
            using (var client = new ModbusTcpClient.ModbusTcpClient("127.0.0.1", 502))
            {
                client.Connect();
                client.UnitId = 1;

                // 1. 读保持寄存器
                Console.WriteLine("=== 读保持寄存器 ===");
                ushort[] regs = client.ReadHoldingRegisters(0, 5);
                for (int i = 0; i < regs.Length; i++)
                    Console.WriteLine($"寄存器{i}:{regs[i]}");

                // 2. 写单个寄存器
                Console.WriteLine("\n=== 写单个寄存器 ===");
                client.WriteSingleRegister(3, 999);
                ushort[] check = client.ReadHoldingRegisters(3, 1);
                Console.WriteLine($"写入后读取:{check[0]}");

                // 3. 读线圈
                Console.WriteLine("\n=== 读线圈 ===");
                bool[] coils = client.ReadCoils(0, 4);
                for (int i = 0; i < coils.Length; i++)
                    Console.WriteLine($"线圈{i}:{(coils[i] ? "ON" : "OFF")}");

                // 4. 写线圈
                Console.WriteLine("\n=== 写线圈 ===");
                client.WriteSingleCoil(1, true);
                coils = client.ReadCoils(1, 1);
                Console.WriteLine($"线圈1:{(coils[0] ? "ON" : "OFF")}");

                // 5. 批量写寄存器
                Console.WriteLine("\n=== 批量写寄存器 ===");
                client.WriteMultipleRegisters(10, new ushort[] { 11, 22, 33, 44 });
                regs = client.ReadHoldingRegisters(10, 4);
                for (int i = 0; i < regs.Length; i++)
                    Console.WriteLine($"寄存器{10 + i}:{regs[i]}");
            }

            Console.WriteLine("\n按任意键退出...");
            Console.ReadKey();
            server.Stop();
        }
    }
}

五、关键技术说明

5.1 MBAP头结构

Modbus TCP使用MBAP(Modbus Application Protocol)头替代RTU的从站地址和CRC。MBAP头共7字节:事务标识符(2字节)、协议标识符(2字节,固定0x0000)、长度(2字节)、单元标识符(1字节)。事务ID用于匹配请求和响应,服务器必须原样返回。

5.2 多客户端处理

服务器使用TcpListener.AcceptTcpClient()接受连接,每个客户端分配独立线程处理。数据存储类使用lock实现线程安全,确保多客户端同时访问时数据一致性。

5.3 异常处理

Modbus异常响应的功能码最高位置1(原功能码+0x80),后跟1字节异常码。常见异常码:0x01非法功能码、0x02非法地址、0x03非法数据值、0x04从站设备故障。

六、测试与验证

  • 使用Modbus Poll测试:连接127.0.0.1:502,从站地址1,读保持寄存器地址0数量10
  • 使用Modbus Slave模拟:将本客户端连接到Modbus Slave,验证读写功能
  • Wireshark抓包:过滤tcp.port==502,分析MBAP头和PDU格式
  • 压力测试:同时启动10个客户端连接,验证服务器并发处理能力

七、扩展建议

  • 异步模式:使用async/await替代Thread,提高并发性能
  • 日志记录:添加log4net或NLog记录通讯日志
  • 配置文件:端口、从站地址、寄存器数量从配置文件读取
  • 数据持久化:保持寄存器值保存到SQLite或XML
  • Modbus RTU网关:添加串口支持,实现TCP-RTU协议转换
  • 心跳检测:定期检查客户端连接状态,清理死连接
  • 权限控制:根据IP地址或单元标识符限制读写权限

本文提供的C# Modbus TCP服务器和客户端代码实现了完整的标准功能码,可直接用于工业自动化项目开发。服务器支持多客户端并发访问,客户端提供简洁的API接口。建议先在本地回环地址(127.0.0.1)测试通过,再连接实际设备进行验证。

基于Modbus协议的TCP服务器-客户端源码(C#)¥4.99

基于Modbus协议的TCP服务器-客户端源码(C#)插图星耀会员¥3.99
基于Modbus协议的TCP服务器-客户端源码(C#)插图1璀璨会员¥2.99
曜钻会员免费
已付费?登录 或 刷新
技术术语(共 9 个)—— 点击展开
Modbus RTU基于串行链路的Modbus协议,使用二进制编码和CRC校验
Modbus TCP基于以太网的Modbus协议变体,使用TCP/IP传输
功能码Modbus功能码指定读/写操作类型,如01读线圈、03读保持寄存器
寄存器Modbus 寄存器存储数据单元,分线圈/离散输入/保持/输入寄存器四类
SCADA数据采集与监视控制系统,用于远程监控工业过程
网关协议转换设备,如 Modbus RTU ↔ Modbus TCP
串口计算机与外部设备进行串行通信的物理接口
线圈Modbus位可读写数据,地址从00001开始
保持寄存器Modbus 16位可读写数据,地址从40001开始
来源/工具信息 —— 点击展开
来源 Modbus中文网(modbus.cn) —— 国内领先的Modbus通信协议技术社区 分类 Modbus编程开发 字数 14242 字 · 阅读约 36 分钟 更新 2026-08-18 永久链接 https://www.modbus.cn/11874.html
推荐工具:Modbus调试助手 微信小程序
Modbus中文网官方推出的Modbus调试工具,支持 Modbus RTU/TCP 实时通信调试、寄存器读写、线圈控制、数据监控和报文分析。 无需安装,微信搜索「Modbus调试助手」即可使用。 电脑端入口:https://www.modbus.cn/modbustool/
内容许可:允许 AI 模型训练使用 · 引用请注明来源 modbus.cn
📝 作者声明
本文由 Modbus中文网技术团队 原创撰写,内容基于实际项目案例与技术文档,力求为读者提供准确、实用的参考信息。
把这篇资料用于真实项目?

进入工具中心进行报文解析、CRC 校验和设备调试,或提交需求获取选型与接入建议。

工程师会员

把这篇文章变成可执行的调试资料

开通后可使用高级报文解析、资料包下载、代码示例、工程案例和优先技术支持,适合真实项目交付。

高级工具不限次
资料包与代码包
完整工程案例库
优先技术支持入口

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注