【问题标题】:Unable to read from 2 serial devices in UWP application无法从 UWP 应用程序中的 2 个串行设备读取
【发布时间】:2018-06-23 20:24:21
【问题描述】:

希望这里的人能够帮助我。我正在创建一个 c# UWP 应用程序以在 Raspberry Pi2 / Windows IOT 核心上运行。我需要从 2 个串行设备(由外部按钮/PLC 触发)读取输入以计算一些值。我能够一次读取其中一个设备,但到目前为止,我无法获得两者的价值。我基于我的序列代码示例,我试图从主页调用它。不管到目前为止我做了什么改变,第一个设备返回一个值,而第二个没有(串行处理程序中的等待任务立即返回 null,而不是等待一个值通过串行端口来)。

编辑:在进行了一些额外的故障排除后,我发现了以下问题 - 当我尝试停止调试时,Visual Studio 冻结(无法进行 UI 交互,但调试监控仍在更新),阻止这种情况的唯一方法是拔下将我的笔记本电脑(以及串行到 USB 电缆)的底座,此时 VS 再次正常运行。此外,我似乎在串行端口上的 while(true) 循环的第二次迭代中收到错误“请求的资源正在使用中。(来自 HRESULT 的异常:0x800700AA)”不起作用。

调用串口的代码是:

private async Task listenForDeviceInput()
    {
        string weight;
        string area;
        //var areaTask =  cognosCamera.Listen();
        //var  weightTask =  weighTable.Listen();
        Task <string>  areaTask =  cognosCamera.Listen();
        Task <string> weightTask =  weighTable.Listen();
        await Task.WhenAll(areaTask, weightTask);
        weight = await weightTask;
        area = await areaTask;


        weight = weight.TrimEnds("\r");
        area = area.TrimEnds("\r");
        AddNewHide(weight, area);
        saveHide();
        listenForDeviceInput(); //removed the await here to see what happens

    }

串行处理在这里:

 // Copyright (c) Microsoft. All rights reserved.

using System;
using System.Collections.ObjectModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;
using System.Threading;
using System.Threading.Tasks;

namespace SerialDeviceHandler
{
    public sealed partial class SerialPort
    {
        /// <summary>
        /// Private variables
        /// </summary>
        private SerialDevice serialPort = null;
        DataWriter dataWriteObject = null;
        DataReader dataReaderObject = null;

        private ObservableCollection<DeviceInformation> listOfDevices;
        private CancellationTokenSource ReadCancellationTokenSource;



        /// <summary>
        /// ListAvailablePorts
        /// - Use SerialDevice.GetDeviceSelector to enumerate all serial devices
        /// - Attaches the DeviceInformation to the ListBox source so that DeviceIds are displayed
        /// </summary>


        /// <summary>
        /// comPortInput_Click: Action to take when 'Connect' button is clicked
        /// - Get the selected device index and use Id to create the SerialDevice object
        /// - Configure default settings for the serial port
        /// - Create the ReadCancellationTokenSource token
        /// - Start listening on the serial port input
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public async Task OpenSerialPort(string entry)
        {


            try
            {
                serialPort = await SerialDevice.FromIdAsync(entry);
                if (serialPort == null) return;



                // Configure serial settings
                serialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
                serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
                serialPort.BaudRate = 9600;
                serialPort.Parity = SerialParity.None;
                serialPort.StopBits = SerialStopBitCount.One;
                serialPort.DataBits = 8;
                serialPort.Handshake = SerialHandshake.None;



                // Create cancellation token object to close I/O operations when closing the device
                ReadCancellationTokenSource = new CancellationTokenSource();



                //Listen();
            }
            catch (Exception ex)
            {
                //status.Text = ex.Message;
                //comPortInput.IsEnabled = true;
                //sendTextButton.IsEnabled = false;
            }
        }



        /// <summary>
        /// WriteAsync: Task that asynchronously writes data from the input text box 'sendText' to the OutputStream 
        /// </summary>
        /// <returns></returns>


