我有一些SerialPort代码,经常需要从串行接口读取数据(例如,COM1)。但是这似乎是非常密集的CPU,如果用户移动窗口或大量数据显示到窗口(例如通过串行行接收到的字节),那么通信就会受到干扰。
考虑到下列守则:
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] buffer = new byte[port.ReadBufferSize];
var count = 0;
try
{
count = port.Read(buffer, 0, buffer.Length);
}
catch (Exception ex)
{
Console.Write(ex.ToString());
}
if (count == 0)
return;
//Pass the data to the IDataCollector, if response != null an entire frame has been received
var response = collector.Collect(buffer.GetSubByteArray(0, count));
if (response != null)
{
this.OnDataReceived(response);
}需要收集代码,因为数据流是常量的,数据必须分析(帧/包)。
port = new SerialPort();
//Port configuration code here...
this.collector = dataCollector;
//Event handlers
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();如果没有用户交互,也没有向窗口添加任何内容,这就可以正常工作,但一旦交互发生,通信就会变得一团糟。超时等..。
例如,这一切都搞砸了:
Dispatcher.BeginInvoke(new Action(() =>
{
var builder = new StringBuilder();
foreach (var r in data)
{
builder.AppendFormat("0x{0:X} ", r);
}
builder.Append("\n\n");
txtHexDump.AppendText(builder.ToString());
txtHexDump.ScrollToEnd();
}),System.Windows.Threading.DispatcherPriority.ContextIdle);
});但是,即使是对log4net的简单调用也会导致问题。
有没有优化SerialPort通信的最佳实践,或者有人能告诉我我做错了什么.
更新:
万一上面说的不是很有道理。我举了一个很简单(也很愚蠢)的小例子:
class Program
{
static void Main(string[] args)
{
var server = new BackgroundWorker();
server.DoWork += new DoWorkEventHandler(server_DoWork);
server.RunWorkerAsync();
var port = new SerialPort();
port.PortName = "COM2";
port.Open();
string input = "";
Console.WriteLine("Client on COM2: {0}", Thread.CurrentThread.ManagedThreadId);
while (input != "/quit")
{
input = Console.ReadLine();
if (input != "/quit")
{
var data = ASCIIEncoding.ASCII.GetBytes(input);
port.Write(data, 0, data.Length);
}
}
port.Close();
port.Dispose();
}
static void server_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Listening on COM1: {0}", Thread.CurrentThread.ManagedThreadId);
var port = new SerialPort();
port.PortName = "COM1";
port.Open();
port.ReceivedBytesThreshold = 15;
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
}
static void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var port = (SerialPort)sender;
int count = 0;
byte[] buffer = new byte[port.ReadBufferSize];
count = ((SerialPort)sender).Read(buffer, 0, buffer.Length);
string echo = ASCIIEncoding.ASCII.GetString(buffer,0,count);
Console.WriteLine("-->{1} {0}", echo, Thread.CurrentThread.ManagedThreadId);
}
}结果可能如下所示:
监听COM1: 6 Client on COM2: 10这是我发送的一些示例数据->6,这是我发送的一些示例数据
所以从端口读取数据发生在主线程上.
这可能是造成我问题的原因之一吗?
发布于 2009-06-10 18:13:24
您的最后一个结论,即事件运行在主线程上,对于Windows可能不是正确的。不要在控制台上测试这个。
对此进行调整的适当方法是:
,则将数据传递给队列或MemoryStream >
发布于 2012-11-20 22:49:31
我很惊讶没人发现这个。SerialPort类在使用DataReceived事件时使用自己的线程。这意味着,例如,如果订阅服务器正在访问任何表单元素,则必须使用调用或BeginInvoke方法进行访问。否则,您将得到一个跨线程操作。在较早版本的.net中,这可能会导致不可预测的行为(取决于PC中的CPU核心),而在较晚的版本中,则会引发异常。
发布于 2009-06-10 15:04:45
您应该重写port_DataReceived过程来读取数据,直到port.BytesToRead大于零为止,如下所示:
private void port_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
var port = (SerialPort)sender;
while (port.BytesToRead > 0)
{
int byte_count = port.BytesToRead;
byte[] buffer = new byte[byte_count];
int read_count = port.Read(buffer, 0, byte_count);
// PROCESS DATA HERE
}
}此外,我建议您只在过程port_DataReceived中的队列列表中插入数据,并在单独的线程中执行数据处理。
https://stackoverflow.com/questions/973631
复制相似问题