Articolo tecnico che spiega cosa sono i pin GPIO (General Purpose Input/Output) di un microcontrollore, come si configurano in Arduino e tre esempi pratici con LED e pulsante.
GPIO è l'acronimo di "General Purpose Input Output" pin.
In una scheda controllata da un microcontrollore, tutti i pin che sono identificati con il termine GPIO sono configurabili con diversi ruoli a seconda di come vengono configurati nel software.
L'uso principale e più comune è quello di "pin discreto", ovvero in grado di essere configurato come INPUT o OUTPUT e di poter gestire segnali digitali con valori di tensione 0 / V(*), dove (V) è la tensione di operatività della scheda (generalmente 3.3V o 5V).
Altri impieghi degli stessi pin, laddove le caratteristiche della scheda lo permettano, potrebbero essere:
In questo articolo prenderemo in considerazione solamente la modalità digitale per la gestione di segnali discreti.
Un GPIO (1-bit) usato come "pin discreto" è in grado di gestire solamente valori di tensione 0 o V(*) e mai valori intermedi.
Un GPIO (1-bit), configurato come OUTPUT, potrebbe essere usato, per esempio, per il controllo dell'accensione di un LED, oppure per controllare un buzzer e farlo suonare con diverse tonalità. Un altro esempio pratico potrebbe essere il controllo di un relè che a sua volta controlla l'interruzione di corrente a un altro dispositivo che richiede più energia (es. una serratura elettromagnetica o una comune lampadina). Dal punto di vista elettronico, si deve fare particolare attenzione affinché il pin di OUTPUT non eroghi una corrente superiore a quella specificata nel datasheet del microcontrollore, pena il danneggiamento permanente dello stesso.

