La porta GPIO della Raspberry Pi – Prima parte

Di - 15 November 2013 - in
Post image for La porta GPIO della Raspberry Pi – Prima parte

Come molti system-on-a-chip, la Raspberry Pi ha una porta GPIO, ovvero una porta generica di input/output (general purpose input/output). Non si tratta dell’unica porta di comunicazione a basso livello, ma le altre hanno utilizzi piú specifici e probabilmente meno interessanti in quanto di piú facile utilizzo. In questo articolo, vedremo di cosa si tratta, pur senza un approfondimento eccessivo sulle funzionalità secondarie dell’interfaccia, che sono molto complesse e richiedono uno sguardo alla documentazione nei casi d’uso particolari.

Un’interfaccia GPIO è un insieme di pin (spesso sono 8, la Raspberry Pi ne ha ben 26, anche se non tutti utilizzabili effettivamente come GPIO) che comunicano quasi direttamente con i registri del processore e che sono facilmente programmabili per collegare periferiche atipiche o addirittura costruite in casa. Quest’interfaccia, quindi, è il vero punto focale della grandissima versatilità della Raspberry Pi, ed è la funzionalità attorno alla quale la macchina è stata creata. Le applicazioni della GPIO nelle attività educative è limitata solo dalla fantasia di studenti ed insegnanti.

Essendo in diretta comunicazione con il processore, e non avendo alcun tipo di protezione elettrica, l’interfaccia GPIO è anche una delle parti piú delicate della nostra Raspberry Pi. Da quello che ho visto in questi mesi di sperimentazione sui forum, le cause piú frequenti di danni irreparabili sono l’utilizzo improprio dei pin GPIO e il collegamento alla porta HDMI di adattatori DVI o VGA troppo esosi. È bene quindi utilizzare i pin a disposizione sapendo bene cosa si sta facendo, ed evitando assolutamente di fare cose tanto per provare, se non si ha a disposizione adeguata documentazione.

L’interfaccia GPIO è un’interfaccia digitale: può inviare e ricevere soltanto segnali digitali, ovvero alternanze di 0 volt e 3.3 volt. Per utilizzare sensori e servomotori che abbiano interfaccia analogica (tipicamente quelli che si utilizzano in robotica) è necessario utilizzare un ADC (un convertitore da analogico a digitale) o sfruttare microcontrollori (come l’Arduino) per fare da interfaccia.

In particolare è bene ricordare che i pin GPIO della Raspberry Pi lavorano a 3.3 volt, e a differenza di altri sistemi a cui si può essere abituati non tollerano i 5 volt. Collegare qualcosa che immetta 5 volt su un pin GPIO equivale a rompere il processore. Considerando che per comodità due dei pin di alimentazione erogano 5 volt, è opportuno evitare di toccarli se non si è assolutamente convinti che vadano toccati.

La porta GPIO è questa qui:

I pin sono numerati dal basso all’alto e poi da sinistra a destra. Per motivi di architettura, però, la numerazione GPIO utilizzata dalle librerie di accesso ai pin è differente e apparentemente casuale. La numerazione GPIO che utilizzerò è valida per la Raspberry Pi attualmente in vendita, chi come me la ha comprata da tempo troverà qualche differenza che annoterò.

Vi elenco in una tabella le funzioni di ogni pin, e per alcuni elencherò una funzione che etichetto come “secondaria” (e di cui parlerò in un prossimo articolo), ma che è in realtà la funzione che i pin hanno di default. La maggior parte dei pin supportano diverse funzioni secondarie di vario livello, e per un’analisi piú approfondita vi rimando alla documentazione (o a questo piú conciso riassunto). Per i pin GPIO sarà anche detto lo status in modalità reset (high se erogano segnale a 3V, low se sono a 0V). La numerazione tra parentesi è quella della vecchia versione.

Pin Funzione Funzione secondaria Stato
1 Alim. 3V3
2 Alim. 5V
3 GPIO 2 (0) I2C SDA high
4 Alim. 5V
5 GPIO 3 (1) I2C SCL high
6 Terra
7 GPIO 4 GPCLK0 high
8 GPIO 14 UART TxD low
9 Terra
10 GPIO 15 UART RxD low
11 GPIO 17 low
12 GPIO 18 PWM low
13 GPIO 27 (21) low
14 Terra
15 GPIO 22 low
16 GPIO 23 low
17 Alim. 3V3
18 GPIO 24 low
19 GPIO 10 SPI MOSI low
20 Terra
21 GPIO 9 SPI MISO low
22 GPIO 25 low
23 GPIO 11 SPI SCLK low
24 GPIO 8 SPI CE0 high
25 Terra
26 GPIO 7 SPI CE1 high

Uno schema un po’ piú grafico e comodo da stamparsi è qui.

Fatta questa introduzione, vediamo come utilizzare i singoli pin.

La libreria Python RPi.GPIO

