所以我一直在试验IOT串行样本和RP2,因为10月份发布了串行引脚。我正在使用windows iot serial sample。有一些我无法弄清楚的问题。
读取数据似乎不完整。我有一个arduino输出一个模拟输入读数通过串行9600波特。在windows universial app上,生病阅读一条完整的行,然后是一条不完整的行。例如:如果arduiono正在输出" 2.25"的值,则应用程序将读取一行2.25然后下一行" .25"(在该时段前面没有任何内容)。我试过在应用程序端和arduino上的延迟没有成功。
在尝试连接时,它会抛出格式化异常。有时可以点击断开连接并重新连接,它会正常工作。其他我必须重新启动arduino。
我在代码示例中思考它,因为如果我从笔记本电脑或覆盆子pi运行,我会遇到同样的问题。
这是程序的c#。我修改了一下。
// 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 SerialSample
{
public sealed partial class MainPage : Page
{
/// <summary>
/// Private variables
/// </summary>
private SerialDevice serialPort = null;
DataWriter dataWriteObject = null;
DataReader dataReaderObject = null;
private ObservableCollection<DeviceInformation> listOfDevices;
private CancellationTokenSource ReadCancellationTokenSource;
public MainPage()
{
this.InitializeComponent();
comPortInput.IsEnabled = false;
sendTextButton.IsEnabled = false;
listOfDevices = new ObservableCollection<DeviceInformation>();
ListAvailablePorts();
}
/// <summary>
/// ListAvailablePorts
/// - Use SerialDevice.GetDeviceSelector to enumerate all serial devices
/// - Attaches the DeviceInformation to the ListBox source so that DeviceIds are displayed
/// </summary>
private async void ListAvailablePorts()
{
try
{
string aqs = SerialDevice.GetDeviceSelector();
var dis = await DeviceInformation.FindAllAsync(aqs);
status.Text = "Select a device and connect";
for (int i = 0; i < dis.Count; i++)
{
listOfDevices.Add(dis[i]);
}
DeviceListSource.Source = listOfDevices;
comPortInput.IsEnabled = true;
ConnectDevices.SelectedIndex = -1;
}
catch (Exception ex)
{
status.Text = ex.Message;
}
}
/// <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
/// - Add text to rcvdText textbox to invoke rcvdText_TextChanged event
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void comPortInput_Click(object sender, RoutedEventArgs e)
{
var selection = ConnectDevices.SelectedItems;
if (selection.Count <= 0)
{
status.Text = "Select a device and connect";
return;
}
DeviceInformation entry = (DeviceInformation)selection[0];
try
{
serialPort = await SerialDevice.FromIdAsync(entry.Id);
// Disable the 'Connect' button
comPortInput.IsEnabled = false;
// 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;
// Display configured settings
status.Text = "Serial port configured successfully!\n ----- Properties ----- \n";
status.Text += "BaudRate: " + serialPort.BaudRate.ToString() + "\n";
status.Text += "DataBits: " + serialPort.DataBits.ToString() + "\n";
status.Text += "Handshake: " + serialPort.Handshake.ToString() + "\n";
status.Text += "Parity: " + serialPort.Parity.ToString() + "\n";
status.Text += "StopBits: " + serialPort.StopBits.ToString() + "\n";
// Set the RcvdText field to invoke the TextChanged callback
// The callback launches an async Read task to wait for data
rcvdText.Text = "Waiting for data...";
// Create cancellation token object to close I/O operations when closing the device
ReadCancellationTokenSource = new CancellationTokenSource();
// Enable 'WRITE' button to allow sending data
sendTextButton.IsEnabled = true;
}
catch (Exception ex)
{
status.Text = ex.Message;
comPortInput.IsEnabled = true;
sendTextButton.IsEnabled = false;
}
}
/// <summary>
/// sendTextButton_Click: Action to take when 'WRITE' button is clicked
/// - Create a DataWriter object with the OutputStream of the SerialDevice
/// - Create an async task that performs the write operation
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void sendTextButton_Click(object sender, RoutedEventArgs e)
{
try
{
if (serialPort != null)
{
// Create the DataWriter object and attach to OutputStream
dataWriteObject = new DataWriter(serialPort.OutputStream);
//Launch the WriteAsync task to perform the write
await WriteAsync();
}
else
{
status.Text = "Select a device and connect";
}
}
catch (Exception ex)
{
status.Text = "sendTextButton_Click: " + ex.Message;
}
finally
{
// Cleanup once complete
if (dataWriteObject != null)
{
dataWriteObject.DetachStream();
dataWriteObject = null;
}
}
}
/// <summary>
/// WriteAsync: Task that asynchronously writes data from the input text box 'sendText' to the OutputStream
/// </summary>
/// <returns></returns>
private async Task WriteAsync()
{
Task<UInt32> storeAsyncTask;
if (sendText.Text.Length != 0)
{
// Load the text from the sendText input text box to the dataWriter object
dataWriteObject.WriteString(sendText.Text);
// Launch an async task to complete the write operation
storeAsyncTask = dataWriteObject.StoreAsync().AsTask();
UInt32 bytesWritten = await storeAsyncTask;
if (bytesWritten > 0)
{
status.Text = sendText.Text + '\n';
status.Text += "Bytes written successfully!";
}
sendText.Text = "";
}
else
{
status.Text = "Enter the text you want to write and then click on 'WRITE'";
}
}
/// <summary>
/// rcvdText_TextChanged: Action to take when text is entered in the 'Read Data' textbox
/// - Create a DataReader object
/// - Create an async task to read from the SerialDevice InputStream
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void rcvdText_TextChanged(object sender, TextChangedEventArgs e)
{
try
{
if (serialPort != null)
{
dataReaderObject = new DataReader(serialPort.InputStream);
await ReadAsync(ReadCancellationTokenSource.Token);
}
}
catch (Exception ex)
{
if (ex.GetType().Name == "TaskCanceledException")
{
status.Text = "Reading task was cancelled, closing device and cleaning up";
CloseDevice();
}
else
{
status.Text = ex.Message;
}
}
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 ReadAsync(CancellationToken cancellationToken)
{
Task<UInt32> loadAsyncTask;
uint ReadBufferLength = 128;
// 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;
// Create a task object to wait for data on the serialPort.InputStream
loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken);
// Launch the task and wait
UInt32 bytesRead = await loadAsyncTask;
if (bytesRead > 0)
{
rcvdText.Text = dataReaderObject.ReadString(bytesRead);
status.Text = bytesRead.ToString();
//status.Text = "\nBytes read successfully!";
}
}
/// <summary>
/// CancelReadTask:
/// - Uses the ReadCancellationTokenSource to cancel read operations
/// </summary>
private 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;
}
}
}
}
这是Arduino Sketch:
void setup()
{
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop()
{
// read the input on analog pin 0:
float sensorValue = analogRead(A3);
sensorValue = (sensorValue / 1023) * 4.30;
// print out the value you read:
Serial.print(sensorValue);
Serial.println("");
delay(1); // delay in between reads for stability
}
Here是显示问题的快速视频的链接。并且你会知道它第一次连接视频hahaha。
提前感谢所有帮助和建议。
答案 0 :(得分:1)
我精简了代码。我相信原始代码中的取消令牌可能是问题的一部分。现在它每次连接和读取:)如果有人想尝试它,这是代码。
using System;
using System.Collections.Generic;
using System.IO;
using Windows.UI.Popups;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using System.Collections.ObjectModel;
using Windows.Devices.Enumeration;
using Windows.Devices.SerialCommunication;
using Windows.Storage.Streams;
using System.Threading;
using System.Threading.Tasks;
namespace Serial_Data_Read
{
public sealed partial class MainPage : Page
{
private SerialDevice serialPort = null;
DataReader dataReaderObject = null;
public uint BytesReceived { get; }
public MainPage()
{
this.InitializeComponent();
ListAvailablePorts();
}
private async void ListAvailablePorts()
{
try
{
string aqs = SerialDevice.GetDeviceSelector();
var dis = await DeviceInformation.FindAllAsync(aqs);
var selectedPort = dis.First();
serialPort = await SerialDevice.FromIdAsync(selectedPort.Id);
serialPort.ReadTimeout = TimeSpan.FromMilliseconds(1000);
serialPort.BaudRate = 9600;
serialPort.Parity = SerialParity.None;
serialPort.StopBits = SerialStopBitCount.One;
serialPort.DataBits = 8;
infoBox.Text = "Serial port configured successfully!\n ----- Properties ----- \n";
infoBox.Text += "BaudRate: " + serialPort.BaudRate.ToString() + "\n";
infoBox.Text += "DataBits: " + serialPort.DataBits.ToString() + "\n";
infoBox.Text += "Handshake: " + serialPort.Handshake.ToString() + "\n";
infoBox.Text += "Parity: " + serialPort.Parity.ToString() + "\n";
infoBox.Text += "StopBits: " + serialPort.StopBits.ToString() + "\n";
data.Text = "configuring port";
}
catch (Exception ex)
{
infoBox.Text = "OOps, Something went wrong! \n" + ex.Message ;
}
}
private async void data_TextChanged(object sender, TextChangedEventArgs e)
{
dataReaderObject = new DataReader(serialPort.InputStream);
try
{
var bytesRecieved = await dataReaderObject.LoadAsync(128);
if (bytesRecieved > 0)
{
data.Text = dataReaderObject.ReadString(bytesRecieved).Trim();
}
}
catch (Exception ex)
{
data.Text = ex.Message;
ListAvailablePorts();
}
finally
{
if (dataReaderObject != null)
{
dataReaderObject.DetachStream();
dataReaderObject = null;
}
}
}
}
}
和xaml ......
<Page
x:Class="Serial_Data_Read.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Serial_Data_Read"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Width="800" Height="480">
<Grid Background="{ThemeResource AppBarItemDisabledForegroundThemeBrush}">
<TextBox x:Name="infoBox" HorizontalAlignment="Left" Margin="10,288,0,0" TextWrapping="Wrap" Text="Waiting to establish a connection" VerticalAlignment="Top" Height="182" Width="382"/>
<TextBox x:Name="data" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Waiting for data" VerticalAlignment="Top" Height="154" Width="780" TextChanged="data_TextChanged" />
</Grid>