在 .net 4.5 中使用异步 API 的示例串行端口通信代码? [英] Sample serial port comms code using Async API in .net 4.5?

查看:14
本文介绍了在 .net 4.5 中使用异步 API 的示例串行端口通信代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

谁能告诉我一个使用 .net 4.5 Async API(async、await、task<>、ReadAsync 等)进行串行通信的工作示例?

Can anyone point me to a working example that uses the .net 4.5 Async API (async, await, task<>, ReadAsync, etc) to do serial communications?

我尝试改编现有的事件驱动串行示例,但遇到了各种可怕的行为 - 端口正在被其他应用程序使用"错误,VS2013 调试器抛出异常并锁定 - 通常需要重新启动 PC 才能恢复.

I've tried to adapt an existing event driven serial sample, and am getting all kinds of horrible behavior - "port in use by other application" errors, VS2013 debugger throwing exceptions and locking up - which usually require a PC reboot to recover from.

编辑

我从头开始编写了自己的示例.这是一个简单的 Winforms 项目,用于写入输出窗口.表单上的三个按钮 - 打开端口、关闭端口和读取数据.ReadDataAsync 方法调用 SerialPort.BaseStream.ReadAsync.

I've written my own sample from scratch. It's a simple Winforms project that writes to the Output window. Three buttons on the form - Open Port, Close Port, and Read Data. The ReadDataAsync method calls SerialPort.BaseStream.ReadAsync.

截至目前,它会从端口读取数据,但我遇到了使其健壮性的问题.

As of now, it will read data from the port, but I'm running into problems making it robust.

例如,如果我拔掉串行电缆,打开端口,然后单击读取数据"两次,我将收到 System.IO.IOException(我有点期待),但我的应用程序停止响应.

For example, if I unplug the serial cable, open the port, and click Read Data twice, I will get an System.IO.IOException (which I kind of expect), but my app stops responding.

更糟糕的是,当我尝试停止我的程序时,VS2013 会抛出一个停止正在进行的调试"对话框,该对话框永远不会完成,我什至无法从任务管理器中杀死 VS.每次发生这种情况时都必须重新启动我的电脑.

Worse, when I try to stop my program, VS2013 throws up a "Stop Debugging in Progress" dialog, which never completes, and I can't even kill VS from Task Manager. Have to reboot my PC every time this happens.

不好.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.IO.Ports;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        private SerialPort _serialPort;

        public Form1()
        {
            InitializeComponent();
        }

        private void openPortbutton_Click(object sender, EventArgs e)
        {
                try
                {
                    if (_serialPort == null )
                        _serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);

                    if (!_serialPort.IsOpen)
                        _serialPort.Open();

                    Console.Write("Open...");
                }
                catch(Exception ex)
                {
                    ClosePort(); 
                    MessageBox.Show(ex.ToString());
                }
        }

        private void closePortButton_Click(object sender, EventArgs e)
        {
            ClosePort();
        }

        private async void ReadDataButton_Click(object sender, EventArgs e)
        {
            try
            {
                await ReadDataAsync();
            }
            catch (Exception ex)
            {
                ClosePort();
                MessageBox.Show(ex.ToString(), "ReadDataButton_Click");
            }
        }

        private async Task ReadDataAsync()
        {
            byte[] buffer = new byte[4096];
            Task<int> readStringTask = _serialPort.BaseStream.ReadAsync(buffer, 0, 100);

            if (!readStringTask.IsCompleted)
                Console.WriteLine("Waiting...");

            int bytesRead = await readStringTask;

            string data = Encoding.ASCII.GetString(buffer, 0, bytesRead);

            Console.WriteLine(data);
        }


        private void ClosePort()
        {
            if (_serialPort == null) return;

            if (_serialPort.IsOpen)
                _serialPort.Close();

            _serialPort.Dispose();

            _serialPort = null;

            Console.WriteLine("Close");
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            ClosePort();
        }

    }
}

推荐答案

我在从 UI 线程关闭 SerialPort 时遇到了类似的问题.下面的 MSDN 博客表明这是由于 UI 线程和执行关闭的本机线程之间的死锁.http:///blogs.msdn.com/b/bclteam/archive/2006/10/10/top-5-serialport-tips-_5b00_kim-hamilton_5d00_.aspx

I've had similar problems closing a SerialPort from the UI thread. The following MSDN blog suggests that it's due to a deadlock between the UI thread and the native thread doing the closing. http://blogs.msdn.com/b/bclteam/archive/2006/10/10/top-5-serialport-tips-_5b00_kim-hamilton_5d00_.aspx

将关闭放入单独的任务中为我修复了它.(该方法是在我项目的一个Protocol容器类中实现的,在点击UI按钮、调用IDispose接口或关闭主窗口时调用.)

Putting the close into a separate task fixed it for me. (The method is implemented in a Protocol container class in my project and called when a UI button is clicked, the IDispose interface invoked or the main window is closed.)

    public Task Close()
    {
        // Close the serial port in a new thread
        Task closeTask = new Task(() => 
        {
            try
            {
                serialPort.Close();
            }
            catch (IOException e)
            {
                // Port was not open
                throw e;
            }
        });
        closeTask.Start();

        return closeTask;
    }

... 然后在我的 UI 命令中...

... and then in my UI command ...

        // The serial stream is stopped in a different thread so that the UI does
        // not get deadlocked with the stream waiting for events to complete.
        await serialStream.Close();

这篇关于在 .net 4.5 中使用异步 API 的示例串行端口通信代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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