向串口发送和接收数据
Sending and receiving data to serialport
我有一个麦哲伦scanner/scale。它通过 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, 0, 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, 0, bytes.Length);
return bytes;
}
我不明白为什么 BytesToRead 和 BytesToWrite 在 this._port.Write(bytes, offset, count);
之后保持为 0
这是 serialportconfig.xml 文件
<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, 0, 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, 0, 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 class 有自己的内置超时(即 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, 0, bytes.Length);
}
}
catch (TimeoutException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
this.DataReceived = false;
}
return bytes;
}
看来Magellan可以重发请求重量的命令(S11)。所以我的解决方案是每当我在 this._port.Write(bytes, offset, count) 之后有 _port.bytesToRead=0 时,然后我重新发送命令 S11。最终,它会响应正确的结果。
我有一个麦哲伦scanner/scale。它通过 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, 0, 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, 0, bytes.Length);
return bytes;
}
我不明白为什么 BytesToRead 和 BytesToWrite 在 this._port.Write(bytes, offset, count);
之后保持为 0这是 serialportconfig.xml 文件
<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, 0, 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, 0, 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 class 有自己的内置超时(即 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, 0, bytes.Length);
}
}
catch (TimeoutException ex)
{
Console.WriteLine(ex.Message);
}
finally
{
this.DataReceived = false;
}
return bytes;
}
看来Magellan可以重发请求重量的命令(S11)。所以我的解决方案是每当我在 this._port.Write(bytes, offset, count) 之后有 _port.bytesToRead=0 时,然后我重新发送命令 S11。最终,它会响应正确的结果。