C# ModbusRtu 通讯例程详解

        说到工控,通讯则是基础。今天我们就来一起学习一下关于ModbusRtu通讯的相关内容。适合初学者积累相关经验。

        首先说明,Modbus通讯协议支持串口通讯、和网口通讯。本文主要是基于串口通讯的Modbus例程。

        第一步,创建通讯库,命名未CHHModbusRtu(各位可自行定义)。在通讯库中创建串口对象,并进行相关设置,创建启动串口、关闭串口的方法。
        private SerialPort MyCom;

        public int RcvTimeOut { get; set; } = 2000;

        public void Connect(string iPortName, int iBaudRate, Parity iParity, int iDataBits, StopBits iStopBits)
        {
            if (MyCom == null || !MyCom.IsOpen)
            {
                MyCom = new SerialPort(iPortName, iBaudRate, iParity, iDataBits, iStopBits);
                MyCom.Open();
            }
        }        

        public void DisConnect()
        {
            if (MyCom.IsOpen)
            {
                MyCom.Close();
            }
        }

        第二步:创建输入输出线圈的读取方法、输入输出寄存器的读取方法

        ///


        /// 读取输出线圈
        ///

        /// 主站/从站地址
        /// 开始地址
        /// 读取长度
        ///
        public byte[] ReadOutputStatus(byte iDevAdd, ushort iAddress, ushort iLength)
        {
            //拼接报文
            List SendCommand = new List();
            SendCommand.Add(iDevAdd);
            SendCommand.Add(0x01);
            SendCommand.Add((byte)(iAddress / 256));
            SendCommand.Add((byte)(iAddress % 256));
            SendCommand.Add((byte)(iLength / 256));
            SendCommand.Add((byte)(iLength % 256));

            byte[] crc = Crc16(SendCommand.ToArray(), SendCommand.Count);
            SendCommand.AddRange(crc);

            byte[] response = null;
            int byteLength = iLength % 8 == 0 ? iLength / 8 : iLength / 8 + 1;
            if (SendAndReceive(SendCommand.ToArray(), ref response))
            {
                //验证
                if (response.Length == 5 + byteLength)
                {
                    if (response[0] == iDevAdd && response[1] == 0x01 && response[2] == byteLength && CheckCRC(response))
                    {
                        return GetByteArray(response, 3, response.Length - 5);
                    }
                    else { return null; }
                }
                else { return null; }

            }
            else { return null; }
        }

        ///


        /// 读取输入线圈
        ///

        /// 从站地址
        /// 开始地址
        /// 读取长度
        ///
        public byte[] ReadInputStatus(byte iDevAdd, ushort iAddress, ushort iLength)
        {
            //拼接报文
            List SendCommand = new List();
            SendCommand.Add(iDevAdd);
            SendCommand.Add(0x02);
            SendCommand.Add((byte)(iAddress / 256));
            SendCommand.Add((byte)(iAddress % 256));
            SendCommand.Add((byte)(iLength / 256));
            SendCommand.Add((byte)(iLength % 256));
            byte[] crc = Crc16(SendCommand.ToArray(), SendCommand.Count);
            SendCommand.AddRange(crc);

            byte[] response = null;
            int byteLength = iLength % 8 == 0 ? iLength / 8 : iLength / 8 + 1;
            if (SendAndReceive(SendCommand.ToArray(), ref response))
            {
                //验证
                if (response.Length == 5 + byteLength)
                {
                    if (response[0] == iDevAdd && response[1] == 0x02 && response[2] == byteLength && CheckCRC(response))
                    {
                        return GetByteArray(response, 3, response.Length - 5);
                    }
                    else { return null; }
                }
                else { return null; }

            }
            else { return null; }
        }

        ///


        /// 读取输出寄存器
        ///

        /// 从站地址
        /// 开始地址
        /// 读取长度
        ///
        public byte[] ReadOutPutReg(byte iDevAdd, ushort iAddress, ushort iLength)
        {
            //拼接报文
            List SendCommand = new List();
            SendCommand.Add(iDevAdd);
            SendCommand.Add(0x03);
            SendCommand.Add((byte)(iAddress / 256));
            SendCommand.Add((byte)(iAddress % 256));
            SendCommand.Add((byte)(iLength / 256));
            SendCommand.Add((byte)(iLength % 256));
            byte[] crc = Crc16(SendCommand.ToArray(), SendCommand.Count);
            SendCommand.AddRange(crc);

            byte[] response = null;
            int byteLength = iLength * 2;
            if (SendAndReceive(SendCommand.ToArray(), ref response))
            {
                //验证
                if (response.Length == 5 + byteLength)
                {
                    if (response[0] == iDevAdd && response[1] == 0x03 && response[2] == byteLength && CheckCRC(response))
                    {
                        return GetByteArray(response, 3, response.Length - 5);
                    }
                    else { return null; }
                }
                else { return null; }
            }
            else { return null; }
        }
        

        ///


        /// 读取输入寄存器
        ///

        /// 从站地址
        /// 开始地址
        /// 读取长度
        ///
        public byte[] ReadInputReg(byte iDevAdd, ushort iAddress, ushort iLength)
        {
            //拼接报文
            List SendCommand = new List();
            SendCommand.Add(iDevAdd);
            SendCommand.Add(0x04);
            SendCommand.Add((byte)(iAddress / 256));
            SendCommand.Add((byte)(iAddress % 256));
            SendCommand.Add((byte)(iLength / 256));
            SendCommand.Add((byte)(iLength % 256));
            byte[] crc = Crc16(SendCommand.ToArray(), SendCommand.Count);
            SendCommand.AddRange(crc);

            byte[] response = null;
            int byteLength = iLength * 2;
            if (SendAndReceive(SendCommand.ToArray(), ref response))
            {
                //验证
                if (response.Length == 5 + byteLength)
                {
                    if (response[0] == iDevAdd && response[1] == 0x04 && response[2] == byteLength && CheckCRC(response))
                    {
                        return GetByteArray(response, 3, response.Length - 5);
                    }
                    else { return null; }
                }
                else { return null; }
            }
            else { return null; }
        }

        第三步:创建发送指令方法

        ///


        /// 发送指令
        ///

        ///
        ///
        public byte[] WriteData(string str)
        {
            byte[] getbyte = ConvertHexStringToBytes(str);
            //拼接报文
            List SendCommand = new List();
            SendCommand.AddRange(getbyte);
            byte[] crc = Crc16(SendCommand.ToArray(), SendCommand.Count);
            SendCommand.AddRange(crc);
            byte[] response = null;
            if (SendAndReceive(SendCommand.ToArray(), ref response))
            {
                if (CheckCRC(response))
                {
                    return GetByteArray(response, 3, response.Length - 5);
                }
                else { return null; }
            }
            else { return null; }
        }

第四步:补充RCR校验、数据处理等方法(源码太多,此处复制一小部分,文末有源码链接)

///


        /// 生成CRC
        ///

        /// 字节组
        /// 字节组长度
        ///
        private byte[] Crc16(byte[] pucFrame, int usLen)
        {
            int i = 0;
            byte[] res = new byte[2] { 0xFF, 0xFF };
            UInt16 iIndex = 0x0000;
            while (usLen-- > 0)
            {
                iIndex = (UInt16)(res[0] ^ pucFrame[i++]);
                res[0] = (byte)(res[1] ^ aucCRCHi[iIndex]);
                res[1] = aucCRCLo[iIndex];
            }
            return res;
        }

        ///


        /// 校验CRC
        ///

        ///
        ///
        private bool CheckCRC(byte[] response)
        {
            byte[] crc = Crc16(response, response.Length - 2);
            if (crc[0] == response[response.Length - 2] && crc[1] == response[response.Length - 1]) return true;
            else return false;
        }

        最后就是进行调用,硬件测试和调用的方法,在源码中均有体现,源码参考地址如下:C#含有ModbusRtu通讯库,通讯示例硬件设备测试例程-C#文档类资源-CSDN文库

你可能感兴趣的:(c#,windows)