다음을 통해 공유


Universal Windows Platform: Serial Class (Part one)


Introduction

In this article, we will discuss everything related to the use of SerialComunication class, included in Windows.Devices namespace. We will see how it is possible with such a class, read and send data from the serial port. At the hardware level, we will make use of Raspberry Pi2 board, Arduino Uno, temperature sensor DHT11 and a simple diode Led both wired on the Arduino Uno pin. We will manage the temperature sensor for the display of data on Raspberry, while the LED will help us to demonstrate how we can send a command from the Arduino Raspberry by SerialComunication class. All, is very simple, the purpose of the article and show how to exchange information between two devices connected with serial port.

 

Hardware required

After this brief introduction, let's move to the next step. For the realization of our circuit, we need the following hardware material:

  • Raspberry Pi2 with 10.0.10586.0 version installed on SD card, equipped with a power supply.
  • HDMI cable so as to connect the Raspberry Pi2 to a monitor.
  • Monitor with HDMI input.
  • ethernet cable.
  • Ethernet-USB 3.0 adapter
  • Breadboard, which is the necessary basis for mounting components and electrical wiring.
  • male-male and male-female jumper.
  • led diode
  • Arduino Uno
  • Power cable USB type B side Arduino Uno board and the USB type to connect the Raspberry.

Necessary software

A level software, you need:

  • Windows 10 build 10.0.10586.0 installed on pc
  • Visual Studio 2015 Update 2
  • Windows SKD 10.0.10586.0 (and the latter still included with Visual Studio 2015 update 2)
  • Arduino IDE or Visual Micro for Arduino
  • Windows 10 IoT core 10.0.10586.0 installed on SD card

 

Windows 10

Before proceeding with the creation of the two projects, namely with Visual Studio 2015 for the UWP, and the Arduino, you must install all the software mentioned above. So it will start the installation of Windows 10 that you find in this link .

 

Visual Studio 2015 update 2

Installing the operating system, and the time to install Visual Studio 2015 update2, find the download link here .

 

Arduino IDE

After installing Visual Studio 2015, and time to devote to the Arduino. As stated earlier, you can choose to avail of the IDE Arduino found at this link .

 

Visual Micro for Arduino

Alternatively, you can download and install this Plug-in that will let you create for Arduino projects directly from Visual Studio 2015. The pro you have available the intellisense for those who know, that an automatic prompter that will help and not a little when writing code. Cons and that unlike the IDE Arduino, not including debugging, if you intend to debug your application you will have to buy it separately.

 

Raspbrerry Pi2

Now that we have everything you need on our PC, and time to think about the Raspberry Pi2 card. To this link , And you can download Windows 10 IoT Core. We must, however, for the installation have to hand a micro SD of at least 8GB, then install the operating system on it, at the end insert the SD card inside the dedicated on Raspberry. To install Windows 10 IoT Core, refer to the following procedure , Which explains in a simple and comprehensive throughout the procedure. We have installed all the necessary software components, and we also all hardware components. Before turning to the creation of the projects, it is necessary to wire the electrical circuit. It is DHT11 connect the sensor and the LED diode to the Arduino board.

Electrical Circuit

Below the final circuit of our project, we realized with Fritzing , An excellent software for the realization of electrical / electronic schemes.

Figure 1: the electrical circuit.

The connections are the following:

  • Anode of the LED diode on pin 13 of the Arduino board one
  • Katodo the LED diode on the Arduino board gnd pin one
  • pin "S" of DHT11 sensor (left pin) to pin 8 of the Arduino board one
  • the central pin of the sensor DHT11, + 5V pin on the Arduino board one
  • the right of DHT11 sensor pin, the pin of the Arduino board gnd one
  • Finally, we connect on the breadboard, two black and red cables to bring power to all of the above components
  • Lastly, connect the USB cable mentioned above, including a USB port of Raspberry Py 2 with the type usb output b of the Arduino board one

These are all necessary connections, and now time to devote himself to the creation of the test project.

Test project.

We start Visual Studio 2015, on the File menu select New Project, select a universal project, and developed in C # as shown in the figure, and we call it Prova Comunicazione seriale.

Figure 2: the test project.

There will be asked which version of the build we want our media project, the following dialog leave everything unchanged and confirm with ok button.

Figure 3: The minimum version and the target of the Windows build.

In this case, we left as minimum version supported 10.0.10240, and target the 10.0.10586.

Confirmed with the OK button, we will be led in the screen named App.xaml.cs. But before you write code to do the display and management of serial communication, we need to enable the capability required, this is to be able to make use of serial device class and DeviceInformation without setting capability, we will receive an exception at runtime, sending in the application crash. In other words, the capabilities are required to declare that in our application we make use of devices and / or system functionality. To enable them, usually just a double click with the mouse on the file in Package.appxmanifest on explores solutions, but in this case it is a particular capability, we must put everything to code. In exploring solutions, we select with a click of the mouse the files mentioned before, F7 key, and we will be led in the code as shown in the figure.

