C#实现MODBUS TCP 通信 第二章 (程序内实现)
上一章,我们对MODBUS 的报文已经有初步了解,本章就在程序内来具体实现,我先建立了一个MODBUS 方法类,类中包含有常用的读写方法,以及数据处理方法,由于我是用在实际生产中,所以对寄存器的值有限制,只能是正数,所以还有数据转换方法,可以作为参考,类的具体代码如下:using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ModbusTCPDemo
{
public class ModbusTCP
{
private Socket socket = null;
public bool Connect(string ip, int port)
{
//实例化Socket
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Connect(IPAddress.Parse(ip), port);
return true;
}
catch (Exception)
{
return false;
}
}
public void DisConnect()
{
if (socket != null)
{
socket.Close();
}
}
//读取寄存器
public ushort[] ReadKeeepReg(ushort start, ushort length)
{
//拼接
List<byte> SendCommand = new List<byte>();
//事物处理标识符
SendCommand.AddRange(new byte[] { 0x00, 0x00 });
//协议标识符
SendCommand.AddRange(new byte[] { 0x00, 0x00 });
//长度
SendCommand.AddRange(new byte[] { 0x00, 0x06 });
//单元标识符
SendCommand.Add(0x01);
//功能码
SendCommand.Add(0x03);
//起始地址
SendCommand.Add((byte)(start / 256));
SendCommand.Add((byte)(start % 256));
//结束地址-长度
SendCommand.Add((byte)(length / 256));
SendCommand.Add((byte)(length % 256));
//发送
socket.Send(SendCommand.ToArray());
//接收
byte[] buffer = new byte;
int count = socket.Receive(buffer, SocketFlags.None);
//验证-截取
byte[] result = new byte;
Array.Copy(buffer, 0, result, 0, count);
if (count == 9 + 2 * length)
{
if (result == 0x03)
{
//解析
ushort[] data = new ushort;
for (int i = 0; i < data.Length; i++)
{
data = BitConverter.ToUInt16(new byte[] { result, result },0);
}
return data;
}
return null;
}
return null;
}
//写入单个寄存器
public List<byte> WriteInputRge(short start, short writedata)
{
//拼接
List<byte> SendCommand = new List<byte>();
//事物处理标识符
SendCommand.AddRange(new byte[] { 0x00, 0x00 });
//协议标识符
SendCommand.AddRange(new byte[] { 0x00, 0x00 });
//长度
SendCommand.AddRange(new byte[] { 0x00, 0x06 });
//单元标识符
SendCommand.Add(0x01);
//功能码
SendCommand.Add(0x06);
//寄存器地址
SendCommand.Add((byte)(start / 256));
SendCommand.Add((byte)(start % 256));
//具体数据
SendCommand.Add((byte)(writedata / 256));
SendCommand.Add((byte)(writedata % 256));
//发送
socket.Send(SendCommand.ToArray());
//接收
byte[] buffer = new byte;
int count = socket.Receive(buffer, SocketFlags.None);
//验证-截取
byte[] result = new byte;
Array.Copy(buffer, 0, result, 0, count);
List<byte> ReceiveCommand = result.ToList();
if (ReceiveCommand == SendCommand)
{
return ReceiveCommand;
}
return null;
}
//写入多个寄存器
public List<byte> BatchWriteInputRge(short start, short length,short[] data)
{
//拼接
List<byte> SendCommand = new List<byte>();
//事物处理标识符
SendCommand.AddRange(new byte[] { 0x00, 0x00 });
//协议标识符
SendCommand.AddRange(new byte[] { 0x00, 0x00 });
//长度
SendCommand.Add((byte)((9 + (length - 1) * 2) / 256));
SendCommand.Add((byte)((9 + (length - 1) * 2) % 256));
//单元标识符
SendCommand.Add(0x01);
//功能码
SendCommand.Add(0x10);
//寄存器地址
SendCommand.Add((byte)(start / 256));
SendCommand.Add((byte)(start % 256));
//寄存器个数
SendCommand.Add((byte)(length / 256));
SendCommand.Add((byte)(length % 256));
//写字节个数
SendCommand.Add((byte)(data.Length*2));
for (int i = 0; i < data.Length; i++)
{
SendCommand.Add((byte)(data / 256));
SendCommand.Add((byte)(data % 256));
}
//发送
socket.Send(SendCommand.ToArray());
//接收
byte[] buffer = new byte;
int count = socket.Receive(buffer, SocketFlags.None);
//验证-截取
byte[] result = new byte;
Array.Copy(buffer, 0, result, 0, count);
List<byte> ReceiveCommand = result.ToList();
if (ReceiveCommand == SendCommand)
{
return ReceiveCommand;
}
return null;
//00 00 00 00 00 0B 01 10 00 0000 020400 9911 55
}
//数据拆分方法,将一个32位int 转换成4个8位int
public int[] Int32BitTo8Bit(int i)
{
int[] ints = new int;
if (i > 0)
{
int n1 = i & 0xffff;
int n2 = i >> 16;
ints = n1 & 0xff;
ints = n1 >> 8;
ints = n2 & 0xff;
ints = n2 >> 8;
int ii = (((ints << 8) + ints) << 16) + ((ints << 8) + ints);
return ints;
}
return null;
}
}
}
实现步骤:
1.建立连接
2.调用方法
ModbusTCP modbusTCP = new ModbusTCP(); //实例化ModbusTCP 类
if (modbusTCP.Connect("127.0.0.1", 502))//调用连接方法
{
int[] data_int = modbusTCP.Int32BitTo8Bit(Convert.ToInt32(zcl));
short[] data_short = new short;
for (int i = 0; i < data_int.Length; i++)
{
data_short = (short)data_int;
}
System.Collections.Generic.List<byte> val = modbusTCP.BatchWriteInputRge(0, (short)data_short.Length, data_short);
if (val != null)
{
string s="";
for (int i = 0; i < val.Count; i++)
{
s +=" " + val.ToString();
}
Console.WriteLine("写入成功返回:"+s);
}
else
{
Console.WriteLine("写入失败!");
}
} 我也来贴一段,英文注释,三菱PLC
using System;
using System.Net;
using System.Net.Sockets;
namespace WithstandVoltage
{
/// <summary>
/// Modbus TCP common driver class. This class implements a modbus TCP master driver.
/// It supports the following commands:
///
/// Read coils
/// Read discrete inputs
/// Write single coil
/// Write multiple cooils
/// Read holding register
/// Read input register
/// Write single register
/// Write multiple register
///
/// All commands can be sent in synchronous or asynchronous mode. If a value is accessed
/// in synchronous mode the program will stop and wait for slave to response. If the
/// slave didn't answer within a specified time a timeout exception is called.
/// The class uses multi threading for both synchronous and asynchronous access. For
/// the communication two lines are created. This is necessary because the synchronous
/// thread has to wait for a previous command to finish.
/// The synchronous channel can be disabled during connection. This can be necessary when
/// the slave only supports one connection.
///
/// </summary>
public class Master
{
// ------------------------------------------------------------------------
// Constants for access
private const byte fctReadCoil = 1;
private const byte fctReadDiscreteInputs = 2;
private const byte fctReadHoldingRegister = 3;
private const byte fctReadInputRegister = 4;
private const byte fctWriteSingleCoil = 5;
private const byte fctWriteSingleRegister = 6;
private const byte fctWriteMultipleCoils = 15;
private const byte fctWriteMultipleRegister = 16;
private const byte fctReadWriteMultipleRegister = 23;
/// <summary>Constant for exception illegal function.</summary>
public const byte excIllegalFunction = 1;
/// <summary>Constant for exception illegal data address.</summary>
public const byte excIllegalDataAdr = 2;
/// <summary>Constant for exception illegal data value.</summary>
public const byte excIllegalDataVal = 3;
/// <summary>Constant for exception slave device failure.</summary>
public const byte excSlaveDeviceFailure = 4;
/// <summary>Constant for exception acknowledge.</summary>
public const byte excAck = 5;
/// <summary>Constant for exception slave is busy/booting up.</summary>
public const byte excSlaveIsBusy = 6;
/// <summary>Constant for exception gate path unavailable.</summary>
public const byte excGatePathUnavailable = 10;
/// <summary>Constant for exception not connected.</summary>
public const byte excExceptionNotConnected = 253;
/// <summary>Constant for exception connection lost.</summary>
public const byte excExceptionConnectionLost = 254;
/// <summary>Constant for exception response timeout.</summary>
public const byte excExceptionTimeout = 255;
/// <summary>Constant for exception wrong offset.</summary>
private const byte excExceptionOffset = 128;
/// <summary>Constant for exception send failt.</summary>
private const byte excSendFailt = 100;
// ------------------------------------------------------------------------
// Private declarations
private static ushort _timeout = 500;
private static ushort _refresh = 10;
private static bool _connected = false;
private static bool _no_sync_connection = false;
private Socket tcpAsyCl;
private byte[] tcpAsyClBuffer = new byte;
private Socket tcpSynCl;
private byte[] tcpSynClBuffer = new byte;
// ------------------------------------------------------------------------
/// <summary>Response data event. This event is called when new data arrives</summary>
public delegate void ResponseData(ushort id, byte unit, byte function, byte[] data);
/// <summary>Response data event. This event is called when new data arrives</summary>
public event ResponseData OnResponseData;
/// <summary>Exception data event. This event is called when the data is incorrect</summary>
public delegate void ExceptionData(ushort id, byte unit, byte function, byte exception);
/// <summary>Exception data event. This event is called when the data is incorrect</summary>
public event ExceptionData OnException;
/// <summary>Response data event. This event is called when new data arrives</summary>
public delegate void DataStreamPrinf(string Msg, byte[] data);
/// <summary>Response data event. This event is called when new data arrives</summary>
public event DataStreamPrinf onDataStreamPrinf;
// ------------------------------------------------------------------------
/// <summary>Response timeout. If the slave didn't answers within in this time an exception is called.</summary>
/// <value>The default value is 500ms.</value>
public ushort timeout
{
get { return _timeout; }
set { _timeout = value; }
}
// ------------------------------------------------------------------------
/// <summary>Refresh timer for slave answer. The class is polling for answer every X ms.</summary>
/// <value>The default value is 10ms.</value>
public ushort refresh
{
get { return _refresh; }
set { _refresh = value; }
}
// ------------------------------------------------------------------------
/// <summary>Displays the state of the synchronous channel</summary>
/// <value>True if channel was diabled during connection.</value>
public bool NoSyncConnection
{
get { return _no_sync_connection; }
}
// ------------------------------------------------------------------------
/// <summary>Shows if a connection is active.</summary>
public bool connected
{
get { return _connected; }
}
// ------------------------------------------------------------------------
/// <summary>Create master instance without parameters.</summary>
public Master()
{
}
// ------------------------------------------------------------------------
/// <summary>Create master instance with parameters.</summary>
/// <param name="ip">IP adress of modbus slave.</param>
/// <param name="port">Port number of modbus slave. Usually port 502 is used.</param>
public Master(string ip, ushort port)
{
connect(ip, port, false);
}
// ------------------------------------------------------------------------
/// <summary>Create master instance with parameters.</summary>
/// <param name="ip">IP adress of modbus slave.</param>
/// <param name="port">Port number of modbus slave. Usually port 502 is used.</param>
/// <param name="no_sync_connection">Disable sencond connection for synchronous requests</param>
public Master(string ip, ushort port, bool no_sync_connection)
{
connect(ip, port, no_sync_connection);
}
// ------------------------------------------------------------------------
/// <summary>Start connection to slave.</summary>
/// <param name="ip">IP adress of modbus slave.</param>
/// <param name="port">Port number of modbus slave. Usually port 502 is used.</param>
/// <param name="no_sync_connection">Disable sencond connection for synchronous requests</param>
public void connect(string ip, ushort port, bool no_sync_connection)
{
try
{
IPAddress _ip;
_no_sync_connection = no_sync_connection;
if (IPAddress.TryParse(ip, out _ip) == false)
{
IPHostEntry hst = Dns.GetHostEntry(ip);
ip = hst.AddressList.ToString();
}
// ----------------------------------------------------------------
// Connect asynchronous client
tcpAsyCl = new Socket(IPAddress.Parse(ip).AddressFamily, SocketType.Stream, ProtocolType.Tcp);
tcpAsyCl.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
tcpAsyCl.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, _timeout);
tcpAsyCl.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, _timeout);
tcpAsyCl.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1);
// ----------------------------------------------------------------
// Connect synchronous client
if (!_no_sync_connection)
{
tcpSynCl = new Socket(IPAddress.Parse(ip).AddressFamily, SocketType.Stream, ProtocolType.Tcp);
tcpSynCl.Connect(new IPEndPoint(IPAddress.Parse(ip), port));
tcpSynCl.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, _timeout);
tcpSynCl.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, _timeout);
tcpSynCl.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1);
}
_connected = true;
}
catch (System.IO.IOException error)
{
_connected = false;
throw (error);
}
}
// ------------------------------------------------------------------------
/// <summary>Stop connection to slave.</summary>
public void disconnect()
{
Dispose();
}
// ------------------------------------------------------------------------
/// <summary>Destroy master instance.</summary>
~Master()
{
Dispose();
}
// ------------------------------------------------------------------------
/// <summary>Destroy master instance</summary>
public void Dispose()
{
if (tcpAsyCl != null)
{
if (tcpAsyCl.Connected)
{
try { tcpAsyCl.Shutdown(SocketShutdown.Both); }
catch { }
tcpAsyCl.Close();
}
tcpAsyCl = null;
}
if (tcpSynCl != null)
{
if (tcpSynCl.Connected)
{
try { tcpSynCl.Shutdown(SocketShutdown.Both); }
catch { }
tcpSynCl.Close();
}
tcpSynCl = null;
}
}
internal void CallException(ushort id, byte unit, byte function, byte exception)
{
if ((tcpAsyCl == null) || (tcpSynCl == null && _no_sync_connection)) return;
if (exception == excExceptionConnectionLost)
{
tcpSynCl = null;
tcpAsyCl = null;
}
if (OnException != null) OnException(id, unit, function, exception);
}
internal static UInt16 SwapUInt16(UInt16 inValue)
{
return (UInt16)(((inValue & 0xff00) >> 8) |
((inValue & 0x00ff) << 8));
}
// ------------------------------------------------------------------------
/// <summary>Read coils from slave asynchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
public void ReadCoils(ushort id, byte unit, ushort startAddress, ushort numInputs)
{
if (numInputs > 2000)
{
CallException(id, unit, fctReadCoil, excIllegalDataVal);
return;
}
WriteAsyncData(CreateReadHeader(id, unit, startAddress, numInputs, fctReadCoil), id);
}
// ------------------------------------------------------------------------
/// <summary>Read coils from slave synchronous.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
/// <param name="values">Contains the result of function.</param>
public void ReadCoils(ushort id, byte unit, ushort startAddress, ushort numInputs, ref byte[] values)
{
if (numInputs > 2000)
{
CallException(id, unit, fctReadCoil, excIllegalDataVal);
return;
}
values = WriteSyncData(CreateReadHeader(id, unit, startAddress, numInputs, fctReadCoil), id);
}
// ------------------------------------------------------------------------
/// <summary>Read discrete inputs from slave asynchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
public void ReadDiscreteInputs(ushort id, byte unit, ushort startAddress, ushort numInputs)
{
if (numInputs > 2000)
{
CallException(id, unit, fctReadDiscreteInputs, excIllegalDataVal);
return;
}
WriteAsyncData(CreateReadHeader(id, unit, startAddress, numInputs, fctReadDiscreteInputs), id);
}
// ------------------------------------------------------------------------
/// <summary>Read discrete inputs from slave synchronous.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
/// <param name="values">Contains the result of function.</param>
public void ReadDiscreteInputs(ushort id, byte unit, ushort startAddress, ushort numInputs, ref byte[] values)
{
if (numInputs > 2000)
{
CallException(id, unit, fctReadDiscreteInputs, excIllegalDataVal);
return;
}
values = WriteSyncData(CreateReadHeader(id, unit, startAddress, numInputs, fctReadDiscreteInputs), id);
}
// ------------------------------------------------------------------------
/// <summary>Read holding registers from slave asynchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
public void ReadHoldingRegister(ushort id, byte unit, ushort startAddress, ushort numInputs)
{
if (numInputs > 125)
{
CallException(id, unit, fctReadHoldingRegister, excIllegalDataVal);
return;
}
WriteAsyncData(CreateReadHeader(id, unit, startAddress, numInputs, fctReadHoldingRegister), id);
}
// ------------------------------------------------------------------------
/// <summary>Read holding registers from slave synchronous.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
/// <param name="values">Contains the result of function.</param>
public void ReadHoldingRegister(ushort id, byte unit, ushort startAddress, ushort numInputs, ref byte[] values)
{
if (numInputs > 125)
{
CallException(id, unit, fctReadHoldingRegister, excIllegalDataVal);
return;
}
values = WriteSyncData(CreateReadHeader(id, unit, startAddress, numInputs, fctReadHoldingRegister), id);
}
// ------------------------------------------------------------------------
/// <summary>Read input registers from slave asynchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
public void ReadInputRegister(ushort id, byte unit, ushort startAddress, ushort numInputs)
{
if (numInputs > 125)
{
CallException(id, unit, fctReadInputRegister, excIllegalDataVal);
return;
}
WriteAsyncData(CreateReadHeader(id, unit, startAddress, numInputs, fctReadInputRegister), id);
}
// ------------------------------------------------------------------------
/// <summary>Read input registers from slave synchronous.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
/// <param name="values">Contains the result of function.</param>
public void ReadInputRegister(ushort id, byte unit, ushort startAddress, ushort numInputs, ref byte[] values)
{
if (numInputs > 125)
{
CallException(id, unit, fctReadInputRegister, excIllegalDataVal);
return;
}
values = WriteSyncData(CreateReadHeader(id, unit, startAddress, numInputs, fctReadInputRegister), id);
}
// ------------------------------------------------------------------------
/// <summary>Write single coil in slave asynchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="OnOff">Specifys if the coil should be switched on or off.</param>
public void WriteSingleCoils(ushort id, byte unit, ushort startAddress, bool OnOff)
{
byte[] data;
data = CreateWriteHeader(id, unit, startAddress, 1, 1, fctWriteSingleCoil);
if (OnOff == true) data = 255;
else data = 0;
WriteAsyncData(data, id);
}
// ------------------------------------------------------------------------
/// <summary>Write single coil in slave synchronous.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="OnOff">Specifys if the coil should be switched on or off.</param>
/// <param name="result">Contains the result of the synchronous write.</param>
public void WriteSingleCoils(ushort id, byte unit, ushort startAddress, bool OnOff, ref byte[] result)
{
byte[] data;
data = CreateWriteHeader(id, unit, startAddress, 1, 1, fctWriteSingleCoil);
if (OnOff == true) data = 255;
else data = 0;
result = WriteSyncData(data, id);
}
// ------------------------------------------------------------------------
/// <summary>Write multiple coils in slave asynchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numBits">Specifys number of bits.</param>
/// <param name="values">Contains the bit information in byte format.</param>
public void WriteMultipleCoils(ushort id, byte unit, ushort startAddress, ushort numBits, byte[] values)
{
ushort numBytes = Convert.ToUInt16(values.Length);
if (numBytes > 250 || numBits > 2000)
{
CallException(id, unit, fctWriteMultipleCoils, excIllegalDataVal);
return;
}
byte[] data;
data = CreateWriteHeader(id, unit, startAddress, numBits, (byte)(numBytes + 2), fctWriteMultipleCoils);
Array.Copy(values, 0, data, 13, numBytes);
WriteAsyncData(data, id);
}
// ------------------------------------------------------------------------
/// <summary>Write multiple coils in slave synchronous.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address from where the data read begins.</param>
/// <param name="numBits">Specifys number of bits.</param>
/// <param name="values">Contains the bit information in byte format.</param>
/// <param name="result">Contains the result of the synchronous write.</param>
public void WriteMultipleCoils(ushort id, byte unit, ushort startAddress, ushort numBits, byte[] values, ref byte[] result)
{
ushort numBytes = Convert.ToUInt16(values.Length);
if (numBytes > 250 || numBits > 2000)
{
CallException(id, unit, fctWriteMultipleCoils, excIllegalDataVal);
return;
}
byte[] data;
data = CreateWriteHeader(id, unit, startAddress, numBits, (byte)(numBytes + 2), fctWriteMultipleCoils);
Array.Copy(values, 0, data, 13, numBytes);
result = WriteSyncData(data, id);
}
// ------------------------------------------------------------------------
/// <summary>Write single register in slave asynchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address to where the data is written.</param>
/// <param name="values">Contains the register information.</param>
public void WriteSingleRegister(ushort id, byte unit, ushort startAddress, byte[] values)
{
byte[] data;
data = CreateWriteHeader(id, unit, startAddress, 1, 1, fctWriteSingleRegister);
data = values;
data = values;
WriteAsyncData(data, id);
}
// ------------------------------------------------------------------------
/// <summary>Write single register in slave synchronous.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address to where the data is written.</param>
/// <param name="values">Contains the register information.</param>
/// <param name="result">Contains the result of the synchronous write.</param>
public void WriteSingleRegister(ushort id, byte unit, ushort startAddress, byte[] values, ref byte[] result)
{
byte[] data;
data = CreateWriteHeader(id, unit, startAddress, 1, 1, fctWriteSingleRegister);
data = values;
data = values;
result = WriteSyncData(data, id);
}
// ------------------------------------------------------------------------
/// <summary>Write multiple registers in slave asynchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address to where the data is written.</param>
/// <param name="values">Contains the register information.</param>
public void WriteMultipleRegister(ushort id, byte unit, ushort startAddress, byte[] values)
{
ushort numBytes = Convert.ToUInt16(values.Length);
if (numBytes > 250)
{
CallException(id, unit, fctWriteMultipleRegister, excIllegalDataVal);
return;
}
if (numBytes % 2 > 0) numBytes++;
byte[] data;
data = CreateWriteHeader(id, unit, startAddress, Convert.ToUInt16(numBytes / 2), Convert.ToUInt16(numBytes + 2), fctWriteMultipleRegister);
Array.Copy(values, 0, data, 13, values.Length);
WriteAsyncData(data, id);
}
// ------------------------------------------------------------------------
/// <summary>Write multiple registers in slave synchronous.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startAddress">Address to where the data is written.</param>
/// <param name="values">Contains the register information.</param>
/// <param name="result">Contains the result of the synchronous write.</param>
public void WriteMultipleRegister(ushort id, byte unit, ushort startAddress, byte[] values, ref byte[] result)
{
ushort numBytes = Convert.ToUInt16(values.Length);
if (numBytes > 250)
{
CallException(id, unit, fctWriteMultipleRegister, excIllegalDataVal);
return;
}
if (numBytes % 2 > 0) numBytes++;
byte[] data;
data = CreateWriteHeader(id, unit, startAddress, Convert.ToUInt16(numBytes / 2), Convert.ToUInt16(numBytes + 2), fctWriteMultipleRegister);
Array.Copy(values, 0, data, 13, values.Length);
result = WriteSyncData(data, id);
}
// ------------------------------------------------------------------------
/// <summary>Read/Write multiple registers in slave asynchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startReadAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
/// <param name="startWriteAddress">Address to where the data is written.</param>
/// <param name="values">Contains the register information.</param>
public void ReadWriteMultipleRegister(ushort id, byte unit, ushort startReadAddress, ushort numInputs, ushort startWriteAddress, byte[] values)
{
ushort numBytes = Convert.ToUInt16(values.Length);
if (numBytes > 250)
{
CallException(id, unit, fctReadWriteMultipleRegister, excIllegalDataVal);
return;
}
if (numBytes % 2 > 0) numBytes++;
byte[] data;
data = CreateReadWriteHeader(id, unit, startReadAddress, numInputs, startWriteAddress, Convert.ToUInt16(numBytes / 2));
Array.Copy(values, 0, data, 17, values.Length);
WriteAsyncData(data, id);
}
// ------------------------------------------------------------------------
/// <summary>Read/Write multiple registers in slave synchronous. The result is given in the response function.</summary>
/// <param name="id">Unique id that marks the transaction. In asynchonous mode this id is given to the callback function.</param>
/// <param name="unit">Unit identifier (previously slave address). In asynchonous mode this unit is given to the callback function.</param>
/// <param name="startReadAddress">Address from where the data read begins.</param>
/// <param name="numInputs">Length of data.</param>
/// <param name="startWriteAddress">Address to where the data is written.</param>
/// <param name="values">Contains the register information.</param>
/// <param name="result">Contains the result of the synchronous command.</param>
public void ReadWriteMultipleRegister(ushort id, byte unit, ushort startReadAddress, ushort numInputs, ushort startWriteAddress, byte[] values, ref byte[] result)
{
ushort numBytes = Convert.ToUInt16(values.Length);
if (numBytes > 250)
{
CallException(id, unit, fctReadWriteMultipleRegister, excIllegalDataVal);
return;
}
if (numBytes % 2 > 0) numBytes++;
byte[] data;
data = CreateReadWriteHeader(id, unit, startReadAddress, numInputs, startWriteAddress, Convert.ToUInt16(numBytes / 2));
Array.Copy(values, 0, data, 17, values.Length);
result = WriteSyncData(data, id);
}
// ------------------------------------------------------------------------
// Create modbus header for read action
private byte[] CreateReadHeader(ushort id, byte unit, ushort startAddress, ushort length, byte function)
{
byte[] data = new byte;
byte[] _id = BitConverter.GetBytes((short)id);
data = _id; // Slave id high byte
data = _id; // Slave id low byte
data = 6; // Message size
data = unit; // Slave address
data = function; // Function code
byte[] _adr = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)startAddress));
data = _adr; // Start address
data = _adr; // Start address
byte[] _length = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)length));
data = _length; // Number of data to read
data = _length; // Number of data to read
return data;
}
// ------------------------------------------------------------------------
// Create modbus header for write action
private byte[] CreateWriteHeader(ushort id, byte unit, ushort startAddress, ushort numData, ushort numBytes, byte function)
{
byte[] data = new byte;
byte[] _id = BitConverter.GetBytes((short)id);
data = _id; // Slave id high byte
data = _id; // Slave id low byte
byte[] _size = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)(5 + numBytes)));
data = _size; // Complete message size in bytes
data = _size; // Complete message size in bytes
data = unit; // Slave address
data = function; // Function code
byte[] _adr = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)startAddress));
data = _adr; // Start address
data = _adr; // Start address
if (function >= fctWriteMultipleCoils)
{
byte[] _cnt = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)numData));
data = _cnt; // Number of bytes
data = _cnt; // Number of bytes
data = (byte)(numBytes - 2);
}
return data;
}
// ------------------------------------------------------------------------
// Create modbus header for read/write action
private byte[] CreateReadWriteHeader(ushort id, byte unit, ushort startReadAddress, ushort numRead, ushort startWriteAddress, ushort numWrite)
{
byte[] data = new byte;
byte[] _id = BitConverter.GetBytes((short)id);
data = _id; // Slave id high byte
data = _id; // Slave id low byte
byte[] _size = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)(11 + numWrite * 2)));
data = _size; // Complete message size in bytes
data = _size; // Complete message size in bytes
data = unit; // Slave address
data = fctReadWriteMultipleRegister; // Function code
byte[] _adr_read = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)startReadAddress));
data = _adr_read; // Start read address
data = _adr_read; // Start read address
byte[] _cnt_read = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)numRead));
data = _cnt_read; // Number of bytes to read
data = _cnt_read; // Number of bytes to read
byte[] _adr_write = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)startWriteAddress));
data = _adr_write; // Start write address
data = _adr_write; // Start write address
byte[] _cnt_write = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)numWrite));
data = _cnt_write; // Number of bytes to write
data = _cnt_write; // Number of bytes to write
data = (byte)(numWrite * 2);
return data;
}
// ------------------------------------------------------------------------
// Write asynchronous data
private void WriteAsyncData(byte[] write_data, ushort id)
{
if ((tcpAsyCl != null) && (tcpAsyCl.Connected))
{
try
{
tcpAsyCl.BeginSend(write_data, 0, write_data.Length, SocketFlags.None, new AsyncCallback(OnSend), null);
onDataStreamPrinf("Send:", write_data);
}
catch (SystemException)
{
CallException(id, write_data, write_data, excExceptionConnectionLost);
}
}
else CallException(id, write_data, write_data, excExceptionConnectionLost);
}
// ------------------------------------------------------------------------
// Write asynchronous data acknowledge
private void OnSend(System.IAsyncResult result)
{
Int32 size = tcpAsyCl.EndSend(result);
if (result.IsCompleted == false) CallException(0xFFFF, 0xFF, 0xFF, excSendFailt);
else tcpAsyCl.BeginReceive(tcpAsyClBuffer, 0, tcpAsyClBuffer.Length, SocketFlags.None, new AsyncCallback(OnReceive), tcpAsyCl);
}
// ------------------------------------------------------------------------
// Write asynchronous data response
private void OnReceive(System.IAsyncResult result)
{
tcpAsyCl.EndReceive(result);
if (result.IsCompleted == false) CallException(0xFF, 0xFF, 0xFF, excExceptionConnectionLost);
ushort id = SwapUInt16(BitConverter.ToUInt16(tcpAsyClBuffer, 0));
byte unit = tcpAsyClBuffer;
byte function = tcpAsyClBuffer;
byte[] data;
byte[] dataprinf = new byte + 6];
Array.Copy(tcpAsyClBuffer, 0, dataprinf, 0, tcpAsyClBuffer + 6);
onDataStreamPrinf("Recv:", dataprinf);
// ------------------------------------------------------------
// Write response data
if ((function >= fctWriteSingleCoil) && (function != fctReadWriteMultipleRegister))
{
data = new byte;
Array.Copy(tcpAsyClBuffer, 10, data, 0, 2);
}
// ------------------------------------------------------------
// Read response data
else
{
data = new byte];
Array.Copy(tcpAsyClBuffer, 9, data, 0, tcpAsyClBuffer);
}
// ------------------------------------------------------------
// Response data is slave exception
if (function > excExceptionOffset)
{
function -= excExceptionOffset;
CallException(id, unit, function, tcpAsyClBuffer);
}
// ------------------------------------------------------------
// Response data is regular data
else if (OnResponseData != null) OnResponseData(id, unit, function, data);
}
// ------------------------------------------------------------------------
// Write data and and wait for response
private byte[] WriteSyncData(byte[] write_data, ushort id)
{
if (tcpSynCl.Connected)
{
try
{
tcpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None);
int result = tcpSynCl.Receive(tcpSynClBuffer, 0, tcpSynClBuffer.Length, SocketFlags.None);
byte unit = tcpSynClBuffer;
byte function = tcpSynClBuffer;
byte[] data;
if (result == 0) CallException(id, unit, write_data, excExceptionConnectionLost);
// ------------------------------------------------------------
// Response data is slave exception
if (function > excExceptionOffset)
{
function -= excExceptionOffset;
CallException(id, unit, function, tcpSynClBuffer);
return null;
}
// ------------------------------------------------------------
// Write response data
else if ((function >= fctWriteSingleCoil) && (function != fctReadWriteMultipleRegister))
{
data = new byte;
Array.Copy(tcpSynClBuffer, 10, data, 0, 2);
}
// ------------------------------------------------------------
// Read response data
else
{
data = new byte];
Array.Copy(tcpSynClBuffer, 9, data, 0, tcpSynClBuffer);
}
return data;
}
catch (SystemException)
{
CallException(id, write_data, write_data, excExceptionConnectionLost);
}
}
else CallException(id, write_data, write_data, excExceptionConnectionLost);
return null;
}
}
}
使用
// Create new modbus master and add event functions
MBmaster = new Master(TextBox_DeviceIP1.Text, 502, true);
MBmaster.OnResponseData += new Master.ResponseData(MBmaster_OnResponseData);
MBmaster.OnException += new Master.ExceptionData(MBmaster_OnException);
MBmaster.onDataStreamPrinf += new Master.DataStreamPrinf(MBmaster_onDataStreamPrinf);
//// Show additional fields, enable watchdog
button_Send1.Enabled = true;
panelCom.BackColor = Color.Lime;
labelCom.Text = "Opened";
this.BeginInvoke(updateTxt, "连接成功!" + "\r\n");
groupBox1.Enabled = true;
实际上,只需要如下
private void SendCommand(byte[] command)
{
var localSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
var waitHandle = localSocket.BeginConnect(_server, null, null);
var isConnected = waitHandle.AsyncWaitHandle.WaitOne(1000, true); //等待 1 秒
_logger.Info($"康耐德IO 是否已连接 :: {isConnected}");
localSocket.EndConnect(waitHandle);
localSocket.Send(command);
}
catch (Exception e)
{
_logger.Error($"康耐德发送命令出错 : {e.Message}");
}
finally
{
localSocket.Disconnect(false);
localSocket.Dispose();
}
} 其他的读写线圈等方法我这没有用到,可以按照上面几个方法来进行编写,也不是很难 你这个有什么用嘛 ? LinearGradientBrush.GradientStopsLinearGradientBrush.GradientStopsLinearGradientBrush.GradientStopsLinearGradientBrush.GradientStopsLinearGradientBrush.GradientStopsLinearGradientBrush.GradientStopsLinearGradientBrush.GradientStops byte unit = 1;
ushort StartAddress;
StartAddress = 0x0664;
MBmaster.WriteSingleCoils(ID, unit, StartAddress, true);
ID++;
this.BeginInvoke(updateTxt, "写入m636=1!");
Thread.Sleep(1000); goldli 发表于 2021-12-1 13:12
你这个有什么用嘛 ?
我自己的学习日记{:1_929:} 写的很详细,谢谢 geekchina 发表于 2021-12-12 10:32
写的很详细,谢谢
共同学习
页:
[1]
2