Introduzione.

In questa serie di articoli, faremo uso di tecnologie che discostano un po’ da ciò che solitamente si vede, ossia applicativi web con asp net per esempio, o applicazioni di tipo gestionali, insomma, il classico sviluppo di applicazioni comuni. Entreremo in un mondo completamente differente, possiamo dire che in parte a che fare con l’internet of things, l’internet delle cose e in parte no. Parleremo di automazione industriale e gestione macchine utensili a plc e non. Vi chiederete: ma che cosa c’entra tutto ciò con lo sviluppo, con Microsoft e con Visual Studio ? In parte e vero e in parte no. Se e vero che parliamo di altri settori, e anche vero che possiamo tranquillamente con Visual Studio, creare interfacce e applicazioni che vanno ad interagire con una macchina utensile e/o un sistema di automazione, inizieremo con quali sono gli strumenti necessari per creare un sistema che andrà ad interagire con un plc Siemens. Proseguiremo creando un progetto con tecnologia WPF. Nel prossimo articolo, sarà creato il progetto con il TIAPORTAL V13, ed eseguiremo il testo dell’applicazione di esempio.

Strumenti necessari.

Di seguito, vediamo cosa occorre come strumenti e software per realizzare quanto descritto precedentemente. Cominciamo dalla parte Microsoft.

Questa e tutta la parte Microsoft. Veniamo ora alla parte Siemens.

  • Totally integated Automation (TIA Portal V13), sarebbe ne più ne meno, l’ide di sviluppo della Siemens con la quale dobbiamo creare tutto il programma plc. Su quest’ultimo si dovrebbe parlare tantissimo, ossia come va utilizzato, quali sono i principi per una buona logica plc, e come apprendere i linguaggi di sviluppo dedicati. Noi daremo qualche dritta necessaria alla creazione del progetto, ma invito per un buon apprendimento ad accedere al sito ufficiale, dove vi saranno tutte le informazioni necessarie per l’apprendimento.

A livello software, abbiamo tutto il necessario, vediamo cosa occorre avere a livello Hardware.

  • Per eseguire al meglio il progetto di esempio, l’ideale è avere come nel mio caso un plc, farò uso della cpu 1211C, parte della famiglia dei prodotti Siemens S71200.
  • Un alimentatore che fornisca una tensione di 24v dc e corrente erogabile di almeno 2 ampere.
  • Cavo patch di rete RJ45 (non incrociato)


Link per i prodotti Siemens.

Lascio brevemente i link necessari per i prodotti Siemens. Da questo link, è possibile scaricare la versione trial del TIAPORTAL V13, e per coloro che non anno un plc, possono scaricare gli emulatori di cpu della famiglia S71200, installarli così da poter eseguire l’emulazione della cpu senza avere necessariamente un plc fisico a casa. in fndo alla pagina troverete i file da scaricare e installare. Altra cosa, per chi non usa un plc fisico, e necessario installare NetToPlcSim, questo per emulare una connessione di rete tra plc e l’interfaccia che creeremo successivamente.


Creazione del progetto con Visual Studio.

Arrivati a questo punto, non ci resta che creare il progetto di esempio partendo da Visual Studio. Una volta scaricato e installato Visual Studio , lo avviamo e creiamo un progetto WPF intitolato S71200 TEST, come da immagine.

IMMAGINE 1

Immagine 1: creazione del progetto WPF.


Creato il progetto, non ci resta che aggiungere due button, una casella di testo e un controllo TextBlock. I button serviranno per impostare a true e false una variabile plc, ovvero un bit, che se vogliamo paragonarlo a net e C# si tratta di una variabile di tipo bool. La casella di testo, serve per immettere il valore che vogliamo impostare alla variabile plc, infine il controllo TextBlock, servirà per visualizzare il valore attuale/impostato della variabile plc. Copiamo nel nostro progetto il codice xaml seguente.


<Window x:Class="S71200_TEST.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:S71200_TEST"
         mc:Ignorable="d"
         Title="S71200 TEST" Height="350" Width="525">
     <Grid>
         <Grid.RowDefinitions>
             <RowDefinition Height="20"/>           
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="Auto"/>
             <RowDefinition Height="*"/>
             <RowDefinition Height="Auto"/>           
         </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
             <ColumnDefinition Width="*"/>
             <ColumnDefinition Width="*"/>
             <ColumnDefinition Width="50"/>
             <ColumnDefinition Width="Auto"/>
             <ColumnDefinition Width="*"/>
             <ColumnDefinition Width="*"/>           
         </Grid.ColumnDefinitions>

        <TextBlock Grid.Row="1" Grid.Column="1" x:Name="tbkTipoVariabile" Text="IMPOSTA BIT"/>
         <TextBox Grid.Row="1" Grid.Column="2" x:Name="tbxImpostaVariabile"/>

        <TextBlock Grid.Row="2" Grid.Column="1" x:Name="tbkValoreVariabile" Text="VALORE ATTUALE"/>
         <TextBlock Grid.Row="2" Grid.Column="2" x:Name="tbkValore"/>

        <Button Grid.Row="4" Grid.Column="1" x:Name="btnSetBit" Content="SET BIT" Click="btnSetBit_Click"/>
         <Button Grid.Row="4" Grid.Column="4" x:Name="btnRESetBit" Content="SET BIT" Click="btnRESetBit_Click"/>       
     </Grid>
</Window>

Dopo l’inserimento del codice, dovremmo avere l’interfaccia come da figura.

IMMAGINE 2

Immagine 2: creazione interfaccia del progetto WPF.


Come detto, si tratta di un semplice esempio, man mano che andiamo avanti, lo arricchiremo con tutte le funzionalità della libreria S7 NET, così da avere alla fine un progetto funzionale che possiamo poi in futuro ampliarlo ulteriormente secondo nostre esigenze. Andiamo ora ad aggiungere come detto mediante nuget, il riferimento alla libreria S7 NET. In esplora soluzioni, andiamo a selezionare la voce Riferimenti, tasto destro del mouse e selezioniamo:

  • Gestisci pacchetti Nuget.

Nella sezione sfoglia digitiamo S7NET, ed ecco che nuget toverà per noi l’estensione che abbiamo chiesto.


IMMAGINE 3

Immagine 3: Ricerca della libreria S7NET su nuget.


Una volata trovata la libreria, la installiamo facendo click con il mouse sul button Installa. Dopo l’istallazione, siamo ora pronti per implementare tutte le funzionalità all’interno del progetto di prova. Torniamo su Visual Studio 2015, e accediamo all’editor di codice C#. La prima cosa da fare, e includere nella classe MainWindow.cs il namespace  S7.NET, come da codice seguente.

/*NameSpace di terze parti*/
using S7.Net;

Eseguita l’importazione del namespace, possiamo scrivere il codice necessario. Come prima cosa, dobbiamo aprire la connessione al plc alla quale vogliamo collegarci, questo avviene creando una nuova istanza della classe S7NET.

        Plc _S71200 = new Plc(CpuType.S71200, "192.168.0.25", 0, 1);


Il codice precedente, crea un nuovo oggetto S7NET, dove dobbiamo implementarne gli argomenti richiesti dal suo costruttore, ossia:

  • CpuType, la famiglia alla quale appartiene il plc, nel nostro caso si tratta di una cpu serie S71200.
  • L’indirizzo ip della cpu, vedremo come andare ad impostarlo nel successivo articolo, facendo uso del software TIAPORTAL V13 Siemens.
  • Il terzo parametro e il rack dove viene posta la cpu, di default e zero, anche perché nel nostro caso di singola stazione plc, il rack può essere uno solo.
  • Ultimo parametro la stazione di posizione del plc, da lasciare per S71200 a 1.

Ora che abbiamo creato l’oggetto di tipo S7NET, è necessario aprire la connessione Ethernet verso il plc, per fare ciò va implementato il metodo Open() come segue.

            _S71200.Open();

Queste sono le istruzioni di codice minime per poter comunicare con il plc S71200 e per qualsiasi altro che e supportato dalla libreria S7NET. Andiamo ora a scrivere il codice per il set/reset del bit. Abbiamo definito nell’interfaccia due button, il primo imposta a true e l’altro reimposta a false il tutto, una TextBox dove andremo a scrivere il valore da impostare, un TextBlock che visualizzerà lo stato del bit. Di seguito il codice C# completo.

using System.Windows;

/*NameSpace di terze parti*/
using S7.Net;

namespace S71200_TEST
{
     /// <summary>
     /// Logica di interazione per MainWindow.xaml
     /// </summary>
     public partial class MainWindow : Window
     {
         Plc _S71200 = new Plc(CpuType.S71200, "192.168.0.25", 0, 1);

        public MainWindow()
         {
             InitializeComponent();
             /*Apro la comunicazione con il plc*/
             _S71200.Open();
         }

        private void btnSetBit_Click(object sender, RoutedEventArgs e)
         {
             /*Se il plc è connesso*/
             if (_S71200.IsConnected)
             {
                 /*Vado a leggere il valore del bit DBX0.0 sul blocco dati DB1*/
                 bool uscita = (bool)_S71200.Read("DB1.DBX0.0");

                /*Se il valore del bit e false*/
                 if (uscita.Equals(false))
                 {
                     /*Imposto a true il bit DBX0.0*/
                     _S71200.Write("DB1.DBX0.0", true);
                     /*Visualizzo lo stato attuale sull'interfaccia*/
                     tbkValore.Text = uscita.ToString();
                 }
             }
         }

        private void btnRESetBit_Click(object sender, RoutedEventArgs e)
         {
             /*Se il plc è connesso*/
             if (_S71200.IsConnected)
             {
                 /*Vado a leggere il valore del bit DBX0.0 sul blocco dati DB1*/
                 bool data1 = (bool)_S71200.Read("DB1.DBX0.0");

                /*Se il valore del bit e true*/
                 if (data1.Equals(true))
                 {
                     /*Imposto a false il bit DBX0.0*/
                     _S71200.Write("DB1.DBX0.0", false);
                     /*Visualizzo lo stato attuale sull'interfaccia*/
                     tbkValore.Text = data1.ToString();
                 }
             }
         }
     }
}


E buona norma, prima di eseguire qualunque operazione, verificare se il plc e connesso con la nostra interfaccia, onde evitare malfunzionamenti con conseguente crash dell’applicazione, perché in qualunque momento o per qualunque motivo può cadere la connessione ethernet.

Scritto il codice, tasto F5 per eseguire il debug del progetto, se tutto è stato scritto correttamente, questo e ciò che dobbiamo visualizzare.


IMMAGINE 4

Immagine 4: L’interfaccia durante il debug.


 Conclusione.

In questa prima parte, è stata fatta una breve introduzione su cosa e come creare un applicazione che possa tramite Visual Studio e la libreria S7NET interagire con un plc della famiglia S71200 Siemens, abbiamo creato una semplice interfaccia e implementato il codice C# in un progetto WPF. Nel prossimo articolo, vedremo come configurare il plc, come programmarlo per metterlo in condizioni di comunicare tramite la libreria S7NET con l’interfaccia creata con Visual Studio 2015.


Introduzione.

Nel precedente articolo che trovate a questo link, abbiamo discusso tutto ciò che riguarda l’utilizzo della Classe SerialComunication, inclusa nel namespace Windows.Devices. In questa seconda e ultima parte, creeremo un progetto di prova con Visual Micro, un Plug-in installabile per poter programmare le schede della famiglia Arduino direttamente da Visual Studio. Alla fine del primo articolo abbiamo creato l’interfaccia grafica e creato il codice per la gestione della comunicazione seriale, con il seguente risultato finale.

WP_20160523_21_49_40_Pro

Figura 2: il progetto finale creato con Visual Studio 2015.

Progetto di prova.

Avviamo Visual Studio 2015, dal menù file selezioniamo nuovo progetto, selezioniamo dai modelli installati la sezione C++  come mostrato in figura, e lo denominiamo Test comunicazione seriale.

Figura 1

Figura 2: il progetto di prova con Visual Micro.

Confermiamo con Ok, e saremo condotti nell’editor di codice come visibile in figura.

Figura 3

Figura 3: il file TestComunicazioneSeriale.ino con Visual Micro.

Siamo a questo punto pronti per scrivere un breve esempio di codice per le schede Arduino. Il vantaggio di utilizzare Visual Micro da un mio punto di vista, e la comodità di avere un intellisense che semplifica non poco la scrittura del codice, suggerendo man mano i metodi e/o proprietà al momento della digitazione di un determinato oggetto. Altra cosa non da poco, quella di eseguire il debug del nostro codice a differenza dell’ide Arduino classico, dove nessuna delle due cose e disponibile. Da evidenziare una cosa: il Debugger per Visual Micro non e incluso di default, ma va acquistato separatamente, avete tuttavia una trial dove e possibile provarlo prima dell’acquisto se lo si ritiene opportuno. Detto questo, scriviamo ora il codice che svolge le seguenti operazioni:

  1. Spegnimento Led con comando denominato 1.
  2. Accensione Led con comando denominato 2.
  3. Pulse 1 secondo Led con comando denominato 3.
  4. Pulse 2 secondi Led con comando denominato 4.

E veramente molto semplice quello che faremo, e una scelta voluta, semplicemente per far capire come funziona la comunicazione seriale tra Arduino e Raspberry pi2, ovvio si può fare tanto ma tanto di più,  ma lo scopo dell’articolo e quello di spiegare il funzionamento senza entrare in cose o argomenti particolari. Scriviamo ora il codice C++ seguente e ne commenteremo poi tutte le fasi.

/*
  Name:        TestComunicazioneSeriale.ino
  Created:    07/08/2016 14:43:27
  Author:    Carmelo La Monica
*/


char incomingByte = '0';   // for incoming serial data
int ledPin = 13;

// the setup function runs once when you press reset or power the board
void setup()
{
    Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
    pinMode(ledPin, OUTPUT);
}

