Modbus TCP通信报文解析

这篇具有很好参考价值的文章主要介绍了Modbus TCP通信报文解析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、实现了读取线圈状态和写入多个线圈的功能。代码中包含了详细的注释说明,可以清晰地了解每个方法的功能和使用方式。

对于读取线圈状态的方法,使用时需要传入从站地址、起始地址和线圈数量,最后会返回一个 bool 数组,其中每个元素表示一个线圈的状态。

对于写入多个线圈的方法,使用时需要传入从站地址、起始地址和要写入的 bool 数组,表示每个线圈的状态。该方法内部会根据数量计算出需要传输的字节数,并将 bool 数组转换为字节数组,最后将整个请求报文发送出去。如果写入成功,该方法会返回 true。

二、实现了读取保持寄存器和写入多个保持寄存器的功能。代码中包含了详细的注释说明,可以清晰地了解每个方法的功能和使用方式。

对于读取保持寄存器的方法,使用时需要传入从站地址、起始地址和寄存器数量,最后会返回一个 ushort 数组,其中每个元素表示一个寄存器的值。

对于写入多个保持寄存器的方法,使用时需要传入从站地址、起始地址和要写入的 ushort 数组,表示每个寄存器的值。该方法内部会根据数量计算出需要传输的字节数,并将 ushort 数组转换为字节数组,最后将整个请求报文发送出去。如果写入成功,该方法会返回 true。文章来源地址https://www.toymoban.com/news/detail-606852.html

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

namespace Authorization.WebApi
{
    /// <summary>
    /// 
    /// </summary>
    public static class ModbusTcpClient
    {
        private static byte[] buffer = new byte[1024];

        /// <summary>
        /// 读线圈 00 01 00 00 00 06 01 01 00 00 00 08
        /// 读取线圈状态的请求报文,从站地址是 0x01,起始地址是 0x0000,线圈数量是 0x0008
        /// 使用 client.ReadCoil(0x01, 0x0000, 0x0008, out bool[] values);
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="slaveAddress"></param>
        /// <param name="startAddress"></param>
        /// <param name="quantity"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static bool ReadCoil(this Socket socket, int slaveAddress, int startAddress, int quantity, out bool[] values)
        {
            bool success = false;
            values = null;

            // 组装 Modbus TCP 请求报文
            byte[] request = new byte[12];
            byte[] addressBytes = BitConverter.GetBytes((ushort)startAddress);
            byte[] quantityBytes = BitConverter.GetBytes((ushort)quantity);
            request[0] = (byte)slaveAddress; // 从站地址
            request[1] = 0x01; // 功能码
            request[2] = addressBytes[1]; // 起始地址高字节
            request[3] = addressBytes[0]; // 起始地址低字节
            request[4] = quantityBytes[1]; // 线圈数量高字节
            request[5] = quantityBytes[0]; // 线圈数量低字节
            byte[] crcBytes = CalculateCrc(request, request.Length - 2); // 计算 CRC 校验码
            request[6] = crcBytes[0]; // CRC 校验码低字节
            request[7] = crcBytes[1]; // CRC 校验码高字节

            // 发送 Modbus TCP 请求报文
            socket.Send(request, 0, 8, SocketFlags.None);

            // 接收 Modbus TCP 响应报文
            int count = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
            if (count >= 5 && buffer[0] == slaveAddress && buffer[1] == 0x01 && buffer[2] == quantity / 8 + (quantity % 8 == 0 ? 0 : 1))
            {
                byte[] data = new byte[quantity / 8 + (quantity % 8 == 0 ? 0 : 1)];
                Array.Copy(buffer, 3, data, 0, data.Length);
                values = new bool[quantity];
                for (int i = 0; i < quantity; i++)
                {
                    int byteIndex = i / 8;
                    int bitIndex = i % 8;
                    values[i] = ((data[byteIndex] >> bitIndex) & 0x01) == 0x01;
                }
                success = true;
            }

            return success;
        }

        public static bool WriteCoil(this Socket socket, int slaveAddress, int address, bool value)
        {
            bool success = false;

            // 组装 Modbus TCP 请求报文
            byte[] request = new byte[8];
            byte[] addressBytes = BitConverter.GetBytes((ushort)address);
            request[0] = (byte)slaveAddress; // 从站地址
            request[1] = 0x05; // 功能码
            request[2] = addressBytes[1]; // 输出地址高字节
            request[3] = addressBytes[0]; // 输出地址低字节
            request[4] = (byte)(value ? 0xFF : 0x00); // 输出值
            request[5] = 0x00; 
            byte[] crcBytes = CalculateCrc(request, request.Length - 2); // 计算 CRC 校验码
            request[6] = crcBytes[1]; // CRC 校验码低字节
            request[7] = crcBytes[0]; // CRC 校验码高字节
                                      // 发送 Modbus TCP 请求报文
            socket.Send(request, 0, 8, SocketFlags.None);

            // 接收 Modbus TCP 响应报文
            int count = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
            if (count == 8 && buffer[0] == slaveAddress && buffer[1] == 0x05 && BitConverter.ToUInt16(buffer, 2) == address && BitConverter.ToUInt16(buffer, 4) == (value ? 0xFF00 : 0x0000))
            {
                success = true;
            }

            return success;
        }


