In questo tutorial approfondirai il meccanismo di comunicazione attraverso la linea seriale, tra Arduino e PC, che hai già incontrato nel corso della tua precedente missione.
Sarà l’occasione per introdurre il tema importante delle comunicazioni elettroniche.
Parliamo ovviamente di comunicazioni digitali, cioè di comunicazioni con segnali elettrici che vengono trattati in modo molto netto, riportando le grandezze ai due valori fondamentali ALTO e BASSO che corrispondono idealmente alle cifre binarie 0 e 1.
Qualunque numero, oltre che con 10 cifre (0,1,2,3,4,5,6,7,8,9) può essere anche scritto usando solo due cifre (0,1), con un sistema che viene chiamato binario.
Per contare attraverso il sistema binario si procede in modo simile al sistema decimale, anche se abbiamo solo due simboli.
Ad esempio uno = 1, due = 10, tre = 11, quattro = 100, cinque = 101, …
Attraverso le comunicazioni elettroniche possiamo trasmettere qualunque sequenza di 1 e 0, quindi qualunque numero e quindi ogni tipo di informazione, poiché caratteri, immagini, suoni, ecc… sono rappresentabili attraverso codifiche numeriche.
La comunicazione tramite il cavo USB avviene secondo un protocollo di tipo seriale, denominato RS232.
I dettagli elettrici relativi ai segnali sono gestiti automaticamente dal microcontrollore di Arduino che ha al suo interno un modulo specializzato per gestire il protocollo seriale RS232.
Se si utilizza la comunicazione seriale, i due PIN digitali etichettati come 0 e 1 su Arduino vengono dedicati a questo scopo e assumono il ruolo di terminali Rx e Tx.
Il codice presentato nel video è riportato di seguito.
void setup(){
// Avvia la comunicazione seriale a 9600 baud
Serial.begin(9600);
// Messaggio iniziale
Serial.println("Scrivi qualcosa e premi INVIO");
}
void loop(){
// Controlla se ci sono dati disponibili da leggere provenienti dal terminale seriale
if (Serial.available() > 0) {
// legge il carattere inviato dal terminale seriale
char receivedChar = Serial.read();
// stampa il carattere sul terminale seriale
Serial.print(receivedChar);
}
}
Le comunicazioni seriali basate sul protocollo RS232 sono considerate uno standard nel sistema Arduino, per cui la libreria Serial è sempre inclusa in qualunque sketch, senza dover inserire istruzioni specifiche, come invece faremo per le altre librerie di comunicazione che incontrerai nei prossimi tutorial.
L’istruzione Serial.begin(9600) inizializza la comunicazione seriale e predispone il microcontrollore per l’utilizzo dei PIN Digitali Arduino 0 e 1 come terminali Rx e Tx.
Questi due PIN sono collegati alla porta USB, per cui anche se il collegamento è effettuato utilizzando il cavetto e la presa USB posta sulla scheda, i due PIN digitali 0 e 1 non possono essere utilizzati quando nello sketch viene usata la Serial.begin.
Esiste anche una libreria opzionale di Arduino, denominata Software Serial, che permette di implementare un protocollo seriale RS232 usando due qualsiasi PIN digitali. La libreria Software Serial è meno efficiente della libreria standard Serial, perché gestisce via software il protocollo e la comunicazione, mentre la Serial sfrutta la capacità hardware di Arduino di gestire questo tipo di comunicazioni.
Nella funzione setup, dopo aver inizializzato la comunicazione seriale viene inviato un messaggio di istruzioni verso il terminale.
L’istruzione Serial.println() invia i dati contenuti tra parentesi verso il terminale seriale e poi invia un carattere speciale di ‘a capo’ detto anche newline . L’effetto è quello di andare a capo nella visualizzazione sulla finestra del terminale.
Il funzionamento della funzione loop è il seguente.
Per prima cosa viene effettuato un test per controllare che dalla linea seriale sia pervenuto qualcosa.
Quando il terminale seriale in esecuzione sul nostro PC invia una sequenza di caratteri, questi vengono automaticamente ricevuti dal microcontrollore di Arduino e memorizzati in un’area di memoria chiamata buffer di ricezione.
La funzione Serial.available() restituisce il valore 0 se il buffer di ricezione è vuoto oppure restituisce un valore maggiore di zero se c’è qualche carattere che ancora non è stato letto.
Il test if (Serial.available() > 0) assume quindi il valore VERO se il buffer contiene qualcosa da leggere oppure il valore FALSO se il buffer di ricezione è vuoto.
Se il test nella istruzione if è VERO (quindi c’è qualcosa da leggere) viene eseguito il blocco tra parentesi graffe costituito dalle due istruzioni char receivedChar = Serial.read() e Serial.print(receivedChar).
La prima istruzione crea una variabile di tipo char chiamata receivedChar e la inizializza con il valore restituito dalla funzione Serial.read().
La Serial.read() estrae dal buffer di ricezione il primo byte (8 bit) di dati disponibili. I numeri di 1 byte (8 bit) sono anche chiamati char perché i caratteri alfabetici sono rappresentabili con numeri ad 8 bit secondo la codifica ASCII.
Quando digitiamo sul terminale seriale, dal nostro PC, un carattere sulla tastiera, il corrispondente valore ASCII viene trasmesso sulla linea seriale e ricevuto da Arduino nel buffer di ricezione.
Il contenuto della variabile receivedChar viene quindi ritrasmesso verso il terminale seriale attraverso l’istruzione successiva Serial.print(receivedChar).
Il ciclo corrente termina e la chiamata successiva alla funzione loop permetterà di leggere e ritrasmettere indietro un altro carattere eventualmente presente nel buffer di ricezione.
Se il test nella istruzione if è FALSO, il blocco viene saltato, non c’è nulla da leggere e la funzione loop termina senza aver fatto nulla.
La funzione loop viene automaticamente richiamata all’infinito, per cui non appena arriveranno altri caratteri nel buffer, questi saranno estratti, uno per volta, e contestualmente ritrasmessi.
Una piccola digressione sul linguaggio C++
Poiché nel linguaggio C/C++ qualunque valore numerico diverso da zero viene interpretato in senso logico come VERO e il valore 0 viene interpretato come valore logico FALSO, il test (Serial.available() > 0) potrebbe essere riscritto più sinteticamente come (Serial.available()), considerando il valore restituito dalla funzione direttamente come un valore di tipo logico.
Troveremo spesso questa forma più sintetica nei successivi esempi di codice.