Figure 4: Applications and Capabilities section of Package.appxmanifest file.

The part that interested us and that between Capabilities tag, and them we're going to enable the use of serial device and DeviceInformation Classes. Insert the following code.

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

 

After the changes, the Capabilities section should take this aspect.

Figure 5: The Package.appxmanifest files after editing

After these changes, save and close the file Package.appxmanifest. Let's take care of the graphical now. In exploring solutions, double click with the mouse on MainPage.xaml file, we will be go into the screen where we define our code using XAML GUI. To summarize briefly, the XAML language, also called declarative code, and used in different technologies, made his debut with Silverlight and WPF applications from version 3.0 of the DOTNET framework, and given the potential and was developed and still used for Mobile applications, desktops and universal as that which we will develop in this article, therefore necessary to define all the interface objects of our application. And very similar for those who know the XML and HTML syntax, and then enclosed between tags, where they are possible further customization of each individual object by means of the properties that we will see shortly. Below, I leave the link the official Microsoft documentation for those who wish to learn every detail of the XAML language. Insert the following code inside the file MainPage.xaml.

<Page
 x:Class="Prova_comunicazione_seriale.MainPage"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:local="using:Prova_comunicazione_seriale"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 mc:Ignorable="d">
 
 <Grid Background="CornflowerBlue"
  
 Margin="0,0,-104,0"> 
 <Grid.RowDefinitions> 
 <RowDefinition Height="*"/> 
 <RowDefinition Height="*"/>  
 <RowDefinition Height="*"/> 
 <RowDefinition Height="*"/>  
 </Grid.RowDefinitions>
 
 
 <Grid.ColumnDefinitions> 
 <ColumnDefinition Width="Auto"/> 
 <ColumnDefinition Width="Auto"/> 
 <ColumnDefinition Width="Auto"/> 
 <ColumnDefinition Width="Auto"/> 
 <ColumnDefinition Width="Auto"/> 
 <ColumnDefinition Width="Auto"/> 
 </Grid.ColumnDefinitions>
 
  
 <!--Riga 0-->
 <TextBlock x:Name="tbkAllarmi"
 Grid.Row="0"
 Grid.ColumnSpan="3"
 Grid.Column="0"
 HorizontalAlignment="Left"
 VerticalAlignment="Center"
 Text="Errori"/>
 
 <Button x:Name="btnSerialConnect"
 Background="AliceBlue"
 Grid.Row="0"
 Grid.Column="4"
 Content="Connect"
 Click="ButtonClick"/>
 
 <Button x:Name="btnSerialDisconnect"
 Background="AliceBlue"
 Grid.Row="0"
 Grid.Column="5"
 Content="Disconnect"
 Click="ButtonClick"/>
 
 
 <!--Riga 1-->
 <TextBlock x:Name="tbkNomeComponente"
 Grid.Row="1"
 Grid.Column="0" 
 HorizontalAlignment="Left"
 VerticalAlignment="Center"
 Text="Componete rilevato"/>
 
 <!--Riga 2-->
 <ListBox x:Name="lstSerialDevices"
 Grid.Row="2"
 Grid.ColumnSpan="6"> 
  
 <ListBox.ItemTemplate> 
 <DataTemplate> 
 <TextBlock Text="{Binding Id}"/> 
 </DataTemplate> 
 </ListBox.ItemTemplate> 
 </ListBox>
 
 
 <!--Riga 3-->
 <Button x:Name="btnAccendiled"
 Background="AliceBlue"
 Grid.Row="3"
 Grid.Column="0"
 Content="Accendi led"
 Click="ButtonClick"/>
 
 <Button x:Name="btnSpegniled"
 Background="AliceBlue"
 Grid.Row="3"
 Grid.Column="1"
 Content="Spegni led"
 Click="ButtonClick"/>
 
 <TextBlock x:Name="tbkStatusLed"
 Grid.Row="3"
 Grid.Column="2"
 VerticalAlignment="Center"
 HorizontalAlignment="Center"/>
 
 <Button x:Name="btnPulse1000ms"
 Background="AliceBlue"
 Grid.Row="3"
 Grid.Column="4"
 Content="Pulse 1000 ms"
 Click="ButtonClick"/>
 
 <Button x:Name="btnPulse2000ms"
 Background="AliceBlue"
 Grid.Row="3"
 Grid.Column="5"
 Content="Pulse 2000 ms"
 Click="ButtonClick"/> 
 </Grid> 
< /Page>

If all are done correctly, this is the screen that'll display being designers.

Figure 6: the screen MainPage.xaml file after writing the declarative code.

 

