2017-01-15 23 views
1

Я пытаюсь создать класс, который инициализирует последовательную связь между малиной и ардуино. Класс также должен быть способен читать и писать через установленное последовательное соединение.Почему мой асинхронный метод не ждет «serialPort = ждет 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); 
} 

Я добавил возможность последовательной связи к Package.appxmanifest.

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

До сих пор все работает отлично. Малина успешно отправляет и получает сообщение от Ардуино на другом конце.

Теперь я стараюсь выполнять эти шаги отдельно. Сначала инициализируйте последовательное соединение, поэтому функции чтения и записи могут использоваться всякий раз, когда они необходимы в приложении.

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()); 
     } 
    } 
} 

Этот код не ждать SerialPort, dataWriter и DataReader инициализацию. Поэтому им никогда не назначают.

Может ли кто-нибудь объяснить мне, почему он не ждет последовательного соединения? И как это должно быть сделано?

Вся помощь приветствуется. Спасибо заранее!

ответ

10

Все ваши async методы возвращают void - это означает, что они начинают выполняться, и вызывающий код не имеет простого способа ожидания, пока не будет фактически завершена, прежде чем продолжить. Как только ваше использование выражения await на чем-то, что еще не завершено, метод async вернется к вызывающему абоненту, запланировав продолжение, которое будет выполняться при завершении работы awaitable. В вашем случае вы просто продолжаете следующее утверждение.

Вместо этого вы должны сделать свои методы async возвратом Task и изменить свой метод вызова, чтобы дождаться завершения асинхронного метода до продолжения. Трудно сделать элегантно, потому что в каждом случае вы вызываете методы async из конструкторов, которые сами по себе не могут быть асинхронными. Возможно, вы захотите рассмотреть использование статических методов async вместо выполнения работы в конструкторах, которые могут вызвать методы async, ожидая их, а затем вызвать фактический конструктор, который не выполняет никакой реальной работы.

Прежде чем перейти к любым подробным изменениям, вы должны действительно узнать больше о том, что делают async и await do - пытаясь использовать их, не понимая их, является рецептом для дальнейших проблем.

+0

Спасибо за ответ. Это был первый раз, когда мне приходилось заниматься асинксом, и я ожидал совершенно другого поведения. Я исправил проблему, выполнив задачу InitSerial() и дождавшись завершения задачи. – MKFreebird

1

Это ваш конструктор:

public SerialController() 
{ 
    InitSerial(); 
} 

Он называет InitSerial() метод, который имеет имеет несколько ждать (ы) в них. Конструктор сразу возвращается, не делая все, что нужно.Тогда вы называете эти методы:

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

Но эти методы зависят от каждой строки кода были выполнены в рамках метода InitSerial, но очевидно, что они не имеют.

Одним из способов решения этой проблемы было бы сделать InitSerial не приватным (внутренним или общедоступным) и вернуть его Task. Когда вы его вызываете, вам нужно подождать, чтобы он был выполнен до завершения. Впоследствии вы можете позвонить serial.Write() и Serial.Read().

Вы должны избегать async void. Они предназначены только для обработки событий. Для других методов возвращает Task или Task<T>.

 Смежные вопросы

  • Нет связанных вопросов^_^