- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
编辑:我已经添加了发送代码和我得到的接收输出示例。
我正在从连接到嵌入式系统的 USB“虚拟”串行端口读取数据。我写了两种接收数据的方法,一种是同步的,一种是异步的。同步的工作,而异步的会丢失或扰乱一点传入的数据。我不知道为什么第二个失败了。
有效的方法 调用 SerialPort.Read 并将读取超时设置为零,并请求接收缓冲区中的所有内容。我检查返回值以查看实际读取了多少字节,然后将数据放入循环缓冲区以供其他地方使用。此方法由定时器中断调用,它可以完美地接收串行数据(通常以高于 1.6 Mbps 的速率且不会丢失数据)。但是,轮询计时器对我来说已经成为一个问题,我更愿意在其余代码中异步接收数据。
丢失数据的方法在串行端口 BaseStream 上等待 ReadAsync 并循环直到被取消。这种方法是有效的,但它经常无序地返回数据包的前导字节,相当频繁地丢失一个字节(大约每几千个数据字节一次),并且偶尔会从数据包中丢失数百个连续字节。
这里可能存在两个完全不同的问题,因为丢失更大块的数据似乎与更高的数据速率和更重的系统事件相关。问题的这一特定部分可能是由于缓冲区溢出——也许是由于 USB 调度程序遇到延迟时 USB 握手失败——但我在这里展示的例子只有非常少量的数据在 50 传输毫秒间隔,系统空闲,除了这个测试程序。
我观察到 ReadAsync 经常在一次读取时返回数据包的第一个字节,而在下一次读取时返回数据包的其余部分。我相信这是预期的行为,因为 MSDN 说如果在一段时间内没有数据可用,ReadAsync 将返回它收到的第一个字节。但是,我认为这种行为与我的问题有某种关系,因为当一个字节丢失或乱序时,它“总是”第一个字节,其余的数据包正常到达。
当数据包很小时,数据包前面的“丢失”字节通常(但不总是)似乎在数据包剩余部分之后的下一次读取中被传递,这对我来说完全没有意义。对于较大的数据包,这种情况偶尔会发生,但更常见的是,当数据包很大时,第一个字节就会丢失。
我已经进行了广泛的搜索,并阅读了我能找到的关于这个主题的所有 SO 问题。我发现其他人似乎有类似的问题(例如: SerialPort.BaseStream.ReadAsync missing the first byte ),但没有人有任何可接受的甚至合理的解决方案。
Ben Voigt ( http://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport ) 和其他似乎真的了解串行通信的人已经推荐在基流上使用 ReadAsync,而且微软的 IOT 团队也推荐了这种方法,所以我不得不相信这种方法应该有效。
问题一:为什么我的代码在 USB 串行 BaseStream 上使用 ReadAsync 丢弃/加扰字节?
问题2:如果 ReadAsync 不能以正确的顺序可靠地返回所有接收到的字节,我是否可以在传统的 SerialPort.Read 周围放置一个异步包装器并等待/循环它,这样我就不必从计时器进行轮询?我读到这是一个坏主意,但我也读到 SerialPort 类在内部是异步的,所以也许这样就可以了?或者我唯一的选择是把它放在一个工作线程上,让它花所有的时间等待?
我的代码如下。我已经设置了serialPort1.ReadTimeout = 0;
和 serialPort1.BaseStream.ReadTimeout = 0;
(我已经尝试过其他持续时间)。
我已经启用了 RTS 和 DTR,并且由于这是一个 USB_serial 端口,它应该在内部处理握手,当我同步读取时它肯定会这样做——但是当我从 BaseStream 读取时可能不是这样?
这是第一种方法:
// this method works perfectly when called from a timer.
// SerialPort.ReadTimeout must be set to zero for this to work.
// It handles incoming bytes reliably at rates above 1.6 Mbps.
private void ReadSerialBytes()
{
if (!serialPort1.IsOpen)
return;
if (serialPort1.BytesToRead > 0)
{
var receiveBuffer = new byte[serialPort1.ReadBufferSize];
var numBytesRead = serialPort1.Read(receiveBuffer, 0, serialPort1.ReadBufferSize);
var bytesReceived = new byte[numBytesRead];
Array.Copy(receiveBuffer, bytesReceived, numBytesRead);
// Here is where I audit the received data.
// the NewSerialData event handler displays the
// data received (as hex bytes) and writes it to disk.
RaiseEventNewSerialData(bytesReceived);
// serialInBuffer is a "thread-safe" global circular byte buffer
// The data in serialInBuffer matches the data audited above.
serialInBuffer.Enqueue(bytesReceived, 0, numBytesRead);
}
}
// This method is called once after the serial port is opened,
// and it repeats until cancelled.
//
// This code "works" but periodically drops the first byte of a packet,
// or returns that byte in the wrong order.
// It occasionally drops several hundred bytes in a row.
private async Task ReadSerialBytesAsync(CancellationToken ct)
{
while((!ct.IsCancellationRequested) && (serialPort1.IsOpen))
{
try
{
serialPort1.BaseStream.ReadTimeout = 0;
var bytesToRead = 1024;
var receiveBuffer = new byte[bytesToRead];
var numBytesRead = await serialPort1.BaseStream.ReadAsync(receiveBuffer, 0, bytesToRead, ct);
var bytesReceived = new byte[numBytesRead];
Array.Copy(receiveBuffer, bytesReceived, numBytesRead);
// Here is where I audit the received data.
// the NewSerialData event handler displays the
// data received (as hex bytes) and writes it to disk.
RaiseEventNewSerialData(bytesReceived);
// serialInBuffer is a "thread-safe" global circular byte buffer
// The data in serialInBuffer matches the data audited above.
serialInBuffer.Enqueue(receiveBuffer, 0, numBytesRead);
}
catch (Exception ex)
{
MessageBox.Show("Error in ReadSerialBytesAsync: " + ex.ToString());
throw;
}
}
}
void SendTestData()
{
byte asyncTestBuffer[256] = { 0 };
for (int i = 0; i < 256; i++)
asyncTestBuffer[i] = i;
while(true)
{
Serial.write(asyncTestBuffer, sizeof(asyncTestBuffer));
delay(50);
}
}
=====
32 msec => Received 256 bytes
000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
7 msec => Received 255 bytes
0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
5 msec => Received 1 bytes
00
=====
55 msec => Received 1 bytes
00
=====
4 msec => Received 255 bytes
0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
42 msec => Received 1 bytes
00
=====
5 msec => Received 255 bytes
0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
68 msec => Received 1 bytes
00
=====
7 msec => Received 255 bytes
0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
31 msec => Received 255 bytes
0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
9 msec => Received 1 bytes
00
=====
33 msec => Received 1 bytes
00
=====
10 msec => Received 255 bytes
0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
55 msec => Received 255 bytes
0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
12 msec => Received 1 bytes
00
=====
12 msec => Received 1 bytes
00
=====
15 msec => Received 255 bytes
0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
68 msec => Received 255 bytes
0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
16 msec => Received 1 bytes
00
=====
14 msec => Received 256 bytes
000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
=====
最佳答案
在逐步完成 .Net SerialPort 类的反编译源代码后,我终于想出了一个答案(仅安装了 resharper Rclick on SerialPort->Navigate->Decompiled Sources
)。
答案 #1:字节乱序问题是由于我程序中的一个错误造成的。我已经取消并重新启动了 readAsync 循环,但是我使用了错误的取消 token ,因此有两个循环副本都在等待来自串行端口的 readAsync。两者都发出中断以返回接收到的数据,但当然这是一个竞争条件,即谁先到达那里。
答案 #2:请注意我使用同步读取方法的方式:我不使用 Received 事件(它不能正常工作)或检查要读取的字节数(这是不可靠的)或类似的东西。我只是将超时设置为零,尝试使用大缓冲区读取,并检查我返回了多少字节。
当以这种方式调用时,同步 SerialPort.Read 首先尝试满足来自内部缓存 [1024] 的接收数据字节的读取请求。如果它仍然没有足够的数据来满足请求,那么它会使用完全相同的缓冲区、(调整后的)偏移量和(调整后的)计数针对底层 BaseStream 发出 ReadAsync 请求。
底线:按照我的使用方式使用时,同步 SerialPort.Read 方法的行为与 SerialPort.ReadAsync 完全相同。我的结论是,在同步方法周围放置一个异步包装器可能没问题,然后等待它。但是,我现在不需要这样做,因为我可以可靠地从基流中读取数据。
更新:我现在使用包含循环的任务从我的串行端口可靠地接收超过 3Mbps 的数据,该循环持续等待 SerialPort.Basestream.ReadAsync 并将结果添加到循环缓冲区中。
关于c# - 从 USB 串行端口读取时,SerialPort.BaseStream.ReadAsync 丢弃或扰乱字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41777981/
我在一本名为 "USB in a NutShell" 的相当棒的书中找到了中断传输提供可靠的传输(通过错误检测和自动重试)。 但我想知道,这能保证有一天不会按顺序交换转移吗?至于总线是串行的,我的猜测
USB 2.0 specifies 4 种传输类型(在第 5.4 节传输类型中): 控制转移 同步传输 中断传输 批量转账 第 5.8 节说批量传输提供: Access to the USB on a
在我正在研究的 SoC 中,有 USB EHCI 兼容 Controller 。 所有 EHCI Controller 都可以作为主机或设备工作吗? EHCI Linux 驱动程序是否涵盖此类 Con
我有一个 USB 调制解调器,它经常掉线。发生这种情况时,我将其从 USB 端口拔出并重新插入,它会立即返回信号;我可以编写一个程序来执行此操作而无需物理断开调制解调器与端口的连接吗? 最佳答案 正如
我正在尝试使用 libusb 与 USB 设备通信,但我觉得自己在比赛的第一站被绊倒了。我确切地知道我需要与哪些端点交谈,等等,但我什至做不到那么远。本质上,我有: usb_device *dev =
是否有工具可以验证在枚举过程中读取的 USB 设备描述符?我遇到过这样的情况,我购买的设备(实验室设备)的 USB 设备描述符不是很有效,并且无法被操作系统正确识别为“加载设备描述符失败”。我知道这并
我正在从事一个需要将信号从外部世界传输到计算机的项目。我有一个生成模拟信号的源,这个信号需要通过 USB 在 PC 上传输。这是我的问题:什么是接口(interface)? 我从源头获得的模拟信号,是
我想知道降低/提高 USB 端口的输出功率在技术上是否可行? 我自己也持怀疑态度,但我要求确定。 最佳答案 如上所述,是的。要获得超过 500mA (USB 2.0) 的电流,请使用组合电缆并联两个或
我正在尝试制作一个 HID USB 设备。我搜索了一下,发现键盘的输出有 8 个字节。第一个字节是修饰符,第二个字节是保留字节,其余 6 个字节是关键代码。我认为在某些情况下,例如“prtsc”,需要
我们正在寻找一个虚拟 USB 链接模拟器;这个程序或服务应该 链接虚拟COM port到仅接受 USB 作为数据链路的应用程序。 virtual COM port是 VSPE来自 Eterlogic
我一直在尝试监视何时插入或移除 USB 设备,它似乎工作得很好。现在唯一困扰我的是,每次我插入或移除设备时,都会多次触发该事件。 我可以毫无问题地将事件分组,但我很好奇为什么它首先发生。 这是我正在使
关闭。这个问题需要更多 focused .它目前不接受答案。 想改进这个问题?更新问题,使其仅关注一个问题 editing this post . 6年前关闭。 Improve this questi
我正在为 USB 设备编写代码。假设 USB 主机开始控制读取传输以从设备读取一些数据,并且请求的数据量(设置数据包中的 wLength)是端点 0 最大数据包大小的倍数。那么在主机接收到所有数据后(
我们正在开发一个带有 arm7(current: LPC2368) 的发送器设备。 本设备采样一个 mv 信号,A/D,并需要将此信号数据发送到 PC。(连续) 同时,PC 需要向 arm7 发送命令
我希望能够使用通过 USB 连接到 PC 的 IR 远程传感器打开和关闭我的 PC。该传感器是使用 AVR 微处理器和 V-USB 软件 USB 实现实现的定制 PCB。 现在,用软件关掉电脑是没有问
我正在使用 STM32L151 与使用 USB CDC 的 PC 进行通信。我使用 STM32 HAL 库来创建我的项目。 我发现 USB 以 1 ms 的间隔发送数据,每次发送 64 个字节。那么,
我们有一个设备要求我们在插入之前安装驱动程序,否则我们需要删除 Windows 8 和 10 自动下载的驱动程序。 我们如何制作一个无论先插还是不插都能正确安装的USB驱动安装器? 最佳答案 在 Wi
我需要填充 USB 存储器,我希望其他人能够以简单的方式重复此操作。所以我不想写“找到一个填满内存的文件”,所以他们必须四处寻找这样的文件。 我想生成 X MB 的数据并将其写入一个文件,然后可以将其
我有一个 Android 平板电脑,它有一个迷你 USB 端口和一个 USB 端口,我想编写一个与 USB key 通信的应用程序。我写了一个demo来找出U盘,但是没有任何反应。 令我不安的是,如果
我正在尝试使用 Android USB Host API 读取我的 USB 游戏 Controller 数据,一旦我让它工作,我将连接其他设备进行测试。我的游戏 Controller 使用 OTG 线
我是一名优秀的程序员,十分优秀!