使用C#实现ModbusRTU通信
公共方法
public class Common { /// <summary> /// 生成CRC校验码 /// </summary> /// <param name="data"></param> /// <returns>返回CRC校验码</returns> public static byte[] CRC16(List<byte> data) { //CRC校验的基本步骤如下: //1.预置:CRC寄存器预置为0xFFFF。 //2.数据输入:报文中除了CRC校验码以外的所有字节(包括设备地址、功能码和数据)按照顺序进行处理。 //4.计算:对每一个字节,从最高位到最低位,将其与CRC寄存器当前的值进行异或运算。如果结果的最高位为1,则将寄存器的值左移一位并与0x8005进行异或运算;如果最高位为0,则只需左移一位。重复此过程,直至8位都处理完毕。然后继续处理下一个字节,直到所有字节都计算完毕。 //4.结果:最后CRC寄存器中的值就是CRC校验码,通常在传输前转换为低字节在前(Little - Endian)的形式,并附加到报文的末尾。 //当接收方收到报文时,会对整个报文(包括CRC校验码)使用相同的CRC计算流程。如果报文未被篡改,计算结果应为0x0000(考虑到了CRC码的加入和计算规则)。如果结果不是0x0000,则表明报文在传输过程中可能遭到了篡改或出现了错误。 //运算 ushort crc = 0xFFFF; for (int i = 0; i < data.Count; i++) { crc = (ushort)(crc ^ (data[i])); for (int j = 0; j < 8; j++) { crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1); } } byte hi = (byte)((crc & 0xFF00) >> 8); //高 byte lo = (byte)(crc & 0x00FF); //低 return [lo, hi]; } /// <summary> /// 错误码 /// </summary> public static Dictionary<byte, string> ErrorCodes = new Dictionary<byte, string> { { 0x01, "非法的功能码"}, { 0x02, "非法的数据地址"}, { 0x03, "非法的数据值"}, { 0x04, "从设备/服务器故障"}, { 0x05, "确认,从设备/服务器需要一个耗时操作"}, { 0x06, "从设备/服务器繁忙"}, { 0x0A, "网关故障"}, { 0x0B, "网关目标设备未能响应"}, }; }
要用到的枚举:
/// <summary> /// 大小端模式 /// </summary> public enum Endian { /// <summary> /// 大端 /// </summary> BigEndian, /// <summary> /// 小端 /// </summary> LittleEndian } /// <summary> /// 功能码 /// </summary> public enum FuncCode { ReadCoils=0x01, ReadDiscreteInputs = 0x02, ReadHoldingRegisters = 0x03, ReadInputRegisters = 0x04, WriteSingleCoil= 0x05, WriteSingleRegister = 0x06, WriteMultipleCoil = 0x0F, WriteMultipleRegisters = 0x10, }
方法:
功能码:0x01、0x02、0x03、0x05、0x06、0x0F、0x10
public class ModbusRTU { private SerialPort _serialPort; private byte _slaveId; /// <summary> /// /// </summary> /// <param name="serialPort">串口</param> /// <param name="slaveId">从站地址</param> public ModbusRTU(SerialPort serialPort, byte slaveId) { _serialPort = serialPort; _slaveId = slaveId; } /// <summary> /// 功能码0x01 /// </summary> /// <param name="startAddress">起始地址</param> /// <param name="count">读取数量</param> /// <returns>bool数组</returns> public bool[] ReadCoils(short startAddress, short count) { //1.发送请求 //2.获取响应数据 //3.分析返回结果。返回bool[] //3.1 校验 //3.2 如果通过,取出数据并bool[] #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] countBytes = BitConverter.GetBytes(count); //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x01,//功能码 startBytes[1],//起始地址H startBytes[0], countBytes[1],//读取长度H countBytes[0], ]; byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = (int)Math.Ceiling(count * 1.0 / 8) + 5;//读取个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.分析返回结果。返回short[] //3.1 校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } //3.2 如果通过,取出数据并bool[] List<byte> dataBytes = readBytes.GetRange(3, readCount - 5); bool[] tempBool = new bool[dataBytes.Count * 8];//临时变量 //05 00 //0000 0101 //0000 0000 //bool[] = [true,false,true,false,12个false] for (int i = 0; i < dataBytes.Count; i++) { for (int j = 0; j < 8; j++) { //判断第j位是否为1 tempBool[i * 8 + j] = (dataBytes[i] & (1 << j)) != 0; } } bool[] result = new bool[count];//最终结果 Array.Copy(tempBool, result, count); return result; #endregion } /// <summary> /// 功能码0x02 /// </summary> /// <param name="startAddress">起始地址</param> /// <param name="count">读取数量</param> /// <returns>bool数组</returns> public bool[] ReadDiscreteInput(short startAddress, short count) { //1.发送请求 //2.获取响应数据 //3.分析返回结果。返回bool[] //3.1 校验 //3.2 如果通过,取出数据并bool[] #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] countBytes = BitConverter.GetBytes(count); //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x02,//功能码 startBytes[1],//起始地址H startBytes[0], countBytes[1],//读取长度H countBytes[0], ]; byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = (int)Math.Ceiling(count * 1.0 / 8) + 5;//读取个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.分析返回结果。返回bool[] //3.1 校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } //3.2 如果通过,取出数据并bool[] List<byte> dataBytes = readBytes.GetRange(3, readCount - 5); bool[] tempBool = new bool[dataBytes.Count * 8];//临时变量 //05 00 //0000 0101 //0000 0000 //bool[] = [true,false,true,false,12个false] for (int i = 0; i < dataBytes.Count; i++) { for (int j = 0; j < 8; j++) { //判断第j位是否为1 tempBool[i * 8 + j] = (dataBytes[i] & (1 << j)) != 0; } } bool[] result = new bool[count];//最终结果 Array.Copy(tempBool, result, count); return result; #endregion } /// <summary> /// 读保持寄存器(16位) 功能码0x03 /// </summary> /// <param name="startAddress">开始地址</param> /// <param name="count">要读的数字个数</param> /// <returns>数字数组</returns> /// <exception cref="Exception"></exception> public short[] ReadHoldingReg16(short startAddress, short count) { //1.发送请求 //2.获取响应数据 //3.分析返回结果。返回short[] //3.1 校验 //3.2 如果通过,取出数据并short[] #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] countRegs = BitConverter.GetBytes(count);//寄存器个数 //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x03,//功能码 startBytes[1],//起始地址H startBytes[0], countRegs[1],//读取长度H countRegs[0], ]; byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = count * 2 + 5;//读取字节个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.分析返回结果。返回short[] //3.1 校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } //3.2 如果通过,取出数据并short[] List<byte> dataBytes = readBytes.GetRange(3, readCount - 5); short[] result = new short[count]; for (int i = 0; i < count; i++) { //BitConverter 只支持小端 List<byte> curBytes = dataBytes.GetRange(i * 2, 2); curBytes.Reverse(); result[i] = BitConverter.ToInt16(curBytes.ToArray()); } return result; #endregion } /// <summary> /// 读保持寄存器(32位) 功能码0x03 /// </summary> /// <param name="startAddress">开始地址</param> /// <param name="count">要读的数字个数</param> /// <param name="endian">大小端模式。默认大端</param> /// <returns>数字数组</returns> /// <exception cref="Exception"></exception> public int[] ReadHoldingReg32(short startAddress, short count, Endian endian = Endian.BigEndian) { //1.发送请求 //2.获取响应数据 //3.分析返回结果。返回int[] //3.1 校验 //3.2 如果通过,取出数据并int[] #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] countRegs = BitConverter.GetBytes(count * 2);//寄存器个数 //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x03,//功能码 startBytes[1],//起始地址H startBytes[0], countRegs[1],//读取长度H countRegs[0], ]; byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = count * 4 + 5;//读取字节个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.分析返回结果。返回short[] //3.1 校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } //3.2 如果通过,取出数据并int[] List<byte> dataBytes = readBytes.GetRange(3, readCount - 5); int[] result = new int[count]; for (int i = 0; i < count; i++) { //BitConverter 只支持小端 List<byte> curBytes = dataBytes.GetRange(i * 4, 4); if (endian == Endian.BigEndian) { curBytes.Reverse(); } result[i] = BitConverter.ToInt32(curBytes.ToArray()); } return result; #endregion } /// <summary> /// 读保持寄存器(32位 float) 功能码0x03 /// </summary> /// <param name="startAddress">开始地址</param> /// <param name="count">要读的数字个数</param> /// <param name="endian">大小端模式。默认大端</param> /// <returns>数字数组</returns> /// <exception cref="Exception"></exception> public float[] ReadHoldingReg32Float(short startAddress, short count, Endian endian = Endian.BigEndian) { //1.发送请求 //2.获取响应数据 //3.分析返回结果。返回int[] //3.1 校验 //3.2 如果通过,取出数据并int[] #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] countRegs = BitConverter.GetBytes(count * 2);//寄存器个数 //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x03,//功能码 startBytes[1],//起始地址H startBytes[0], countRegs[1],//读取长度H countRegs[0], ]; byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = count * 4 + 5;//读取字节个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.分析返回结果。返回short[] //3.1 校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } //3.2 如果通过,取出数据并int[] List<byte> dataBytes = readBytes.GetRange(3, readCount - 5); float[] result = new float[count]; for (int i = 0; i < count; i++) { //BitConverter 只支持小端 List<byte> curBytes = dataBytes.GetRange(i * 4, 4); if (endian == Endian.BigEndian) { curBytes.Reverse(); } result[i] = BitConverter.ToSingle(curBytes.ToArray()); } return result; #endregion } #region 写单线圈 功能码0x05 /// <summary> /// 写单线圈 功能码0x05 /// </summary> /// <param name="startAddress">起始地址</param> /// <param name="value">写的值</param> public void WriteSingleCoil(short startAddress, bool value) { //1.发送请求 //2.获取响应数据 //3.校验 #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] writeValueBytes = value ? [0xFF, 0x00] : [0x00, 0x00];//写入的值bytes //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x05,//功能码 startBytes[1],//起始地址H startBytes[0], ]; sendBytes.AddRange(writeValueBytes); byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = 8;//读取字节个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } #endregion } #endregion #region 写多线圈 功能码0x0F /// <summary> /// 写多线圈 功能码0x0F /// </summary> /// <param name="startAddress">起始地址</param> /// <param name="values">写的多个值</param> public void WriteMultipleCoil(short startAddress, bool[] values) { //1.发送请求 //2.获取响应数据 //3.校验 #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] valueCountBytes = BitConverter.GetBytes(values.Length);//值的个数bytes int bytesCount = (int)Math.Ceiling(values.Length * 1.0 / 8);//写入的字节个数 //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x0F,//功能码 startBytes[1],//起始地址H startBytes[0], valueCountBytes[1],//值的个数bytes valueCountBytes[0], (byte)bytesCount//写入的字节个数 ]; //将bool[]转成byte[] BitArray bitArray = new BitArray(values); byte[] writeBytes = new byte[bytesCount]; bitArray.CopyTo(writeBytes, 0); sendBytes.AddRange(writeBytes); byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = 8;//读取字节个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } #endregion } #endregion #region 写单个寄存器 功能码0x06 /// <summary> /// 写单个寄存器 功能码0x06 /// </summary> /// <param name="startAddress">起始地址</param> /// <param name="value">写的多个值</param> public void WriteSingleReg(short startAddress, short value) { //1.发送请求 //2.获取响应数据 //3.校验 #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] valueBytes = BitConverter.GetBytes(value);//小端 //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x06,//功能码 startBytes[1],//起始地址H startBytes[0], valueBytes[1],//写进去的值 valueBytes[0], ]; byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = 8;//读取字节个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } #endregion } #endregion #region 写多个寄存器(32位int) 功能码0x10 /// <summary> /// 写多个寄存器(32位int) 功能码0x10 /// </summary> /// <param name="startAddress">起始地址</param> /// <param name="values">写的多个值</param> /// <param name="endian">大小端</param> public void WriteMultipleReg32Int(short startAddress, int[] values, Endian endian = Endian.BigEndian) { //1.发送请求 //2.获取响应数据 //3.校验 #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] regCountbytes = BitConverter.GetBytes(values.Length * 2); //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x10,//功能码 startBytes[1],//起始地址H startBytes[0], regCountbytes[1],//寄存器数量 regCountbytes[0], (byte)(values.Length*4)//字节数 ]; foreach (int i in values) { byte[] curBytes = BitConverter.GetBytes(i);//小端 if (endian == Endian.BigEndian)//如果是大端 { curBytes = curBytes.Reverse().ToArray(); } sendBytes.AddRange(curBytes); } byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = 8;//读取字节个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } #endregion } #endregion #region 写多个寄存器(32位float) 功能码0x10 /// <summary> /// 写多个寄存器(32位float) 功能码0x10 /// </summary> /// <param name="startAddress">起始地址</param> /// <param name="values">写的多个值</param> /// <param name="endian">大小端</param> public void WriteMultipleReg32Float(short startAddress, float[] values, Endian endian = Endian.BigEndian) { //1.发送请求 //2.获取响应数据 //3.校验 #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] regCountbytes = BitConverter.GetBytes(values.Length * 2); //发送的bytes List<byte> sendBytes = [ _slaveId,//从机地址 0x10,//功能码 startBytes[1],//起始地址H startBytes[0], regCountbytes[1],//寄存器数量 regCountbytes[0], (byte)(values.Length*4)//字节数 ]; foreach (float i in values) { byte[] curBytes = BitConverter.GetBytes(i);//小端 if (endian == Endian.BigEndian)//如果是大端 { curBytes = curBytes.Reverse().ToArray(); } sendBytes.AddRange(curBytes); } byte[] crcBytes = Common.CRC16(sendBytes); sendBytes.AddRange(crcBytes); _serialPort.Write(sendBytes.ToArray(), 0, sendBytes.Count); #endregion #region 2.获取响应数据 int readCount = 8;//读取字节个数 List<byte> readBytes = new List<byte>();//返回的byte[] try { while (readBytes.Count < readCount) { readBytes.Add((byte)_serialPort.ReadByte()); } } catch (Exception) { //异常处理,比如超时异常等 } #endregion #region 3.校验 if (readBytes[1] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[readBytes[2]]}"); } List<byte> checkBytes = readBytes.GetRange(0, readBytes.Count - 2); //checkBytes[3] = 0x05;//测试篡改数据 byte[] checkCodeBytes = Common.CRC16(checkBytes); checkBytes.AddRange(checkCodeBytes); if (!checkBytes.SequenceEqual(readBytes)) { throw new Exception("校验失败"); } #endregion } #endregion }
调用:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Btn01_Click(object sender, RoutedEventArgs e) { SerialPort serialPort = new SerialPort("COM1"); serialPort.BaudRate = 9600; serialPort.DataBits = 8; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; serialPort.ReadTimeout = 500;//读超时时间 单位毫秒 serialPort.Open(); ModbusRTU modbusRTU = new ModbusRTU(serialPort, 0x01); modbusRTU.ReadCoils(0, 1); } private void Btn02_Click(object sender, RoutedEventArgs e) { SerialPort serialPort = new SerialPort("COM1"); serialPort.BaudRate = 9600; serialPort.DataBits = 8; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; serialPort.ReadTimeout = 500;//读超时时间 单位毫秒 serialPort.Open(); ModbusRTU modbusRTU = new ModbusRTU(serialPort, 0x01); bool[] rst = modbusRTU.ReadDiscreteInput( 0, 5); } /// <summary> /// 03功能码 16位 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Btn03_Click(object sender, RoutedEventArgs e) { SerialPort serialPort = new SerialPort("COM1"); serialPort.BaudRate = 9600; serialPort.DataBits = 8; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; serialPort.ReadTimeout = 500;//读超时时间 单位毫秒 serialPort.Open(); ModbusRTU modbusRTU = new ModbusRTU(serialPort, 0x01); modbusRTU.ReadHoldingReg16(0, 3); } private void Btn03_32_Click(object sender, RoutedEventArgs e) { SerialPort serialPort = new SerialPort("COM1"); serialPort.BaudRate = 9600; serialPort.DataBits = 8; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; serialPort.ReadTimeout = 500;//读超时时间 单位毫秒 serialPort.Open(); ModbusRTU modbusRTU = new ModbusRTU(serialPort, 0x01); modbusRTU.ReadHoldingReg32Float(0, 3, Endian.BigEndian); } private void Btn05_Click(object sender, RoutedEventArgs e) { SerialPort serialPort = new SerialPort("COM1"); serialPort.BaudRate = 9600; serialPort.DataBits = 8; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; serialPort.ReadTimeout = 500;//读超时时间 单位毫秒 serialPort.Open(); ModbusRTU modbusRTU = new ModbusRTU(serialPort, 0x01); modbusRTU.WriteSingleCoil(3, true); } private void Btn0F_Click(object sender, RoutedEventArgs e) { SerialPort serialPort = new SerialPort("COM1"); serialPort.BaudRate = 9600; serialPort.DataBits = 8; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; serialPort.ReadTimeout = 500;//读超时时间 单位毫秒 serialPort.Open(); ModbusRTU modbusRTU = new ModbusRTU(serialPort, 0x01); modbusRTU.WriteMultipleCoil(1, [true,true,true,false,false,true,true,false,true,true]); } private void Btn06_Click(object sender, RoutedEventArgs e) { SerialPort serialPort = new SerialPort("COM1"); serialPort.BaudRate = 9600; serialPort.DataBits = 8; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; serialPort.ReadTimeout = 500;//读超时时间 单位毫秒 serialPort.Open(); ModbusRTU modbusRTU = new ModbusRTU(serialPort, 0x01); modbusRTU.WriteSingleReg(9,456); } private void Btn10_Click(object sender, RoutedEventArgs e) { SerialPort serialPort = new SerialPort("COM1"); serialPort.BaudRate = 9600; serialPort.DataBits = 8; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; serialPort.ReadTimeout = 500;//读超时时间 单位毫秒 serialPort.Open(); ModbusRTU modbusRTU = new ModbusRTU(serialPort, 0x01); modbusRTU.WriteMultipleReg32Int(2, [123,456,789], Endian.LittleEndian); } private void Btn10_float_Click(object sender, RoutedEventArgs e) { SerialPort serialPort = new SerialPort("COM1"); serialPort.BaudRate = 9600; serialPort.DataBits = 8; serialPort.Parity = Parity.None; serialPort.StopBits = StopBits.One; serialPort.ReadTimeout = 500;//读超时时间 单位毫秒 serialPort.Open(); ModbusRTU modbusRTU = new ModbusRTU(serialPort, 0x01); modbusRTU.WriteMultipleReg32Float(2, [(float)123.1, (float)456.5, (float)789.6]); } }

浙公网安备 33010602011771号