This is truly something very simple at the interface, the purpose is to demonstrate how to send and receive data via the serial port. Let us now of writing managed code, in this example we will use C #. F7 key, we will be led in the code editor, paste the following C # code.

using System; 
using System.Collections.ObjectModel; 
using System.Threading; 
using System.Threading.Tasks; 
using Windows.Devices.Enumeration; 
using Windows.Devices.SerialCommunication; 
using Windows.Storage.Streams; 
using Windows.UI.Xaml; 
using Windows.UI.Xaml.Controls;
 
// Il modello di elemento per la pagina vuota ? documentato all'indirizzo http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x410
 
namespace Prova_comunicazione_seriale 
{ 
 /// <summary> 
 /// Pagina vuota che pu? essere usata autonomamente oppure per l'esplorazione all'interno di un frame. 
 /// </summary> 
 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() 
 { 
 InitializeComponent();
 
 btnAccendiled.IsEnabled = false; 
 btnSpegniled.IsEnabled = false; 
 listOfDevices = new  ObservableCollection<DeviceInformation>(); 
 ListAvailablePorts(); 
 }
 
 
 private async void ListAvailablePorts() 
 { 
 try
 { 
 string aqs = SerialDevice.GetDeviceSelector(); 
 var dis = await DeviceInformation.FindAllAsync(aqs);
 
 for (int i = 0; i < dis.Count; i++) 
 { 
 listOfDevices.Add(dis[i]); 
 }
 
 lstSerialDevices.ItemsSource = listOfDevices; 
 btnAccendiled.IsEnabled = true; 
 btnSpegniled.IsEnabled = true; 
 lstSerialDevices.SelectedIndex = -1; 
 } 
 catch (Exception ex) 
 { 
 tbkAllarmi.Text = ex.Message; 
 } 
 }
 
 
 private async void ButtonClick(object sender, RoutedEventArgs e) 
 { 
 var buttonClicked = sender as  Button;
 
 switch(buttonClicked.Name) 
 { 
 case "btnSerialConnect": 
 SerialPortConfiguration(); 
 break;
 
 case "btnSerialDisconnect": 
 SerialPortDisconnect(); 
 break;
 
 case "btnAccendiled": 
 if (serialPort != null) 
 { 
 dataWriteObject = new  DataWriter(serialPort.OutputStream); 
 await ManageLed("2"); 
 }
 
 if (dataWriteObject != null) 
 { 
 dataWriteObject.DetachStream(); 
 dataWriteObject = null; 
 }
 
 break;
 
 case "btnSpegniled": 
 if (serialPort != null) 
 { 
 dataWriteObject = new  DataWriter(serialPort.OutputStream); 
 await ManageLed("1"); 
 }
 
 if (dataWriteObject != null) 
 { 
 dataWriteObject.DetachStream(); 
 dataWriteObject = null; 
 }
 
 break;
 
 case "btnPulse1000ms": 
 if (serialPort != null) 
 { 
 dataWriteObject = new  DataWriter(serialPort.OutputStream); 
 await ManageLed("3"); 
 }
 
 if (dataWriteObject != null) 
 { 
 dataWriteObject.DetachStream(); 
 dataWriteObject = null; 
 }
 
 break;
 
 case "btnPulse2000ms": 
 if (serialPort != null) 
 { 
 dataWriteObject = new  DataWriter(serialPort.OutputStream); 
 await ManageLed("4"); 
 }
 
 if (dataWriteObject != null) 
 { 
 dataWriteObject.DetachStream(); 
 dataWriteObject = null; 
 }
 
 break; 
 } 
 }
 
 
 private  async void SerialPortConfiguration() 
 { 
 var selection = lstSerialDevices.SelectedItems;
 
 if (selection.Count <= 0) 
 { 
 tbkAllarmi.Text = "Seleziona un oggetto per la connessione seriale!"; 
 return; 
 }
 
 DeviceInformation entry = (DeviceInformation)selection[0];
 
 try
 { 
 serialPort = await SerialDevice.FromIdAsync(entry.Id); 
 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; 
 tbkAllarmi.Text = "Porta seriale correttamente configurata!";
 
 ReadCancellationTokenSource = new  CancellationTokenSource();
 
 Listen(); 
 }
 
 catch (Exception ex) 
 { 
 tbkAllarmi.Text = ex.Message; 
 btnAccendiled.IsEnabled = false; 
 btnSpegniled.IsEnabled = false; 
 } 
 }
 
 
 private void  SerialPortDisconnect() 
 { 
 try
 { 
 CancelReadTask(); 
 CloseDevice(); 
 ListAvailablePorts(); 
 } 
 catch (Exception ex) 
 { 
 tbkAllarmi.Text = ex.Message; 
 } 
 }
 
 
 private async Task ManageLed(string value) 
 { 
 var accendiLed = value;
 
 Task<UInt32> storeAsyncTask;
 
 if (accendiLed.Length != 0) 
 { 
 dataWriteObject.WriteString(accendiLed);  
 
 storeAsyncTask = dataWriteObject.StoreAsync().AsTask();
 
 UInt32 bytesWritten = await storeAsyncTask; 
 if (bytesWritten > 0) 
 { 
 tbkAllarmi.Text = "Valore inviato correttamente"; 
 } 
 }
 
 else
 { 
 tbkAllarmi.Text = "Nessun valore inviato"; 
 } 
 }
 
 
 private async void Listen() 
 { 
 try
 { 
 if (serialPort != null) 
 { 
 dataReaderObject = new  DataReader(serialPort.InputStream);
 
 while (true) 
 { 
 await ReadData(ReadCancellationTokenSource.Token); 
 } 
 } 
 }
 
 catch (Exception ex) 
 { 
 tbkAllarmi.Text = ex.Message;
 
 if (ex.GetType().Name == "TaskCanceledException") 
 { 
 CloseDevice(); 
 }
 
 else
 { 
 tbkAllarmi.Text = "Task annullato"; 
 } 
 }
 
 finally
 { 
 if (dataReaderObject != null) 
 { 
 dataReaderObject.DetachStream(); 
 dataReaderObject = null; 
 } 
 } 
 }
 
 
 private async Task ReadData(CancellationToken cancellationToken) 
 { 
 Task<UInt32> loadAsyncTask;
 
 uint ReadBufferLength = 1024;
 
 cancellationToken.ThrowIfCancellationRequested();
 
 dataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
 
 loadAsyncTask = dataReaderObject.LoadAsync(ReadBufferLength).AsTask(cancellationToken);
 
 UInt32 bytesRead = await loadAsyncTask; 
 if (bytesRead > 0) 
 { 
 tbkStatusLed.Text = dataReaderObject.ReadString(bytesRead);  
 } 
 }
 
 
 private void  CancelReadTask() 
 { 
 if (ReadCancellationTokenSource != null) 
 { 
 if (!ReadCancellationTokenSource.IsCancellationRequested) 
 { 
 ReadCancellationTokenSource.Cancel(); 
 } 
 } 
 }
 
 
 private void  CloseDevice() 
 { 
 if (serialPort != null) 
 { 
 serialPort.Dispose(); 
 } 
 serialPort = null;
 
 btnAccendiled.IsEnabled = false; 
 btnSpegniled.IsEnabled = false; 
 listOfDevices.Clear(); 
 } 
 } 
}