// the loop function runs over and over again until power down or reset
void loop()
{

    // send data only when you receive data:
    if (Serial.available() > 0)
    {
         // read the incoming byte:
        incomingByte = Serial.read();
    }

    if (incomingByte == '1')
    {
        Serial.println("LedOff");
        digitalWrite(ledPin, LOW);    // sets the LED off    
        incomingByte = '0';
    }

    if (incomingByte == '2')
    {
        Serial.println("LedOn");
        digitalWrite(ledPin, HIGH);   // sets the LED on
        incomingByte = '0';
    }

    if (incomingByte == '3')
    {
        Serial.println("LedOn");
        digitalWrite(ledPin, HIGH);   // sets the LED on
        delay(1000);                  // waits for a second           

        Serial.println("LedOff");
        digitalWrite(ledPin, LOW);    // sets the LED off
        delay(1000);
    }

    if (incomingByte == '4')
    {
        digitalWrite(ledPin, HIGH);   // sets the LED on
        Serial.println("LedOn");
        delay(2000);                  // waits for a second                  

        digitalWrite(ledPin, LOW);    // sets the LED off
        Serial.println("LedOff");
        delay(2000);
    }
}

Analiziamo il codice appena scritto. Definiamo due variabili:

char incomingByte = '0';   // for incoming serial data
int ledPin = 13;

La prima di tipo char, dove andremo a verificare i valori, che possono essere da 1 a 4 come scritto precedentemente. La seconda e la variabile int ledPin, ossia dove andremo a collegare il led, per la precisione sul pin 13 della scheda Arduino Uno.

void setup()
{
    Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
    pinMode(ledPin, OUTPUT);
}

Nel metodo setup(), che viene eseguito una sola volta, inizializziamo la comunicazione seriale con una baudrate di 9600 bit/s e impostiamo la variabile ledPin come un uscita (OUTPUT)con l’istruzione pinMode, così da dare un valore di tensione quando da codice la imposteremo ad 1 accendendo in questo modo il Led.

// the loop function runs over and over again until power down or reset
void loop()
{

    // send data only when you receive data:
     if (Serial.available() > 0)
     {
         // read the incoming byte:
         incomingByte = Serial.read();
     }

    if (incomingByte == '1')
     {
         Serial.println("LedOff");
         digitalWrite(ledPin, LOW);    // sets the LED off    
         incomingByte = '0';
     }

    if (incomingByte == '2')
     {
         Serial.println("LedOn");
         digitalWrite(ledPin, HIGH);   // sets the LED on
         incomingByte = '0';
     }

    if (incomingByte == '3')
     {
         Serial.println("LedOn");
         digitalWrite(ledPin, HIGH);   // sets the LED on
         delay(1000);                  // waits for a second           

        Serial.println("LedOff");
         digitalWrite(ledPin, LOW);    // sets the LED off
         delay(1000);
     }

    if (incomingByte == '4')
     {
         digitalWrite(ledPin, HIGH);   // sets the LED on
         Serial.println("LedOn");
         delay(2000);                  // waits for a second                  

        digitalWrite(ledPin, LOW);    // sets the LED off
         Serial.println("LedOff");
        delay(2000);
    }
}

Nel metodo loop() che viene eseguito in maniera continua, utilizziamo una serie di istruzioni if, andando a comparare il valore della variabile incomingByte. Come e possibile osservare, ci sono quattro costrutti if tutti con una condizione, 1,2,3 o 4. Tornando per un attimo al progetto creato nella prima parte, abbiamo assegnato ad ogni button dell’interfaccia un valore che sarà inviato alla porta seriale dopo il click si di essi, per precisone:

  1. Tasto “Spegni Led” scriverà valore ‘1’ sulla porta seriale.
  2. Tasto “Accendi Led” scriverà valore ’2’ sulla porta seriale.
  3. Tasto “Pulse 1000 ms” scriverà valore ‘3’ sulla porta seriale.
  4. Tasto “Pulse 2000 ms” scriverà valore ‘4’ sulla porta seriale.

Il valore inviato dall’interfaccia sulla Raspberry Pi2 e Windows 10 IoT, sarà letto nel metodo loop() del programma sulla scheda Arduino uno, inizierà il confronto dei costrutti if, se uno dei quattro soddisfa la condizione, sarà eseguito il codice al suo interno. Supponiamo che si faccia click sul pulsante “Pulse 1000 ms”, sarà inviato il valore ‘3’ sulla porta seriale, e sarà soddisfatta sul codice C++ Arduino la seguente condizione.

    if (incomingByte == '3')
     {
        Serial.println("LedOn");
        digitalWrite(ledPin, HIGH);   // sets the LED on
        delay(1000);                  // waits for a second           

        Serial.println("LedOff");
        digitalWrite(ledPin, LOW);    // sets the LED off
        delay(1000);
    }

A questo punto incomingByte avrà valore ‘3’ per cui avremo un lampeggio con campionatura di un secondo del led, questo grazie all’istruzione delay(1000), che sta a significare una pausa di un secondo. Tutto continuerà così fino a quando non daremo un altro comando dell’interfaccia Windows 10, se facessimo click sul pulsante “Spegni Led”, sarà eseguita la prima condizione if sul codice C++ Arduino, perché incomingByte avrà valore ‘1’, spegnendo così il Led se osserviamo il codice precedente.

Test del progetto.

Di seguito un video che dimostra tutto ciò che abbiamo letto e affrontato in questi due articoli. Un video vale a volte più di mille righe di testo e/o parole. Trovare il video a questo link.

Conclusioni.

In questa seconda parte, abbiamo completato e dimostrato con un esempio semplicissimo in che modo possono comunicare via seriale una scheda Raspberry Pi2 con installato Windows IoT core e una scheda Arduino Uno. Abbiamo visto la gestione del progetto con Visual Studio e un applicazione di tipo Universal nella prima parte, concludendo poi con la seconda parte creando un esempio con Visual Micro, e visto in maniera pratica mediante video il funzionamento finale del progetto. Ora tocca a voi e buon coding Smile.


Introduzione.

In questo articolo, sarà discusso tutto ciò che riguarda l’utilizzo della Classe SerialComunication, inclusa nel namespace Windows.Devices. Vedremo in che modo è possibile con tale classe, leggere e inviare dati dalla porta seriale. A livello hardware, faremo uso della scheda Raspberry Pi2, Arduino Uno, più un sensore di temperatura DHT11 e un semplice Diodo Lied entrambi cablati sui pin della scheda Arduino Uno. Gestiremo il sensore di temperatura per la visualizzazione dei dati sulla Raspberry, mentre il led ci servirà per dimostrare in che modo possiamo inviare un comando dalla Raspberry ad Arduino mediante la classe SerialComunication. Di per se, e tutto decisamente semplice, lo scopo dell’articolo e dimostrare come poter scambiare informazioni tra due device connessi mediante la porta seriale.

Hardware necessario.

Dopo questa breve introduzione, passiamo allo step successivo. Per la realizzazione del nostro circuito, abbiamo bisogno del seguente materiale hardware:

  • Raspberry Pi2 con installata la versione 10.0.10586.0  su sd card , dotata di cavo di alimentazione.
  • Cavo Hdmi così da connettere la Raspberry Pi2 a un monitor.
  • Monitor dotato di ingresso HDMI.
  • Cavo ethernet.
  • Adattatore ethernet-USB 3.0
  • Breadboard, ovvero la base necessaria per il montaggio componenti e cablaggio elettrico.
  • Jumper maschio-maschio e maschio-femmina.
  • Diodo led
  • Scheda Arduino Uno
  • Cavo di alimentazione usb tipo B lato scheda Arduino Uno e usb tipo la per la connessione sulla Raspberry.

Software necessario.