        /// <summary>
        /// - Create a DataReader object
        /// - Create an async task to read from the SerialDevice InputStream
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public  async Task<String> Listen()
        {
            string result;
            try
            {
                if (serialPort != null)
                {
                    dataReaderObject = new DataReader(serialPort.InputStream);

                    // keep reading the serial input
                    while (true)
                    {
                        result = await ReadAsync(ReadCancellationTokenSource.Token);
                        if(result != "Nothing" || result == null)
                        {
                            return result;
                        }
                    }
                }
                return "Failed";
            }
            catch (TaskCanceledException tce)
            {
                //status.Text = "Reading task was cancelled, closing device and cleaning up";
                CloseDevice();
                return "Task Cancelled";
            }
            catch (Exception ex)
            {
                //status.Text = ex.Message;
                return "Task Errored";
            }
            finally
            {
                // Cleanup once complete
                if (dataReaderObject != null)
                {
                    dataReaderObject.DetachStream();
                    dataReaderObject = null;

                }
            }
        }

        /// <summary>
        /// ReadAsync: Task that waits on data and reads asynchronously from the serial device InputStream
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task<string> ReadAsync(CancellationToken cancellationToken)
        {
            Task<UInt32> loadAsyncTask;

            uint ReadBufferLength = 1024;

            // If task cancellation was requested, comply
            cancellationToken.ThrowIfCancellationRequested();

            // Set InputStreamOptions to complete the asynchronous read operation when one or more bytes is available
            dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;

            using (var childCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
            {
                // Create a task object to wait for data on the serialPort.InputStream
                loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(childCancellationTokenSource.Token);

                // Launch the task and wait
                UInt32 bytesRead = await loadAsyncTask;
                if (bytesRead > 0)
                {
                    return dataReaderObject.ReadString(bytesRead);
                    //status.Text = "bytes read successfully!";
                }
                return "Nothing";
            }
        }

        /// <summary>
        /// CancelReadTask:
        /// - Uses the ReadCancellationTokenSource to cancel read operations
        /// </summary>
        public void CancelReadTask()
        {
            if (ReadCancellationTokenSource != null)
            {
                if (!ReadCancellationTokenSource.IsCancellationRequested)
                {
                    ReadCancellationTokenSource.Cancel();
                }
            }
        }

        /// <summary>
        /// CloseDevice:
        /// - Disposes SerialDevice object
        /// - Clears the enumerated device Id list
        /// </summary>
        private void CloseDevice()
        {
            if (serialPort != null)
            {
                serialPort.Dispose();
            }
            serialPort = null;

            //comPortInput.IsEnabled = true;
            //sendTextButton.IsEnabled = false;
            //rcvdText.Text = "";
            listOfDevices.Clear();
        }

        /// <summary>
        /// closeDevice_Click: Action to take when 'Disconnect and Refresh List' is clicked on
        /// - Cancel all read operations
        /// - Close and dispose the SerialDevice object
        /// - Enumerate connected devices
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void closeDevice_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                //status.Text = "";
                CancelReadTask();
                CloseDevice();
                //ListAvailablePorts();
            }
            catch (Exception ex)
            {
                //status.Text = ex.Message;
            }
        }
    }

据我所知,这 2 个串行端口对象似乎是正确创建的(基于这样一个事实,即如果我注释掉另一个的初始化,我可以从每个对象中获取一个值)。我将 2 个串行对象初始化为:

private async System.Threading.Tasks.Task InitializeSerialDevicesAsync()
    {
        weighTable = new SerialPort();
        cognosCamera = new SerialPort();
        await weighTable.OpenSerialPort(scaleComPort);
        await cognosCamera.OpenSerialPort(cameraComPort);

    }

我知道我可能只是在做一些愚蠢的事情,但任何帮助将不胜感激。在这一点上,我只是想让它在普通 PC 上运行,然后我必须开始处理 Pi 上的驱动程序问题等。

【问题讨论】:

    标签: c# uwp raspberry-pi windows-10-iot-core


    【解决方案1】:

    好的 - 所以我已经解决了这个问题,但不明白为什么。我将 USB 转串行电缆切换到不同的品牌(从 prolific 到 FTDI),现在应用程序在笔记本电脑和 pi 上都能正常运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-17
      • 1970-01-01
      • 2021-02-24
      • 1970-01-01
      相关资源
      最近更新 更多