Let's take a closer look at the above code. When the application starts running the constructor of the MainPage class.

It is first of all recalled method InitializeComponent (), which will handle the graphical interface for management. They are disabled the button to request power and led off. Later recalled ListAvailablePorts () method, which takes care of checking if in our case on Raspberry Pi2 are connected components. If so, we will have in listBox control, all of the components recognized Id. To click on the button btnSerialConnect, it is called the asynchronous method SerialPortConfiguration (), which deals with performing all the serial port configuration, and if all goes well, we will have a message that indicates that the configuration was successful. At this point we are ready to connect with one of the devices connected to Raspberry. It will also be recalled another method, Listen (), which will launch a Task called ReadData (). This task will listen so go read each incoming value on the serial port and display all on-screen. The Task ManageLed () is invoked to click on one of the button controls. As you can see, this task takes as input a parameter of type string, which will be used to perform a particular action on the Arduino Uno board, the Arduino board will send a confirmation of action taken, which will be intercepted by the Task ReadData (), so as to be displayed in our application. We now come to the last step, with the procedure for the execution of our example created with Visual Studio.

Compile and debug the test project

In exploring solutions, mouse click on the project name, right-click and select the "Properties" command. We will be led to another screen, where there will be a series of tabs. We order affecting the "Application" tab and "Debug" tab. On the first tab, leave everything as in the picture.

Figure 7: The Application tab.

Now for the "Debug" tab, here perform some changes, namely:

  • target device
  • ip address of the target device
  • Authentication Mode

 

On target device we set "Remote Computer".

Of ip address, we need to enter the IP address provided by Raspberry board Py 2.

Last setting, the authentication mode, insert "Universal (non-encrypted protocol).

Below the Debug settings screen.

Figure 8: the debug tab.

We are now ready to debug our application on Raspberry Py 2. F5, and if everything is done correctly, this and that'll show onscreen.

Figure 9: The test project screen.

Conclusions.

In this first part, we did an overview of the hardware necessary part, saw what software components are installed, and ended with the creation of the project and finally debugged application with Visual Studio 2015 update2. Obviously still missing the part relating to the Arduino one, the code sketches in order to exchange data between the two boards, we will see in the second and final part.