A livello Software, sono necessari:

  • Windows 10 build 10.0.10586.0 installata su pc
  • Visual Studio 2015 Update 2
  • Windows SKD 10.0.10586.0 (quest’ultimo e comunque incluso con VisualStudio 2015 update 2.
  • Ide Arduino o Visual Micro for Arduino
  • Windows 10 IoT core 10.0.10586.0 installato su sd card

Windows 10.

Prima di procedere con la creazione dei due progetti, ossia quello con Visual Studio 2015 per le UWP, e quello per Arduino, è necessario installare tutti i software indicati precedentemente. Per cui si partirà dall’installazione di Windows 10 che trovate a questo link.

Visual Studio 2015 update 2.

Installato il sistema operativo, e il momento di installare Visual Studio 2015 update2, trovate il link per il download qui.

Ide Arduino.

Terminata l’installazione di Visual Studio 2015, e l’ora di dedicarsi ad Arduino. Come specificato in precedenza, potete scegliere se avvalervi dell’ide Arduino che trovate a questo link.

Visual Micro for Arduino.

In alternativa, è possibile scaricare ed installare questo plug-in che vi permetterà di creare progetti per Arduino direttamente da Visual Studio 2015. Il pro che avete a disposizione l’intellisense per chi lo conosce, ossia un suggeritore automatico che vi aiuterà e non poco durante la scrittura del codice. Il contro e che a differenza dell’ide Arduino, non e incluso il debug, se intendete debuggare le vostre applicazioni dovrete acquistarlo separatamente.

Raspbrerry Pi2.

Ora che abbiamo installato tutto il necessario sul nostro pc, e ora di pensare alla scheda Raspberry Pi2. A questo link, e possibile scaricare Windows 10 IoT Core. Dobbiamo però, per l’installazione avere a portata di mano una micro sd di almeno 8gb, quindi eseguire l’installazione del sistema operativo su di essa, al termine inserire la sd card all’interno dell’alloggiamento dedicato sulla Raspberry. Per l’installazione di Windows 10 Iot Core, rimando alla seguente procedura, che spiega in maniera semplice ed esaustiva tutto il procedimento.  Abbiamo installato tutti i componenti software necessari, e abbiamo anche tutta la componentistica hardware. Prima di dedicarci alla creazione dei progetti, è necessario cablare il circuito elettrico. Si tratta di collegare il sensore DHT11 e il diodo Led alla scheda Arduino.

Circuito elettrico.

Qui di seguito il circuito finale del nostro progetto, realizzato con Fritzing , un ottimo software per la realizzazione di schemi elettrici/elettronici.

Figura 1

Figura 1: il circuito elettrico.

I collegamenti sono i seguenti:

  • Anodo del diodo led sul pin 13 della scheda Arduino uno
  • Katodo del diodo led sul pin gnd della scheda Arduino uno
  • il pin “S” del sensore DHT11, (pin a sinistra) sul pin 8 della scheda Arduino uno
  • il pin centrale del sensore DHT11, sul pin +5v della scheda Arduino uno
  • il pin di destra del sensore DHT11, sul pin gnd della scheda Arduino uno
  • Infine colleghiamo sulla breadboard, due cavi di colore rosso e nero in modo da portare l’alimentazione a tutti i componenti precedenti
  • Ultima cosa, colleghiamo il cavo usb menzionato in precedenza, tra una porta usb della Raspberry pi2 con l’uscita usb tipo b della scheda Arduino uno

Questi sono tutti i collegamenti necessari, e giunto ora il momento di dedicarsi alla creazione del progetto di prova.

Progetto di prova.

Avviamo Visual Studio 2015, dal menù file selezioniamo nuovo progetto, selezioniamo un progetto di tipo universale e sviluppato in C#  come mostrato in figura, e lo denominiamo Prova comunicazione seriale.

Figura 2

Figura 2: il progetto di prova.

Ci verrà chiesto quale versione della build vogliamo che il nostro progetto supporti, alla seguente finestra di dialogo lasciamo tutto inalterato e confermiamo con tasto ok.

Figura 3

Figura 3: la versione minima e quella di target della build di Windows.

In questo caso, abbiamo lasciato come versione minima supportata la 10.0.10240, e quella di destinazione la 10.0.10586.

Confermato con il tasto ok, saremo condotti nella schermata denominata App.xaml.cs. Ma prima di scrivere codice per la parte grafica e per la gestione della comunicazione seriale, dobbiamo abilitare la capability necessaria, questo per far si di poter fare uso della classe SerialDevice e DeviceInformation, senza l’impostazione delle capability, riceveremo un eccezione a Runtime, mandando in crash l’applicativo. In altre parole, le capability sono necessarie per dichiarare che nella nostra applicazione facciamo uso di dispositivi e/o funzionalità di sistema. Per abilitarle, solitamente basta un doppio click con il mouse sul file in esplora soluzioni Package.appxmanifest, ma in questo caso trattandosi di una capability particolare, dobbiamo inserire tutto da codice. In esplora soluzioni, selezioniamo con un click del mouse il file menzionate prima, tasto F7 e saremo condotti nell’editor di codice come visibile in figura.

Figura 4

Figura 4: la sezione Applications e Capabilities del file Package.appxmanifest.


La parte che interessa e noi e quella tra i tag Capabilities, e li che andremo ad abilitare l’utilizzo delle Classi SerialDevice e DeviceInformation. Inseriamo il codice che segue.

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

Dopo le modifiche, la sezione Capabilities deve assumere questo aspetto.

Figura 5

 Figura 5: il file Package.appxmanifest dopo la modifica

Dopo queste modifiche, salviamo e chiudiamo il file Package.appxmanifest. Occupiamoci adesso dell’interfaccia grafica. In esplora soluzioni, doppio click con il mouse sul file MainPage.xaml, saremo condotti nella schermata dove dovremo definire mediante codice xaml la nostra interfaccia grafica. Per riassumere brevemente, il linguaggio xaml, detto anche codice dichiarativo, e utilizzato in diverse tecnologie, ha fatto il suo esordio con applicazioni Silverlight e Wpf dalla versione 3.5 del dotnet framework, e viste la potenzialità e stato evoluto e utilizzato tutt’ora anche per applicazioni mobile, desktop e universali come quella che svilupperemo in questo articolo, necessario quindi per definire tutti gli oggetti dell’interfaccia della nostra applicazione. E molto simile per chi la conosce alla sintassi xml, quindi racchiuso tra tag, dove sono possibili ulteriori personalizzazioni di ogni singolo oggetto mediante le proprietà che vedremo a breve. Qui di seguito, lascio il link alla documentazione ufficiale Microsoft per chi volesse approfondire ogni dettaglio del linguaggio xaml. Inseriamo il codice seguente all’interno del 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 0-->
         <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>



Se tutto è stato eseguito in maniera corretta, questa e la schermata che visualizzeremo in fase di designer.

Figura 6

 Figura 6: la schermata del file MainPage.xaml dopo la scrittura del codice dichiarativo.


Si tratta veramente di qualcosa di molto semplice a livello di interfaccia, lo scopo è dimostrare come inviare e ricevere dati tramite porta seriale. Occupiamoci adesso della scrittura del codice gestito, useremo in questo esempio C#. Tasto F7, saremo condotti nell’editor di codice, incolliamo il codice C# che segue.


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


Diamo uno sguardo più da vicino al codice precedente. All’avvio dell’applicazione viene eseguito il costruttore della classe MainPage.

Viene prima di tutto richiamato il medoto InitializeComponent(), che si occuperà della gestione per l’interfaccia grafica. Vengono disabilitati i button di richiesta accensione e spegnimento led. Successivamente richiamato il metodo ListAvailablePorts(), il quale si occupa di verificare se nel nostro caso sulla Raspberry Pi2 vi sono componenti collegati. In caso positivo, avremo nel controllo listBox, tutti gli Id dei componenti rilevati. Al click sul button btnSerialConnect, viene richiamato il metodo asincrono SerialPortConfiguration(), che si occupa di eseguire tutta la configurazione della porta seriale, e se tutto va a buon fine, avremo un messaggio che indicherà che la configurazione e avvenuta correttamente. A questo punto siamo pronti per collegarci con uno dei dispositivi connessi alla Raspberry. Sarà richiamato anche un altro metodo, Listen(), il quale lancerà un Task denominato ReadData(). Questo task, resterà in ascolto in modo da andare a leggere ogni valore in entrata sulla porta seriale e visualizzerà tutto a video. Il Task ManageLed(), viene richiamato al click su uno dei controlli button. Come potete osservare, questo task vuole in ingresso un parametro di tipo string, che servirà per eseguire una determinata azione sulla scheda Arduino Uno, la scheda Arduino invierà una conferma di azione eseguita, che sarà intercettata dal Task ReadData(), così da essere visualizzata nella nostra applicazione. Passiamo ora all’ultimo step, ossia la procedura per l’esecuzione del nostro esempio creato con Visual Studio.

Compilazione e debug del progetto di prova.

In esplora soluzioni, click con il mouse sul nome del progetto, tasto destro e selezioniamo il il comando “Proprietà”. Saremo condotti in un altra schermata, dove ci saranno una serie di schede. A noi interessano nell’ordine la schede “Applicazione” e “Debug”. Sulla prima scheda, lasciamo tutto come in figura.

Figura 7 Figura 7: la scheda applicazione.

Passiamo ora alla scheda “Debug”, qui eseguire alcune modifiche, ossia:

  • Dispositivo di destinazione
  • Indirizzo ip del dispositivo di destinazione
  • Modalità di autenticazione

Su dispositivo di destinazione impostiamo “Computer remoto”.

Su indirizzo ip, dobbiamo inserire l’indirizzo ip fornito dalla scheda Raspberry pi2. 

Ultima impostazione, nella modalità di autenticazione, inseriamo “Universale(protocollo non crittografato).

Di seguito la schermata Debug con le impostazioni.

Figura 8

Figura 8: la scheda debug.

Ora siamo pronti per eseguire il debug della nostra applicazione sulla Raspberry pi2. Tasto F5, e se tutto è stato eseguito correttamente, questo e ciò che visualizzeremo a video.

WP_20160523_21_49_40_Pro

Figura 8: la schermata del progetto di prova.

Conclusioni.

In questa prima parte, abbiamo fatto una panoramica sulla parte hardware necessaria, visto quali componenti software vanno installati, e terminato con la creazione del progetto ed eseguito infine il debug dell’applicazione con Visual Studio 2015 update2. Ovviamente manca ancora la parte inerente alla scheda Arduino uno, ossia lo sketch di codice per poter scambiare dati tra le due schede, lo vedremo nella seconda e ultima parte.


Introduzione.

Con questo mini articolo e con la mia esperienza iniziale, vorrei porre una breve panoramica della libreria di Windows Remote Arduino, una delle tecnologie utilizzate nella Più grande sfida Arduino Maker del mondo.


Cosa e Windows Remote Arduino.

Windows Remote Arduino, è una libreria open - source, che permette a qualsiasi dispositivo Windows 10, sia esso un Windows Phone, Surf ace, PC, o anche Raspberry Pi 2 e altre schede con installato Windows 10, di controllare a distanza una scheda Arduino in diverse modalità. La libreria consente agli sviluppatori di poter integrare con i sensori Arduino nei progetti Windows, e gestire attività o applicativi di una certa complessità dove con il solo Arduino non sarebbe possibile realizzare a pieno. Trovate la libreria Windows Remote Arduino sulla pagina GitHub dedicata, all’interno di un repository intitolato "remote-wiring”. Per coloro che si avvicinano per la prima volta al mondo Windows, Arduino o generalizzando all’Internet of Things, qui di seguito trovate un buon punto di partenza. Di seguito, vediamo in dettaglio cosa e quali funzionalità la libreria Windows remote Arduino, è in grado di controllare:

  • GPIO Pin analogici e digitali di I/O.
    • La funzione Digital Write().
    • La funzione Digital Read().
    • Ingressi analogici (PWM) mediante funzione AnalogRead().
    • Uscite analogiche (PWM) mediante funzione AnalogWrite().
    • Impostazione dei pin, quindi dichiarandoli come input o output.
    • Ricezione di eventi quando i valori dei pin subiscono una variazione di stato logico.
  • Inviare e ricevere dati tra dispositivi mediante protocollo I2C.

Uno sguardo più da vicino.

Ora che abbiamo visto un po' di quello che Windows Remote Arduino può fare, prima di scrivere codice o iniziare a spiegarne qualcosa, esploriamo come funziona il tutto. In questa sezione vedremo il processo che sta alla base della progettazione della libreria, dando uno sguardo da vicino alla struttura e come detto, passando alla parte pratica dai prossimi articoli con esempi di codice. Vedremo sia la parte hardware sia la parte software. Per coloro che invece intendono proseguire il percorso di sviluppo sin da subito, le istruzioni di installazione complete ed esempi di codice possono essere trovati a questo link.

Le decisioni che stanno alla base della progettazione.

Discutiamo in merito alla progettazione delle API di Windows Remote Arduino. Per esempio, partendo dalle funzioni pinMode e digitalWrite, familiari agli sviluppatori Arduino che, anziché reinventarle, sono rimaste invariate allo scopo di lasciare ciò che è già familiare senza stravolgere la sintassi agevolando così la fase di sviluppo.

Le API sono state realizzate per rispecchiare il più possibile quelli che sono i concetti Arduino. Ci sono naturalmente dei cambiamenti, poiché il WinRT è fondamentalmente diverso dal Wiring base utilizzato negli sketch Arduino. Tuttavia, con un po' di riorganizzazione, è possibile utilizzare gran parte della logica e comandi di uno sketch Arduino in un applicativo Windows 10 UWP utilizzando la libreria Windows Remote Arduino.

Dopo aver progettato le API, è necessario un protocollo per facilitare la comunicazione tra Windows 10 e una scheda della famiglia Arduino, il protocollo utilizzato e Firmata, a mio avviso è stata la scelta più sensata. Anche in questo caso, si tratta di un progetto open - source che è stato implementato in molti altri linguaggi, tra cui Arduino Wiring, incluso oltretutto di default nei progetti Arduino.

Architettura.

Per quanto ho letto e capito, Windows Remote Arduino, è suddiviso in tre strati. Il primo denominato Stream comunication, ossia la comunicazione fisica, lo strato iniziale, necessario per lo scambio di dati e informazioni tra Windows e il dispositivo Arduino. Al di sopra del livello iniziale di comunicazione, abbiamo il protocollo FirmData che abbiamo discusso precedentemente, che si occupa di decodificare i dati grezzi in arrivo e renderli messaggi comprensibili. Infine, l’ultimo strato denominato RemoteWiring, il quale astrae tutti i messaggi di protocollo è consente così il controllo remoto delle schede Arduino da Windows.

Concetti iniziali per lo sviluppo con la libreria.

Per tutti i casi di utilizzo, la classe RemoteDevice contenuta nello strato RemoteWiring, e il punto di partenza, il punto iniziale che lo sviluppatore deve utilizzare per l’interazione tra i due dispositivi. Per interagire, abbiamo a disposizione le seguenti implementazioni IStream che dobbiamo necessariamente utilizzare al momento che creiamo un oggetto RemoteDevice: usbserial, BluetoothSerial, NetworkSerial o DfRobotBleSerial, contenuti nello strato Stream comunication menzionato precedentemente. Dopo aver invocato il metodo begin() sull'oggetto Stream, tutte le successive chiamate delle API vengono effettuate tramite l'istanza RemoteDevice creata. Possiamo così impostare i modi o stati dei pin, leggere i valori di pin digitali e/o analogici, avviare la comunicazione I2C ad altri dispositivi che supportano questo protocollo, e pilotare anche servo esempio motori stepper o altro hardware semplicemente utilizzando questa singola classe.

Espandere le funzionalità di Windows Remote Arduino.

Per gli utenti più esperti, Windows Remote Arduino consente anche di personalizzare i comandi e funzionalità, questo mediante Firmata SysEx - ulteriori informazioni possono essere reperite a questo Link. Per esempio la gestione della comunicazione SPI, è possibile tramite comandi SysEx. I comandi SysEx consentono agli sviluppatori di scrivere codice complesso o personalizzato che può essere eseguito con Windows Remote Arduino.

L'aggiunta del supporto SPI.

Solitamente, vi sono due metodi di comunicazione – (I2C e SPI) - che microcontrollori tipicamente usano per comunicare con altri dispositivi. Questo è comunemente richiesto per molti sensori, e altro hardware che hanno un proprio MCU. Ciascuno di questi due metodi hanno i loro pro e contro, ma entrambi sono ampiamente supportati con Arduino.

Adesso, la libreria Windows Remote Arduino dipende dal protocollo Firmata per funzionare. Uno degli svantaggi di usare Firmata è che non vi è alcun supporto SPI esistente – ora le operazioni SPI con Windows Remote Arduino sono possibili utilizzando i comandi avanzati SysEx come menzionato prima. Fortunatamente, l'architettura a tre strati consentirebbe allo strato Firmata da scambiare in maniera relativamente semplice con un'altra implementazione del protocollo. Da lì, la classe RemoteDevice potrebbe essere modificata per accettare il nuovo protocollo, o una nuova implementazione di RemoteDevice potrebbe essere scritta per utilizzare il nuovo livello di protocollo.

Conclusione.

In questo primo articolo, ho cercato sulle basi della mia iniziale esperienza con Windows Remote Arduino, di dare dei cenni iniziali, su cosa e, cosa possiamo fare, come funziona, quali sono i pro e contro che ogni cosa purtroppo ha. Sono fiducioso che pian piano diventerà un’ottima scelta per gestire da Windows 10 i sensori della famiglia Arduino, non che pilotare qualcosa di più complesso come servomotori, motori stepper e altro hardware che in questo momento richiede uno sviluppo più accurato. Nei prossimi articoli, inizieremo la parte pratica, partendo dalla creazione dei un progetto UWP, e installare la libreria Windows Remote Arduino mediante Nuget.

Ulteriori risorse.

Di seguito lascio ulteriori link per approfondire in dettaglio come funziona la libreria Windows Remote Arduino.


Introduzione.

Riprendiamo il nostro percorso sullo sviluppo e prototipazione con la board RaspberryPi2. Nel precedente articolo che trovate a questo link, il nostro obbiettivo era quello di comandare l’accensione di un Led. In questi ultimi giorni tra l’altro, e uscita la nuova release di Windows 10 IoT, ossia la 10.0.10586.0, che ha portato con se diverse novità che vedremo negli articoli successivi a questo. Il nostro scopo ora, e quello come da titolo, di gestire un sensore di tipo analogico. A differenza di uno digitale, il sensore analogico detto in maniera molto sintetica, si prenda come esempio uno di temperatura, fornisce un valore di tensione costante nel tempo, secondo il valore di temperatura che è rilevato dal sensore stesso. Altro esempio, un potenziometro, ossia una resistenza di tipo variabile, che secondo come agiamo su di essa mediante la sua manopola, varierà il suo valore in Ohm e di conseguenza varia anche il valore della tensione in uscita. Fino alla versione 10.0.10240.0 alla quale faremo riferimento, non vi e la possibilità di collegare sensori analogici sui pin della Gpio poiché mancano ingressi e uscite PWM (acronimo di power with modulation), per cui dobbiamo ricorrere ai cosiddetti ADC Converter (Analog to digital converter), ossia un circuito elettronico in grado di convertire un segnale analogico in valore di tipo binario espresso in byte.

 

Hardware necessario.

Dopo questa breve introduzione, passiamo allo step successivo. Per la realizzazione del nostro circuito, abbiamo bisogno del seguente materiale hardware:

  • Raspberry Pi2 con installata la versione 10.0.10240.0 dotata di cavo di alimentazione.
  • Cavo Hdmi così da connettere la Raspberry Pi2 a un monitor.
  • Monitor dotato di ingresso HDMI.
  • Cavo ethernet.
  • Breadboard, ovvero la base necessaria per il montaggio componenti e cablaggio elettrico.
  • Jumper maschio-maschio e maschio-femmina.
  • Sensore di temperatura analogica TMP36.
  • ADC converter MCP3008.

Un breve accenno sul circuito integrato MCP3008.   

Come da datasheet che trovate a questo link, si tratta di un convertitore analogico/digitale alimentato ad una tensione Max di 5 v DC, risoluzione 10 bit. Di seguito le caratteristiche principali.

 

  • 10-bit resolution
  • ± 1 LSB Max DNL
  • ± 1 LSB Max INL
  • 4 (MCP3004) or 8 (MCP3008) input channels
  • Analog inputs programmable as single-ended or pseudo-differential pairs
  • On-chip sample and hold
  • SPI serial interface (modes 0,0 and 1,1)
  • Single supply operation: 2.7V - 5.5V
  • 200 ksps max. sampling rate at VDD = 5V
  • 75 ksps max. sampling rate at VDD = 2.7V
  • Low power CMOS technology
  • 5 nA typical standby current, 2 µA max.
  • 500 µA max. active current at 5V
  • Industrial temp range: -40°C to +85°C • Available in PDIP, SOIC and TSSOP packages

Possiamo osservare che il tipo di comunicazione con la raspberry avviene mediante protocollo SPI. Di seguito la piedinatura.

clip_image002[10]

Figura 1: La piedinatura dell’MCP3008.

Partendo dal pin 1 al pin 8, abbiamo I canali da CH0 A CH7, dove andremo a collegare l’uscita del/I sensori analogici. Ogni canale come vedremo, va configurato seguendo le indicazioni del costruttore come da datasheet allegato. I pin 16-15 vanno collegati al positivo, I pin 14-9 allo zero volt (o Ground della raspberry Pi2). I pin 13-12-11-10 sui pin del bus SPI0 o SPI1 della scheda Raspberry.

 

Circuito elettrico/elettronico. 

Qui di seguito il circuito finale del nostro progetto, realizzato con Fritzing, un ottimo software per la realizzazione di schemi elettrici/elettronici.

clip_image004[9]

Figura 2: Il circuito elettronico.

Per non confondersi nei collegamenti elettrici, vediamo di seguito come collegare la Gpio con l’intergrato MCP 3008. Osservando la figura 1, vediamo che tra I pin 1 e 16 abbiamo un segno di riconoscimento, ruotando di 90° il componente in senso antiorario, il pin 1 sarà quello in basso a sinistra, il pin 8 quello in basso a destra, il 9 in alto a destra e il 16 in alto a sinistra.

  • PIN 16 MCP3008 ----> 3,3V DC (CAVO ROSSO)
  • PIN 15 MCP3008 ----> 3,3V DC (CAVO ROSSO)
  • PIN 14 MCP3008 ----> GND (CAVO NERO)
  • PIN 13 MCP3008 ----> SPIO_SCLK (CAVO ROSSO)
  • PIN 12 MCP3008 ----> SPIO_MISO (CAVO GRIGIO)
  • PIN 11 MCP3008 ----> SPIO_MOSI (CAVO BLU)
  • PIN 10 MCP3008 ----> SPIO_CE0_N DC (CAVO VERDE)
  • PIN 9 MCP3008   ----> GND (CAVO NERO)
  • PIN 1 MCP3008   ----> PIN VOUT SENSORE TMP36 DC (CAVO GIALLO)

Questi sono I collegamenti del circuito integrato MCP3008 con la scheda Raspberry Pi2.

 

Sensore di temperatura TMP36.   

clip_image006[8]

Figura 3: Piedinatura sensore TMP36.

Si tratta di un sensore di temperatura analogico, il quale fornisce un valore di tensione di 10mv per grado direttamente proporzionale al valore di temperatura che è rilevato. Ha un range di lettura che va da -40  a 125 °C. Vediamo ora come collegarlo. Guardando l’immagine precedente, notiamo che ha tre pin, il primo a sinistra(1) lo colleghiamo alla tensione di 3,3 v DC, il pin centrale(2) come da figura sull’ingresso CH0 del MPC3008, il pin di destra(3) su GND.

 

  • PIN SINISTRA TMP36   ----> 3,3V DC (CAVO ROSSO)
  • PIN CENTRALE TMP36 ----> SU PIN 1 MCP3008(CAVO GIALLO)
  • PIN DESTRA TMP36     ----> GND (CAVO NERO)

 

Creazione del progetto di prova con Visual Studio 2015. 

Terminata la parte hardware, dai materiali necessari ai componenti e loro caratteristiche, e giunto ora il momento di dedicarsi alla parte software. Useremo per la creazione del progetto Visual Studio 2015. Se ancora non e stato eseguito, oltre Visual Studio 2015 e sistema operativo Windows 10 (almeno la versione Professional), e necessario scaricare ed installare L’sdk per lo sviluppo su Windows 10 che trovare a questo link. A installazioni terminate, avviamo Visual Studio 2015, e creiamo mediante il comando File, nuovo progetto un’applicazione usando il template App vuota(Windows universale) come mostrato in figura e denominiamo il progetto con “AnalogTemperature”.

 

clip_image008[9] 

Figura 4: La schermata Nuovo progetto.

Confermiamo con tasto OK. A progetto creato, per sviluppare in ambito IoT, abbiamo bisogno delle librerie necessarie. In esplora soluzioni posizioniamo il cursore su “Riferimenti”, tasto destro selezioniamo “Aggiungi riferimento”, e nella successiva schermata alla sezione “Estensioni” selezioniamo Windows IoT Exstension for the UWP come visibile nella successiva immagine.

clip_image010[9]

Figura 5: La schermata Gestione riferimenti.

A livello di Estensioni abbiamo tutto il necessario. Dobbiamo ora creare un paio di classi che ci serviranno per la gestione del sensore TMP36 e MCP 3008.

 

Creazione Classi MCP3008 e TMP36.  

In esplora soluzioni, posizioniamo il cursore sul nome del progetto, tasto destro del mouse e scegliamo il comando “Inserisci” e subito dopo “Classe” e diamo il nome MCP3008 come il circuito integrato. Con la stessa procedura, creiamo una classe chiamata TMP36. All’interno della classe MCP3008 inseriamo il codice seguente.

using System;

using Windows.Devices.Enumeration;

using Windows.Devices.Spi;

using Windows.UI.Popups;

 

namespace AnalogTemperature

{

    public class MCP3008

    {

        SpiDevice _DEVICE;

        TMP36 _TMP36 = new TMP36();

        string _CHOICECHANNEL;

 

 

        const double _MAXVALUE = 1023.0;

        const int _MINVALUE = 0;

        const int _RESOLUTIONBITS = 10;

        const int _SHIFTBYTE = 8;

 

        byte[] _CH0 = new byte[] { 1, 0x80, 0 };

        byte[] _CH1 = new byte[] { 1, 0x90, 0 };

        byte[] _CH2 = new byte[] { 1, 0xA0, 0 };

        byte[] _CH3 = new byte[] { 1, 0xB0, 0 };

        byte[] _CH4 = new byte[] { 1, 0xC0, 0 };

        byte[] _CH5 = new byte[] { 1, 0xD0, 0 };

        byte[] _CH6 = new byte[] { 1, 0xE0, 0 };

        byte[] _CH7 = new byte[] { 1, 0xF0, 0 };

        byte[] _DATARECEIVED = new byte[] { 0, 0, 0 };

 

 

 

        /// <param name="serialcomunication">Define type comunication</param>

        /// <param name="channel">Define number channel of MCP3008</param>

        /// <param name="spicomunication">Define spicomunication channel</param>

        /// <param name="mode">Define spi mode</param>

        public async void InitializeMCP3008(SerialComunication serialcomunication,Channel channel,SpiComunication spicomunication, SpiMode mode)

        {

            var spiconnectionsettings = new SpiConnectionSettings((int)spicomunication);

            spiconnectionsettings.ClockFrequency = _TMP36.CLOCK_SIGNAL;

            spiconnectionsettings.Mode = mode;

 

            string spiDevice = SpiDevice.GetDeviceSelector(spicomunication.ToString());

            var deviceInformation = await DeviceInformation.FindAllAsync(spiDevice);

 

            if(deviceInformation != null && deviceInformation.Count > 0)

            {

                _DEVICE = await SpiDevice.FromIdAsync(deviceInformation[0].Id, spiconnectionsettings);

                _CHOICECHANNEL = channel.ToString();

            }

 

            else

            {

                var dialog = new MessageDialog("Device not found");

                await dialog.ShowAsync();

                return;

            }

        }

 

        public double ReturnResult()

        {

            switch (_CHOICECHANNEL)

            {

                case "CH0":

                    _DEVICE.TransferFullDuplex(_CH0, _DATARECEIVED);

                    break;

 

                case "CH1":

                    _DEVICE.TransferFullDuplex(_CH1, _DATARECEIVED);

                    break;

 

                case "CH2":

                    _DEVICE.TransferFullDuplex(_CH2, _DATARECEIVED);

                    break;

 

                case "CH3":

                    _DEVICE.TransferFullDuplex(_CH3, _DATARECEIVED);

                    break;

 

                case "CH4":

                    _DEVICE.TransferFullDuplex(_CH4, _DATARECEIVED);

                    break;

 

                case "CH5":

                    _DEVICE.TransferFullDuplex(_CH5, _DATARECEIVED);

                    break;

 

                case "CH6":

                    _DEVICE.TransferFullDuplex(_CH6, _DATARECEIVED);

                    break;

 

                case "CH7":

                    _DEVICE.TransferFullDuplex(_CH7, _DATARECEIVED);

                    break;

            }

 

            var result = ((_DATARECEIVED[1] & 0x03) << _SHIFTBYTE) + _DATARECEIVED[2];

            var mvolt = result * (_TMP36.VOLTAGE / _MAXVALUE);

            var tempCelsius = mvolt / _RESOLUTIONBITS;

            return tempCelsius;

        }

    }

 

    public enum SerialComunication

    {

        SINGLE_ENDED,

        DIFFERENTIAL

    }

 

    public enum Channel

    {

        CH0, CH1, CH2, CH3, CH4, CH5, CH6, CH7

    }

 

    public enum SpiComunication

    {

        SPI0,

        SPI1

    }

}

Analizziamo il codice precedente. Sono state definite delle variabili a livello di classe. La prima non e altro che la classe base per verificare e gestire device collegati alla/e porte SPI della Gpio.

        SpiDevice _DEVICE;

 

Qui definiamo un nuovo oggetto di tipo TMP36 che vedremo dopo.

 

        TMP36 _TMP36 = new TMP36();

 

Le variabili che seguono, sono tutte le caratteristiche del circuito intergrato MCP3008, partendo da _MAXVALUE, che sarà il valore massimo in una risoluzione 10 bit come da caratteristiche che trovate nel datasheet. _MINVALUE rappresenta il valore  minimo, _RESOLUTIONBITS e la risoluzione massima del MCP3008,  _SHIFTBYTE rappresenta lo spostamento di 8 bit che va eseguito una volta acquisiti i valori che ci vengono restituiti dal pin DOUT del MCP3008. Le variabili da _CH0 A _CH7, rappresentano gli otto canali disponibili in cui e possibile collegare un componente di tipo analogico, noi useremo in questo esempio il _CH0. La variabile _CHOICECHANNEL, servirà per memorizzare quale canale e stato utilizzato e passare il byte con la configurazione corretta, lo vedremo nel metodo ReturnResult(). Rimane ancora _DATARECEIVED,  il byte che contiene alla fine le informazioni in bit da elaborare e mostrare all’utente come temperatura rilevata.

 

        string _CHOICECHANNEL;

        const double _MAXVALUE = 1023.0;

        const int _MINVALUE = 0;

        const int _RESOLUTIONBITS = 10;

        const int _SHIFTBYTE = 8;

 

        byte[] _CH0 = new byte[] { 1, 0x80, 0 };

        byte[] _CH1 = new byte[] { 1, 0x90, 0 };

        byte[] _CH2 = new byte[] { 1, 0xA0, 0 };

        byte[] _CH3 = new byte[] { 1, 0xB0, 0 };

        byte[] _CH4 = new byte[] { 1, 0xC0, 0 };

        byte[] _CH5 = new byte[] { 1, 0xD0, 0 };

        byte[] _CH6 = new byte[] { 1, 0xE0, 0 };

        byte[] _CH7 = new byte[] { 1, 0xF0, 0 }

 byte[] _DATARECEIVED = new byte[] { 0, 0, 0 };

Il metodo InitializeMCP3008, richiede alcuni parametri, il primo e il tipo di gestione lettura dei dati dai canali su MCP3008, che possiamo impostare su “single-ended” o “differenzial” come richiesto nel datasheet, il canale sul quale colleghiamo il sensore  nel nostro caso TMP36 su CH0, quale porta SPI utilizziamo sulla Gpio, infine il modo di comunicazione sul bus SPI.

        /// <param name="serialcomunication">Define type comunication</param>

        /// <param name="channel">Define number channel of MCP3008</param>

        /// <param name="spicomunication">Define spicomunication channel</param>

        /// <param name="mode">Define spi mode</param>

        public async void InitializeMCP3008(SerialComunication serialcomunication,Channel channel,SpiComunication spicomunication, SpiMode mode)

        {

 

Viene definita un istanza della classe SpiConnectionSettings, passando come argomento un intero che definisce quale bus SPI viene utilizzato, per noi sarà 0.

 

            var spiconnectionsettings = new SpiConnectionSettings((int)spicomunication);

 

Impostiamo poi la frequenza di clock e la modalità. Notiamo per impostare la frequenza di clock facciamo uso di una proprietà della classe TMP36.

 

            spiconnectionsettings.ClockFrequency = _TMP36.CLOCK_SIGNAL;

            spiconnectionsettings.Mode = mode;

 

Successivamente, con la classe SpiDevice e il metodo GetDeviceSelector, otteniamo tutti i bus SPI presenti sulla scheda Raspberry Pi2.   

 

            string spiDevice = SpiDevice.GetDeviceSelector(spicomunication.ToString());

 

In questa sezione con la classe DeviceInformation, recuperiamo tutte le informazioni necessarie sul/i bus SPI.  

 

            var deviceInformation = await DeviceInformation.FindAllAsync(spiDevice);

 

Se il parametro deviceInformation non e null, e maggiore di zero, possiamo definire quale bus SPI utilizzare,  aprire il canale di comunicazione che abbiamo impostato, per noi sarà come detto SPI0, passando al metodo FromIdAsync l’Id del bus e la configurazione.

 

            if(deviceInformation != null && deviceInformation.Count > 0)

            {

                _DEVICE = await SpiDevice.FromIdAsync(deviceInformation[0].Id, spiconnectionsettings);

                _CHOICECHANNEL = channel.ToString();

            }

 

            Else

 

Se non sono stati rilevati bus SPI avvertiamo l’utente con una MessageDialog.

 

            {

                var dialog = new MessageDialog("Device not found");

                await dialog.ShowAsync();

                return;

            }

        }

In questo metodo, secondo il canale che abbiamo deciso di usare, sarà chiamato sempre il metodo TransferFullDuplex, che si occuperà di inviare le impostazioni di ciascun canale sul bus SPI selezionato, e come secondo parametro il byte dove vi saranno memorizzati i dati convertiti da segnale analogico a digitale che dobbiamo poi elaborare in maniera opportuna. Infine avremo il risultato che sarà poi il nostro valore di temperatura finale.

        public double ReturnResult()

        {

            switch (_CHOICECHANNEL)

            {

                case "CH0":

                    _DEVICE.TransferFullDuplex(_CH0, _DATARECEIVED);

                    break;

 

                case "CH1":

                    _DEVICE.TransferFullDuplex(_CH1, _DATARECEIVED);

                    break;

 

                case "CH2":

                    _DEVICE.TransferFullDuplex(_CH2, _DATARECEIVED);

                    break;

 

                case "CH3":

                    _DEVICE.TransferFullDuplex(_CH3, _DATARECEIVED);

                    break;

 

                case "CH4":

                    _DEVICE.TransferFullDuplex(_CH4, _DATARECEIVED);

                    break;

 

                case "CH5":

                    _DEVICE.TransferFullDuplex(_CH5, _DATARECEIVED);

                    break;

 

                case "CH6":

                    _DEVICE.TransferFullDuplex(_CH6, _DATARECEIVED);

                    break;

 

                case "CH7":

                    _DEVICE.TransferFullDuplex(_CH7, _DATARECEIVED);

                    break;

            }

 

            var result = ((_DATARECEIVED[1] & 0x03) << _SHIFTBYTE) + _DATARECEIVED[2];

            var mvolt = result * (_TMP36.VOLTAGE / _MAXVALUE);

            var tempCelsius = mvolt / _RESOLUTIONBITS;

            return tempCelsius;

        }

    }

