C# 中未读取完整的串口数据
我正在使用 .Net Framework 4 并用 C# 创建一个串行端口 GUI 应用程序。在某些情况下,SerialPort 对象(端口)不会接收所有数据(我将其与混合信号示波器进行比较)
例如,如果连接的设备发送:
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
我可以接收:
0x00 0x01 0x02 0x03 0x04 0x08 0x09
我尝试了具有相同问题的不同代码:
使用数据接收事件填充缓冲区:
private void dataReceived(object sender, SerialDataReceivedEventArgs e) { while (port.BytesToRead > 0){ byte[] newBytes = new byte[port.BytesToRead]; int LengthRead = port.Read(newBytes, 0, newBytes.Length); Array.Resize(ref newBytes, LengthRead); System.Buffer.BlockCopy(newBytes,0,缓冲区,positionInBuffer,newBytes.Length); positionInBuffer += newBytes.Length; } }
循环预期的字节数,在本例中导致 TimeoutException:
while (port.BytesToRead <预期大小) { 系统.Threading.Thread.Sleep(10); 等待循环++; if (waitingLoop > TimeOut) // 等待1s超时 抛出新的 TimeoutException(); } newBytes = 新字节[预期大小]; LengthRead = port.Read(newBytes, 0, newBytes.Length); if (LengthRead != newBytes.Length) 抛出新的 TimeoutException(); // 或任何异常,并不重要...
我尝试更改 ReadBufferSize 大小、超时信息...但没有任何效果。 有什么想法吗?
I'm using .Net framework 4 and create a serial port GUI application in C#. In some cases, the SerialPort object (port) doesn't receive all the data (I compare it with a Mixed Signal Oscilloscope)
For example, if the connected device sends:
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
I can receive:
0x00 0x01 0x02 0x03 0x04 0x08 0x09
I tried different codes having the same issue:
Use the data received event to fill a buffer:
private void dataReceived(object sender, SerialDataReceivedEventArgs e) { while (port.BytesToRead > 0){ byte[] newBytes = new byte[port.BytesToRead]; int LengthRead = port.Read(newBytes, 0, newBytes.Length); Array.Resize(ref newBytes, LengthRead); System.Buffer.BlockCopy(newBytes, 0, buffer, positionInBuffer, newBytes.Length); positionInBuffer += newBytes.Length; } }
Looping for an expected number of bytes, in this case causing the TimeoutException:
while (port.BytesToRead < expectedSize) { System.Threading.Thread.Sleep(10); waitingLoop++; if (waitingLoop > TimeOut) // wait for a 1s timeout throw new TimeoutException(); } newBytes = new byte[expectedSize]; LengthRead = port.Read(newBytes, 0, newBytes.Length); if (LengthRead != newBytes.Length) throw new TimeoutException(); // or any exception, doesn't matter...
I tried to change the ReadBufferSize size, the timeout info,... but nothing works.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这段代码中有一些微妙的错误。第一个片段的 Array.Resize() 不执行任何操作,也许 buffer 需要调整大小?当接收到的字节数多于预期大小时,第二个片段会引发 TimeoutException。这当然是可能的,而不是超时问题。
但我认为真正的问题是你如何处理这段代码之外的数组。一般来说,调用 SerialPort.Read() 只能获取几个字节。串行端口速度很慢。您需要某种协议来知道何时收到“完整”响应。一种非常常见(非二进制)的方法是简单地用换行符终止响应。然后您只需在 DataReceived 事件处理程序中使用 ReadLine() 即可。对于您的情况,目前尚不清楚正确的方法是什么。
还要实现 ErrorReceived 事件。当发生错误时,它会告诉您,例如 SerialError.Overrun 或 RXOver,这些错误也会导致字节消失。
There are subtle mistakes in this code. The first snippet's Array.Resize() does nothing, maybe buffer needs to be resized instead? The second snippet bombs on a TimeoutException when more bytes were received than expectedSize. Which is certainly possible and not a timeout problem.
But I think the real problem is what you do with the array outside of this code. In general, calling SerialPort.Read() only gets you a couple of bytes. Serial ports are slow. You need some kind of protocol to know when a 'full' response is received. A very common (non-binary) one is simply terminating the response with a line-feed. Then you'd just use ReadLine() in the DataReceived event handler. It isn't obvious what the proper approach would be in your case.
Also implement the ErrorReceived event. It will tell you when something bad happened, like SerialError.Overrun or RXOver, errors that also make bytes disappear.
尝试在串行端口上配置软件(XON/XOF)或硬件(例如RTS/CTS)握手,以匹配正在传输的设备的配置。
Try to configure software (XON/XOF) or hardware (e.g. RTS/CTS) handshaking on the serial port, to match the configuration of the device that's transmitting.
感谢您的回答。
实际上我在串行数据中有某种协议。它是这样的:
我通常正确地获取ID、SIZE,然后监听预期的“大小”数据字节(大小小于1000并且串行端口运行在115200,所以它应该是很短的时间)。
但是,当我等待它们时,例如使用第二个代码(等待循环),它们永远不会出现在我的 C# 代码中,即使它们确实通过了串行线(用范围检查)。仍在运行第二个代码,我得到了第一个 TimeOutException(在等待循环上),这意味着我没有在 1 秒内收到所有数据(也尝试增加到 5 秒)。因此,在进入 SerialPort.Read() 函数之前会捕获错误。
无论如何,我将检查 ErrorReceived 事件以检查是否捕获到某些内容...
关于 Array.Resize() 我写了这个,以防 SerialPort.Read() 返回的数据的字节数少于预期的字节数。缓冲区的大小预先设置为我的串行端口缓冲区的最大大小(4096)。
关于我在代码中的第二个错误,你是完全正确的。我应该更好地使用更合适的例外:)
Thanks for the answers.
Actually I have some kind of protocol in the serial data. It's something like:
I usually correctly get the ID, the SIZE and then I listen for the expected 'size' data bytes (size is less than 1000 and the serial port running at 115200, so it should be a short time).
But when I wait for them, for example with the 2nd code (waiting loop), they never come up on my C# code even if they are really passing thought the serial line (checked with the scope). Still running the 2nd code, I got the 1st TimeOutException (on the waiting loop) which means I don't receive all the data within the 1s (also tried to increase to 5s). So the error is catch before going to the SerialPort.Read() function.
Anyway, I will check for the ErrorReceived event to check if I catch something...
Regarding the Array.Resize() I wrote this in case the returned data of SerialPort.Read() has less bytes than the expected ones. Buffer is pre-sized at the max size of my SerialPort buffer (4096).
Regarding my 2nd mistake in the code you are complitly right. I should better use a more appropriate exception :)