正确地从串口异步连续读取 [英] Continuously reading from serial port asynchronously properly

查看:22
本文介绍了正确地从串口异步连续读取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只想说我今天才开始尝试使用 Async,所以我对自己在做什么的理解非常有限.

I'm just going to preface this by saying I just started trying to use Async today, so I have a very limited understanding of what I am doing.

我之前使用线程从串行端口读取数据,将该数据处理为要写入的数据,然后再写入.我有一个线程读取数据并将其放入缓冲区,另一个线程处理来自缓冲区的数据,最后一个线程写入它.这样,如果我点击一个按钮,我可以发送额外的数据.

I was previously using threads to read data from a serial port, process that data into data to write, and then writing it. I had 1 thread reading data and placing it into a buffer, another thread processing data from a buffer, and a final thread writing it. This way if I clicked a button, I could send additional data.

现在我只是想学习并确保我做的一切都正确,所以我尝试从串行端口读取数据,并将该数据添加到多行文本框中.代码如下:

Now I am just trying to learn and ensure I am doing everything properly, so I am trying to read data from the serial port, and add that data to a multilined textbox. Here's the code:

连接串口,如果成功,调用异步的UpdateMessageBox:

Connect to serial port, if successful, call UpdateMessageBox which is async:

private void serialConnectClick(object sender, EventArgs e)
{
    if (!_serialConnected)
    {
        _serialConnected = SerialConnect(portCombo.Text, int.Parse(baudCombo.Text));
        if (!_serialConnected)
        {
            portCombo.SelectedIndex = 0;
            messageTextBox.Text += "Failed to connect.
";
            return;
        }

        serialConnectBtn.Text = "Disconnect";
        serialStatusLabel.Text = "Serial: Connected";
        serialStatusLabel.ForeColor = Color.Blue;
        messageTextBox.Text += "Connected
";
        VDIportCombo.Enabled = false;
        soundSuccess.Play();
        UpdateMessageBox(); // this is an async function
    }
}

这会不断调用 ReadLineAsync 并将结果添加到文本框:

This continuously calls ReadLineAsync and adds the result to the textbox:

public async Task UpdateMessageBox()
{
    messageTextBox.Text += "Reading data from serial.";
    while (_serialConnected)
    {
        string message = await SerialReadLineAsync(serial);
        messageTextBox.Text += message;
    }
}

这会在 SerialPort.BaseStream 上执行 ReadAsync,并且仅在我们得到整行时才返回数据(由换行符表示):

And this does ReadAsync on the SerialPort.BaseStream, and only returns data when we get a full line (denoted by a newline character):

async Task<string> SerialReadLineAsync(SerialPort serialPort)
{
    byte[] buffer = new byte[1];
    string result = string.Empty;
    Debug.WriteLine("Let's start reading.");

    while (true)
    {
        await serialPort.BaseStream.ReadAsync(buffer, 0, 1);
        result += serialPort.Encoding.GetString(buffer);

        if (result.EndsWith(serialPort.NewLine))
        {
            result = result.Substring(0, result.Length - serialPort.NewLine.Length);
            result.TrimEnd('
','
');
            Debug.Write(string.Format("Data: {0}", result));
            result += "
";
            return result;
        }
    }
}

我做的每一件事都正确吗?我可以从 UI 线程调用异步方法吗?Visual Studios 告诉我我应该使用 await,但这只是建议.

Am I doing everything correctly? Can I call an async method from the UI thread? Visual studios is telling me I should use await, but it is just suggesting that.

我希望其他代码在 UI 线程持续读取时运行,因此我不想 await UpdateMessageBox 函数.如果这是一个线程,我只想让读取线程在后台运行,我只会做 myReadThread.Start(),异步有类似的东西吗?

I want other code to run on the UI thread while it is continuously reading, so I don't want to await the UpdateMessageBox function. If this were a thread, I would just want the read thread to operate in the background, and I would just do myReadThread.Start(), is there something similar for async?

澄清一下,这段代码确实有效,但我想知道这是否是我正在做的事情的正确"方式.

Just to clarify, this code does work, but I want to know if it's the "proper" way to do what I am doing.

推荐答案

你需要改变:

private void serialConnectClick(object sender, EventArgs e)

private async void serialConnectClick(object sender, EventArgs e)

...并将对 UpdateMessageBox(); 的调用更改为:

...and change the call to UpdateMessageBox(); to:

await UpdateMessageBox().ConfigureAwait(true);

UpdateMessageBox 应使用 ConfigureAwait(true) 以捕获当前上下文 (UI),否则 messageTextBox.Text += message;将在不同的线程上执行:

UpdateMessageBox should use ConfigureAwait(true) in order to capture the current context (UI) else the messageTextBox.Text += message; would execute on a different thread:

public async Task UpdateMessageBox()
{
    messageTextBox.Text += "Reading data from serial.";
    while (_serialConnected)
    {
        string message = await SerialReadLineAsync(serial).ConfigureAwait(true);
        messageTextBox.Text += message;
    }
}

SerialReadLineAsync中,你可以改变:

await serialPort.BaseStream.ReadAsync(buffer, 0, 1);

...到:

await serialPort.BaseStream.ReadAsync(buffer, 0, 1).ConfigureAwait(false);

...因为 SerialReadLineAsync 语句与 UI 无关.

...because SerialReadLineAsync statements are not related to the UI.

一般提示是"async all the way",这意味着任何 awaitasync 方法的方法也需要进行 async 并依次 awaited.在调用堆栈中重复此操作.

The general tip is "async all the way" which means any method that awaits an async method also needs to be made async and in turn awaited. Repeat this up the call-stack.

这篇关于正确地从串口异步连续读取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