_DATARECEIVED, e un array di byte, a noi servono i primi due bit di sinistra del secondo elemento, mentre il primo, ossia _DATARECEIVED[0] lo ignoriamo perché non vi sarà alcun valore. Andiamo poi a sommare  _DATARECEIVED[1] con_DATARECEIVED[2]. I calcoli successivi, non fanno altro che ricavare il valore di temperatura, da notare _TMP36.VOLTAGE, che vedremo dopo. Ho inserito inoltre tre enumerazioni che serviranno nel momento in cui nella MainPage definiamo il codice per implementare il metodo InitializeMCP3008, sono il tipo di comunicazione, il canale utilizzato e su quale bus SPI intendiamo inviare e ricevere dati.

    public enum SerialComunication

    {

        SINGLE_ENDED,

        DIFFERENTIAL

    }

 

    public enum Channel

    {

        CH0, CH1, CH2, CH3, CH4, CH5, CH6, CH7

    }

 

    public enum SpiComunication

    {

        SPI0,

        SPI1

    }

 Questo e il necessario per la classe MCP3008. Passiamo ora alla classe TMP36, dopo averla creata, inseriamo il codice che segue.  

namespace AnalogTemperature

{

    public class TMP36

    {

        const int _CLOCKSIGNAL = 1650000;

