Realizzare un'applicazione con Micro Framework.NET

Di Raffaele Rialdi

In un precedente articolo ho avuto modo di introdurre l’architettura del nuovo Microsoft Micro Framework.NET. È quindi giunto il momento di realizzare un’applicazione con Visual Studio e provarla su un hardware reale.

In questa pagina

Creazione di un progetto Creazione di un progetto
Anatomia dell’applicazione creata dal wizard Anatomia dell’applicazione creata dal wizard
Una vera applicazione Una vera applicazione
Conclusione Conclusione

Creazione di un progetto

Per sviluppare con il Micro Framework è necessario Visual Studio 2005 Standard Edition o superiore installato su Windows Server 2003, Windows XP oppure Windows Vista.

Dopo aver installato Visual Studio, si scarica il Micro Framework SDK dal sito MSDN e si procede all’installazione. La procedura di setup aggiunge a Visual Studio un nuovo tipo di progetto nel gruppo del linguaggio C# che è l’unico supportato in questa versione di Micro Framework.

*

Ci sono quattro tipologie di progetti disponibili nei template di progetto.

Il progetto di tipo Class Library consiste nella creazione di una DLL. La creazione di assembly separati nelle applicazioni favorisce il riuso del software in altri progetti ed è una buona abitudine. Naturalmente nell’ambito del Micro Framework la memoria è un bene particolarmente prezioso, perciò è importante non abusare della frammentazione in più assembly.

Le Console Application servono a creare applicazioni che non fanno uso del display LCD. Per esempio un’applicazione che legge delle merci tramite barcode seriale/bluetooth o RFID e trasmette le informazioni via TCP/IP potrebbe fare a meno del display, prediligendo una comunicazione audio o con dei semplici LED. La classe Program generata non deriva da nessun’altra classe e ha in Main il suo punto di ingresso.

Il progetto Device Emulator serve a riprodurre nel modo più fedele possibile il target hardware dell’applicazione. Ogni progetto può avere una configurazione hardware con differenze come il numero di periferiche utilizzate, la risoluzione e dimensione dello schermo LCD, il numero di pulsanti e la loro disposizione. Il progetto Device Emulator permette di creare un nuovo emulatore che riproduca fedelmente il target hardware per velocizzare la fase di sviluppo. L’assembly prodotto da questo progetto è destinato ad essere eseguito sul PC e quindi può usufruire di tutte le potenzialità del Framework.NET.

Il progetto Windows Application crea un’applicazione analoga alla Console Application ma che ha il supporto per lo schermo LCD. È importante notare che, sia in questo tipo di progetto che in quello Console, nelle proprietà del progetto Micro Framework il subsystem è sempre impostato a “Console Application” e mai a “Windows Application”. Nel Framework.NET questa impostazione serve ad indicare al loader di Windows il contesto nel quale aprire l’applicazione. Nel Micro Framework questa impostazione non viene usata e l’unica differenza fra i due tipi di progetti è nel codice generato dal wizard. La classe Program generata deriva da Microsoft.SPOT.Application che fornisce il supporto per WPF creando internamente un Dispatcher.

Per cominciare a realizzare la prima applicazione, prendiamo in esame una Windows Application così come viene creata dal wizard del Micro Framework.

*

 

Anatomia dell’applicazione creata dal wizard

Il file AssemblyInfo.cs contiene, come avviene in tutte le versioni del Framework.NET, gli attributi relativi alle informazioni che appariranno nel tab “Version” nelle proprietà del file (prese da risorse del computer). Modificando l’attributo AssemblyVersion da 1.0.0.0 a 1.0.0.* otterremo la numerazione automatica delle ricompilazioni:

[assembly: AssemblyVersion("1.0.0.*")]

Questa modifica è molto utile per tenere traccia dei file che vengono generati ed evitare confusione fra i file in fase di test e quelli in deploy sull’hardware.

Come è usuale, nella cartella References sono presenti gli assembly referenziati nel progetto. Oltre a quelli di sistema possono essere aggiunti solo quegli assembly che usano la porzione di Base Class Library disponibile nel Micro Framework. Tipicamente si aggiungono le dll prodotte con l’opzione “Class Library” di Micro Framework del wizard di Visual Studio.

È importante notare che, per quanto sia semplice il sorgente, non si può aggiungere una Class Library creata per una diversa versione del Framework.NET in quanto le opzioni di compilazione presenti nel file .csproj sono differenti e non creano ad esempio il file “.pe” necessario ai progetti Micro Framework.
Nonostante questo, la portabilità del codice non è persa. Visual Studio permette infatti di referenziare un sorgente presente in una cartella differente senza farne una copia locale che comprometterebbe la manutenibilità del sorgente duplicato.
Se perciò avessimo un’ipotetica classe Adder del Framework.NET che volessimo aggiungere ad uno dei progetti di Micro Framework sarebbe necessario aggiungere un link ad un file esistente, selezionando “Add As Link” nel pulsante della dialog di scelta del file.

*

Le risorse

La cartella Resources contiene le risorse usate all’interno del progetto. Per una Windows Application viene creata automaticamente una risorsa di tipo Font.

Le Font del Micro Framework sono di tipo raster a singola altezza e descritte in un formato proprietario che permette di contenere le dimensioni occupate. Nella cartella “C:\Program Files\Microsoft .NET Micro Framework\v2.0.3036\Fonts” sono presenti due font: small.tinyfnt e NinaB.tinyfnt, rispettivamente di 1KB e 2KB.

Al momento non sono disponibili altre font, tantomeno esistono tool per realizzarle e questo è il maggiore impedimento ad applicazioni che debbano essere globalizzate. Con tutta probabilità si attende per la prossima versione del Micro Framework una soluzione a questo problema.

Per aggiungere un’altra font al progetto è necessario aprire la finestra delle risorse facendo doppio click sul file Resources.resx, scegliere il menu “Add existing file” e selezionando la font NinaB.tinyfnt.

*

Con la stessa procedura si possono aggiungere altri tipi di risorse come delle bitmap. L’esempio non è casuale perché proprio quando viene aggiunta una bitmap, Visual Studio automaticamente aggiunge per errore l’assembly System.Drawing.dll.

*

Se non viene rimosso questo assembly, la compilazione viene eseguita normalmente ma all’avvio dell’applicazione si ottiene un errore dall’emulatore:

"Error: Assembly file '' does not exist! Load failed.".

Per risolvere basta perciò rimuovere l’assembly System.Drawing.dll.

L’operazione di aggiunta di una risorsa fa si che la classe Resources presente nel file Resources.Designer.cs venga automaticamente rigenerata. Questa classe permette di accedere alle risorse in modo strong-typed e di beneficiare di Intellisense nell’editor di Visual Studio.

Per accedere ad una delle risorse referenziate è sufficiente usare la classe Resources.

Font f = Resources.GetFont(Resources.FontResources.NinaB);

Oppure

Bitmap led = Resources.GetBitmap(Resources.BitmapResources.LedOn);

La classe Program

Dopo aver creato un’istanza della classe Program, viene chiamato il metodo CreateWindow che restituisce un’istanza di una Microsoft.SPOT.Presentation.Window, inizializzato il managed driver per la gestione dei pulsanti ed infine dato il controllo alla coda dei messaggi di WPF tramite il metodo Run.

Il metodo CreateWindow recupera le risorse Font e String usate sul display, e istanzia tutti i controlli via codice visto che ovviamente WPF del Micro Framework non ha il supporto per XAML. Le dimensioni dello schermo LCD vengono ricavate dinamicamente grazie alla classe SystemMetrics che può anche indicare il numero di colori supportato dal display LCD.

L’evento di pressione del tasto hardware viene sottoscritto durante la creazione della finestra e gestito nel metodo OnButtonUp che viene eseguito nel contesto del thread corrente.

 

Una vera applicazione

Il codice preparato dal wizard è prezioso ed è una buona base per costruire un’applicazione. Per mettere alla prova il Micro Framework ho provato a realizzare una versione evoluta di un piccolo firmware che ho scritto qualche tempo fa per un microcontrollore. L’idea è quella di un piccolo device che permetta di contare le vasche durante un allenamento di nuoto. Ogni volta che si compiono due vasche con la mano si preme il device il quale conta le vasche grazie ad un piccolo interrutore da mouse.

Il progetto

Per la versione Micro Framework di questa applicazione ho pensato a qualcosa di più complesso. La nuova versione implementa un cronografo che memorizza i tempi di tutte le vasche.

Il pulsante di Start avvia il cronografo che può anche essere messo in pausa e riavviato con pressioni successive. Il pulsante di Stop ferma il cronografo e crea un’istanza della classe SwimTiming che memorizza il numero sequenziale della vasca, la data/ora di fine vasca e il TimeSpan del tempo impiegato a realizzare la coppia di vasche, millisecondi compresi.

Ogni volta che viene fermato il cronografo, l’istanza di SwimTiming viene aggiunta ad una collection SwimTimingCollection e, grazie all’override del metodo ToString, creata la stringa che viene aggiunta alla ListBox dello storico dei tempi. Tra le informazioni mostrate appare anche la differenza con il tempo della vasca precedente.

Nella porzione inferiore dello schermo una seconda ListBox può mostrare il tempo in fase di misurazione, la media dei tempi fin qui accumulati, il tempo più alto e quello più basso.

Infine è possibile scaricare tutti i dati della collection dei tempi sulla porta seriale e recuperarli su un PC permettendo, ad esempio, di utilizzare Excel per realizzare un grafico con la prestazione della giornata.

*

Naturalmente, per motivi di spazio, nell’articolo presenterò solo le parti tecnicamente più rilevanti del progetto.

La gestione di un cronografo

Il Micro Framework non è un sistema real time perciò la gestione del cronografo non è triviale. Per ovviare ai possibili ritardi che possono influenzare la precisione della misurazione ho creato una classe Chrono che internamente utilizza il timer Microsoft.SPOT.ExtendedTimer che mima per funzionalità la già nota classe System.Threading.Timer, anch’essa utilizzabile nel Micro Framework.

La classe Chrono fornisce i metodi Start, Pause e Stop ed un evento IntervalElapsed che informa circa lo stato del cronografo e il tempo trascorso.

Il timer è asincrono rispetto all’interfaccia utente perciò, così come nel Framework.NET, è necessario chiamare BeginInvoke e far si che i controlli grafici vengano accessi dal thread principale. La scelta di BeginInvoke è preferibile rispetto a Invoke così da poter liberare il thread del timer al più presto senza attendere il termine dell’esecuzione del gestore dell’evento.

// evento della classe Chrono
void Chrono_IntervalElapsed(object sender, ChronoEventArgs e)
{
_DelArgs[0] = sender;
_DelArgs[1] = e;
this.Dispatcher.BeginInvoke(_ChronoDel, _DelArgs);
}

// metodo eseguito nel contesto del thread principale
void Chrono_IntervalElapsed_Dispatched(object sender, ChronoEventArgs e)
{
_ClockText.TextContent = _Chrono.GetFormattedTime(
e.State == ChronoState.Paused || e.State == ChronoState.Stopped);
_ClockText.UpdateLayout();
if(e.State == ChronoState.Stopped)
AddNewTime(new SwimTiming(DateTime.Now, e.Elapsed));
}

Anche la gestione standard dei pulsanti può inserire dei ritardi. Come abbiamo visto in precedenza è lo stesso Micro Framework ad eseguire la chiamata a BeginInvoke per chiamare i gestori degli eventi dei pulsanti nel contesto del thread principale. Per evitare il piccolo ritardo che ne può derivare è possibile modificare leggermente la class GPIOButtonInputProvider sottoscrivendo direttamente l’event handler dell’interrupt.

InterruptPort _PlayPausePort;
InterruptPort _StopPort;
...
_PlayPausePort = new InterruptPort(..., false, Port.ResistorMode.PullUp,
Port.InterruptMode.InterruptEdgeBoth);
_StopPort = new InterruptPort(..., false, Port.ResistorMode.PullUp,
Port.InterruptMode.InterruptEdgeBoth);

void PlayPause_OnInterrupt(Cpu.Pin port, bool state, TimeSpan time)
{
if(!state)// ci interessa solo il rilascio del pulsante
return;
if(_Chrono.State == ChronoState.Running ||
 _Chrono.State == ChronoState.Started)
{
_Chrono.Pause();
return;
}
_Chrono.Start();
}

Questo implica naturalmente di dover utilizzare l’istruzione lock di C# sui metodi Start, Stop, Pause e il gestore dell’evento del timer per evitare problemi di concorrenza con potenziale corruzione delle variabili in comune.

public void Start()
{
lock(_Sync)
{
...
}
}

L’interfaccia grafica

L’uso dei timer è un compito semplice anche su un assembler di un microcontrollore a 8 bit. La gestione di un display LCD grafico è invece un compito molto più complesso e il Micro Framework rende questo compito non solo triviale ma secondo una logica object oriented.

Il Micro Framework ci mette a disposizione una serie di classi che permettono un approccio molto simile a quelle di WPF (Windows Presentation Foundation) del Framework.NET 3.0. L’elemento principale è la Window che rappresenta il primo elemento grafico che ricopre l’intero LCD.

Dopo aver dimensionato la finestra grazie a SystemMetrics, è necessario creare i controlli. Vista l’assenza del colore trasparente, ad ogni controllo viene assegnato il brush del background. È necessario fare attenzione nell’uso di sfumature quando si sovrappongono controlli perché le tonalità potrebbero leggermente variare. Come si può vedere nel LCD in figura, le bitmap devono essere preparate per avere il colore di background ma in caso di sfumatura la forma rettangolare risalta immediatamente.

Le classi di presentazione grafica sono divise in tre categorie: layout, controlli di presentazione dati e disegno.

Tra i controlli di layout la classe StackPanel fa da regina, anche per l’assenza della Grid che renderebbe i controlli troppo dipendenti dalle caratteristiche fisiche dello schermo LCD. Tutta la presentazione dei controlli deve quindi essere pensata secondo una logica a stack con un’orientazione verso l’alto oppure verso sinistra.

Il primo elemento di layout dell’applicazione in esame è uno StackPanel verticale. Il primo elemento aggiunto alla collection Children è una ListBox che conterrà la lista dei tempi. Subito sotto viene aggiunto un controllo Border che ha come Child un nuovo StackPanel, questa volta orizzontale.

*

All’interno dello StackPanel orizzontale sono presenti una ListBox e un Border il quale a sua volta ospita un controllo Text.

*

Una bellissima caratteristica di WPF è quella di poter personalizzare in modo molto semplice anche i ListBoxItem. Per la lista superiore, il ListBoxItem contiene uno StackPanel il quale ospita tre elementi: un Border con dentro un Text, una Image ed un Text.

Il primo Border è necessario per dare una larghezza fissa all’elemento che contiene il numero consecutivo delle rilevazioni e poterle allineare sul margine destro. Diversamente i numeri superiori a nove sarebbero allineati in modo errato.

*

Per la ListBox inferiore la costruzione è analoga. Da notare che i ListBoxItem hanno impostato il margine in modo da limitare la dimensione del rettangolo che evidenzia l’elemento selezionato.

*

ListBoxItem CreateLowerItem(Brush Background, string Content,
int Width, int Height, HorizontalAlignment HAlign)
{
ListBoxItem lbi = new ListBoxItem();
lbi.Background = Background;
lbi.HorizontalAlignment = HorizontalAlignment.Left;
lbi.SetMargin(10, 2, 10, 2);
lbi.Child = CreateText(Content, HAlign, VerticalAlignment.Bottom);
...
}

Così come nel Framework 3.0 la superficie virtuale che ospita i ListBoxItem è uno StackPanel che è ospitato a sua volta da uno ScrollViewer che astrae la logica dello scrolling. Mentre lo StackPanel non ha Background, lo ScrollViewer ne è dotato e il suo default è bianco.

Per ovviare al problema della trasparenza è perciò necessario impostare il colore, nel nostro caso la sfumatura con gradiente, anche allo ScrollViewer, altrimenti la superficie sottostante i ListBoxItem sarà bianca.

Inoltre la ListBox superiore non deve avere un elemento selezionato ma è sufficiente che sia scrollabile. Per questo motivo il numero di pixel da spostare ogni volta che si chiamano i metodi LineUp e LineDown dello ScrollViewer è regolata dalla proprietà LineHeight.

Questo è il metodo che inserisce un nuovo elemento nella lista superiore.

void AddNewTime(SwimTiming st)
{
_SwimTimings.Add(st);
_HistoryListBox.Items.Insert(0, 
CreateUpperItem(_UnselectedItemBrush, st.Number.ToString(),
 st.ToString(), _HistoryListBox.Width, 0, HorizontalAlignment.Left));

ScrollViewer sv = _HistoryListBox.Items[0].Parent.Parent as ScrollViewer;
sv.Background = _UnselectedItemBrush;
sv.LineHeight = _HistoryListBox.Items[
_HistoryListBox.Items.Count-1].ActualHeight + 4;
sv.ScrollingStyle = ScrollingStyle.LineByLine;
}

La gestione dei tasti

La modalità di gestione dei tasti è identica a quella presente nel wizard. Le uniche modifiche riguardano i comandi che questi impartiscono.

Per esempio il tasto Down può scrollare la ListBox superiore oppure cambiare l’elemento selezionato di quella inferiore.

private void OnButtonUp(object sender, ButtonEventArgs e)
{
Debug.Print(e.Button.ToString());
if(e.Button == Button.Down)// _StatisticsListBox
{
if(_StatisticsListBox.SelectedIndex == _StatisticsListBox.Items.Count - 1)
return;
else
_StatisticsListBox.SelectedIndex++;
}

if(e.Button == Button.Up)// _StatisticsListBox
{
if(_StatisticsListBox.SelectedIndex == 0)
return;
else
_StatisticsListBox.SelectedIndex--;
}


if(e.Button == Button.FastForward)// _HistoryListBox
{
if(_HistoryListBox.Items.Count == 0)
return;
ScrollViewer sv = _HistoryListBox.Items[0].Parent.Parent as ScrollViewer;
sv.LineDown();
sv.Invalidate();
}
...
}

Scaricare i dati su PC

Il Micro Framework ci mette a disposizione il meccanismo della serializzazione per persistere in pochi byte la collection grazie all’attributo Serializable. La mia classe helper TimeSpanFormatter e il reference alla collection a cui l’elemento appartiene vengono marcati con NonSerialized per escluderli dalla serializzazione.

[Serializable]
public class SwimTiming : IComparable
{
int _Number;
DateTime _TimeStart;
TimeSpan _Elapsed;

[NonSerialized]
SwimTimingCollection _List;
...
}

[Serializable]
public class SwimTimingCollection : ArrayList
{
int Counter = 0;

[NonSerialized]
TimeSpanFormatter _TimeSpanFormatter;
...
}

In questa applicazione la seriale è una porta di comunicazione sufficiente allo scopo visti i pochi byte necessari a descrivere la lista dei tempi, ma analogamente sarebbe possibile utilizzare un’altra periferica.

Il trasferimento dei dati avviene grazie al metodo Upload. Naturalmente sul PC sarà necessario decodificare il formato binario manualmente in quanto la serializzazione del Micro Framework è studiata per mantenere contenute le sue dimensioni.

private void Upload()
{
SerialPort.Configuration config = new SerialPort.Configuration(
SerialPort.Serial.COM1, SerialPort.BaudRate.Baud19200, false);
SerialPort port = new SerialPort(config);
byte[] Blob = Reflection.Serialize(_SwimTimings,
typeof(SwimTimingCollection));
port.Write(Blob, 0, Blob.Length);
port.Dispose();
}

In alternativa è possibile creare un semplice formato XML concatenando le stringhe ed ottenere dalla classe UTF8Encoding l’array di bytes da passare al metodo Write della classe SerialPort.

L’hardware di test

Tutto quanto detto si apprezza molto di più usando un vero hardware al posto dell’emulatore.

Il primo hardware development kit che è apparso sul mercato è il Freescale i.MXS Development Kit ma molti altri stanno cominciando ad arrivare sul mercato. I prezzi sono abbordabili, intorno ai 500$, ed altri produttori stanno proponendo offerte similari come Embedded Fusion con “Tahoe development platform” e SJJ Embedded Micro Solutions con “.NET Micro Framework Development Kit”.

Le principali caratteristiche della scheda Freescale i.MXS usata per l’esempio di questo articolo sono:

  • CPU ARM920T 100 MHz

  • Display LCD 2.5” a colori (QVGA)

  • 32MB SDRAM + 8MB Flash

  • 1 Porta USB 1.1

  • 2 Porte RS232 (1 connettore 9Pin + 1 connettore espansione)

  • 2 interfacce I2C (1 reale + 1 simulata via I/O)

  • 1 espansione Audio

*

È importante notare che queste sono delle piattaforme di sviluppo che consentono di eseguire il debug di un’applicazione direttamente sull’hardware. I device sui quali dovrà funzionare l’applicazione saranno, con tutta probabilità, molto più contenuti sia in dimensione che prezzi in quanto le periferiche presenti sul kit di sviluppo non sono sempre tutte necessarie.

Dopo aver provato il Micro Framework con l’emulatore di Visual Studio, la prima operazione da compiere è quella di installare il driver USB fornito dal produttore.

Per prima cosa è importante alimentare sempre la scheda prima di effettuarne la connessione. Poi si collega il cavo USB e si procede all’installazione del driver così come richiesto da Windows. Se tutto procede regolarmente, il driver viene installato sotto la classe dei device USB nel device manager di Windows. È importante installare la versione più recente del driver. In prima battuta ho avuto una versione preliminare del driver che veniva vista correttamente nel device manager ma non era possibile usare la scheda da Visual Studio. Questo è un chiaro sintomo di un problema del driver.

Sempre dal disco del produttore è importante installare l’emulatore specifico della board, nel mio caso l’emulatore iMXS di FreeScale. Questo consente di provare l’applicazione con le stesse periferiche e con la stessa mappatura delle I/O sui pulsanti della scheda.

Per selezionare il device o l’emulatore da utilizzare, si aprono le proprietà del progetto Micro Framework in Visual Studio. Nella form di configurazione è presente il tab “Micro Framework” che permette di scegliere la porta e il device o l’emulatore da usare.

*

*

Nel progetto di esempio di FreeScale viene fornito anche il file CPU.cs che contiene diverse classi per la gestione delle I/O di questa scheda.

Per poter provare il progetto sull’hardware si inizia importando CPU.cs con “add existing files” di Visual Studio ed eseguendo alcune modifiche al file GPIOButtonInputProvider.cs.

*

Il file della FreeScale ha un namespace differente e, per evitare di modificarlo, è preferibile dichiarare un alias per il namespace:

using iMXsBoard = Microsoft.SPOT.Hardware.FreescaleMXSDemo;

La rimappatura dei pulsanti è semplice e si limita alla variazione dell’array di ButtonPad creato dal wizard.

ButtonPad[] buttons = new ButtonPad[]
{
    new ButtonPad(this, Button.Left  , Cpu.Pin.GPIO_Pin0),
    new ButtonPad(this, Button.Right , Cpu.Pin.GPIO_Pin1),
    new ButtonPad(this, Button.Up    , Cpu.Pin.GPIO_Pin2),
    new ButtonPad(this, Button.Select, Cpu.Pin.GPIO_Pin3),
    new ButtonPad(this, Button.Down  , Cpu.Pin.GPIO_Pin4),
};

La nuova mappatura sarà perciò la seguente:

ButtonPad[] buttons = new ButtonPad[]
{
new ButtonPad(this, Button.Left  , iMXsBoard.Pins.GPIO_PORT_B_16),
new ButtonPad(this, Button.Right , iMXsBoard.Pins.GPIO_PORT_B_12),
new ButtonPad(this, Button.Up    , iMXsBoard.Pins.GPIO_PORT_B_11),
new ButtonPad(this, Button.Select, iMXsBoard.Pins.GPIO_PORT_B_8),
new ButtonPad(this, Button.Down  , iMXsBoard.Pins.GPIO_PORT_B_10),
new ButtonPad(this, Button.Menu  , iMXsBoard.Pins.GPIO_PORT_B_13),
new ButtonPad(this, Button.Rewind  , iMXsBoard.Pins.GPIO_PORT_B_14),
new ButtonPad(this, Button.FastForward  , iMXsBoard.Pins.GPIO_PORT_B_15),
};

Per capire che la porta B_16 corrisponde al pulsante sinistro ed eseguire il mapping corretto, è necessario osservare la scheda e il suo schema elettrico. Nella figura a sinistra sono presenti i pulsanti così come appaiono nella scheda fisica, da S1 a S10.

Nello schema elettrico si può vedere come la connessione della porta B_16 (marcata PB16) sia collegata al pulsante S7, da cui si ricava lo schema a destra. Dalla figura così ricavata l’associazione del pulsante Button.Left alla porta B_16 diventa intuitiva.

*

*

Un altro punto importante è la configurazione hardware dei pulsanti che possono avere resistenze di pullup oppure di pulldown. Guardando sul data sheet di FreeScale si osserva facilmente che sono in configurazione di pullup.

*

Questo significa che la configurazione delle resistenze non deve essere cambiata. È invece necessario disabilitare il filtro anti-glitch che evita falsi rimbalzi sulla pressione dei pulsanti, poiché non è supportato dalla scheda.

public ButtonPad(GPIOButtonInputProvider sink, Button button, Cpu.Pin pin)
{
this.sink = sink;
this.button = button;

port = new InterruptPort(pin,
false,   // i.MXS non supporta AntiGlitch
Port.ResistorMode.PullUp,  // Verficare sullo schema elettrico
Port.InterruptMode.InterruptEdgeBoth);

port.OnInterrupt += new GPIOInterruptEventHandler(this.Interrupt);
}

Lo strumento di configurazione hardware

Dal sito del Micro Framework è possibile scaricare MFDeploy, un tool che permette di cancellare la nostra applicazione sulla scheda qualora non riesca più a fare il boot.

*

Se dopo aver scelto USB nella casella a fianco non è visibile il nome del device, significa che il driver non sta comunicando con la scheda o che il driver è difettoso.

  • Ping permette di verificare che il loader presente sulla scheda stia funzionando correttamente.

  • Erase consente la cancellazione della nostra applicazione managed dalla scheda.

  • Deploy permette di ricaricare il loader (CLR compreso) sulla scheda. Questa procedura va effettuata solo se necessario ed eseguibile solo in una modalità speciale che si abilita accendendo la scheda mentre vengono premuti i pulsanti Up e Down contemporaneamente.

 

Conclusione

La semplicità di uso di una piattaforma di sviluppo permette la creazione di applicazioni che, diversamente, avrebbero richiesto un tempo difficilmente investibile. Il tempo di realizzazione e la qualità dell’interfaccia utente ottenuta sono nettamente a vantaggio del Micro Framework rispetto a soluzioni più classiche, almeno per progetti in cui la battaglia dei costi non si giochi sui centesimi.

Grazie a Visual Studio si riesce a sviluppare ed eseguire il debugging dell’applicazione sia con l’emulatore che direttamente sulla scheda collegata via USB. Questo permette l’analisi sotto debugger di scenari che difficilmente sarebbero ripetibili tramite un emulatore e con una serie di comodità come solo i progammatori di Visual Studio sono abituati.

*

Per tutte quelle applicazioni per cui il real time è indispensabile, Micro Framework è comunque utilizzabile comunicando tramite I2C o SPI con un tradizionale processore a cui demandare le operazioni real time. Il risultato di questa unione è certamente una soluzione molto potente in quanto permette di sfruttare al meglio i due mondi.

L’applicazione di esempio è pubblicata sulla pagina http://www.coolbugs.com/articoli/microframework.aspx