Modbus-RTU协议C#实现

该代码示例展示了如何使用C#实现Modbus-RTU协议的读取和写入操作,包括读取寄存器和线圈状态,以及写入单个线圈和寄存器。同时,文中包含了CRC16校验的过程,确保数据传输的准确性。通过SerialPort类进行串口通信,完成与从站的数据交互。
摘要由CSDN通过智能技术生成

1、安装依赖包
System.IO.Ports
2、读协议

/// <summary>
        /// Modbus-RTU协议读实例
        /// </summary>
        private static void Read()
        {
            //组装一个请求报文
            // 01 03 00 00 00 0A C5 CD
            byte slave = 0x01;
            //byte function = 0x03;   //读单个寄存器
            byte function = 0x01;   //读单个线圈状态
            int startAddress = 0;
            int length = 10;

            List<byte> bytes = new List<byte>();
            bytes.Add(slave);
            bytes.Add(function);
            bytes.Add(BitConverter.GetBytes(startAddress)[1]);
            bytes.Add(BitConverter.GetBytes(startAddress)[0]);
            bytes.Add(BitConverter.GetBytes(length)[1]);
            bytes.Add(BitConverter.GetBytes(length)[0]);
            //CRC校验
            bytes = CRC16(bytes);
            //组装好了进行串口通信
            SerialPort serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            serialPort.Open();
            //向从站发送请求
            serialPort.Write(bytes.ToArray(), 0, bytes.Count);
            Task.Run(async () =>
            {
                await Task.Delay(100);
                byte[] buffer = new byte[serialPort.BytesToRead];
                serialPort.DiscardInBuffer();

                List<byte> bufferList = new List<byte>(buffer);
                bufferList.RemoveAt(0);
                bufferList.RemoveAt(0);
                bufferList.RemoveAt(0);
                bufferList.RemoveAt(bufferList.Count - 1);
                bufferList.RemoveAt(bufferList.Count - 1);
                //读寄存器
                //for(int i = 0; i < bufferList.Count; i++)
                //{
                //    List<byte> valueList = new List<byte>();
                //    valueList.Add(bufferList[i]);
                //    valueList.Add(bufferList[++i]);
                //    valueList.Reverse();
                //    ushort value=BitConverter.ToUInt16(valueList.ToArray(), 0);
                //    Console.WriteLine(value);
                //}
                //读线圈 09 00
                bufferList.Reverse();
                var values = string.Join("", bufferList.Select(x => Convert.ToString(x, 2).PadLeft(8, '0')).ToList()).ToList();
                values.Reverse();
                for (int i = 0; i < values.Count; i++)
                {
                    Console.WriteLine(Convert.ToBoolean(int.Parse(values[i].ToString())));
                }
            });
        }

3、写协议

/// <summary>
        /// Modbus-RTU协议写实例
        /// </summary>
        private static void Write()
        {
            //组装报文
            byte slave = 0x01;
            //byte function = 0x05;   //写单个线圈状态
            byte function = 0x06;   //写单个寄存器
            int startAddress = 0;
            bool value = false;
            int iv = 123;

            List<byte> bytes = new List<byte>();
            bytes.Add(slave);
            bytes.Add(function);
            bytes.Add(BitConverter.GetBytes(startAddress)[1]);
            bytes.Add(BitConverter.GetBytes(startAddress)[0]);
            //单线圈的写入
            //bytes.Add(value ? (byte)0xFF : (byte)0x00);
            //bytes.Add(0x00);
            //单寄存器写入
            bytes.Add(BitConverter.GetBytes(iv)[1]);
            bytes.Add(BitConverter.GetBytes(iv)[0]);
            //CRC校验
            bytes = CRC16(bytes);
            SerialPort serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            serialPort.Open();
            //向从站发送请求
            serialPort.Write(bytes.ToArray(), 0, bytes.Count);
            //接收后如果报文一致,说明发送请求成功
        }

4、CRC16校验

/// <summary>
        /// CRC-16校验
        /// </summary>
        /// <param name="value"></param>
        /// <param name="poly"></param>
        /// <param name="crcInit"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        private static List<byte> CRC16(List<byte> value,ushort poly=0xA001,ushort crcInit=0xFFFF)
        {
            if (value == null || !value.Any())
                throw new ArgumentException("");
            //运算
            ushort crc = crcInit;
            for(int i=0; i<value.Count; i++)
            {
                crc = (ushort)(crc ^ value[i]);
                for(int j=0; j<8; j++)
                {
                    crc=(crc&1)!=0?(ushort)((crc>>1)^poly):(ushort)(crc>>1);
                }
            }
            byte hi = (byte)((crc & 0xFF00) >> 8);
            byte lo=(byte)(crc & 0xFF);
            List<byte> buffer = new List<byte>();
            buffer.AddRange(value);
            buffer.Add(lo);
            buffer.Add(hi);
            return buffer;
        }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
/// /// 读保持寄存器03 /// /// 数据读取延迟 /// 设备从站地址 /// 数据起始地址 /// 寄存器数量 /// 返回的寄存器数值 /// 返回异常描述 /// 是否读取成功 public bool ReadHoldReg(int timeout, byte slaveAddress, ushort startAddress, ushort regCountIn, out ushort[] holdRegs, out ModbusException ex) /// /// 读输入寄存器04 /// /// 数据读取延迟 /// 设备从站地址 /// 数据地址 /// 寄存器数量 /// 返回的寄存器数值 /// 返回异常描述 /// 是否读取成功 public bool ReadInputReg(int timeout, byte slaveAddress, ushort startAddress, ushort regCountIn, out ushort[] InputRegs, out ModbusException ex) /// /// 写单寄存器(06功能码) /// /// 数据读取延迟 /// 设备从站地址 /// 寄存器地址 /// 寄存器值 /// 返回异常描述 /// 是否写入成功 public bool WriteSingleReg(int timeout, byte slaveAddress, ushort regAdr, ushort regValue, out ModbusException ex) /// /// 写单个线圈(05功能码) /// /// 数据读取延迟 /// 设备从站地址 /// 寄存器地址 /// 寄存器值 /// 返回异常描述 /// 是否写入成功 public bool WriteSingleCoil(int timeout, byte slaveAddress, ushort regAdr, ushort ONorOFF, out ModbusException ex) /// /// 写多寄存器(10功能码) /// /// 数据读取延迟 /// 设备从站地址 /// 寄存器起始地址 /// 寄存器值 /// 返回异常描述 /// 是否写入成功 public bool WriteMutilReg(int timeout, byte slaveAddress, ushort regAdr, ushort[] regValue, out ModbusException ex) ....................
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大浪淘沙胡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值