        const double _VOLTAGE = 2000;

 

 

        public int CLOCK_SIGNAL

        {

            get

            {

                return _CLOCKSIGNAL;

            }

        }

 

        public double VOLTAGE

        {

            get

            {

                return _VOLTAGE;

            }

        }

    }

}

 

Semplicemente, sono definiti dei parametri che sono la frequenza di clock, e la tensione massima che può il sensore erogare a massimo regime, il  TMP36 a 125° c, eroga una tensione di circa 2 vdc.

 

 

Creazione dell’interfaccia grafica e codice nella classe MainPage.  

 

Definite alche le classi necessarie, vediamo come implementare il tutto nella Classe MainPage. In esplora soluzioni, doppio click con il mouse su MainPage.xaml, entrati nell’editor di codice definiamo la nostra interfaccia grafica, inserendo il seguente codice XAML.

 

<Page

    x:Class="AnalogTemperature.MainPage"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="using:AnalogTemperature"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    mc:Ignorable="d">

 

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

 

        <Grid.RowDefinitions>

            <RowDefinition Height="Auto"/>

            <RowDefinition Height="Auto"/>           

        </Grid.RowDefinitions>

 

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="Auto"/>

            <ColumnDefinition Width="Auto"/>

            <ColumnDefinition Width="Auto"/>           

        </Grid.ColumnDefinitions>

       

       

            <TextBlock Grid.Row="0" Grid.ColumnSpan="3" x:Name="txtHeader" FontSize="50" Text="TMP 36 AND MCP 3008 SAMPLE"/>

            <TextBlock Grid.Column="0" Grid.Row="1" x:Name="txtReadingTemp" FontSize="30" Margin="15,0,0,0" Text="Temperature value is:"/>

            <TextBlock Grid.Column="1" Grid.Row="1" x:Name="txtReading" FontSize="30" Margin="15,0,0,0"/>

            <TextBlock Grid.Column="2" Grid.Row="1" x:Name="txtCelsius" FontSize="30" Margin="15,0,0,0" Text="°C"/>                  

    </Grid>

</Page>

 

Di per se e molto semplice, ma sufficiente per visualizzare il valore di temperatura restituito dal metodo ReturnResult() della classe MCP3008 che rappresenta il nostro obbiettivo. Con tasto F7, entriamo nell’editor di codice C#, inserendo la parte sottostante.

 

using System;

using Windows.UI.Xaml;

using Windows.UI.Xaml.Controls;

using Windows.Devices.Spi;

 

// Il modello di elemento per la pagina vuota è documentato all'indirizzo http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x410

 

namespace AnalogTemperature

{

    /// <summary>

    /// Pagina vuota che può essere utilizzata autonomamente oppure esplorata all'interno di un frame.

    /// </summary>

    public sealed partial class MainPage : Page

    {

        DispatcherTimer _timer = new DispatcherTimer();

        MCP3008 _mcp3008 = new MCP3008();

 

        public MainPage()

        {

            InitializeComponent();

            _mcp3008.InitializeMCP3008(SerialComunication.SINGLE_ENDED, Channel.CH0, SpiComunication.SPI0,SpiMode.Mode0);

            _timer.Interval = new TimeSpan(0, 0, 5);

            _timer.Start();

            _timer.Tick += _timer_Tick;

        }

 

        private void _timer_Tick(object sender, object e)

        {

            txtReading.Text = Math.Round(_mcp3008.ReturnResult()).ToString();

        }

    }

}

 

 

Analizzando il precedente codice C#, inizializziamo un Timer.

 

        DispatcherTimer _timer = new DispatcherTimer();

 

Definiamo un oggetto di tipo MCP3008.

 

        MCP3008 _mcp3008 = new MCP3008();

 

Ne implementiamo il metodo InitializeMCP3008,passando i parametri necessari.

 

            _mcp3008.InitializeMCP3008(SerialComunication.SINGLE_ENDED, Channel.CH0, SpiComunication.SPI0,SpiMode.Mode0);

 

Impostiamo la proprietà Interval del timer con un valore di tipo TimeSpan di 5 secondi,  lo avviamo con il metodo Start() ,e gestiamo infine il suo evento Tick.

 

             _timer.Interval = new TimeSpan(0, 0, 5);

            _timer.Start();

            _timer.Tick += _timer_Tick;

 

 

All’interno dell’evento Tick, andiamo a valorizzare la proprietà Text del controllo TextBox txtReading, mostrando il valore di temperatura richiamando il metodo ReturnResult(), ma prima arrotondiamo il valore con la classe statica Math e il metodo Round() per togliere i decimali di troppo.

 

 

        private void _timer_Tick(object sender, object e)

        {

            txtReading.Text = Math.Round(_mcp3008.ReturnResult()).ToString();

        }

 

 

 

Test dell’applicazione.

 

Terminata la parte di codice, prima di eseguire il test dell’applicazione, ci sono un paio di cose da vedere. La prima essendo che stiamo sviluppando su Raspberry Pi2, e quella di impostare la compilazione in modalità ARM, lo si può eseguire dal menù a tendina come presente in figura.

 

clip_image012[8]

Figura 6: Il menù principale di Visual Studio 2015.

 

In riferimento all’immagine precedente, noterete che è attivata l’esecuzione come “Computer remoto”. Questo perché vogliamo eseguire l’applicazione sulla scheda Raspberry Pi2. Selezionate questa modalità, e alla schermata seguente andiamo a selezionate il device e l’indirizzo IP della Raspberry Pi2 deselezionando l’autenticazione, in alternativa è possibile modificare queste impostazioni, selezionando il progetto, tasto destro del mouse, selezioniamo il comando “Proprietà” e subito dopo “Debug”, saremo condotti nella seguente schermata.

 

clip_image014[8]

Figura 7: La sezione debug nelle proprietà del progetto.

 

Terminata quest’attività, possiamo eseguire il Debug dell’applicazione. Tasto F5, e se tutto è stato eseguito in maniera corretta, ecco cosa visualizzeremo a monitor.

 

clip_image016[8]

 

Figura 8: L’applicazione di esempio in esecuzione sulla Raspberry Pi2 e Windows 10 IoT.

 

 

Conclusione.

 

In quest’articolo, e stata fatta un’introduzione su cosa sono i sensori Analogici, cosa e un convertitore ADC, perché la scheda RaspberryPi2 necessita di questo componente per fare uso dei sensori e strumenti con segnale analogico. Nei prossimi articoli, vedremo di approfondire questi argomenti, utilizzando altri componenti e vedere come adattare diverse tipologie di sensori e strumenti analogici sul convertitore ADC e Raspberry.

Introduzione.

Riprendiamo il nostro percorso dall’articolo Arduino due e Mobile Service, che trovate a questo link. Abbiamo visto come da una scheda Arduino due è possibile salvare mediante Rest Api i valori di temperatura e umidità letti da un sensore DHT11. In quest’articolo, vediamo come visualizzare i dati presenti nella tabella del Mobile Service su un dispositivo Windows Phone.

Creazione dell’applicazione Windows Phone.

Apriamo Visual Studio 2015, dal menù “File”, “Nuovo progetto”, andiamo a selezionare il template “Applicazione vuota” come visibile in figura e la denominiamo SensorFarm.

clip_image002

Creato il progetto, come prima cosa aggiungeremo nelle reference il pacchetto WindowsAzure.MobileServices mediante Nuget come rappresentato nelle figure successive.

clip_image004

Digitiamo ora nella casella di ricerca WindowsAzure.MobileSerices e click sul pulsante installa.

clip_image006

Click su “Accetto” nelle successive schermate.

clip_image008

A fine installazione, dobbiamo avere una condizione come mostrato in figura.

clip_image010

Abbiamo installato il package necessario per interagire con il Mobile Service creato seguendo il precedente articolo, andiamo ora a creare l’interfaccia e il codice per la visualizzazione dei dati.

Creazione dell’interfaccia grafica.

Procediamo ora con la creazione dell’interfaccia grafica, rimaniamo nel file MainPage.xaml, ed inseriamo il codice seguente.

<Page
    x:Class="SensorFarm.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SensorFarm"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <ListBox Grid.Row="0" x:Name="lstValue" Background="CornflowerBlue" FontSize="20">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="20"/>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>

                        <TextBlock Grid.Row="0" Grid.Column="0" Text="Temp value"/>
                        <TextBlock Grid.Row="0" Grid.Column="2" Foreground="Yellow" Text="{Binding tempvalue }"/>
                        <TextBlock Grid.Row="0" Grid.Column="3" Text="°c"/>

                        <TextBlock Grid.Row="1" Grid.Column="0" Text="Humidity value"/>
                        <TextBlock Grid.Row="1" Grid.Column="2" Foreground="Red" Text="{Binding humidityvalue }"/>
                        <TextBlock Grid.Row="1" Grid.Column="3" Text="%"/>

                        <TextBlock Grid.Row="2" Grid.Column="0" Text="Created at"/>
                        <TextBlock Grid.Row="2" Grid.Column="2" Foreground="Green" Text="{Binding __createdAt }"/>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Page>

Analizziamo il codice precedente. E stato definito il grid principale, dentro il quali sono inseriti I controlli che compongono l’interfaccia, vi e un controllo ListBox con al suo interno un datatemplate composto da un altro controllo grid con al suo interno una serie di controlli TextBlock, dove in alcuni di essi la proprietà Text e in Binding con delle proprietà della classe tabsensor che vedremo successivamente. Non descriveremo cosa e il DataBinding, poiché esula dal contesto di questo articolo. Gli altri controlli TextBlock anno invece nella proprietà Text del testo statico. Se tutto il codice è stato inserito in maniera corretta, la nostra interfaccia avrà quest’aspetto.

clip_image012

