简体   繁体   English

C# 异步串行端口读取

[英]C# Async Serial Port Read

I have a class which reads from the serial port using the DataReceived event handler in C#.我有一个类,它使用 C# 中的 DataReceived 事件处理程序从串行端口读取。 When I receive data, I know the header will have 5 bytes, so I don't want to do anything with the data until I have at least that.当我接收数据时,我知道标头将有 5 个字节,所以我不想对数据做任何事情,直到我至少有了那个。 My current code is below:我当前的代码如下:

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

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

As I understand it, this code is blocking and needs to be improved.据我了解,这段代码是阻塞的,需要改进。 I'm looking for suggestions on how to do this.我正在寻找有关如何执行此操作的建议。 Would another event handler inside the DataReceived event handler be appropriate? DataReceived 事件处理程序中的另一个事件处理程序是否合适?

Use async programming (don't forget to target first your application to .NET Framework 4.5).使用异步编程(不要忘记首先将您的应用程序定位到 .NET Framework 4.5)。

Here you've my implementation as extension methods for SerialPort .在这里,您将我的实现作为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;
        }
    }
}

and here how to read:以及如何阅读:

public async void Work()
{
   try
   {
       var data = await serialPort.ReadAsync(5);
       DoStuff(data);
   }
   catch(Exception excepcion)
   {
       Trace.WriteLine(exception.Message);
   }
}

That burns 100% core, you don't want to do that.这会消耗 100% 的核心,你不想那样做。 The proper way is to have your program block on the Read() call.正确的方法是让你的程序块在 Read() 调用上。 You'd write it similar to this:你会像这样写:

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

void ReceiveHeader() {
    while (rcveLength < 5) {
        rcveLength += serialPort.Read(rcveBuffer, rcveLength, 5 - rcveLength);
    }
}

Or if you use the DataReceived event then it can look like this:或者,如果您使用 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...
        }
    }

Don't forget to set rcveLength back to 0 after you've got the entire message and processed it.在获得整个消息并对其进行处理后,不要忘记将 rcveLength 设置回 0。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM