GPIO

Valuta questo articolo 0 Voti

Autori: Lorenzo Maiorfi e Gianluca Ruta

A titolo di esempio, vediamo ora come sviluppare da zero un'applicazione per il .NET Micro Framework. Per iniziare, ci proponiamo di sperimentare con la gestione delle porte I/O digitali.

Dopo aver creato un nuovo progetto di tipo ".NET Micro Framework Console Application", andiamo ad editare l'interno del metodo denominato "Main". Esso rappresenta il cosiddetto "entry-point" del nostro firmware, ossia (ad eccezione di quanto concerne gli inizializzatori o i costruttori statici di cui parleremo in futuro) la porzione di codice eseguita all'avvio del dispositivo.

Per familiarizzare con i tre tipi di porta digitale definiti nelle classi base del framework, definiamo nel nostro firmware tre diversi oggetti, rispettivamente di tipo InputPort, OutputPort e TristatePort, come illustrato nel frammento d codice che segue:

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace USBIziTest
{
    public class Program
    {
        static ArrayList al;

        public static class MyPins
        {
            public const Cpu.Pin GPIO39 = (Cpu.Pin)GHIElectronics.NETMF.Hardware.USBizi.Pin.IO39;
            public const Cpu.Pin GPIO1 = (Cpu.Pin)GHIElectronics.NETMF.Hardware.USBizi.Pin.IO1;
            public const Cpu.Pin GPIO2 = (Cpu.Pin)GHIElectronics.NETMF.Hardware.USBizi.Pin.IO2;
            public const Cpu.Pin GPIO3 = (Cpu.Pin)GHIElectronics.NETMF.Hardware.USBizi.Pin.IO3;            
            public const Cpu.Pin GPIO5 = (Cpu.Pin)GHIElectronics.NETMF.Hardware.USBizi.Pin.IO5;
            public const Cpu.Pin GPIO7 = (Cpu.Pin)GHIElectronics.NETMF.Hardware.USBizi.Pin.IO7;
        }

        public static void Main()
        {
            //Inizializza la porta I/O 39 come porta di ingresso con resistenza di pull up interna
            InputPort ip = new InputPort(MyPins.GPIO39, true, Port.ResistorMode.PullUp);

            //Inizializza la porta I/O 2 come porta di uscita (è quella collegata al led presente sulla scheda USBizi)
            OutputPort op = new OutputPort(MyPins.GPIO2, false);

            //Inizializza le porte I/O 1, 3, 5 e 7 come porte tristate
            TristatePort tp1 = new TristatePort(MyPins.GPIO1, false, false, Port.ResistorMode.PullUp);
            TristatePort tp3 = new TristatePort(MyPins.GPIO3, false, false, Port.ResistorMode.PullUp);
            TristatePort tp5 = new TristatePort(MyPins.GPIO5, false, false, Port.ResistorMode.PullUp);
            TristatePort tp7 = new TristatePort(MyPins.GPIO7, false, false, Port.ResistorMode.PullUp);

            //Per realizzare l'accensione in sequenza si utilizza una collezione che includa le porte tristate
            al = new ArrayList();
            al.Add(tp1);
            al.Add(tp3);
            al.Add(tp5);
            al.Add(tp7);

            bool ipState;
            int step = 0;

            //Imposta la situazione di partenza: led acceso e primo relé acceso
            op.Write(true);
            StepUp(al, 0);

            //ciclo ripetuto all'infinito
            while (true)
            {
                //Legge lo stato della porta di ingresso
                ipState = ip.Read();

                //Se si legge un valore basso
                if (!ipState)
                {
                    //Cambia lo stato di accensione/spegnimento del led
                    op.Write(!op.Read());

                    //Conta un passo in più e di conseguenza accende/spegne i relé 
                    //passando al metodo opportuno il valore del resto della divisione del passo attuale per 4
                    step ++;
                    StepUp(al, step % 4);
                }

                Thread.Sleep(200);
            }

        }

        //Questo metodo consente di realizzare l'accensione in sequenza dei relé utilizzando
        //la collezione delle porte tristate e l'indice dell'elemento nella collezione che va acceso
        private static void StepUp(ArrayList al, int step)
        {
            foreach (object tp in al)
            {
                if (al.IndexOf(tp) == step)
                {
                    ((TristatePort)tp).Active = true;
                    ((TristatePort)tp).Write(false);
                }
                else
                {
                    if (((TristatePort)tp).Active == true)
                        ((TristatePort)tp).Active = false;
                }
            }
        }

    }
}

Per verificare il funzionamento dell'applicazione potremo utilizzare il debugger integrato sia nel caso in cui utilizzeremo l'emulatore, sia nel caso in cui invece sceglieremo di "programmare" il firmware appena scritto nella flash di un microcontrollore reale. Per rendere più interessante la sperimentazione noi mostriamo il test di quanto scritto su una piattaforma hardware reale (e non emulata), costituita dalla scheda di sviluppo USBizi prodotta da GHI Electronics (ogni scheda GHI basata sullo stesso chip può essere utilizzata senza alcuna modifica); per verificare l'utilizzo di una porta di uscita utilizzeremo un led presente sulla scheda stessa, per l'uso di una porta di ingresso utilizzeremo invece un microswitch collegato ad un pin con resistenza di pull-up interna, mentre per l'uso di una porta "tristate" controlleremo gli ingressi open-collector di una scheda per il controllo di relé a quattro canali (costituita dal kit Velleman K2633). Il sistema di test è illustrato nella figura che segue:

Una volta effettuata la "programmazione" della flash del microcontrollore, questo effettuerà il reboot ed il nostro firmware verrà avviato. Per come abbiamo implementato la logica di controllo, all'avvio dell'applicazione il led verrà acceso così come verrà attivato il primo relé della scheda di controllo. Da quel momento in poi, ad ogni chiusura del microswitch il led invertirà il proprio stato e verrà attivato il successivo relé in sequenza (con "rollover").