Figura 1 - Rappresentazione di un segnale digitale emesso da un GPIO configurato come OUTPUT.
Quando configuriamo un GPIO come OUTPUT ed impostiamo il suo stato come 0 logico (LOW), la tensione presente su quel pin è prossima a zero volt. Invece quando lo impostiamo come 1 logico (HIGH), la tensione presente sul pin è prossima al valore di tensione di lavoro del microcontrollore, generalmente 5 volt (per Arduino Uno) oppure 3.3 volt per gli altri modelli (esempio: Arduino MKR1000).
In ambiente Arduino ci sono tre funzioni fondamentali che permettono la configurazione e il controllo dei GPIO:
pinMode() è la funzione che permette di far "cambiare stato" al pin GPIO. Le possibili scelte sono:
digitalWrite().Questa funzionalità è utile per non creare situazioni di "incertezza" che possano generare falsi risultati 0/1 logico nel momento della lettura del GPIO. Infatti quando un pin GPIO non è collegato a nulla (floating), è in uno stato indefinito, situazione sempre da evitare nei circuiti logici.
La funzione pinMode(par1, par2) accetta due parametri: il par1 è il numero del pin GPIO che desideriamo configurare. Questo può essere direttamente il numero del pin, oppure un alias come ad esempio A0, oppure un altro nome precedentemente definito con la direttiva #define. Il parametro par2 può essere una delle tre possibilità spiegate prima, ovvero come vogliamo che il pin venga configurato.
Vediamo qualche esempio:
1// Il pin 13 diventa un OUTPUT2pinMode(13, OUTPUT);
oppure in caso di utilizzo della direttiva #define:
1// Imposto la direttiva "LED = 13"2#define LED 1334// La parola "LED" viene sostituita con "13" dal compilatore5pinMode(LED, OUTPUT);
in questo altro esempio, configuriamo il pin A0 come OUTPUT:
1pinMode(A0, OUTPUT);
digitalWrite(par1, par2) è la funzione che permette di controllare lo stato del GPIO quando è impostato come OUTPUT. Anche questa funzione deve essere utilizzata con due parametri: par1 è il numero del pin GPIO, da usare in modo identico a come abbiamo già visto con pinMode(). Il parametro par2 è invece lo stato che vogliamo impostare: con HIGH impostiamo un valore "1" logico, mentre con LOW impostiamo un valore "0" logico.
Vediamo qualche esempio. L'esempio che segue imposta prima il GPIO 13 come uscita (OUTPUT), poi lo imposta a valore logico "1" o HIGH. Questa operazione risulta nell'avere 5 volt presenti sul pin 13 di Arduino Uno.
1pinMode(13, OUTPUT);2digitalWrite(13, HIGH);
digitalRead(par1) è la funzione che ci permette di leggere lo stato di un pin GPIO precedentemente configurato come ingresso digitale (INPUT). La funzione restituisce un valore 0/1 in funzione del valore di tensione presente sul pin GPIO al momento dell'esecuzione. Come già detto, prima di usare questa funzione, il pin deve essere pre-configurato con una delle possibili modalità di INPUT disponibili per pinMode().
Qualche esempio. Nell'esempio che segue, il pin GPIO (4) viene configurato come INPUT, poi una variabile a viene dichiarata come int e acquisisce il valore 0/1 restituito dalla funzione digitalRead() per il pin (4).
1pinMode(4, INPUT);2int a = digitalRead(4);
Il codice che segue, in termini di funzionalità, è identico al precedente. La differenza sta nel fatto che è più leggibile e più semplice da manutenere:
#define e viene chiamato BUTTON;a viene dichiarata prima dell'uso.1#define BUTTON 42int a;3pinMode(BUTTON, OUTPUT);4a = digitalRead(BUTTON);
La variabile a verrà riempita con il valore 0/1 in funzione della presenza di tensione (0-5V) sul pin GPIO (4).
Per sperimentare in modo pratico l'uso delle funzioni e dei GPIO, leggete tutto l'articolo con gli esercizi proposti.
Nel caso di Arduino UNO Rev.3, i pin GPIO sono collegati direttamente al microcontrollore ATMEGA328P (datasheet). Stessa cosa anche per Arduino UNO R4 equipaggiato con chip Renesas RA4. I pin GPIO digitali sono quelli riportati nella figura seguente. È importante sapere che ciascun GPIO è in grado di erogare una quantità di corrente limitata che non deve mai essere superata. Questo valore è riportato normalmente nel datasheet del microcontrollore, ma anche nella pagina web della scheda, il cui valore riportato, nella sezione "Tech specs", è di max 20 mA per pin.
Invece per Arduino UNO R4, questo valore è di 8 mA.


Anche i pin analogici (A0 ÷ A5) possono essere configurati come pin digitali. Infatti utilizzando pinMode(), digitalWrite() e digitalRead() su questi pin, possiamo sfruttarli allo stesso modo dei classici pin digitali D0 ÷ D13.
L'esempio più semplice e immediato è il collegamento di un piccolo LED (rosso) da 3mm su un GPIO di Arduino. La sua resistenza di protezione (fondamentale per non danneggiare il LED) è generalmente del valore di 220Ω, considerando che un LED rosso deve essere alimentato con una tensione compresa tra 1.8V e 2.2V, e la corrente che scorre al suo interno è di circa 10-20 mA.

Figura 2 - Un LED controllato da un GPIO di Arduino Uno.
Calcolare il valore della resistenza (nel disegno R3) è molto semplice. Considerando che la tensione di uscita del GPIO in questione è 5V, la tensione di lavoro del LED è 2V circa e la corrente di operatività del LED è di circa 15 mA (0.015 A), la resistenza la calcoliamo secondo la legge di Ohm:
RLed = (5.0 - 2.0) / 0,015 = 200Ω
che approssimiamo al valore commerciale di 220Ω. Nello standard di valori di resistenze (serie E12), con una tolleranza del 5% sul valore, corrisponde a:
Rosso (2) - Rosso (2) - Marrone (x10) - Oro (5%) = 220Ω valore, 5% tolleranza
A questo punto, come faccio ad accendere il LED?
Ora dobbiamo dare sufficienti istruzioni al codice Arduino al fine di accendere il LED. Come abbiamo già detto, in ambiente Arduino il controllo dei pin GPIO si fa tramite le funzioni dedicate pinMode(), digitalWrite() e digitalRead().
Nel caso dell'esempio che segue, useremo solo pinMode() e digitalWrite(), in quanto useremo il GPIO (13) solo come uscita (OUTPUT).
L'esercizio è il classico "blink", ovvero un codice di esempio che fa lampeggiare un LED. Dopo aver collegato un LED come in figura 2, useremo pinMode() solo nella funzione setup(). Questo perché l'impostazione del GPIO è necessario farla una sola volta e non ripetutamente.
1#define LED 1323setup() {4 pinMode(LED, OUTPUT);5}
Invece nella funzione loop() useremo digitalWrite() più volte per accendere e spegnere il LED, modificando ogni volta lo stato logico del pin GPIO:
1loop() {2 digitalWrite(LED, HIGH);3 delay(200);4 digitalWrite(LED, LOW);5 delay(200);6}
La funzione delay() è necessaria per rallentare l'esecuzione del programma e vedere l'effetto "lampeggio" del LED. Il valore 200 indica il numero di millisecondi di pausa prima di eseguire l'istruzione successiva.
Discorso diverso invece se si vuole controllare un carico più impegnativo in termini di corrente richiesta. Per fare un esempio, una bobina di un relè non sarebbe controllabile se collegata direttamente a un pin GPIO di Arduino, perché richiederebbe troppa corrente per essere eccitata. In questo caso dovremmo utilizzare un transistor NPN o MOSFET per controllare la bobina del relè. Nell'esempio seguente, un transistor NPN è controllato e mandato in stato di saturazione attraverso la corrente erogata dal GPIO che scorre sulla base (B). In questo caso la corrente che scorre nella resistenza (R1) è calcolabile, con una certa approssimazione, con la seguente formula:
I(R1) = (vGPIO - 0,7) / R1 -> (5.0 - 0.7) / 10.000 = 0,43 mA
Dove 0,7 è la caduta di tensione della giunzione B-E del transistor NPN, e la corrente che scorre in R2, nel calcolo, è trascurata. La resistenza R2 ha lo scopo di mantenere la base del transistor a un valore di tensione basso durante i cambi di stato (input/output) del GPIO e durante gli stati di reset.

Figura 2 (continua) - Esempio di controllo di un relè da un pin di Arduino impostato come OUTPUT.
Questa volta useremo il GPIO configurato come INPUT e collegheremo a esso un tasto, il quale, a ogni pressione, modifica il livello di tensione presente sul pin.
Nelle immagini che seguono è raffigurato un tipico circuito di collegamento di un pulsante su un GPIO digitale (il GPIO 7 nell'esempio). In condizione di riposo, il pulsante è un circuito aperto, quindi la tensione nel punto del GPIO (7) è pari alla tensione VCC (5 volt), veicolata attraverso la resistenza da 10k ohm. Quindi, in condizioni di riposo, il livello logico all'ingresso del GPIO (7) è pari a "1". Quando il tasto viene premuto, la tensione presente nel punto del GPIO (7) è pari a zero volt, perché il tasto mette in corto-circuito il punto GPIO (7) con il pin GND (ground). In questa condizione, il livello logico del GPIO (7) è pari a "0".

Figura 3: schema elettrico del collegamento del tasto.

Figura 4: schema circuitale del collegamento del tasto.
Dal punto di vista del software, questa volta dovremo configurare il GPIO come INPUT:
1pinMode(7, INPUT);
...e poi leggere lo stato logico del GPIO riportandolo in una variabile numerica:
1int a = digitalRead(7);
A questo punto il contenuto della variabile è possibile stamparlo nel monitor seriale o utilizzarlo per un'altra azione.
Nell'esempio (completo) che segue viene eseguita la lettura continua del GPIO (7) e stampato il suo livello logico nel monitor seriale:
1#define BUTTON 723void setup() {4 pinMode(BUTTON, INPUT);5 Serial.begin(9600);6}78void loop() {9 int a;10 a = digitalRead(BUTTON);11 Serial.print("GPIO:");12 Serial.println(a);13 delay(200);14}
Di seguito il suo output: quando il tasto è rilasciato, il livello logico è "1"; quando viene premuto, il livello logico è "0".

Figura 5: output sul monitor seriale dell'esempio 2.
In questo ultimo esempio usiamo contemporaneamente le due funzioni di GPIO, sia come OUTPUT che come INPUT. Rispetto all'esempio precedente, la parte del tasto è invariata, mentre per la parte OUTPUT useremo un LED collegato al GPIO (13), in modo simile al primo esempio.
Nota: il LED potrebbe anche essere omesso, visualizzando il LED che sta direttamente sulla scheda Arduino. Nelle schede Arduino Uno Rev3 il LED è collegato al pin GPIO (13).

Figura 6: schema circuitale del collegamento tasto-LED.
Il codice che segue effettua una lettura continua dello stato GPIO (BUTTON) e lo confronta con "1" (vedere la riga if (a == 1)). Se la condizione si verifica, viene eseguita la funzione digitalWrite(LED, HIGH), altrimenti, se non si verifica, viene eseguita la funzione digitalWrite(LED, LOW).
Quindi il LED, collegato al GPIO (13) pre-impostato come OUTPUT, verrà alimentato in funzione dello stato logico del GPIO.
1#define BUTTON 72#define LED 1334void setup() {5 pinMode(BUTTON, INPUT);6 pinMode(LED, OUTPUT);7 Serial.begin(9600);8}910void loop() {11 int a;12 a = digitalRead(BUTTON);13 if (a == 1) {14 digitalWrite(LED, HIGH);15 } else {16 digitalWrite(LED, LOW);17 }18 Serial.print("GPIO:");19 Serial.println(a);20 delay(200);21}
Codice completo dell'esempio.
Una volta compreso questo esempio e come si "legge" lo stato di un GPIO digitale configurato come INPUT, è facile comprendere che lo stesso potrebbe essere usato, per esempio, per verificare lo stato di un sensore di presenza a infrarossi o della posizione di uno switch. Dal punto di vista elettronico, si deve fare particolare attenzione affinché il pin di INPUT non riceva una tensione fuori dai suoi limiti operativi, pena il danneggiamento permanente del microcontrollore.
Questo limite è generalmente il valore di operatività della logica della scheda. Nel caso di Arduino UNO Rev 3 e delle nuove schede Rev 4, ovvero tutte quelle della famiglia Arduino equipaggiate con il microcontrollore Renesas RA4M1, è di 0-5 volt; mentre, ad esempio, la scheda Arduino Nano 33 IoT funziona a 3.3 volt, quindi sarà 0-3.3 volt. È necessario prestare attenzione alla tensione applicata al pin, verificando le specifiche del costruttore.
In questo articolo abbiamo visto:
Se sei arrivato alla fine di questa pagina, ci auguriamo che l'argomento sia stato di tuo interesse.
L'obiettivo di questo sito è divulgare tutorial e corsi sulle materie elettronica e programmazione, con la speranza di poter aiutare sempre più persone che desiderano aumentare le proprie conoscenze.
Tutti i tutorial e gli articoli sono scritti con cura e verificati. Per mantenere sempre alto il livello di qualità delle informazioni fornite, puoi aiutarci nei seguenti modi:
Inoltre non dimenticare di rimanere in contatto con noi attraverso i social network. Se non lo fai adesso, probabilmente non ci rivedrai più:
Facebook · Instagram · YouTube · X (Twitter)
Grazie per il tuo contributo!
Iscriviti alla newsletter per ricevere i prossimi.