Il modo piú semplice per programmare i pin GPIO è utilizzare Python. Non è un linguaggio che mi sia particolarmente simpatico, per questioni di design, ma è certamente molto semplice e molto diffuso nelle scuole e nelle università. Ottima scelta, quindi, quella della Raspberry Foundation che ha voluto usare questo linguaggio come linguaggio d’elezione.

Quella in Python, che andiamo ad esplorare, non è l’unica possibile libreria. Esistono librerie per altri linguaggi, come la wiringpi e la bcm2835 entrambe per C. Esistono anche diversi modi per utilizzare l’interfaccia da shell, e vedremo qualcosa a riguardo.

Installazione

Per installare RPi.GPIO dobbiamo prima di tutto installare pip, il gestore pacchetti di Python:

sudo apt-get install pyton-pip

Poi dovremo installare gli strumenti di sviluppo. Qui installo quelli di Python 3, se preferite Python 2 togliete il 3 dal comando che segue:

sudo apt-get install python3-dev

Infine, installiamo tramite pip due pacchetti che ci servono: distribute e RPi.GPIO:

sudo pip install distribute
sudo pip install RPi.GPIO

 Principali comandi

I comandi piú utili sono pochissimi:

  • setmode imposta il metodo di riferimento ai pin. Se le si passa il valore GPIO.BOARD si indica che si vuole accedere ai pin attraverso il loro numero, mentre se le si passa GPIO.BCM si indica che si utilizzerà il numero di porta GPIO (che ricordo essere differente in alcuni casi se la scheda è di vecchio tipo).
  • setup serve ad impostare un pin come pin di input o di output. Prende in ingresso tre valori: il primo è il numero del pin, il secondo è la costante GPIO.IN se si vuole usare il pin come input e GPIO.OUT se lo si vuole usare come output. Il terzo valore, facoltativo, permette di impostare alcune opzioni.
  • input analizza l’input del pin che gli si dà come argomento. Restituisce 0 se lo stato del pin è “low” e 1 se è “high”.
  • output imposta lo stato di un pin a “high” o “low”. Prende due argomenti: il primo è il numero del pin, il secondo è lo stato (1 oppure True oppure GPIO.HIGH per “high” e 0 oppure False oppure GPIO.LOW per “low”)
  • cleanup riporta tutti i pin utilizzati allo stato originale.

Esempio

Vediamo un esempio minimo di programma, che faccia solo output su di un LED, traducendo in codice Morse ciò che gli passiamo come argomento. Il programma è commentato:

#!/usr/bin/python

#Librerie
import sys
import RPi.GPIO as GPIO
import time

####################
#Configurazione    #
####################

#Pin del led
ledPin=22

#Durata dell'accensione per il punto e della linea (in secondi)
durPunto=0.2
durLinea=0.5

#Modalita' di indicazione del led (numerazione GPIO)
GPIO.setmode(GPIO.BCM)

####################
#Dati utili        #
####################

#Codice Morse
MORSE = {"'": '.----.','(': '-.--.-',')': '-.--.-',',': '--..--','-': '-....-','.': '.-.-.-','/': '-..-.','0': '-----','1': '.----','2': '..---','3': '...--','4': '....-','5': '.....','6': '-....','7': '--...','8': '---..','9': '----.',':': '---...',';': '-.-.-.','?': '..--..','A': '.-','B': '-...','C': '-.-.','D': '-..','E': '.','F': '..-.','G': '--.','H': '....','I': '..','J': '.---','K': '-.-','L': '.-..','M': '--','N': '-.','O': '---','P': '.--.','Q': '--.-','R': '.-.','S': '...','T': '-','U': '..-','V': '...-','W': '.--','X': '-..-','Y': '-.--','Z': '--..','_': '..--.-'}

####################
#Funzioni          #
####################

#Accende e spegne rapidamente il led per il punto
def punto():
    GPIO.output(ledPin, 1)
    time.sleep(durPunto)
    GPIO.output(ledPin,0)
    time.sleep(durPunto)

#Accende e spegne lentamente il led per la linea
def linea():
    GPIO.output(ledPin, 1)
    time.sleep(durLinea)
    GPIO.output(ledPin,0)
    time.sleep(durPunto)

####################
#Programma         #
####################

def main(argv):

    GPIO.setup(ledPin, GPIO.OUT)

    #Per ogni parola passata come comando
    for arg in argv:
        #Per ogni lettera della parola
        for lettera in arg:
            #Per ogni segno del Morse corrispondente
            for segno in MORSE[lettera.upper()]:
                if segno == '-':
                    linea();
                else:
                    punto();
        time.sleep(durLinea)
    GPIO.cleanup()

#elimino il primo argomento
main(sys.argv[1:])

Salviamo il file come morse.py, per poi dargli da terminale i permessi di esecuzione:

chmod ugo+x morse.py