Non preoccupiamoci se vediamo quest’aspetto, poiché avendo definito un datatemplate e non avendo dati di esempio da visualizzare, vedremo il tutto quando l’applicazione sarà in esecuzione. Terminata l’interfaccia grafica, occupiamoci ora della parte di codebheind.

Creazione della classe tabsensor.

Procediamo ora alla creazione della classe tabsensor, necessaria per la gestione e visualizzazione dei dati, cosa importante, dobbiamo chiamarla con lo stesso nome assegnato alla tabella sul Mobile Service, stessa cosa per le proprietà, ossia il nome e il tipo di variabile, devono corrispondere a quelle sul Mobile Service, diversamente oltre non visualizzare I dati rischiamo di avere un’eccezione a runtime. Creiamo una nuova classe denominata tabsensor, mettendoci con il mouse sul nome del progetto, tasto destro e selezioniamo “Aggiungi”, “Classe”, saremo condotti nella schermata seguente come mostrato in figura.

clip_image014

A classe creata, inseriamo il codice C# seguente.

using System;

namespace SensorFarm
{
    public class tabsensor
    {
        public string id { get; set; }
        public string tempvalue { get; set; }
        public string humidityvalue { get; set; }
        public DateTime __createdAt { get; set; }
    }
}

Sono state definite quattro proprietà, id, tempvalue, humidityvalue e __createdAt. L’ultimo e presente di default al momento della creazione della tabella sul Mobile Service, che non fa altro che memorizzare quando abbiamo inserito l’ultimo record, stessa cosa vale per la proprietà Id, che non e altro che la chiave primaria della tabella. Questa classe la useremo al momento che andiamo a recuperare I dati dalla tabella.

Creazione della classe ServiceData.

Ultima classe da creare, e quella per interagire con I MobileService per recuperare e visualizzare I dati dalla tabella tabsensor, con la stessa procedura per la creazione della classe tabsensor, creiamo una classe denominata ServiceData ed inseriamo il codice seguente.

using System;
using System.Collections.Generic;
using Windows.UI.Popups;
using Windows.UI.Xaml.Controls;

namespace SensorFarm
{
    public class ServiceData
    {
        List<tabsensor> sensor = new List<tabsensor>();

        public async void GetData(ListBox lstValue)
        {
            try
            {
                sensor = await App.MobileService.GetTable<tabsensor>().ToListAsync();
                lstValue.ItemsSource = sensor;
            }

            catch (Exception ex)
            {
                await new MessageDialog(ex.Message).ShowAsync();
            }
        }
    }
}

Analizzando il codice, è stata definita una collection di tipo tabsensor, la classe creata in precedenza, il metodo GetData, richiede un oggetto di tipo ListBox, noi passeremo il riferimento a quello creato nell’interfaccia grafica, in seguito il metodo GetTable<>, richiede un parametro di tipo IMobileServiceTable, ed ecco che ora capiamo perché la classe tabsensor deve essere identica alla tabella presente sul MobileService. Dopo andiamo a valorizzare la proprietà ItemSource al parametro lstValue del metodo GetData con il valore della variabile sensor, così da visualizzare I dati della tabella sul controllo ListBox passato come riferimento al metodo. Qui capiamo anche il funzionamento del databinding, sono state valorizzate le proprietà della classe tabsensor implicitamente poiché abbiamo definito e valorizzato la collection sensor di tipo tabsensor. Consiglio di approfondire quest’argomento perché è molto più vasto di quanto affermato ora.

Modifica della classe App.xaml.cs.

Per accedere al Mobile Service creato abbiamo ancora bisogno di una cosa, autenticarci mediante un uri e un application key che ci viene fornito al momento della creazione del Mobile Service su Microsoft Azure. Solitamente troviamo nella sezione DASHBOARD il “MOBILE SERVICE URL” e l’application keys facendo un clik sul button “MANAGE KEYS” che troviamo in basso a sinistra nel portale di Microsoft Azure. Individuato sul portale questi due cose, apriamo il file App.xaml.cs ed inseriamo prima di tutto il namespace seguente.

using Microsoft.WindowsAzure.MobileServices;

Questo è necessario per fare uso della classe MobileServiceClient, la quale fornisce il necessario per l’autenticazione. Aggiungiamo ora il codice come segue.

