C# 异步串行端口读取

C# 异步串行端口读取,c#,asynchronous,serial-port,blocking,C#,Asynchronous,Serial Port,Blocking,我有一个类,它使用C#中的DataReceived事件处理程序从串行端口读取数据。当我收到数据时,我知道报头将有5个字节,所以在至少有5个字节之前,我不想对数据做任何事情。我目前的代码如下: while (serialPort.BytesToRead<5) { //Do nothing while we have less bytes than the header size } //Once at least 5 bytes are received, process header

我有一个类,它使用C#中的DataReceived事件处理程序从串行端口读取数据。当我收到数据时,我知道报头将有5个字节,所以在至少有5个字节之前,我不想对数据做任何事情。我目前的代码如下:

while (serialPort.BytesToRead<5)
{
//Do nothing while we have less bytes than the header size
}

//Once at least 5 bytes are received, process header

while(serialPort.BytesToRead会燃烧100%的内核,您不想这样做。正确的方法是将程序块放在Read()调用上。您可以这样编写:

private byte[] rcveBuffer = new byte[MaximumMessageSize];
private int rcveLength;

void ReceiveHeader() {
    while (rcveLength < 5) {
        rcveLength += serialPort.Read(rcveBuffer, rcveLength, 5 - rcveLength);
    }
}
private byte[]rcveBuffer=新字节[MaximumMessageSize];
私人住宅;
void ReceiveHeader(){
而(rcveLength<5){
rcveLength+=serialPort.Read(rcveBuffer,rcveLength,5-rcveLength);
}
}
或者,如果使用DataReceived事件,则它可以如下所示:

    private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) {
        if (e.EventType != System.IO.Ports.SerialData.Chars) return;
        if (rcveLength < 5) {
            rcveLength += serialPort.Read(rcveBuffer, rcveLength, 5 - rcveLength);
        }
        if (rcveLength >= 5) {
            // Got the header, read the rest...
        }
    }
private void serialPort\u DataReceived(对象发送方,System.IO.Ports.SerialDataReceivedEventArgs e){
if(e.EventType!=System.IO.Ports.SerialData.Chars)返回;
如果(rcveLength<5){
rcveLength+=serialPort.Read(rcveBuffer,rcveLength,5-rcveLength);
}
如果(rcveLength>=5){
//得到标题,读剩下的。。。
}
}
在获得整个消息并对其进行处理后,不要忘记将rcveLength设置回0。

使用异步编程(不要忘记首先将应用程序定向到.NET Framework 4.5)

这里是我作为
SerialPort
扩展方法的实现

using System;
using System.IO.Ports;
using System.Threading.Tasks;

namespace ExtensionMethods.SerialPort
{
    public static class SerialPortExtensions
    {
        public async static Task ReadAsync(this SerialPort serialPort, byte[] buffer, int offset, int count)
        {
            var bytesToRead = count;
            var temp = new byte[count];

            while (bytesToRead > 0)
            {
                var readBytes = await serialPort.BaseStream.ReadAsync(temp, 0, bytesToRead);
                Array.Copy(temp, 0, buffer, offset + count - bytesToRead, readBytes);
                bytesToRead -= readBytes;
            }
        }

        public async static Task<byte[]> ReadAsync(this SerialPort serialPort, int count)
        {
            var buffer = new byte[count];
            await serialPort.ReadAsync(buffer, 0, count);
            return buffer;
        }
    }
}

Hans,非常感谢您的回复。如果最初收到的字节少于5个,它似乎会停止,我需要弄清楚如何“循环”再次返回。例如,我总是读取一个20字节的数组。串行端口通常一次提取所有20个字节,但有时它会提取,比如1个字节,然后是19个字节。在这种情况下,上面的代码读取1个字节,然后停止。我是否需要在某个地方睡眠,以便为剩余的数据输入时间?当剩下的字节到达了。你们不应该再做类似“循环返回”这样的事情当然,我不知道为什么不会发生这种情况。一些你实际读取字节但没有实际使用它们的错误是常见的。FWI:我不得不使用
System.IO.Ports.SerialPort SerialPort
而不是
SerialPort SerialPort
。我不知道我是否搞错了什么,但它只想这样工作。是的,我正在使用系统.IO.port
——但是,我仍然无法让它读取任何内容:(但是我发现
ReadTimeout
BaseStream
上不起作用,下面是如何添加ad超时:
public async void Work()
{
   try
   {
       var data = await serialPort.ReadAsync(5);
       DoStuff(data);
   }
   catch(Exception excepcion)
   {
       Trace.WriteLine(exception.Message);
   }
}