代码神秘地在函数中间结束(串行端口数据接收处理程序)
Code mysteriously end in middle of function (serialport datareceived handler)
我在 C# 代码中有一个 SerialPort DataReceived
事件处理程序:
void serPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) {
SerialPort sp = (SerialPort)sender;
string indata = "";
while (sp.ReadBufferSize > 0) {
int bytes = sp.ReadBufferSize;
char[] result = new char[bytes];
sp.Read(result, 0, bytes);
indata += new string(result).Replace("[=10=]", "");
}
Dispatcher.Invoke((Action)(() => port1out.Text += indata + "\n"));
}
使用断点,我知道调用了函数,正在执行while循环,甚至indata
变量包含接收到的数据,但是当while循环结束时,整个监听器结束。没有文本添加到 port1out
文本框。我试图在 Dispatcher.Invoke... 行之后(和之前)添加无所事事的代码,使用断点并且它没有执行 - 代码在 while 循环之后结束。
为什么?为什么没有执行整个语句?
你的循环永远不会结束,因为 ReadBufferSize
will never be zero. You are misunderstanding what ReadBufferSize
means. It is not the amount of data waiting to be read, but the maximum amount of data the SerialPort
class will hold (or buffer) while it waits for you to read out. What you should be looking at instead is the BytesToRead
属性.
您也可以调用 ReadExisting()
method as is shown on the MSDN example。
丢掉 DataReceived 事件,改用这个:
void ReadFromPort(SerialPort p)
{
Stream s = p.BaseStream;
s.ReadTimeout = 20;
// 1/50th of a second and 10 serial bits per byte
byte[] buffer = new byte[p.BaudRate / 500];
ReadSerialStream(s, buffer);
}
void async ReadSerialStream(Stream s, byte[] buffer)
{
int bytesRead = await s.ReadAsync(buffer, 0, buffer.Length);
string indata = Encoding.ASCII.GetString(
buffer.Take(bytesRead).Where(b => b != 0).ToArray());
port1out.Text += indata + Environment.Newline;
ReadSerialStream(s, buffer);
// or use an infinite while loop. With async methods, recursion is safe
}
实际上正在进行读取将使虚拟串行端口真正开始传输数据。如果您改为依赖 DataReceived
和 BytesToRead
,您的数据可能会卡在(例如)USB 传输缓冲区中,并且永远不会到达串行端口对象。或者您最终可能会为每个单独的字节进行多次 USB 传输(首先报告 "buffer not empty" 标志,然后传输缓冲区内容)。 ReadAsync
在所有级别上都更有效率。此外,它在 async/await 范例中工作,直接在 UI 线程上接收串行事件,因此您不必搞乱跨线程调用或同步访问内部数据结构。
我在 C# 代码中有一个 SerialPort DataReceived
事件处理程序:
void serPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) {
SerialPort sp = (SerialPort)sender;
string indata = "";
while (sp.ReadBufferSize > 0) {
int bytes = sp.ReadBufferSize;
char[] result = new char[bytes];
sp.Read(result, 0, bytes);
indata += new string(result).Replace("[=10=]", "");
}
Dispatcher.Invoke((Action)(() => port1out.Text += indata + "\n"));
}
使用断点,我知道调用了函数,正在执行while循环,甚至indata
变量包含接收到的数据,但是当while循环结束时,整个监听器结束。没有文本添加到 port1out
文本框。我试图在 Dispatcher.Invoke... 行之后(和之前)添加无所事事的代码,使用断点并且它没有执行 - 代码在 while 循环之后结束。
为什么?为什么没有执行整个语句?
你的循环永远不会结束,因为 ReadBufferSize
will never be zero. You are misunderstanding what ReadBufferSize
means. It is not the amount of data waiting to be read, but the maximum amount of data the SerialPort
class will hold (or buffer) while it waits for you to read out. What you should be looking at instead is the BytesToRead
属性.
您也可以调用 ReadExisting()
method as is shown on the MSDN example。
丢掉 DataReceived 事件,改用这个:
void ReadFromPort(SerialPort p)
{
Stream s = p.BaseStream;
s.ReadTimeout = 20;
// 1/50th of a second and 10 serial bits per byte
byte[] buffer = new byte[p.BaudRate / 500];
ReadSerialStream(s, buffer);
}
void async ReadSerialStream(Stream s, byte[] buffer)
{
int bytesRead = await s.ReadAsync(buffer, 0, buffer.Length);
string indata = Encoding.ASCII.GetString(
buffer.Take(bytesRead).Where(b => b != 0).ToArray());
port1out.Text += indata + Environment.Newline;
ReadSerialStream(s, buffer);
// or use an infinite while loop. With async methods, recursion is safe
}
实际上正在进行读取将使虚拟串行端口真正开始传输数据。如果您改为依赖 DataReceived
和 BytesToRead
,您的数据可能会卡在(例如)USB 传输缓冲区中,并且永远不会到达串行端口对象。或者您最终可能会为每个单独的字节进行多次 USB 传输(首先报告 "buffer not empty" 标志,然后传输缓冲区内容)。 ReadAsync
在所有级别上都更有效率。此外,它在 async/await 范例中工作,直接在 UI 线程上接收串行事件,因此您不必搞乱跨线程调用或同步访问内部数据结构。