问题描述
我有一台麦哲伦扫描仪/秤。它通过 rs232 连接到我的电脑。当我在 ComTestSerial 程序上发送命令“S11”时,我收到了重量。但是,使用我的 vb.net 代码,我无法收到回复。结果我得到一个 TimeoutException。
发送命令的文件:
Dim yy() As Byte = System.Text.Encoding.ASCII.GetBytes("S11" & vbLf)
Me.Port.Send(yy)
Dim input = Me.Port.Receive
Return Me.ExtractMeasurement(input)
从串口写入和读取的文件:
public void Send(byte b)
{
byte[] bytes = new byte[1] { b };
this.Send(bytes);
}
public void Send(byte[] bytes)
{
this.Send(bytes,bytes.Length);
}
public void Send(byte[] bytes,int offset,int count)
{
this._port.Write(bytes,offset,count);
}
public byte[] Receive()
{
int attempts = 1;
Boolean dataReceived;
try
{
while (!this.DataReceived && this._port.BytesToRead == 0 && attempts < 15)
{
System.Threading.Thread.Sleep(100);
attempts++;
}
}
finally
{
dataReceived = this.DataReceived;
this.DataReceived = false;
}
if (!dataReceived && this._port.BytesToRead == 0) throw new TimeoutException();
byte[] bytes = new byte[this._port.BytesToRead];
this._port.Read(bytes,bytes.Length);
return bytes;
}
我不明白为什么 BytesToRead 和 BytesToWrite 在此之后保持 0._port.Write(bytes,count);
<PortName>COM3:</PortName>
<Baudrate>Baud_9600</Baudrate>
<DataBits>Eight</DataBits>
<Parity>None</Parity>
<StopBits>One</StopBits>
<FlowCtrl>CtsRts</FlowCtrl>
更新:我发现如果我发送 vbCr 而不是 vbLf 我有时会得到正确的响应。但问题是有时。我有时会收到 TimeoutException,有时会收到响应。我正在使用从 RS232 到 USB 的适配器。这可能是问题吗?
这里是所有与串口相关的代码:
public class SerialPortAdapter
{
#region Private Members
private System.IO.Ports.SerialPort _port;
private Object _dataReceivedLock = new Object();
private Boolean _dataReceived;
#endregion
#region Constructor/Destructor
public SerialPortAdapter(SerialCnfg config)
{
if (string.IsNullOrEmpty(config.PortName))
{
this._port = new System.IO.Ports.SerialPort();
}
else
{
string portName = config.PortName.TrimEnd(':');
this._port = new System.IO.Ports.SerialPort(portName);
}
this._port.WriteTimeout = 2000;
this._port.ReadTimeout = 2000;
this._port.SetBaudrate(config.Baudrate);
this._port.SetDataBits(config.DataBits);
this._port.SetStopBits(config.StopBits);
this._port.SetHandshake(config.FlowCtrl);
this._port.SetParity(config.Parity);
}
~SerialPortAdapter()
{
this.Close();
this._port = null;
}
#endregion
#region Public Properties
public Boolean IsOpen
{
get { return this._port.IsOpen; }
}
public System.Text.Encoding Encoding
{
get { return this._port.Encoding; }
set { this._port.Encoding = value; }
}
#endregion
#region Public Methods
public void open()
{
if (this.IsOpen) return;
this.DataReceived = false;
this.AttachPortHandlers();
this._port.open();
}
public void Close()
{
if (!this.IsOpen) return;
this._port.Close();
this.DetachPortHandlers();
this.DataReceived = false;
}
public void Send(byte b)
{
byte[] bytes = new byte[1] { b };
this.Send(bytes);
}
public void Send(byte[] bytes)
{
this.Send(bytes,bytes.Length);
return bytes;
}
#endregion
#region Private Properties
private Boolean DataReceived
{
get
{
lock (this._dataReceivedLock)
{
return this._dataReceived;
}
}
set
{
lock (this._dataReceivedLock)
{
this._dataReceived = value;
}
}
}
#endregion
#region Initialization/Finalization
private void AttachPortHandlers()
{
this._port.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.OnDataReceived);
}
private void DetachPortHandlers()
{
this._port.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(this.OnDataReceived);
}
#endregion
#region Event Handlers
private void OnDataReceived(Object sender,System.IO.Ports.SerialDataReceivedEventArgs e)
{
this.DataReceived = true;
}
#endregion
}
解决方法
根据您发布的代码,您正在尝试处理自己的超时异常。 SerialPort 类有自己的内置超时(即,ReadTimeout、WriteTimeout),您可以在构造函数中设置它们。因此,您不需要其他方法来处理超时,因为它是多余的。此外,请远离 System.Threading.Sleep 方法,因为它会极大地浪费资源 Why is Thread.Sleep so harmful。
我建议您稍微重构一下您的代码,以摆脱自我强加的 Throw TimeoutException。
这里只是一个建议:
public byte[] Receive()
{
try
{
byte[] bytes = new byte[]{};
while(_port.BytesToRead > 0)
{
bytes = new byte[this._port.BytesToRead];
this._port.Read(bytes,bytes.Length);
}
}
catch (TimeoutException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
this.DataReceived = false;
}
return bytes;
}
,
如果您重新发送请求重量的命令(S11),麦哲伦似乎可以工作。所以我的解决方案是每当我在 this._port.Write(bytes,offset,count) 之后有 _port.bytesToRead=0 时,然后我重新发送命令 S11。最终,它会响应正确的结果。