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();
            }
        }

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

        /// <summary>
        /// 读取输出线圈
        /// </summary>
        /// <param name="iDevAdd">主站/从站地址</param>
        /// <param name="iAddress">开始地址</param>
        /// <param name="iLength">读取长度</param>
        /// <returns></returns>
        public byte[] ReadOutputStatus(byte iDevAdd, ushort iAddress, ushort iLength)
        {
            //拼接报文
            List<byte> SendCommand = new List<byte>();
            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; }
        }

        /// <summary>
        /// 读取输入线圈
        /// </summary>
        /// <param name="iDevAdd">从站地址</param>
        /// <param name="iAddress">开始地址</param>
        /// <param name="iLength">读取长度</param>
        /// <returns></returns>
        public byte[] ReadInputStatus(byte iDevAdd, ushort iAddress, ushort iLength)
        {
            //拼接报文
            List<byte> SendCommand = new List<byte>();
            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; }
        }

        /// <summary>
        /// 读取输出寄存器
        /// </summary>
        /// <param name="iDevAdd">从站地址</param>
        /// <param name="iAddress">开始地址</param>
        /// <param name="iLength">读取长度</param>
        /// <returns></returns>
        public byte[] ReadOutPutReg(byte iDevAdd, ushort iAddress, ushort iLength)
        {
            //拼接报文
            List<byte> SendCommand = new List<byte>();
            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; }
        }
        

        /// <summary>
        /// 读取输入寄存器
        /// </summary>
        /// <param name="iDevAdd">从站地址</param>
        /// <param name="iAddress">开始地址</param>
        /// <param name="iLength">读取长度</param>
        /// <returns></returns>
        public byte[] ReadInputReg(byte iDevAdd, ushort iAddress, ushort iLength)
        {
            //拼接报文
            List<byte> SendCommand = new List<byte>();
            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; }
        }

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

        /// <summary>
        /// 发送指令
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public byte[] WriteData(string str)
        {
            byte[] getbyte = ConvertHexStringToBytes(str);
            //拼接报文
            List<byte> SendCommand = new List<byte>();
            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校验、数据处理等方法(源码太多,此处复制一小部分,文末有源码链接)

/// <summary>
        /// 生成CRC
        /// </summary>
        /// <param name="pucFrame">字节组</param>
        /// <param name="usLen">字节组长度</param>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// 校验CRC
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        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文库

  • 24
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值