public sealed partial class App : Application
    {
        public static MobileServiceClient client = new MobileServiceClient(“mobineserviceurl here”, "appkey here");

//Altro codice C# della classe App.xaml.cs

Test dell’applicazione.

Abbiamo eseguito tutto il necessario, e arrivato il momento di provare quanto creato. Tasto F5 ed eseguiamo l’applicazione in modalità Debug, se abbiamo eseguito tutto correttamente, ecco l’applicazione in fase di esecuzione.

clip_image016

Se invece si verifica un problema, tipo assenza della connessione Wifi o rete dati, ecco cosa visualizzeremo a runtime.

clip_image018

Conclusione.

In questo terzo articolo abbiamo visto in che modo e possibile visualizzare I dati presenti su un Mobile Service e quali sono le classi necessarie per ottenere tutto ciò. Io ho preferito creare un’applicazione Windows Phone 8.1, ma vi sono comunque altri modi per la visualizzazione. Nel prossimo articolo, amplieremo quest’applicazione inserendo dei valori d’impostazione, immaginiamo di visualizzare la temperatura di casa nostra sul device, inseriremo a che ora vogliamo che accenda la caldaia di casa, a che temperatura dovrà allo stesso modo far accendere la caldaia, il tutto visto e letto dalla scheda Arduino due utilizzata nel precedente articolo.


Introduzione.

In questo articolo, faremo una breve introduzione sulla scheda Arduino due, partendo dalla parte hardware, per terminare spiegando tutta la procedura per lo sviluppo e un semplice sketch di prova. Vedremo nell’ordine:

  • Caratteristiche hardware
  • Installazione delle librerie necessarie per lo sviluppo
  • Impostazione dei parametri
  • Progetto di esempio
  • Conclusione

Caratteristiche hardware.

La scheda Arduino due, è basata su processore AT91SAM3X8E, Cortex-ME CPU, ed e la prima scheda di questa famiglia basata su 32 bit ARM  micro controller. A livello hardware, dispone di ben 54 piedini tra I/O, trasmissione e ricezione dati, ingressi Analogici e molto altro. Qui di seguito il pin mapping e altre componenti hardware:

  • 12 Piedini utilizzabili come uscite PWM
  • 12 ingressi analogici
  • 16 ingressi digitali
  • 4 UARTs porta seriale hardware
  • 2 pin DAC, ovvero funzionamento da analogico a digitale
  • 2 TWI
  • Jack per alimentazione scheda
  • Porta mini usb nativa
  • Porta mini usb programmabile
  • Uscite GND, 3,3 e 5 volt per alimentazione componentistica esterna
  • SPI Header
  • JTAG Header
  • Tasto di reset
  • Tasto per la cancellazione (erase) dello sketch all’interno della memoria

Qui di seguito un anteprima della scheda Arduino due.

Arduino due

Oltre al fatto che Arduino Due e basato su 32bit ARM, ci sono ancora delle differenze con altre schede, ovvero per funzionare necessita di una tensione di funzionamento di 3,3v anziché 5, evitare quindi di alimentare con tensioni superiori a quella nominale, poiché vi è il rischio di danneggiare l’intera scheda.

Abbiamo detto precedentemente, che dispone di due porte mini usb :

  • Native usb SAM3X: ovvero quando vogliamo usare la scheda Arduino Due come una normale periferica, prendiamo esempio da un pc che fa uso di periferiche come mouse e tastiera, o anche come host e permettere ad altre periferiche di collegarsi ad essa sempre mediante tale porta.
  • Programming ATMEGA16U2 : utilizzata per caricare gli sketch di codice, in poche parole per la programmazione.

Retro scheda Arduino due

Inoltre e compatibile con tutti gli shield Arduino, e con componenti utilizzati su Arduino Uno, purché la pinatura sia le medesima, esempio pratico possiamo collegare la scheda Ethernet shield utilizzata su Arduino Uno, poiché la pinatura è perfettamente compatibile come visibile in figura.

Arduino due e la ethernet shield

Per un maggiore approfondimento sulla parte hardware, lascio qui di seguito questo link, dove è possibile trovare maggiori informazioni e dettagli a riguardo.

Installazione delle librerie necessarie per lo sviluppo.

Ora che conosciamo le principali caratteristiche hardware, è giunto il momento di passare alla parte di sviluppo. Questo però comporta alcune procedure da eseguire. Prima cosa, scaricare e installare l’ide di Arduino al momento l’ultima versione e la 1.6.4. Dopo l’installazione, se proviamo ad avviare l’ide di Arduino, ci accorgeremo che tra le board disponibili non compare nella sezione Scheda la possibilità di selezionare Arduino due. Perché tutto ciò ? Semplicemente dobbiamo scaricare ed installare tutte le librerie necessarie. Iniziamo subito, per prima cosa avviamo l’ide di sviluppo, nel menù strumenti , scheda scegliamo il comando Boards Manager come mostrato in figura.

1-Boards manager

Saremo condotti nella schermata Boards Manager, dove è possibile eseguire il download delle librerie per Arduino Due e non solo, esempio abbiamo le librerie per schede della famiglia Intel.

2-Select version

A noi interessa scaricare le librerie sotto la voce Arduino SAM Boards (32-bits-ARM Cortex.M3), selezioniamolo.

3-Select version ide Arduino

Prima di eseguire il download dobbiamo ancora selezionare la versione dell’ide, selezioniamo l’ultima versione installata.

4-Download libraries

Inizierà il processo di installazione, saranno scaricati i tools necessari più i file delle relative definizioni delle boards, come visibile nelle immagini successive.

5-Download board definitions

6-Download tool

Dopo il download di tutti i file necessari, partirà il processo di installazione delle boards e dei tool.

7-Installing boards

7-Intalling tools

Terminata l’installazione, se tutto e andato a buon fine, visualizzeremo nella schermata Boards Manager la scritta “INSTALLED” come mostrato in figura.

8-Libraries installed 

Abbiamo ora tutto il necessario a livello software per iniziare lo sviluppo con Arduino due, tuttavia dobbiamo ancora eseguire un paio di cose prima di metterci al lavoro.

Impostazione dei parametri. 

Terminata l’installazione, dobbiamo ora andare a selezionare come scheda di default Arduino due e selezionare ancora la porta seriale alla quale connettiamo la scheda, diversamente non possiamo trasferire alcun contenuto all’interno della scheda. Vediamo come procedere, avviamo l’ide di Arduino, nel menù Strumenti selezioniamo nuovamente Scheda, e a differenza di prima, ecco che abbiamo in fondo alla voce di menù la possibilità di selezionare la scheda Arduino due. Notiamo che abbiamo due possibilità di scelta, quella che interessa a noi e la prima, ovvero Arduino Due (Programming Port), poiché come menzionato precedentemente, dobbiamo usare la scheda non da periferica o da host,  ma bensì dobbiamo programmarla.

9-Selezione scheda default

Terminata quest’attività, dobbiamo ancora selezionare la porta seriale, sempre dal menù Strumenti, selezioniamo questa volta la dicitura Porta, e impostiamo quella corretta, nel mio caso COM4, ma generalmente Arduino Due utilizza questa porta seriale, come visibile in figura.

10-Selezione porta seriale


Progetto di esempio.

Impostata anche la porta seriale, siamo pronti per creare uno sketch di esempio, in riferimento a quest’articolo scritto precedentemente, colleghiamo una ethernet shield alla scheda Arduino due come mostrato all’inizio dell’articolo, successivamente colleghiamo la Programming Port di Arduino due alla porta Usb del nostro pc, che provvederà a dare tensione ad entrambe le schede.

Scheda Arduino due in funzione

Carichiamo ora lo sketch di codice seguente che trovate nell’articolo menzionato prima, che si occuperà di rendere attiva la scheda ethernet shield.

// Importo le librerie Ethernet
#include <SPI.h>
#include <Ethernet.h>

// Impostazioni base
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // MAC address

void setup()
{
     // Imposto una connessione seriale per verificare i dati.
     Serial.begin(9600);

    // Diamo alla Ethernet shield un secondo per inizializzarsi
     delay(1000);    
}

void loop()
{
     // Connessione Ethernet usando MAC e IP fisso
         if(Ethernet.begin(mac) == 0)
         {
           Serial.println("Connesso");
         }
  
         else
         {
           Serial.println("Errore nella connessione");
         }  
}

Con tasto carica, identificabile dal simbolo di una freccia verso destra, possiamo finalmente inviare alla scheda il codice che abbiamo digitato precedentemente, questa è la procedura di caricamento, come visibile nelle immagini successive.

11-Compilazione sketch

12-Caricamento sketch

13-Sketch caricato

Se tutto e stato eseguito correttamente, dobbiamo visualizzare la scritta Caricamento completato come mostrato dall’ultima immagine.

Conclusione.

In questo breve articolo, si e voluto mostrare in maniera generale la scheda Arduino Due, partendo dalle principali caratteristiche Hardware, alle librerie e boards necessarie per poterla programmare, abbiamo visto quali sono i passaggi necessari per selezionare la scheda e porta seriale, terminando poi con un piccolo sketch di esempio, e inviare poi tutto alla scheda, così da poter visualizzare in rete una scheda ethernet shield, compatibile come detto con Arduino Due.


Introduzione.

Nel precedente articolo Arduino Due Development, è stata fatta un introduzione su questa scheda, eseguita la configurazione iniziale partendo dall’installazione delle librerie necessarie, per terminare con la configurazione della scheda Ethernet shield, con la quale la scheda Arduino Due potrà accedere a Internet. In questo secondo articolo, vedremo come Arduino può interagire con i servizi di Microsoft Azure, precisamente con i Mobile Service. Partiremo dalla creazione di un Mobile Service, continueremo costruendoci un piccolo circuito usando il sensore di temperatura e umidità DHT11, terminando con la parte di codice che si occuperà di trasferire le informazioni rilevate dal sensore su Microsoft Azure. Vedremo nell’ordine:

  • Creazione di un Mobile Service.
  • Montaggio del circuito elettronico.
  • Scrittura del codice per l’upload dei dati dal sensore a Microsoft Azure.
  • Test dell’applicazione.
  • Conclusioni.

Creazione di un Mobile Service.

La creazione di un Mobile service è molto semplice, per prima cosa occorre avere un account Microsoft e una sottoscrizione ad Azure. Entrati nel portale, alla schermata iniziale premiamo il tasto New che troviamo in basso a sinistra come mostrato in figura.

Figura 1

Alla successiva schermata, dobbiamo assegnare un nome al Mobile Service, scegliere se usare un DataBase esistente o crearne uno free da 20 mb, Dove situarlo, nel mio caso il Data Center più vicino e North Europe, per cui questo non sarà uguale per tutti, ma e consigliabile scegliere il Data Center più vicino a voi, ultima cosa, la parte di Backend, io lascerò Javascript.

Figura 2

Prossimo passo, creare un DataBase, quindi un nome da assegnargli, scegliere se creare un nuovo database SqlServer, e ultima cosa inserire le credenziali, come mostrato in figura.

Figura 3

Terminata quest’attività, attendiamo che Azure crei il Mobile Service, noteremo che avremo un mobile service e un DataBase.

Figura 4

Figura 5

Siamo ora pronti per creare una tabella all’interno del DataBase sensorfarm_db. Click con il mouse su sensorfarm nella sezione Mobile Service, alla successiva schermata click sul pulsante posto di fianco alla scritta “ADD A TABLE”. Sarà visualizzata un altra schermata dove dovremo inserire il nome della tabella, inseriamo tabsensor come mostrato nella figura seguente.

Figura 6

Lasciamo tutti gli altri campi così come sono e click sul tasto rappresentato con segno di spunta posto in basso a destra e attendiamo che venga creata la tabella.

Figura 7

Abbiamo fino a qui terminato la procedura per la creazione di un Mobile Service, passiamo ora alla realizzazione del circuito elettronico.


Montaggio del circuito elettronico.

Per la realizzazione del circuito, occorrono i seguenti componenti:

  • Scheda Arduino Due
  • Scheda Ethernet shield
  • Sensore DHT11
  • BreadBoard (base per il collegamento del sensore)
  • Colmeter (cavi per il collegamento tra la scheda Arduino Due e il sensore DHT11)
  • Alimentatore per il collegamento della scheda Arduino due

Di seguito lascio le immagini del circuito finale. Il sensore può funzionare da una tensione di 3,3 Vdc fino ad un massimo di 5,5V. Per maggiore chiarezza sul collegamento e funzionamento, rimando alla documentazione ufficiale.

Figura 8

Nell’immagine precedente, bisogna precisare che la scheda Ethernet Shield, va sovrapposta sulla scheda Arduino Due, così da avere i pin necessari per il collegamento, vedere la freccia nera da destra verso sinistra. Ho lasciato separate le due schede solo per visualizzare tutti i componenti necessari. Terminato il collegamento ecco come deve essere in pratica il nostro circuito.

Figura 9

Come e possibile notare la scheda Ethernet Shield viene sovrapposta alla scheda Arduino Due.


Scrittura del codice per l’upload dei dati dal sensore a Microsoft Azure.

Terminata anche la realizzazione del circuito, siamo pronti per iniziare la parte software, prima cosa da fare se non eseguito, e scaricare le librerie necessarie per utilizzare il sensore DHT11 che trovate a questo link. Dopo il download, è  necessario eseguirne l’installazione, possiamo eseguirla un due modalità:

  • Estraendo i file all’interno del file .zip e copiarli manualmente nella directory C:\Program Files (x86)\Arduino\libraries
  • Seguire la seguente procedura, Avviare l’ide di Arduino, dal menù  Sketch andiamo a selezionare il comando Include Library e successivamente Add .ZIP Library… come mostrato in figura.

Figura 10

Andiamo a selezionare il file .zip che abbiamo scaricato che solitamente viene messo nella cartella Download.

Figura 11

Confermiano con il comando Apri, ed ecco che se andiamo a verificare che tutto sia andato a buon fine troviamo il file dht11 tra le librerie disponibili.

Figura 12

Con questa procedura, i file vengono estratti e salvati non nella directory precedente, ma in C:\Users\nome utente\Documents\Arduino, dove “nome utente” cambierà a seconda di cosa avete inserito al momento dell’installazione del sistema operativo, nel mio caso è C:\Users\CARMELO LA MONICA\Documents\Arduino. Abbiamo installato le librerie necessarie, passiamo adesso alla scrittura del codice. Avviamo l’ide Arduino e creiamo un file Sketch denominato DHT11 Sample. ed inseriamo il codice seguente al suo interno.

#include <SPI.h>
#include <Ethernet.h>
#include <dht11.h>

// Ethernet shield MAC address (sticker in the back)
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

/*You can find this values in your Mobile Service dashboard
   server = namemobileservice.azure-mobile.net
   table_name = nametable
   ams_key = your keyvalue, find in home page mobile service, with a click on button MANAGE KEYS*/

const char* server = "sensorfarm.azure-mobile.net";
const char* table_name = "tabsensor";
const char* ams_key = "NyWPlQgRcUWHsrGwcwhHMRxVLtnItA64";

EthernetClient client;
char buffer[64];
dht11 DHT;
#define  DHT11_PIN 4


/*This method use Mobile service REST API fot to write value*/
void write_sensorvalue(double tempvalue, double humidityvalue)
{
   if (client.connect(server, 80)) {
    
     /*Table name in Mobile service*/
     sprintf(buffer, "POST /tables/%s HTTP/1.1", table_name);
     client.println(buffer);

    /*Sever name in Mobile Service*/
     sprintf(buffer, "Host: %s", server);
     client.println(buffer);

    /*Mobile Services application key*/
     sprintf(buffer, "X-ZUMO-APPLICATION: %s", ams_key);
     client.println(buffer);

    // JSON content type for the information
     client.println("Content-Type: application/json");

    /*Write values of temperature and humidity from DHT11 sensor*/
     sprintf(buffer, "{\"tempvalue\":\"%f\",\"humidityvalue\":\"%f\"}", tempvalue, humidityvalue);

    // Content length
     client.print("Content-Length: ");
     client.println(strlen(buffer));

    // End of headers
     client.println();

    // Request body
     client.println(buffer);

  }
  
   else
   {
     Serial.println("no connection available!");
   }
     client.stop();
}

/*-------------------------------------------------------*/
/*Setup method*/
/*-------------------------------------------------------*/
void setup()
{
   Serial.begin(9600);

  if (Ethernet.begin(mac) == 0)
   {
     Serial.println("ethernet shield failed");
     for (;;);
   }
  
   // Ethernet shield initialization:
   delay(1000);
}

/*-------------------------------------------------------*/
/*Loop method*/
/*-------------------------------------------------------*/
void loop()
{
   /*Read value from sensor input*/
   int chk = DHT.read(DHT11_PIN);

  /*Call method writ_sensorvalue and pass sensor parameter for to save on mobile service*/
   write_sensorvalue((DHT.temperature), (DHT.humidity));

  /*Time wait for new input data*/
   delay(10000);
}

Vediamo il funzionamento del codice. Includiamo in questo caso la libreria installata per il sensore dht11, nella fattispecie il file dht11.h, mentre le altre due librerie vi erano già nel precedente articolo. Ci sono tre variabili di tipo const char*, che non sono altro che il nome della tabella, il nome del server e il codice key, tutti necessari per l’upload dei dati.

#include <dht11.h>

const char* server = "sensorfarm.azure-mobile.net";
const char* table_name = "tabsensor";
const char* ams_key = "reperibile da portale";

Andiamo a dichiarare ancora altre tre variabili

char buffer[64];
dht11 DHT;
#define  DHT11_PIN 4

Dove la prima sarà il buffer di dati in upload, la seconda rappresenta il file dht11 dove mediante i metodi e altre variabili saremo in grado di leggere i valori di temperatura e umidità dal sensore. Ultima variabile non fa altro che impostare il pin 4 della scheda Arduino Due come Input per il sensore, quindi dobbiamo necessariamente collegare il pin “Signal” del sensore DHT11 sul pin 4 della scheda. Il metodo write_sensorvalue, è la parte più interessante, poiché si occupa di eseguire l’upload dei dati su Azure, vediamo le parti di codice più significative.

/*Table name in Mobile service*/
     sprintf(buffer, "POST /tables/%s HTTP/1.1", table_name);
     client.println(buffer);

    /*Sever name in Mobile Service*/
     sprintf(buffer, "Host: %s", server);
     client.println(buffer);

    /*Mobile Services application key*/
     sprintf(buffer, "X-ZUMO-APPLICATION: %s", ams_key);
     client.println(buffer);

Eseguiamo una richiesta HTTP e una chiamata di tipo POST, dove dobbiamo indicare il nome della tabella cerata precedentemente, il nome del Server il codice key, questo per poter eseguire consentire il corretto upload dei dati.

// JSON content type for the information
client.println("Content-Type: application/json");

/*Write values of temperature and humidity from DHT11 sensor*/
sprintf(buffer, "{\"tempvalue\":\"%f\",\"humidityvalue\":\"%f\"}", tempvalue, humidityvalue);

Con il codice precedente, specifichiamo in che formato stiamo inviando i dati, quindi tipo JSON, e nell’ultima parte di codice specifichiamo il pattern, ovvero cosa ritroveremo nella tabella tabsensor quando andremo a verificare se i dati sono stati caricati correttamente. Il metodo Setup lo abbiamo già visto nel precedente articolo, mentre più interessante e il metodo Loop.

void loop()
{
   /*Read value from sensor input*/
   int chk = DHT.read(DHT11_PIN);

  /*Call method writ_sensorvalue and pass sensor parameter for to save on mobile service*/
   write_sensorvalue((DHT.temperature), (DHT.humidity));

  /*Time wait for new input data*/
   delay(10000);
}

Dichiariamo una variabile di tipo int, che non fa altro che leggere lo stato del sensore di temperatura e umidità, questo mediante il metodo read che come parametro richiede il pin di ingresso. Richiamiamo poi il metodo write_sensorvalue passando come parametri i valori di temperatura e umidità tramite DHT.temperature e DHT.humidity. L’ultima istruzione di codice non e altro che un tempo di attesa di dieci secondi prima di avviare una nuova lettura. Abbiamo così terminato la parte relativa al codice, siamo ora pronti per eseguire le prove di funzionalità, ma prima dobbiamo caricare lo sketch di codice sulla scheda Arduino Due, per questa procedura rimando al precedente articolo.


Test dell’applicazione.

Diamo un occhiata adesso all’interno della tabella tabsensor, è troveremo questa situazione.

Figura 13

Questo perché non abbiamo definito nessun record al suo interno, ma soprattutto nessuna colonna. Possiamo alimentare ora la scheda Arduino Due in diversi modi, o con il suo alimentatore, o attaccandoci tramite porta usb del nostro pc, dove attualmente siamo perché abbiamo caricato precedentemente lo sketch di codice. Se tutto procede in modo corretto dovremmo vedere lampeggiare i led verdi della scheda Ethernet Shield, ciò sta a significare che e andata in funzione, ma soprattutto se andiamo sul portale Azure e verificare se i dati che sono stati caricati, e se tutto è stato eseguito correttamente ecco cosa ci troveremo.

Figura 14 

Notiamo dall’immagine che i servizi di Azure anno aggiunto per noi i campi tempvalue e humidityvalue, con altri campi, id, timestamp e version questi ultimi non fanno parte del nostro codice ma vengono aggiunti automaticamente al momento in cui viene inserito un nuovo record nella tabella tabsensor, in altre parole non ci siamo dovuti preoccupare noi di questo, ci ha pensato Azure per noi.


Conclusione.

In questo secondo articolo, abbiamo visto come da Arduino e possibile interagire con Microsoft Azure e i Mobile Service, creando un semplice circuito dove leggiamo mediante sensore dht11 i valori di temperatura e umidità, per poi andare a salvare i dati all’interno della tabella tabsensor. Nel prossimo articolo, creeremo un applicazione Windows Phone 8.1 che farà in modo di visualizzare i dati ed intraprendere poi un azione da eseguire.


Introduzione.

Terzo articolo introduttivo sull’ Internet of Things, scritto con la collaborazione di Piero Sbressa. Terminata la procedura di installazione di Windows 10 IoT Core che trovate a questo link, proveremo ora a creare un applicazione in modo far lampeggiare un Led, precisando però che normalmente far accendere o lampeggiare un led non e considerato IoT, ma in questo caso, serve per dare un introduzione e un idea su come sviluppare future applicazioni o prototipi con Raspberry Pi2 con Visual Studio 2015.


Circuito elettronico.

Il materiale che ci serve lo trovate nella seguente immagine:

WP_20150920_009

  • 1 LED del colore che volete (Rosso, verde o giallo)
  • 1 Resistenza a 220 Ohm.
  • 2 cavi connettori
  • 1 Breadboard

Il collegamento finale lo vedete nelle seguenti foto:

WP_20150912_012

WP_20150913_002

WP_20150913_003

WP_20150913_004

Qui di seguito trovate lo schema elettronico del circuito. Premetto che per creare un circuito o disegnarlo, sono necessari per mia esperienza personale, oltre un software dedicato, delle basi sulle parti hardware e basi di elettronica, diversamente il mio consiglio e dedicarsi allo sviluppo del codice e lasciare a terzi i compiti precedenti.

FIGURA 1

Dall’immagine precedente, notiamo che abbiamo due cavi, uno di colore nero e uno rosso. Il cavo di colore nero che rappresenta lo zero volt lo colleghiamo sul pin GPIO5 corrispondente al pin 29 che troviamo sulla GPIO della scheda Raspberry Pi2. Il cavo rosso sul pin 3.3V PWR corrispondente al pin 1. Di seguito la piedinatura del connettore GPIO così da agevolarci per il collegamento.

FIGURA 2

Cosa importante, il Diodo Led per funzionare, deve essere collegato in maniera corretta, ossia il katodo (lo si riconosce perché e il piedino più corto) va collegato sullo zero volt, l’anodo ossia l’altro piedino sul positivo, che in questo caso sarà dato dal pin 3.3V PWR. Un errato cablaggio non permetterà al Diodo led di funzionare , è potrebbe danneggiare il componente, la resistenza è importante perché generalmente un Diodo Led funziona ad una tensione di circa 3,3v dc, in questo caso la resistenza fa si che vi sia una caduta di tensione necessaria e fornire così la tensione corretta.


Impostazione del pc in modalità sviluppatore.

Una cosa che va eseguita prima di mettersi a sviluppare codice e impostare la modalità “sviluppatore” del nostro pc. La procedura e di per se semplice. Puntiamo il mouse sull’icona delle notifiche come mostrato in figura.

FIGURA 3

Alla successiva finestra di dialogo, selezionare “Tutte le impostazioni”.

FIGURA 4

Saremo condotti alla schermata seguente, selezioniamo il comando “Aggiornamento e sicurezza”.

FIGURA 5

Alla schermata seguente andiamo a selezionare il comando “Per sviluppatori”, e andiamo a selezionare la voca “Modalità sviluppatore.

FIGURA 6

Apparirà una finestra di dialogo dove dobbiamo confermare mediante tasto “Si” l’attivazione di tale modalità.

FIGURA 7

Diamo conferma e abbiamo abilitato il nostro pc per lo sviluppo.

FIGURA 8

Ora siamo pronti per creare il nostro primo progetto IoT.


Creazione del progetto.

Prima di iniziare con lo sviluppo, dobbiamo ancora scaricare ed installare la libreria Windows IoT Core Project Templates che trovate a questo link. In questa libreria troverete tutto il necessario per lo sviluppo su Raspberry Pi2, che vedremo in seguito nel corso dell’articolo. Apriamo ora Visual Studio, e creiamo un nuovo progetto Universal Windows App, in c#.

image

Dobbiamo a questo punto aggiungere  una Reference all’ sdk Windows IoT Exstension for the UWP, come nella figura seguente.

image

Aggiungiamo ora nella Grid dello Xaml il seguente codice:

<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">

    <Ellipse x:Name="LED" Fill="LightGray" Stroke="White" Width="100" Height="100" Margin="10"/>

    <TextBlock x:Name="GpioStatus" Text="Waiting to initialize GPIO..." Margin="10,50,10,10" TextAlignment="Center" FontSize="26.667" />

    <Button Name="AccendeSpegneLEDButton" Content="Accendi LED" HorizontalAlignment="Center" Click="AccendeSpegneLEDButton_Click"/>

</StackPanel>

Mentre nel code-behind mettiamo il seguente codice:

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

using System;
using Windows.Devices.Gpio;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Media;

namespace Blinky
{
    public sealed partial class MainPage : Page
    {
        private const int LED_PIN = 5;
        private GpioPin pin;
        private GpioPinValue pinValue;
        private SolidColorBrush yellowBrush = new SolidColorBrush(Windows.UI.Colors.Yellow);
        private SolidColorBrush grayBrush = new SolidColorBrush(Windows.UI.Colors.LightGray);

        public MainPage()
        {
            InitializeComponent();
            InitGPIO();
        }

        private void InitGPIO()
        {
            var gpio = GpioController.GetDefault();

            // Show an error if there is no GPIO controller
            if (gpio == null)
            {
                pin = null;
                GpioStatus.Text = "Non c'è il GPIO controller su questo device.";
                return;
            }

            pin = gpio.OpenPin(LED_PIN);
            pinValue = GpioPinValue.High;
            pin.Write(pinValue);
            pin.SetDriveMode(GpioPinDriveMode.Output);

            GpioStatus.Text = "GPIO pin correttamente inizializzati.";

        }

        private void AccendeSpegneLEDButton_Click(object sender, RoutedEventArgs e)
        {
            if (pinValue == GpioPinValue.High)
            {
                pinValue = GpioPinValue.Low;
                pin.Write(pinValue);
                LED.Fill = yellowBrush;
                AccendeSpegneLEDButton.Content = "Spegni LED";
            }
            else
            {
                pinValue = GpioPinValue.High;
                pin.Write(pinValue);
                LED.Fill = grayBrush;
                AccendeSpegneLEDButton.Content = "Accendi LED";
            }

        }
    }
}  

Terminata la parte di codice, prima di eseguire il test dell’applicazione, ci sono un paio di cose da vedere. La prima essendo che stiamo sviluppando su Raspberry Pi2, e quella di impostare la compilazione in modalità ARM, lo si può eseguire dal menù a tendina come presente in figura.

FIGURA 9

In riferimento all’immagine precedente, noterete che è attivata l’esecuzione come “Computer remoto”. Questo perché vogliamo eseguire l’applicazione sulla scheda Raspberry Pi2. Selezionate questa modalità, e alla schermata seguente andiamo a selezionate il device e l’indirizzo ip della Raspberry Pi2. deselezionando l’autenticazione, in alternativa è possibile modificare queste impostazioni, selezionando il progetto, tasto destro del mouse, selezioniamo il comando “Proprietà” e subito dopo “Debug”, saremo condotti nella seguente schermata.

FIGURA 10


Esecuzione dell’applicazione.

Possiamo ora procedere con l’esecuzione della nostra prima applicazione. Tasto F5 e se abbiamo fatto tutto correttamente il nostro LED si accenderà dopo aver cliccato sul pulsante, come possiamo vedere dalle seguenti immagini.

WP_20150912_011


WP_20150920_017


Conclusione.

In questo articolo, abbiamo creato la nostra prima applicazione con Raspberry Pi2 e Visual Studio 2015, partendo dalla progettazione, realizzazione del circuito elettronico, per terminare con la programmazione e scrittura del codice per la gestione del led. Nei successivi articoli, cercheremo di creare altri progetti di prova, lo scopo di questi mini articoli è quello di dare un introduzione su come progettare e realizzare un proprio progetto e perché no, riuscire poi a farci business.  Articolo scritto da Piero Sbressa (www.crystalweb.it) e Carmelo La Monica, Microsoft Contributor (http://community.visual-basic.it/carmelolamonica/default.aspx)


In questo secondo articolo scritto con la collaborazione di Piero Sbressa dedicato  all’IoT, e dopo l’introduzione che trovate a questo link,  vediamo ora come scaricare, installare e configurare Windows 10 IoTCore su una scheda Raspberry Pi2 più qualche personalizzazione a sistema operativo installato.


Hardware necessario.

Per chi non sapesse cosa è la Raspberry Pi2, è un microcomputer, con 4 porte USB, 1 presa LAN, 1 presa HDMI più le prese per l’alimentazione e lo slot della Mini SD. La versione 2 è uscita in primavera ed è pienamente compatibile con Windows 10 IoT Core.  Iniziamo, prima di procedere, a preparare il materiale hardware che ci servirà, eccone un anteprima.

WP_20150920_001

La Raspberry Pi2

WP_20150920_003

Tastiera e mouse USB (o anche in una sola USB come nel mio caso)

WP_20150920_006

Cavo Ethernet

Cavo HDMI

WP_20150920_002

Cavo di alimentazione fornito con la scheda.

WP_20150920_004

Scheda Micro SD da almeno 8 GB con adattatore

WP_20150920_005

Ora che abbiamo tutto il necessario per la componentistica Hardware, possiamo iniziare a collegare cavi e scheda, ma non ancora quello di alimentazione (poiché, non essendoci interruttore, la Raspberry Pi2 si avvierà immediatamente), a meno che non facciamo uso di una presa di corrente con interruttore dedicato.


Installazione di Windows 10 IoT Core su micro sd.

Abbiamo accennato all’inizio, che la Raspberry Pi2 dispone di uno slot per Micro SD, ed e li che andremo ad installare il sistema operativo su Micro SD. Precisazione,  il pc che preparerà il disco per la Raspberry Pi2, dovrà avere necessariamente installato Windows 10. Per preparare la micro SD, dobbiamo come prima cosa scaricare la ISO di Windows 10 IOT Core.

Ci colleghiamo a questo sito internet: http://go.microsoft.com/fwlink/?LinkId=616847 per scaricare la ISO.

Una volta salvato il file (IOT Core RPi2.ISO), doppio click con il mouse, e automaticamente si monterà un drive virtuale con il file Windows_10_IoT_Core_RPi2.msi da installare.

image

Installiamo quindi il file Windows_10_IoT_Core_RPi2. Quando l’installazione è completata,troveremo un file in C:\Program Files (x86)\Microsoft IoT\FFU\RaspberryPi2 chiamato flash.ffu, sarà il file che ci servirà per l’installazione di Windows 10 IoT Core. Ricordarsi a questo punto di espellere il CD virtuale. Siamo ora pronti per installare Windows 10 IoT Core all’interno della Micro SD. 


Cerchiamo il programma WindowsIoT nel sistema,

image

apriamo WindowsIoTImageHelper, e saremo condotti alla seguente schermata.

image

Inseriamo la nostra micro SD nello slot del pc sulla quale e installato Windows 10, click con il mouse sul pulsante Refresh. ATTENZIONE: la seguente procedura cancellerà tutto il contenuto della Micro SD.   

image

Il software ha rilevato la scheda Micro SD come visibile in figura precedente. Mediante il pulsante “Browse” andiamo a selezionare ora il file flash.ffu e click con il mouse su pulsante “Flash”.

image

image

  Partirà quindi la procedura di installazione, la quale richiederà pochi minuti. 

image

Terminata, possiamo estrarre la scheda micro SD (ricordandoci sempre di fare prima la procedura di espulsione dispositivi). Inseriamo quindi la micro SD nello slot presente sulla Raspberry Pi2, e possiamo adesso collegare alla rete elettrica la nostra scheda. Se abbiamo fatto tutto correttamente nei passaggi precedenti, dovremo vedere una schermata come questa.

WP_20150920_007


Personalizzazione scheda.

La prima cosa che ci balzerà all’occhio, e che Raspberry Pi2 non dispone di una Shell, ossia non ha un Explorer come invece troviamo in un pc Desktop o Portatile. Tuttavia possiamo, se lo desideriamo, eseguire delle personalizzazioni, vediamole subito. Partiamo con il nome del computer. Dobbiamo ricorrere ad uno strumento che usano quotidianamente gli it-pro , ovvero Powershell. Avendo Windows 10 installato, Powershell è già incluso nel sistema e non c’è bisogno di scaricarlo. Apriamo quindi una sessione di Powershell ISE, come Amministratore, dalla casella di testo di ricerca.

image

Si aprirà Powershell.

image

Poiché dovremo gestire una macchina da remoto, dobbiamo come prima cosa avviare il servizio relativo. Quindi digitiamo in Powershell net start WinRM come visibile in figura.

image

Dobbiamo ora assicurarci che il dispositivo sia visibile nella rete. Possiamo verificarlo in due modi: pingare sull’indirizzo ip che compare nella schermata sopra, oppure usare un tool chiamato Windows IoT Core Watcher, che farà vedere le schede disponibili sulla rete.

image

A questo punto digitiamo in Powershell il seguente comando.

Set-Item WSMan:\localhost\Client\TrustedHosts -Value <machine-name or IP Address>

dove al posto <machine-name or IP Address> dovremo digitare l’indirizzo ip o il nome della macchina. Nel mio caso, il comando sarà:

Set-Item WSMan:\localhost\Client\TrustedHosts -Value 192.168.1.50

Visualizzeremo una finestra come da figura seguente, alla quale risponderemo Si.

image

Eseguita questa procedura, possiamo ora connetterci alla Raspberry Pi2, mediante questo comando:

Enter-PSSession -ComputerName <machine-name or IP Address> -Credential <machine-name or IP Address or localhost>\Administrator

dove andremo a metterci il nostro ip o il nome della macchina:

Enter-PSSession -ComputerName 192.168.1.50 -Credential 192.168.1.50\Administrator


Verrà richiesta la password di accesso:

image

La password di default è p@ssw0rd, ma possiamo sempre cambiarla in seguito. L’operazione può durare anche diverse decine di secondi. Dobbiamo essere pazienti e aspettare.Se abbiamo fatto tutto correttamente saremo ora connessi alla Raspberry Pi2. Ce ne accorgiamo perché all’inizio della riga avremo l’indirizzo ip del dispositivo (o il suo nome).

image

Per cambiare il nome del dispositivo, procediamo con il dare i seguenti comandi:

setcomputername <new-name>

Dove al posto di <new-name> metteremo il nuovo nome.

Bisognerà quindi riavviare il dispositivo con

shutdown /r /t 0

e infine riconnetterci in remoto con,

Set-Item WSMan:\localhost\Client\TrustedHosts -Value <new-name>

Se tutto è stato eseguito in maniera esatta, vedremo che sotto Device name abbiamo il nome del pc che abbiamo scelto precedentemente.

WP_20150920_008

Abbiamo così terminato la fase di installazione di Windows 10 IoT Core ed eseguito la modifica del nome del computer. Siamo ora pronti per iniziare a creare e testare progetti mediante l’utilizzo di Visual Studio 2015 che vedremo successivamente.

Articolo scritto da Piero Sbressa (www.crystalweb.it) e Carmelo La Monica, Microsoft Contributor (http://community.visual-basic.it/carmelolamonica/default.aspx)


Calendar

<<  May 2017  >>
MonTueWedThuFriSatSun
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar

Tag cloud

AuthorList