从 C# 中的串口读取
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/644954/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reading from the serial port in C#
提问by sarsnake
I have tried using Readline() and data gets dropped, I tried using Read() but I am not sure how to have an error proof method of doing it, since I may get several packets one after another and I have no way of knowing that there is going to be another packet coming in. In between packets BytesToRead is 0, so I can't use it. When reading data to the buffer to you have a timer or put the thread to sleep to allow for all the packets to arrive?
我试过使用 Readline() 并且数据被丢弃,我试过使用 Read() 但我不知道如何有一个错误证明方法来做到这一点,因为我可能会一个接一个地收到几个数据包,我无法知道将会有另一个数据包进来。在数据包之间 BytesToRead 是 0,所以我不能使用它。将数据读取到缓冲区时,您有一个计时器或让线程进入睡眠状态以允许所有数据包到达?
I am lost. Don't know what to try next.
我搞不清楚了。不知道接下来要尝试什么。
I should mention that I get no guarantee that the string coming off the serial port will be ended with \n or \r or \r\n. I simply need a fool proof way to read ALL the packets that will come from the scale when the user presses PRINT on it.
我应该提到,我不能保证从串行端口出来的字符串将以 \n 或 \r 或 \r\n 结尾。我只需要一种万无一失的方法来读取用户在秤上按下 PRINT 时来自秤的所有数据包。
Someone answered here with the idea I liked - waiting for a certain amount of time for all the packets, but they erased their answer. ANy chance you could re-post it?
有人在这里回答了我喜欢的想法 - 等待所有数据包的一定时间,但他们删除了他们的答案。你有机会重新发布吗?
回答by Samuel
Have you tried listening to the DataRecieved
event of the SerialPort
class?
你有没有试过听课的DataRecieved
事件SerialPort
?
public class MySerialReader : IDisposable
{
private SerialPort serialPort;
private Queue<byte> recievedData = new Queue<byte>();
public MySerialReader()
{
serialPort = new SerialPort();
serialPort.Open();
serialPort.DataReceived += serialPort_DataReceived;
}
void serialPort_DataReceived(object s, SerialDataReceivedEventArgs e)
{
byte[] data = new byte[serialPort.BytesToRead];
serialPort.Read(data, 0, data.Length);
data.ToList().ForEach(b => recievedData.Enqueue(b));
processData();
}
void processData()
{
// Determine if we have a "packet" in the queue
if (recievedData.Count > 50)
{
var packet = Enumerable.Range(0, 50).Select(i => recievedData.Dequeue());
}
}
public void Dispose()
{
if (serialPort != null)
serialPort.Dispose();
}
回答by Byron Ross
We went through the same process a while ago.
我们前段时间经历了同样的过程。
The only way to read 'packets' is to have some concept of where the start and end of them are in a stream.
读取“数据包”的唯一方法是了解它们在流中的开始和结束位置。
From msdn:
从msdn:
Because the SerialPort class buffers data, and the stream contained in the BaseStream property does not, the two might conflict about how many bytes are available to read. The BytesToRead property can indicate that there are bytes to read, but these bytes might not be accessible to the stream contained in the BaseStream property because they have been buffered to the SerialPort class.
因为 SerialPort 类缓冲数据,而 BaseStream 属性中包含的流不缓冲,所以两者可能会在有多少字节可供读取方面发生冲突。BytesToRead 属性可以指示有要读取的字节,但 BaseStream 属性中包含的流可能无法访问这些字节,因为它们已缓冲到 SerialPort 类。
We used a backround thread (you could use a BackgroundWorker) to read the data into a buffer. If you can't reliably set the terminating character using the SerialPort.Newline property (because, say, it varies!) then you will need to implement your own packet detection system because you wont be able to use the blocking SerialPort.Readline() method.
我们使用后台线程(您可以使用 BackgroundWorker)将数据读入缓冲区。如果您不能使用 SerialPort.Newline 属性可靠地设置终止字符(因为,比如说,它会变化!)那么您将需要实现自己的数据包检测系统,因为您将无法使用阻塞 SerialPort.Readline()方法。
You could just read into a byte buffer using SerialPort.Read() (or string using the SerialPort.ReadExisting() method) and generate an event when you detect a valid packet in the data. Note that Read() (and I assume ReadExisting() ) empty the SerialPort's buffer, so you'll need to keep the data somewhere else.
您可以使用 SerialPort.Read() (或使用 SerialPort.ReadExisting() 方法的字符串)读入字节缓冲区,并在检测到数据中的有效数据包时生成事件。请注意, Read() (我假设 ReadExisting() )清空了 SerialPort 的缓冲区,因此您需要将数据保存在其他地方。
If you set the SerialPort.ReadTimeout, you can handle the TimeoutException and have an easy way to handle conditions where your device is not transmitting. This is a good way to reset your packet detection if you are using a fixed number of bytes, or some other non-terminated scheme. (use SerialPort.DiscardInBuffer() on a timeout if you don't need partial packets).
如果您设置了 SerialPort.ReadTimeout,您就可以处理 TimeoutException 并有一个简单的方法来处理您的设备没有传输的情况。如果您使用固定数量的字节或其他一些非终止方案,这是重置数据包检测的好方法。(如果您不需要部分数据包,请在超时时使用 SerialPort.DiscardInBuffer())。
Good luck
祝你好运
回答by albay
Since bytes may come in at any time, buffering incoming data is critical. So you should
由于字节可能随时进入,因此缓冲传入数据至关重要。所以你应该
- buffer the incoming data
- scan your buffer to find complete data
- remove the used data from the buffer
- 缓冲传入的数据
- 扫描您的缓冲区以找到完整的数据
- 从缓冲区中删除使用过的数据
I am just wondering if you are still having problems with the serial port. If so, I developed a serial port programming language in C# and I believe it solves nearly all of the problems that everybody encounters with.
我只是想知道您是否仍然遇到串行端口的问题。如果是这样,我用 C# 开发了一种串口编程语言,我相信它几乎解决了每个人遇到的所有问题。
Would you please take a look and try it ? For example; you can buffer incoming data from the serial port like the following and do string operations easily.
请您看一下并尝试一下好吗?例如; 您可以像下面这样缓冲来自串行端口的传入数据,并轻松执行字符串操作。
state Init
// define a global variable
our $BUFFER = "";
jump(Receive);
end state
state Receive
recv();
$len = length($DATA_PACKET);
if("$len > 0") {
$BUFFER += $DATA_PACKET;
call(Parser);
}
end state
state Parser
// check if buffer matchs regular expression pattern
if(match($BUFFER, "(?<WILLDELETE>.*?<STX>(?<DATA>.*?)<ETX>(?<CHECKSUM>[0-9A-F]{2}))")) {
// Received complete data
$lenData = length($WILLDELETE);
$BUFFER = remove($BUFFER, 0, $lenData);
// Do operations with the other parsed fields. $DATA and $CHECKSUM in this example.
}
end state
Project is freely available on sourceforge and if you have any questions, please feel free to ask.
项目可在 sourceforge 上免费获得,如果您有任何问题,请随时提出。