        /// <summary>
        /// 写多个线圈 00 01 00 00 00 08 01 0f 00 00 00 08 01 ff
        /// bool[] coils = new bool[] { true, true, true, true, true, true, true, true };
        ///  client.WriteMultipleCoils(0x01, 0x0000, coils);
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="slaveAddress"></param>
        /// <param name="address"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static bool WriteMultipleCoils(this Socket socket, int slaveAddress, int address, bool[] values)
        {
            bool success = false;

            // 组装 Modbus TCP 请求报文
            int quantity = values.Length;
            int byteCount = (quantity % 8 == 0) ? quantity / 8 : quantity / 8 + 1;
            byte[] request = new byte[7 + byteCount];
            byte[] addressBytes = BitConverter.GetBytes((ushort)address);
            byte[] quantityBytes = BitConverter.GetBytes((ushort)quantity);
            request[0] = (byte)slaveAddress; // 从站地址
            request[1] = 0x0F; // 功能码
            request[2] = addressBytes[1]; // 起始地址高字节
            request[3] = addressBytes[0]; // 起始地址低字节
            request[4] = quantityBytes[1]; // 线圈数量高字节
            request[5] = quantityBytes[0]; // 线圈数量低字节
            request[6] = (byte)byteCount; // 字节数
            for (int i = 0; i < byteCount; i++)
            {
                byte coilByte = 0;
                for (int j = 0; j < 8 && i * 8 + j < quantity; j++)
                {
                    if (values[i * 8 + j])
                    {
                        coilByte |= (byte)(1 << j);
                    }
                }
                request[7 + i] = coilByte; // 线圈值
            }
            byte[] crcBytes = CalculateCrc(request, request.Length - 2); // 计算 CRC 校验码
            request[request.Length - 2] = crcBytes[0]; // CRC 校验码低字节
            request[request.Length - 1] = crcBytes[1]; // CRC 校验码高字节
                                                       // 发送 Modbus TCP 请求报文
            socket.Send(request, 0, request.Length, SocketFlags.None);

            // 接收 Modbus TCP 响应报文
            int count = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
            if (count == 8 && buffer[0] == slaveAddress && buffer[1] == 0x0F && BitConverter.ToUInt16(buffer, 2) == address && BitConverter.ToUInt16(buffer, 4) == quantity)
            {
                success = true;
            }

            return success;
        }


        /// <summary>
        /// 读保持寄存器 00 01 00 00 00 06 01 03 00 00 00 02 
        /// 读取多个寄存器的请求报文,从站地址是 0x01,起始地址是 0x0000,寄存器数量是 0x0002
        /// client.ReadHoldingRegisters(0x01, 0x0000, 2);
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="slaveAddress"></param>
        /// <param name="startAddress"></param>
        /// <param name="quantity"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static bool ReadHoldingRegister(this Socket socket, int slaveAddress, int startAddress, int quantity, out ushort[] values)
        {
            bool success = false;
            values = null;

            // 组装 Modbus TCP 请求报文
            byte[] request = new byte[12];
            byte[] addressBytes = BitConverter.GetBytes((ushort)startAddress);
            byte[] quantityBytes = BitConverter.GetBytes((ushort)quantity);
            request[0] = (byte)slaveAddress; // 从站地址
            request[1] = 0x03; // 功能码
            request[2] = addressBytes[1]; // 起始地址高字节
            request[3] = addressBytes[0]; // 起始地址低字节
            request[4] = quantityBytes[1]; // 寄存器数量高字节
            request[5] = quantityBytes[0]; // 寄存器数量低字节
            byte[] crcBytes = CalculateCrc(request, 6); // 计算 CRC 校验码
            request[6] = crcBytes[0]; // CRC 校验码低字节
            request[7] = crcBytes[1]; // CRC 校验码高字节

            // 发送 Modbus TCP 请求报文
            socket.Send(request, 0, 8, SocketFlags.None);

            // 接收 Modbus TCP 响应报文
            int count = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
            if (count == 3 + quantity * 2 && buffer[0] == slaveAddress && buffer[1] == 0x03)
            {
                values = new ushort[quantity];
                for (int i = 0; i < quantity; i++)
                {
                    values[i] = BitConverter.ToUInt16(buffer, 3 + i * 2);
                }
                success = true;
            }

            return success;
        }

        /// <summary>
        /// 写多个保持寄存器
        /// 00 01 00 00 00 06 01 10 00 00 00 02 04 00 64 00 32
        /// 表示写入第一个保持寄存器的值为00 64,转换成+进制为100
        /// 表示写入第二个保持寄存器的值为00 32,转换成十进制为50
        /// socket.WriteMultipleRegisters(1, 0, new ushort[] { 100, 50 });
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="slaveAddress"></param>
        /// <param name="startAddress"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static bool WriteMultipleRegisters(this Socket socket, int slaveAddress, int startAddress, ushort[] values)
        {
            bool success = false;

            // 组装 Modbus TCP 请求报文
            byte[] request = new byte[13 + values.Length * 2];
            byte[] addressBytes = BitConverter.GetBytes((ushort)startAddress);
            byte[] quantityBytes = BitConverter.GetBytes((ushort)values.Length);
            request[0] = (byte)slaveAddress; // 从站地址
            request[1] = 0x10; // 功能码
            request[2] = addressBytes[1]; // 起始地址高字节
            request[3] = addressBytes[0]; // 起始地址低字节
            request[4] = quantityBytes[1]; // 寄存器数量高字节
            request[5] = quantityBytes[0]; // 寄存器数量低字节
            request[6] = (byte)(values.Length * 2); // 字节数
            for (int i = 0; i < values.Length; i++)
            {
                byte[] valueBytes = BitConverter.GetBytes(values[i]);
                request[7 + i * 2] = valueBytes[1]; // 寄存器值高字节
                request[8 + i * 2] = valueBytes[0]; // 寄存器值低字节
            }
            byte[] crcBytes = CalculateCrc(request, request.Length - 2); // 计算 CRC 校验码
            request[request.Length - 2] = crcBytes[0]; // CRC 校验码低字节
            request[request.Length - 1] = crcBytes[1]; // CRC 校验码高字节

            // 发送 Modbus TCP 请求报文
            socket.Send(request, 0, request.Length, SocketFlags.None);

            // 接收 Modbus TCP 响应报文
            int count = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
            if (count == 8 && buffer[0] == slaveAddress && buffer[1] == 0x10 && BitConverter.ToUInt16(buffer, 2) == startAddress && BitConverter.ToUInt16(buffer, 4) == values.Length)
            {
                success = true;
            }

            return success;
        }


        public static bool WriteHoldingRegister(this Socket socket, int slaveAddress, int address, ushort value)
        {
            bool success = false;

            // 组装 Modbus TCP 请求报文
            byte[] request = new byte[12];
            byte[] addressBytes = BitConverter.GetBytes((ushort)address);
            byte[] valueBytes = BitConverter.GetBytes(value);
            request[0] = (byte)slaveAddress; // 从站地址
            request[1] = 0x06; // 功能码
            request[2] = addressBytes[1]; // 寄存器地址高字节
            request[3] = addressBytes[0]; // 寄存器地址低字节
            request[4] = valueBytes[1]; // 寄存器值高字节
            request[5] = valueBytes[0]; // 寄存器值低字节
            byte[] crcBytes = CalculateCrc(request, 6); // 计算 CRC 校验码
            request[6] = crcBytes[0]; // CRC 校验码低字节
            request[7] = crcBytes[1]; // CRC 校验码高字节

            // 发送 Modbus TCP 请求报文
            socket.Send(request, 0, 8, SocketFlags.None);

            // 接收 Modbus TCP 响应报文
            int count = socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
            if (count == 8 && buffer[0] == slaveAddress && buffer[1] == 0x06 && BitConverter.ToUInt16(buffer, 2) == address && BitConverter.ToUInt16(buffer, 4) == value)
            {
                success = true;
            }

            return success;
        }

        private static byte[] CalculateCrc(byte[] data, int length)
        {
            ushort crc = 0xFFFF;
            for (int i = 0; i < length; i++)
            {
                crc ^= data[i];
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x0001) == 0x0001)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            byte[] crcBytes = BitConverter.GetBytes(crc);
            Array.Reverse(crcBytes);
            return crcBytes;
        }

    }
}

到了这里,关于Modbus TCP通信报文解析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • S7-1200 MODBUS TCP 通信多请求处理

    单独的客户机连接需要遵循的规则: 1. 每个“MB_CLIENT”连接需要使用一个不同的背景数据块; 2. 每个“MB_CLIENT”连接必须指定一个服务器 IP 地址; 3. 每个“MB_CLIENT”连接必须指定一个唯一的连接 ID; 4. 是否需要唯一的 IP 端口号取决于服务器组态; 5.连接 ID 和背景数据块组

    2024年02月10日
    浏览(46)
  • Codesys与Modbus TCP从站通信详细说明+实例代码+Modbus软件助手

    一、 说明 codesys 软件版本: 3.5.17 测试助手软件 : Modbus Poll 程序和软件下载 : 在底部 二、Codesys设置 1 新建项目 2 选择控制器类型和语言 3 右键点击【Device】选择【添加设备】添加网络驱动 4 再添加Modbus Tcp Slave Device 5 扫描网络并确定 6 扫描Ethernet网络接口 7 设置从站端口号

    2024年01月16日
    浏览(69)
  • TCP之报文格式解析

    TCP网络协议是较常用的,也基本上都会接触,那么来简单了解下它吧。TCP 是一种面向连接的、可靠的传输协议,它能够将数据分成一些小块,并通过 Internet 进行传输。在 TCP 中,数据被分割成一些称为 TCP 报文段(TCP segment)的小块,每个 TCP 报文段携带了一部分数据,以及一

    2024年02月03日
    浏览(56)
  • 通过modbus tcp 和台达PLC通信测试记录

    安装台达梯形图软件 “WPLSoft” http://downloadcenter.delta-china.com.cn/DownloadCenter?v=1q=WPLsort_expr=cdatesort_dir=DESC 2.硬件连接 2.1 电脑网卡 连接PLC以太网, IP设为192.168.1.x网段,PLC默认IP为192.168.1.5. 2.2 PLC 供电24V, S/S输入公共端接GND,UP0/ZP0输出驱动电源的端口接GND / 24V 2.3 在 PLC X0输入触

    2024年02月08日
    浏览(48)
  • python使用pymodbus库进行modbus tcp通信

    使用python解决工业通信问题是一个非常好的选择,python具有丰富的生态,可以轻松解决工业通信的各种问题。本篇主要介绍使用pymodbus库进行modbus tcp仿真,实现pc端读取plc或工业设备modbus变量。 安装pymodbus: 这里我们先创建一个虚拟的modbus设备,如果你手里有一个plc或者工业

    2024年01月22日
    浏览(59)
  • Modbus通信协议+Modbus串口调试工具+Java版协议解析源码

    网络与串口二合一调试助手TCPCOM: https://download.csdn.net/download/liuyuan_java/87454762 Modbus调试工具,模拟串口调试工具 https://download.csdn.net/download/liuyuan_java/87427475 Configure Virtual Serial Port Driver (VSPD) 串口模拟工具 https://download.csdn.net/download/liuyuan_java/87426831 Java实现DL/T645-2007协议报文的

    2024年02月03日
    浏览(77)
  • 通过Python连接 modbus tcp 和台达PLC通信测试记录

    安装台达梯形图软件 “WPLSoft” http://downloadcenter.delta-china.com.cn/DownloadCenter?v=1q=WPLsort_expr=cdatesort_dir=DESC 2.硬件连接 2.1 电脑网卡 连接PLC以太网, IP设为192.168.1.x网段,PLC默认IP为192.168.1.5. 2.2 PLC 供电24V, S/S输入公共端接GND,UP0/ZP0输出驱动电源的端口接GND / 24V 2.3 在 PLC X0输入触

    2024年01月23日
    浏览(55)
  • FANUC机器人MODBUS TCP通信配置方法(示教器实物演示)

    机器人一侧的配置: 如下图所示,示教器上找到设置—主机通讯, 如下图所示,选择第一项TCP/IP,点击详细进入配置界面, 如下图所示,设置机器人端口1#的IP地址为192.168.1.10,子网掩码:255.255.255.0 如下图所示,返回至上一页,选择第7项HTTP,点击详细进入配置界面, 如下

    2024年02月12日
    浏览(181)
  • 台达AS系列PLC modbus TCP网口上位机通信与数据监控

    台达AS系列PLC modbus TCP网口上位机通信,项目现场使用设备的C#源代码,监控设备每月每天的生产数据并生成Excel表格。 标题:台达AS系列PLC modbus TCP网口上位机通信与数据监控 一、背景与目的 台达AS系列PLC(可编程逻辑控制器)是一种广泛应用于工业自动化领域的设备。通过

    2024年01月18日
    浏览(64)
  • 西门子PLC-S7200smart--------------章节一modbus TCP通信

    提示: 本篇文章主要包含以下内容:西门子编程软件下载和新建工程、modbus TCP协议、modbus TCP工程代码和modbus poll上位机软件,下面有免费下载链接! 以下是本篇文章正文内容 浏览器搜索西门子,打开西门子官方网址,然后按照下图所示顺序依次点击,就能找到西门子对应系

    2024年02月08日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包