C# - 通过串行端口轮询设备
C# - Polling a device by serial port
遇到问题。我需要使用Modbus协议通过串口轮询设备。
但是轮询设备需要很长时间 - 大约 2 秒。
是的,我的程序还在一个单独的线程中不断地轮询设备,但我希望它更快。
也许有人可以帮助我如何优化我的代码。我将不胜感激。
public override RcResult ExecuteModBus(RcModBusDevice device, byte[] request, out byte[] answer)
{
answer = null;
var result = new RcResult();
OnLogMessage?.Invoke(this, "ExecuteModBus LOCK?");
lock (communication)
{
OnLogMessage?.Invoke(this, "ExecuteModBus LOCK!");
var dt = DateTime.Now;
if (device != null)
{
serialPort.WriteTimeout = device.SendTimeout;
serialPort.ReadTimeout = device.ReceiveTimeout;
}
serialPort.DiscardOutBuffer();
serialPort.DiscardInBuffer();
OnLogMessage?.Invoke(this, "REQUEST->:" + Utils.BytesToHex(request));
try
{
serialPort.Write(request, 0, request.Length);
}
catch(Exception ex)
{
result.ErrorCode = 1;
result.ErrorText = ex.Message;
return result;
}
var tmp = new byte[0x2000];
int dataLength = 0;
try
{
for (int i = 0; i < tmp.Length; i++)
tmp[dataLength++] = (byte)serialPort.ReadByte();
}
catch (Exception ex)
{
}
var crc = Utils.GetCRC(tmp, 0, dataLength - 2);
if (crc[0] != tmp[dataLength - 2] || crc[1] != tmp[dataLength - 1])
{
result.ErrorCode = 1;
result.ErrorText = "Bad CRC";
}
answer = new byte[dataLength];
Array.Copy(tmp, 0, answer, 0, dataLength);
OnLogMessage?.Invoke(this, "ANSWER<-:" + Utils.BytesToHex(answer));
if (device != null)
SaveToLog(DbID, device.DbID, dt, Utils.BytesToHex(request), DateTime.Now, Utils.BytesToHex(answer));
if (dataLength == 0)
result.ErrorCode = 1;
}
OnLogMessage?.Invoke(this, "ExecuteModBus UNLOCK");
return result;
}
我在另一个论坛找到了答案。
错误是端口读取超时。
var tmp = new byte[0x2000];
int dataLength = 0;
try
{
while(true)
{
byte receiveByte= (byte)serialPort.ReadByte();
// We received one byte. Check buffer size
if (dataLength >= tmp.Length)
{
// Buffer to small
result.ErrorCode = 1; // Appropriate ErrorCode
result.ErrorText = "Buffer Overrun";
return result;
}
// Add it to receive buffer
tmp[dataLength++] = receiveByte;
// Set character Timeout after we received the first byte of the answer
if (dataLength == 1)
{
// Set new character timeout according to Modbus spec.
// At least 3.5 characters silence but here we take about
// 5 times more chars to be on the safe side
//
// 10Bit/Byte mS ca. 5x3.5
serialPort.ReadTimeout= (10 * 1000 * 18) / serialPort.Baudrate;
}
// Don't eat CPU too aggressive (has to be proofed whether it really helps)
Thread.Sleep(0);
}
}
catch (TimeoutException ex)
{
// Expected exception. No more character received in the specified
// character timeout period
}
catch (Exception ex)
{
// Other than (TimeoutException is an error condition
result.ErrorCode = 1; // Appropriate ErrorCode
result.ErrorText = ex.Message;
return result;
}
遇到问题。我需要使用Modbus协议通过串口轮询设备。
但是轮询设备需要很长时间 - 大约 2 秒。
是的,我的程序还在一个单独的线程中不断地轮询设备,但我希望它更快。
也许有人可以帮助我如何优化我的代码。我将不胜感激。
public override RcResult ExecuteModBus(RcModBusDevice device, byte[] request, out byte[] answer)
{
answer = null;
var result = new RcResult();
OnLogMessage?.Invoke(this, "ExecuteModBus LOCK?");
lock (communication)
{
OnLogMessage?.Invoke(this, "ExecuteModBus LOCK!");
var dt = DateTime.Now;
if (device != null)
{
serialPort.WriteTimeout = device.SendTimeout;
serialPort.ReadTimeout = device.ReceiveTimeout;
}
serialPort.DiscardOutBuffer();
serialPort.DiscardInBuffer();
OnLogMessage?.Invoke(this, "REQUEST->:" + Utils.BytesToHex(request));
try
{
serialPort.Write(request, 0, request.Length);
}
catch(Exception ex)
{
result.ErrorCode = 1;
result.ErrorText = ex.Message;
return result;
}
var tmp = new byte[0x2000];
int dataLength = 0;
try
{
for (int i = 0; i < tmp.Length; i++)
tmp[dataLength++] = (byte)serialPort.ReadByte();
}
catch (Exception ex)
{
}
var crc = Utils.GetCRC(tmp, 0, dataLength - 2);
if (crc[0] != tmp[dataLength - 2] || crc[1] != tmp[dataLength - 1])
{
result.ErrorCode = 1;
result.ErrorText = "Bad CRC";
}
answer = new byte[dataLength];
Array.Copy(tmp, 0, answer, 0, dataLength);
OnLogMessage?.Invoke(this, "ANSWER<-:" + Utils.BytesToHex(answer));
if (device != null)
SaveToLog(DbID, device.DbID, dt, Utils.BytesToHex(request), DateTime.Now, Utils.BytesToHex(answer));
if (dataLength == 0)
result.ErrorCode = 1;
}
OnLogMessage?.Invoke(this, "ExecuteModBus UNLOCK");
return result;
}
我在另一个论坛找到了答案。 错误是端口读取超时。
var tmp = new byte[0x2000];
int dataLength = 0;
try
{
while(true)
{
byte receiveByte= (byte)serialPort.ReadByte();
// We received one byte. Check buffer size
if (dataLength >= tmp.Length)
{
// Buffer to small
result.ErrorCode = 1; // Appropriate ErrorCode
result.ErrorText = "Buffer Overrun";
return result;
}
// Add it to receive buffer
tmp[dataLength++] = receiveByte;
// Set character Timeout after we received the first byte of the answer
if (dataLength == 1)
{
// Set new character timeout according to Modbus spec.
// At least 3.5 characters silence but here we take about
// 5 times more chars to be on the safe side
//
// 10Bit/Byte mS ca. 5x3.5
serialPort.ReadTimeout= (10 * 1000 * 18) / serialPort.Baudrate;
}
// Don't eat CPU too aggressive (has to be proofed whether it really helps)
Thread.Sleep(0);
}
}
catch (TimeoutException ex)
{
// Expected exception. No more character received in the specified
// character timeout period
}
catch (Exception ex)
{
// Other than (TimeoutException is an error condition
result.ErrorCode = 1; // Appropriate ErrorCode
result.ErrorText = ex.Message;
return result;
}