Colleghiamo al pin GPIO 22 (che è il pin numero 15 su qualsiasi versione della scheda) il resistore adatto al led (circa 300 ohm, ma dipende molto dal tipo di led e dal colore, se non avete idea chiedete al venditore) e poi nostro LED, da collegare a sua volta ad uno dei pin di terra. Ecco lo schema.

A questo punto eseguiamolo, anteponendo il comando sudo, poiché l’interfaccia GPIO può essere utilizzata solo da amministratore:

sudo ./morse.py testo

Vedremo lampeggiare il led componendo in morse la parola “testo”. Allo script possiamo tranquillamente passare un’intera frase.

RPi.GPIO supporta anche funzioni piú avanzate, tra cui la possibilità di inviare impulsi periodici (PWM). Per approfondire rimando alla documentazione sull’input, quella sull’output e quella sul PWM.

L’accesso da shell: il comando gpio

Tra le utility installate sulla Raspberry Pi si trova il comando gpio che permette di fare da shell operazioni analoghe a quelle fattibili in Python.

Le opzioni corrispondenti a quelle di RPi.GPIO sono le seguenti:

  • mode, analogo a setup, imposta la modalità di un pin. Prende come parametri il numero associato al pin e la modalità, che può essere “in”, “out” o “pwm”, oppure una delle modalità dei resistori interni: “up”, “down”, “tri”, per funzionalità avanzate.
  • write, analogo a output, se il pin è in modalità out, permette di impostarlo come attivo o spento. Prende in ingresso il numero del pin e 0 per spento e 1 per attivo.
  • read, analogo di input, legge se ci sia o meno segnale su un pin impostato come input. Prende in ingresso il numero del pin  e stampa 0 o 1.
  • reset, analogo a cleanup ma un po’ piú violento, resetta l’intero set di pin GPIO, che siano stati usati o meno, e rischia quindi di influire su cose gestite in altro modo.

La numerazione delle porte utilizzata da questo comando è ancora differente sia dalla numerazione GPIO che da quella fisica dei pin. Può però essere utilizzata la numerazione GPIO attraverso l’opzione -g. L’analogo del Python:

GPIO.setup(22, GPIO.OUT)
GPIO.output(22, 1)

in shell sarà:

gpio -g mode 22 out
gpio -g write 22 1

Il comando ha moltissime altre funzioni, in parte legate a protocolli di comunicazione che esploreremo nei prossimi articoli, e per un approfondimento rimando alla manpage del comando stesso:

man gpio

Un’interfaccia web (e non solo): WebIOPi

Esistono anche diverse interfacce web, piú o meno avanzate, che permettono una comoda gestione dei singoli pin attraverso semplici interruttori che li accendano, spengano o ne cambino la modalità. In genere sono poco pratiche da programmare, ma rendono facilissimo il test di ciò che si sta facendo. Quella a mio avviso piú interessante, anche per il suo offrire anche una API REST molto completa, che la rende facilmente programmabile, è WebIOPi.

L’installazione su Raspbian è banale: si scarica con wget, si decomprime e si installa con uno script:

wget http://webiopi.googlecode.com/files/WebIOPi-0.6.0.tar.gz
tar xvzf WebIOPi-0.6.0.tar.gz
cd WebIOPi-0.6.0
sudo ./setup.sh

A questo punto, basterà lanciare il servizio per eseguirla:

sudo service webiopi start

Se sarà necessario fermare il servizio il comando per farlo è:

sudo service webiopi stop

Se si vuole fare in modo che il servizio si attivi da sé all’accensione della Raspberry Pi e si chiuda allo spegnimento, basterà dare una volta il comando:

sudo update-rc.d webiopi defaults

Una volta attivato il servizio, aprite un browser e digitate l’indirizzo

http://localhost:8000

(se non siete sulla Raspberry Pi ma su un computer nella stessa rete, mettete l’indirizzo della Raspberry Pi al posto di localhost). Vi sarà chiesto username e password (il default è “webiopi” come user e “raspberry” come password), e vi comparirà una finestra analoga a questa:

Poco altro da dire: basta toccare i vari “in” e “out” per cambiare la modalità, e i numeri dei pin per accenderli o spegnerli. Testare i vostri circuiti prima ancora di scrivere il programma per governarli sarà semplicissimo.

L’API REST è molto semplice e supporta input, output e PWM. La documentazione si trova qui.

In un prossimo articolo, vedremo i protocolli di comunicazione piú complessi, e come collegare alcuni tipi di sensore a specifici pin GPIO.

Leave a Reply

Lorenzo Breda Articolo scritto da

Studente di Informatica a Roma, si occupa di programmazione web sopratutto lato server, e di accessibilità del web. Utilizza e ama Debian GNU/Linux, e si interessa di fisica, fumetto, trekking e fotografia (gli ultimi due possibilmente abbinati). Collabora con Googlab da aprile 2012.

Contatta l'autore

Previous post:

Next post: