Modbus 串口 C#

前言

Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto),并且现在是工业电子设备之间常用的连接方式。

Modbus允许多个 (大约240个) 设备连接在同一个网络上进行通信,举个例子,一个测量温度和湿度的装置,并且将结果发送给计算机。在数据采集与监视控制系统(SCADA)中,Modbus通常用来连接监控计算机和远程终端控制系统(RTU)。

常用用法

在这里插入图片描述

通讯格式

以功能码03为例
在这里插入图片描述

C#实验常用的03,06,10

 public class Modbus
    {
    
    
        protected SerialPort port;
        public Modbus(SerialPort serialPort)
        {
    
    
            this.port = serialPort;
        }

        public void OpenPort()
        {
    
    
            try
            {
    
    
                if (!port.IsOpen)
                {
    
    
                    port.Open();
                }
                port.DiscardInBuffer();
                port.DiscardOutBuffer();
            }
            catch (Exception ex)
            {
    
    
            }
        }

        public void ClosePort()
        {
    
    
            try
            {
    
    
                if (port != null && port.IsOpen)
                {
    
    
                    port.Close();
                    port = null;
                }
            }
            catch (Exception ex)
            {
    
    
            }
        }

        protected int ReadData(byte[] buffer, int expectCount = 0)
        {
    
    
            int r = port.Read(buffer, 0, buffer.Length);
            while (port.BytesToRead > 0)
            {
    
    
                int n = port.Read(buffer, r, buffer.Length - r);
                r += n;
            }
            while (r < expectCount)
            {
    
    
                r += port.Read(buffer, r, buffer.Length - r);
            }       
            return r;
        }

        /// <summary>
        /// 读取保持型寄存器 功能码03
        /// </summary>
        /// <param name="stationID">站号</param>
        /// <param name="addr">寄存器地址</param>
        /// <param name="length">寄存器数量</param>
        /// <param name="buffer">接收数据的缓存</param>
        /// <returns>收到的字节数</returns>
        public int ReadRegister(int stationID, ushort addr, int length, byte[] buffer)
        {
    
    
            OpenPort();
            byte[] cmdHead = new byte[6];
            cmdHead[0] = (byte)stationID;
            cmdHead[1] = 0x03;
            cmdHead[2] = (byte)((addr >> 8) & 0xFF);
            cmdHead[3] = (byte)(addr & 0xFF);
            cmdHead[4] = (byte)((length >> 8) & 0xFF);
            cmdHead[5] = (byte)(length & 0xFF);
            byte[] command = CRC.AppendCRC16(cmdHead);
            //发送指令
            port.Write(command, 0, command.Length);
            int bytes = ReadData(buffer, 5 + 2 * length);
            return bytes;
        }


        /// <summary>
        /// 写入保持型寄存器 功能码06
        /// </summary>
        /// <param name="stationID">站号</param>
        /// <param name="addr">寄存器地址</param>
        /// <param name="value">写入值</param>
        /// <returns></returns>
        public int WriteRegister(int stationID, ushort addr, int value, byte[] buffer = null)
        {
    
    
            OpenPort();
            byte[] cmdHead = new byte[6];
            cmdHead[0] = (byte)stationID;
            cmdHead[1] = 0x06;
            cmdHead[2] = (byte)((addr >> 8) & 0xFF);
            cmdHead[3] = (byte)(addr & 0xFF);
            cmdHead[4] = (byte)((value >> 8) & 0xFF);
            cmdHead[5] = (byte)(value & 0xFF);
            byte[] command = CRC.AppendCRC16(cmdHead);

            //发送指令。
            port.Write(command, 0, command.Length);
            if (buffer != null)
            {
    
    
                int bytes = ReadData(buffer, 8);
                return bytes;
            }
            return 0;
        }

        /// <summary>
        /// 写入一段连续的寄存器 功能码10
        /// </summary>
        /// <param name="stationID">站号</param>
        /// <param name="addr">寄存器地址</param>
        /// <param name="value">写入值</param>
        /// <returns></returns>
        public int WriteRegisters(int stationID, ushort addr, byte[] value, byte[] buffer = null)
        {
    
    
            OpenPort();
            int registerCount = value.Length / 2;
            byte[] cmdHead = new byte[7 + value.Length];
            cmdHead[0] = (byte)stationID;
            cmdHead[1] = 0x10;
            cmdHead[2] = (byte)((addr >> 8) & 0xFF);
            cmdHead[3] = (byte)(addr & 0xFF);
            cmdHead[4] = (byte)((registerCount >> 8) & 0xFF);
            cmdHead[5] = (byte)(registerCount & 0xFF);
            cmdHead[6] = (byte)(value.Length & 0xFF);
            for (int i = 0; i < value.Length; i++)
            {
    
    
                cmdHead[7 + i] = value[i];
            }
            byte[] command = CRC.AppendCRC16(cmdHead);

            //发送指令。
            port.Write(command, 0, command.Length);
            if (buffer != null)
            {
    
    
                int bytes = ReadData(buffer, 8);
                return bytes;
            }
            return 0;
        }

长期分享工控干货,喜欢的话可以点赞关注,谢谢!

猜你喜欢

转载自blog.csdn.net/bayinglong/article/details/128119467