2017-01-15 49 views
1

我正在嘗試創建一個初始化樹莓和arduino之間的串行連接的類。課程還應能夠讀寫已建立的串行連接。爲什麼我的異步方法不等待「serialPort = await SerialDevice.FromIdAsync()」?

我使用的代碼來自microsoft developers website

using Windows.Storage.Streams; 
using Windows.Devices.Enumeration; 
using Windows.Devices.SerialCommunication; 

public async void Serial() 
{ 
    /* Find the selector string for the serial device */ 
    string aqs = SerialDevice.GetDeviceSelector("UART0"); 
    /* Find the serial device with our selector string */ 
    var dis = await DeviceInformation.FindAllAsync(aqs); 
    /* Create an serial device with our selected device */ 
    SerialDevice SerialPort = await SerialDevice.FromIdAsync(dis[0].Id); 
    /* 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; 

    /* Write a string out over serial */ 
    string txBuffer = "Hello Serial"; 
    DataWriter dataWriter = new DataWriter(); 
    dataWriter.WriteString(txBuffer); 
    uint bytesWritten = await SerialPort.OutputStream.WriteAsync(dataWriter.DetachBuffer()); 

    /* Read data in from the serial port */ 
    const uint maxReadLength = 1024; 
    DataReader dataReader = new DataReader(SerialPort.InputStream); 
    uint bytesToRead = await dataReader.LoadAsync(maxReadLength); 
    string rxBuffer = dataReader.ReadString(bytesToRead); 
} 

我在serial.appxmanifest中添加了serialcommunication功能。

<Capabilities> 
    <DeviceCapability Name="serialcommunication"> 
    <Device Id="any"> 
     <Function Type="name:serialPort" /> 
    </Device> 
    </DeviceCapability> 
</Capabilities> 

到目前爲止一切正常。樹莓在另一端成功發送和接收來自Arduino的消息。

現在我試着單獨做這些步驟。首先初始化串行連接,以便在應用程序需要時使用讀取和寫入功能。

的MainPage

namespace SerialUART 
{ 
    public sealed partial class MainPage : Page 
    { 
     private SerialController serial = new SerialController(); 

     public MainPage() 
     { 
      this.InitializeComponent(); 
      serial.Write(); 
      serial.Read(); 
     } 
    } 
} 

SerialController

using Windows.Devices.Enumeration; 
using Windows.Devices.SerialCommunication; 
using Windows.Storage.Streams; 

namespace SerialUART 
{ 
    class SerialController 
    { 
     private SerialDevice SerialPort; 
     private DataWriter dataWriter; 
     private DataReader dataReader; 

     public SerialController() 
     { 
      InitSerial(); 
     } 

     private async void InitSerial() 
     { 
      string aqs = SerialDevice.GetDeviceSelector("UART0"); 
      var dis = await DeviceInformation.FindAllAsync(aqs); 
      SerialPort = await SerialDevice.FromIdAsync(dis[0].Id);  
      // The program does not wait here and executes Write() 
      // after Write() the following code will be executed 
      SerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000); 
      SerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000); 
      SerialPort.BaudRate = 9600; 
      SerialPort.Parity = SerialParity.None; 
      SerialPort.StopBits = SerialStopBitCount.One; 
      SerialPort.DataBits = 8; 
      dataWriter = new DataWriter(); 
      dataReader = new DataReader(SerialPort.InputStream); 
     } 

     public async void Read() 
     { 
      /* Read data in from the serial port */ 
      const uint maxReadLength = 1024; 
      uint bytesToRead = await dataReader.LoadAsync(maxReadLength); 
      string rxBuffer = dataReader.ReadString(bytesToRead); 
      Debug.WriteLine(rxBuffer); 
     } 

     public async void Write() 
     { 
      /* Write a string out over serial */ 
      string txBuffer = "Hello Serial"; 
      dataWriter.WriteString(txBuffer); 
      uint bytesWritten = await SerialPort.OutputStream.WriteAsync(dataWriter.DetachBuffer()); 
     } 
    } 
} 

此代碼不會等待一個串口,dataWriter和DataReader初始化。所以他們永遠不會被分配到。

誰能向我解釋爲什麼它不等待串行連接?它應該如何完成?

所有幫助表示讚賞。 在此先感謝!

回答

10

你的所有async方法返回void - 這意味着他們開始執行,並且調用的代碼具有等待,直到它繼續前實際完成沒有簡單的方法。只要您使用await表達的東西,還沒有完成,異步方法將返回給調用者,已預約的延續,當awaitable完成將執行。就你而言,你只是繼續下一個陳述。

相反,你應該讓你的異步方法返回Task,並改變你的調用方法等待異步方法繼續之前完成。這是很難做到的優雅因爲在每種情況下你調用構造函數從異步方法,它可以本身並不異步。你可能要考慮使用異步靜態方法,而不是做在構造函數,它可以調用異步方法,等待他們的工作,然後調用一個實際的構造函數,並不做任何實際工作。

在進行任何詳細的更改之前,您應該仔細閱讀有關asyncawait所做的更多操作 - 嘗試在不理解它們的情況下使用它們是導致進一步問題的祕訣。

+0

感謝您的回覆。這是我第一次需要處理異步,並期待完全不同的行爲。我通過使InitSerial()成爲任務來解決問題,並等待任務的完成。 – MKFreebird

1

這是你的構造:

public SerialController() 
{ 
    InitSerial(); 
} 

它將調用具有有幾個等待(S)在他們InitSerial()方法。構造函數立即返回,沒有做任何需要的事情。然後調用這些方法:

serial.Write(); 
serial.Read(); 

但是,這些方法依賴於每一行代碼已經在InitSerial方法內執行,但顯然他們沒有。

解決這個問題的一種方法是使InitSerial不是私有的(內部或公共的),並讓它返回Task。當你調用它時,你需要等待它,以便它已經被執行完成。之後,您可以撥打serial.Write()Serial.Read()。您應該避免async void。它們僅用於事件處理。其他方法返回TaskTask<T>