使用C#实现ModbusTCP通信
公共方法
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, }
ModbusTCP协议封装
/// <summary> /// ModbusTCP协议封装 /// </summary> public class ModbusTCP { private Socket _socket; private static readonly object lockObj = new object(); public ModbusTCP(Socket socket) { _socket = socket; } #region 功能码0x01 0x02 /// <summary> /// 功能码0x01 0x02 /// </summary> /// <param name="funcCode">功能码。只支持01、02</param> /// <param name="startAddress">起始地址</param> /// <param name="count">读取数量</param> /// <returns>bool数组</returns> public bool[] ReadBools(FuncCode funcCode, short startAddress, short count) { if (funcCode != FuncCode.ReadCoils && funcCode != FuncCode.ReadDiscreteInputs) { throw new Exception("该方法只支持功能码01、02"); } //1.发送请求(send) //2.获取响应数据(receive) //3.分析返回结果。返回bool[] //3.1 校验 //3.2 如果通过,取出数据并bool[] lock (lockObj) { #region 1.发送请求 //发送的bytes List<byte> sendBytes = GetReadBytes(funcCode, startAddress, count); _socket.Send(sendBytes.ToArray()); #endregion #region 2.获取响应数据 int readCount = (int)Math.Ceiling(count * 1.0 / 8) + 9;//读取字节个数 List<byte> receiveBytes = GetReceiveBytes(readCount); #endregion #region 3.分析返回结果。返回bool[] //3.1 校验 ExceptionCheck(sendBytes, receiveBytes); //3.2 如果通过,取出数据并bool[] List<byte> dataBytes = receiveBytes.GetRange(9, readCount - 9); bool[] tempBool = new bool[dataBytes.Count * 8];//临时变量 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 } } #endregion #region 写单线圈 功能码0x05 /// <summary> /// 写单线圈 功能码0x05 /// </summary> /// <param name="startAddress">起始地址</param> /// <param name="value">写的值</param> public void WriteSingleCoil(short startAddress, bool value) { lock (lockObj) { //1.发送请求 //2.获取响应数据 //3.校验 #region 1.发送请求 byte[] writeValueBytes = value ? [0xFF, 0x00] : [0x00, 0x00];//写入的值bytes List<byte> sendBytes = GetSingleWriteBytes(FuncCode.WriteSingleCoil, startAddress, writeValueBytes); _socket.Send(sendBytes.ToArray()); #endregion #region 2.获取响应数据 List<byte> receiveBytes = GetReceiveBytes(12); #endregion #region 3.校验 ExceptionCheck(sendBytes, receiveBytes); #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.校验 lock (lockObj) { #region 1.发送请求 byte[] valueCountBytes = BitConverter.GetBytes(values.Length);//值的个数bytes int bytesCount = (int)Math.Ceiling(values.Length * 1.0 / 8);//写入的字节个数 //发送的bytes //将bool[]转成byte[] BitArray bitArray = new BitArray(values); byte[] writeBytes = new byte[bytesCount]; bitArray.CopyTo(writeBytes, 0); List<byte> sendBytes = GetMultipleWriteBytes(FuncCode.WriteMultipleCoil, startAddress, valueCountBytes, (byte)bytesCount, writeBytes); _socket.Send(sendBytes.ToArray()); #endregion #region 2.获取响应数据 List<byte> receiveBytes = GetReceiveBytes(12); //读取字节个数12 #endregion #region 3.校验 ExceptionCheck(sendBytes, receiveBytes); #endregion } } #endregion #region 读保持寄存器(16位) 功能码0x03 0x04 /// <summary> /// 读保持寄存器(16位) 功能码0x03 0x04 /// </summary> /// <param name="funcCode">功能码。只支持03、04</param> /// <param name="startAddress">开始地址</param> /// <param name="count">要读的数字个数</param> /// <returns>数字数组</returns> /// <exception cref="Exception"></exception> public short[] ReadReg16(FuncCode funcCode, short startAddress, short count) { if (funcCode != FuncCode.ReadHoldingRegisters && funcCode != FuncCode.ReadInputRegisters) { throw new Exception("该方法只支持功能码03、04"); } //1.发送请求 //2.获取响应数据 //3.分析返回结果。返回short[] //3.1 校验 //3.2 如果通过,取出数据并short[] lock (lockObj) { #region 1.发送请求 //发送的bytes List<byte> sendBytes = GetReadBytes(funcCode, startAddress, count); _socket.Send(sendBytes.ToArray()); #endregion #region 2.获取响应数据 int readCount = count * 2 + 9;//读取字节个数 List<byte> receiveBytes = GetReceiveBytes(readCount); #endregion #region 3.分析返回结果。返回short[] //3.1 校验 ExceptionCheck(sendBytes, receiveBytes); //3.2 如果通过,取出数据并short[] List<byte> dataBytes = receiveBytes.GetRange(9, readCount - 9); 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 } } #endregion #region 读保持寄存器(32位 int) 功能码0x03 0x04 /// <summary> /// 读保持寄存器(32位) 功能码0x03 0x04 /// </summary> /// <param name="startAddress">开始地址</param> /// <param name="count">要读的数字个数</param> /// <param name="endian">大小端模式。默认大端</param> /// <returns>数字数组</returns> /// <exception cref="Exception"></exception> public int[] ReadReg32Int(FuncCode funcCode, short startAddress, short count, Endian endian = Endian.BigEndian) { if (funcCode != FuncCode.ReadHoldingRegisters && funcCode != FuncCode.ReadInputRegisters) { throw new Exception("该方法只支持功能码03、04"); } //1.发送请求 //2.获取响应数据 //3.分析返回结果。返回int[] //3.1 校验 //3.2 如果通过,取出数据并int[] lock (lockObj) { #region 1.发送请求 //发送的bytes List<byte> sendBytes = GetReadBytes(funcCode, startAddress, (short)(count * 2)); _socket.Send(sendBytes.ToArray()); #endregion #region 2.获取响应数据 int readCount = count * 4 + 9;//读取字节个数 List<byte> receiveBytes = GetReceiveBytes(readCount); #endregion #region 3.分析返回结果。返回int[] ExceptionCheck(sendBytes, receiveBytes); //3.2 如果通过,取出数据并int[] List<byte> dataBytes = receiveBytes.GetRange(9, readCount - 9); 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 } } #endregion #region 读保持寄存器(32位 float) 功能码0x03 0x04 /// <summary> /// 读保持寄存器(32位 float) 功能码0x03 0x04 /// </summary> /// <param name="startAddress">开始地址</param> /// <param name="count">要读的数字个数</param> /// <param name="endian">大小端模式。默认大端</param> /// <returns>数字数组</returns> /// <exception cref="Exception"></exception> public float[] ReadReg32Float(FuncCode funcCode, short startAddress, short count, Endian endian = Endian.BigEndian) { //1.发送请求 //2.获取响应数据 //3.分析返回结果。返回int[] //3.1 校验 //3.2 如果通过,取出数据并int[] lock (lockObj) { #region 1.发送请求 //发送的bytes List<byte> sendBytes = GetReadBytes(funcCode, startAddress, (short)(count * 2)); _socket.Send(sendBytes.ToArray()); #endregion #region 2.获取响应数据 int readCount = count * 4 + 9;//读取字节个数 List<byte> receiveBytes = GetReceiveBytes(readCount); #endregion #region 3.分析返回结果。返回short[] //3.1 校验 ExceptionCheck(sendBytes, receiveBytes); //3.2 如果通过,取出数据并int[] List<byte> dataBytes = receiveBytes.GetRange(9, readCount - 9); 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 } } #endregion #region 写单个寄存器 功能码0x06 /// <summary> /// 写单个寄存器 功能码0x06 /// </summary> /// <param name="startAddress">起始地址</param> /// <param name="value">写的多个值</param> public void WriteSingleReg(short startAddress, short value) { //1.发送请求 //2.获取响应数据 //3.校验 lock (lockObj) { #region 1.发送请求 byte[] valueBytes = BitConverter.GetBytes(value).Reverse().ToArray();//小端 List<byte> sendBytes = GetSingleWriteBytes(FuncCode.WriteSingleRegister, startAddress, valueBytes); _socket.Send(sendBytes.ToArray()); #endregion #region 2.获取响应数据 List<byte> receiveBytes = GetReceiveBytes(12); //读取字节个数 #endregion #region 3.校验 ExceptionCheck(sendBytes, receiveBytes); #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.校验 lock (lockObj) { #region 1.发送请求 byte[] regCountbytes = BitConverter.GetBytes(values.Length * 2); //发送的bytes List<byte> valuesBytes = new List<byte>();//值的byte集合 foreach (int i in values) { byte[] curBytes = BitConverter.GetBytes(i);//小端 if (endian == Endian.BigEndian)//如果是大端 { curBytes = curBytes.Reverse().ToArray(); } valuesBytes.AddRange(curBytes); } List<byte> sendBytes = GetMultipleWriteBytes(FuncCode.WriteMultipleRegisters, startAddress, regCountbytes, (byte)(values.Length * 4), valuesBytes.ToArray()); _socket.Send(sendBytes.ToArray()); #endregion #region 2.获取响应数据 List<byte> receiveBytes = GetReceiveBytes(12); //读取字节个数 #endregion #region 3.校验 ExceptionCheck(sendBytes, receiveBytes); #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) { lock (lockObj) { //1.发送请求 //2.获取响应数据 //3.校验 #region 1.发送请求 byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] regCountbytes = BitConverter.GetBytes(values.Length * 2); //发送的bytes List<byte> valuesBytes = new List<byte>(); foreach (float i in values) { byte[] curBytes = BitConverter.GetBytes(i);//小端 if (endian == Endian.BigEndian)//如果是大端 { curBytes = curBytes.Reverse().ToArray(); } valuesBytes.AddRange(curBytes); } List<byte> sendBytes = GetMultipleWriteBytes(FuncCode.WriteMultipleRegisters, startAddress, regCountbytes, (byte)(values.Length * 4), valuesBytes.ToArray()); _socket.Send(sendBytes.ToArray()); #endregion #region 2.获取响应数据 List<byte> receiveBytes = GetReceiveBytes(12); //读取字节个数 #endregion #region 3.校验 ExceptionCheck(sendBytes, receiveBytes); #endregion } } #endregion #region 私有方法 private ushort TransId = 0;//事务标识符 /// <summary> /// 设置事务标识符 /// </summary> private void SetTransId() { if (TransId == ushort.MaxValue) { TransId = 0; } else { TransId++; } } #region 请求读操作字节封装(适用于功能码01、02、03、04) /// <summary> /// 请求读操作字节封装(适用于功能码01、02、03、04) /// </summary> /// <param name="funcCode"></param> /// <param name="startAddress"></param> /// <param name="count"></param> /// <returns></returns> private List<byte> GetReadBytes(FuncCode funcCode, short startAddress, short count) { byte[] startBytes = BitConverter.GetBytes(startAddress); byte[] countBytes = BitConverter.GetBytes(count); SetTransId();//设置事务标识符 byte[] transBytes = BitConverter.GetBytes(TransId); //发送的bytes return [ transBytes[0],//事务标识符 transBytes[1], 0x00,0x00,//协议标识符 0x00,0x06,//长度 0x01,//单元标识符 (byte)funcCode,//功能码 startBytes[1],//起始地址H startBytes[0], countBytes[1],//读取长度H countBytes[0], ]; } #endregion #region 获取读写操作响应字节封装 /// <summary> /// 获取读写操作响应字节封装 /// </summary> /// <param name="receiveCount">需要读取的字节数</param> /// <returns></returns> private List<byte> GetReceiveBytes(int receiveCount) { byte[] receiveBytes = new byte[receiveCount]; try { _socket.Receive(receiveBytes); } catch (Exception) { //异常处理,比如超时异常等 } return receiveBytes.ToList(); } #endregion #region 异常码校验 /// <summary> /// 校验响应的结果 /// </summary> /// <param name="sendBytes">响应的结果</param> /// <param name="receiveBytes">响应的结果</param> /// <exception cref="Exception"></exception> private void ExceptionCheck(List<byte> sendBytes, List<byte> receiveBytes) { if (receiveBytes[7] > 0x80)//出异常了 { throw new Exception($"出异常了,异常信息:{Common.ErrorCodes[receiveBytes[8]]}"); } //是否是同一次事务 if (!sendBytes.GetRange(0, 2).SequenceEqual(receiveBytes.GetRange(0, 2))) { throw new Exception("发送和接收不是同一次事务"); } } #endregion #region 单个写请求的报文 (适用于功能码05、06) private List<byte> GetSingleWriteBytes(FuncCode funcCode, short startAddress, byte[] valusBytes) { SetTransId();//设置事务标识符 byte[] transBytes = BitConverter.GetBytes(TransId); byte[] startBytes = BitConverter.GetBytes(startAddress); List<byte> sendBytes = [ transBytes[0],//事务标识符 transBytes[1], 0x00,0x00,//协议标识符 0x00,0x06,//长度 0x01,//单元标识符 (byte)funcCode,//功能码 startBytes[1],//起始地址H startBytes[0], ]; sendBytes.AddRange(valusBytes); return sendBytes; } #endregion #region 多个写请求的报文 (适用于功能码06、10) /// <summary> /// /// </summary> /// <param name="funcCode"></param> /// <param name="startAddress"></param> /// <param name="valueCountBytes">写数量</param> /// <param name="bytesCount"></param> /// <param name="valuesBytes">值</param> /// <returns></returns> private List<byte> GetMultipleWriteBytes(FuncCode funcCode, short startAddress, byte[] valueCountBytes, byte bytesCount, byte[] valuesBytes) { byte[] startBytes = BitConverter.GetBytes(startAddress); SetTransId();//设置事务标识符 byte[] transBytes = BitConverter.GetBytes(TransId); short len = (short)(7 + valuesBytes.Length);//长度 byte[] lenBytes = BitConverter.GetBytes(len); List<byte> sendBytes = [ transBytes[0],//事务ID transBytes[1], 0x00,0x00,//协议标识符 lenBytes[1],lenBytes[0],//长度 0x01,//单元标识符 (byte)funcCode,//功能码 startBytes[1],//起始地址H startBytes[0], valueCountBytes[1],//值的个数bytes valueCountBytes[0], bytesCount//写入的字节个数 ]; sendBytes.AddRange(valuesBytes);//值 字节数组 return sendBytes; } #endregion #endregion }
调用
public partial class TCPCaseBySelf : Window, INotifyPropertyChanged { private Socket socket; private ModbusTCP modbusTCP; public TCPCaseBySelf() { InitializeComponent(); DataContext = this;//上下文 Connect();//连接 #region 读取三个状态输出 Task.Run(async () => { while (true) { Dispatcher.Invoke(() => { ReadOutputStatus();//读取三个状态输出 }); await Task.Delay(1000); } }); #endregion #region 数字量输入 Task.Run(async () => { while (true) { Dispatcher.Invoke(() => { ReadInputStatus(); }); await Task.Delay(1000); } }); #endregion #region 模拟量输出 Task.Run(async () => { while (true) { Dispatcher.Invoke(() => { ReadOutputNum(); }); await Task.Delay(1000); } }); #endregion #region 模拟量输入 Task.Run(async () => { while (true) { Dispatcher.Invoke(() => { ReadIutputNum(); }); await Task.Delay(1000); } }); #endregion #region 读float Task.Run(async () => { while (true) { Dispatcher.Invoke(() => { ReadFloat(); }); await Task.Delay(1000); } }); #endregion #region 读int Task.Run(async () => { while (true) { Dispatcher.Invoke(() => { ReadInt(); }); await Task.Delay(1000); } }); #endregion #region 读short Task.Run(async () => { while (true) { Dispatcher.Invoke(() => { ReadShort(); }); await Task.Delay(1000); } }); #endregion #region 测试代码 // if (modbusTCP == null) // { // modbusTCP = new ModbusTCP(socket); // } //int[] rst= modbusTCP.ReadReg32Int(FuncCode.ReadHoldingRegisters,10,1); #endregion } #region 属性值改变通知 public event PropertyChangedEventHandler? PropertyChanged; /// <summary> /// 属性值改变通知 /// </summary> /// <param name="propName"></param> private void PropChanged(string propName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } #endregion #region 连接 /// <summary> /// 连接 /// </summary> private void Connect() { socket = new Socket(SocketType.Stream, ProtocolType.Tcp); socket.Connect("127.0.0.1", 502); } #endregion #region 三个输出状态操作 private bool outputStatus0; public bool OutputStatus0 { get { return outputStatus0; } set { outputStatus0 = value; PropChanged("OutputStatus0"); } } private bool outputStatus1; public bool OutputStatus1 { get { return outputStatus1; } set { outputStatus1 = value; PropChanged("OutputStatus1"); } } private bool outputStatus2; public bool OutputStatus2 { get { return outputStatus2; } set { outputStatus2 = value; PropChanged("OutputStatus2"); } } /// <summary> /// 读取三个状态输出 /// </summary> private void ReadOutputStatus() { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } bool[] result = modbusTCP.ReadBools(FuncCode.ReadCoils, 0, 3); OutputStatus0 = result[0]; OutputStatus1 = result[1]; OutputStatus2 = result[2]; } } private void cb0_Click(object sender, RoutedEventArgs e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteSingleCoil(0, OutputStatus0); } } private void cb1_Click(object sender, RoutedEventArgs e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteSingleCoil(1, OutputStatus1); } } private void cb2_Click(object sender, RoutedEventArgs e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteSingleCoil(2, OutputStatus2); } } #endregion #region 数字量输入 private void ReadInputStatus() { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } bool[] result = modbusTCP.ReadBools(FuncCode.ReadDiscreteInputs, 0, 3); if (result[0]) { BorderLight0.Background = new SolidColorBrush(Colors.Red); } else { BorderLight0.Background = new SolidColorBrush(Colors.LightGray); } if (result[1]) { BorderLight1.Background = new SolidColorBrush(Colors.Red); } else { BorderLight1.Background = new SolidColorBrush(Colors.LightGray); } if (result[2]) { BorderLight2.Background = new SolidColorBrush(Colors.Red); } else { BorderLight2.Background = new SolidColorBrush(Colors.LightGray); } } } #endregion #region 模拟量输出 操作 private void ReadOutputNum() { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } short[] result = modbusTCP.ReadReg16(FuncCode.ReadHoldingRegisters, 0, 4); sVar0.Value = result[0]; sVar1.Value = result[1]; sVar2.Value = result[2]; sVar3.Value = result[3]; } } private void sVar0_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteSingleReg(0, (short)sVar0.Value); } } private void sVar1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteSingleReg(1, (short)sVar1.Value); } } private void sVar2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteSingleReg(2, (short)sVar2.Value); } } private void sVar3_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteSingleReg(3, (short)sVar3.Value); } } #endregion #region 模拟量输入 private void ReadIutputNum() { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } short[] result = modbusTCP.ReadReg16(FuncCode.ReadInputRegisters, 0, 4); txtInputReg0.Text = result[0].ToString(); txtInputReg1.Text = result[1].ToString(); txtInputReg2.Text = result[2].ToString(); txtInputReg3.Text = result[3].ToString(); } } #endregion #region int 操作 private void ReadInt() { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } int[] result = modbusTCP.ReadReg32Int(FuncCode.ReadHoldingRegisters, 10, 1); txtInt.Text = result[0].ToString(); } } private void txtInt_TextChanged(object sender, TextChangedEventArgs e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteMultipleReg32Int(10, [int.Parse(txtInt.Text)]); } } #endregion #region float 操作 private void ReadFloat() { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } float[] result = modbusTCP.ReadReg32Float(FuncCode.ReadHoldingRegisters, 8, 1); txtFloat.Text = result[0].ToString(); } } private void txtFloat_TextChanged(object sender, TextChangedEventArgs e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteMultipleReg32Float(8, [float.Parse(txtFloat.Text)]); } } #endregion #region short 操作 private void ReadShort() { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } short[] result = modbusTCP.ReadReg16(FuncCode.ReadHoldingRegisters, 12, 1); txtShort.Text = result[0].ToString(); } } private void txtShort_TextChanged(object sender, TextChangedEventArgs e) { if (socket != null && socket.Connected) { if (modbusTCP == null) { modbusTCP = new ModbusTCP(socket); } modbusTCP.WriteSingleReg(12, short.Parse(txtShort.Text)); } } #endregion private void Window_Closed(object sender, EventArgs e) { if (socket != null && socket.Connected) { socket.Close(); } } }

浙公网安备 33010602011771号