Diario in codice imparare nuove parole

Capitolo 3 - Cominciamo a scrivere

“Le parole sono tutto quello che abbiamo, perciò è meglio che siano quelle giuste”
Raymond Carver,tratto da Niente trucchi da quattro soldi

Nel primo capitolo abbiamo parlato del procedimento di risoluzione dei problemi, della loro schematizzazione sotto forma di algoritmi ed infine della loro trasposizione in programma.

Abbiamo capito che programmare significa non soltanto ragionare a fondo sulle cose ma anche scrivere.

Scrivere è un’azione quotidiana: quando lo facciamo ci serviamo di molte parole diverse, alcune sono semplici mentre altre racchiudono molti diversi significati che variano a seconda del contesto. Possiamo formare innumerevoli combinazioni e configurarle in altrettanti modi per descrivere un fatto o una azione in modo più o meno preciso.

Quando scriviamo - un sms, una mail, un racconto o un appunto - possiamo anche servirci dell’ambiguità intrinseca delle parole, magari per veicolare con il nostro discorso un qualche messaggio nascosto, correndo talvolta il rischio che le nostre parole possano essere travisate e interpretate in un modo diverso da quello sperato.

A tal proposito, quando il nostro interlocutore è l’elaboratore, è necessario cambiare radicalmente il nostro modo di parlare e di scrivere; il testo dovrà essere asciugato da ogni ambiguità e contenere messaggi molto semplici e chiari, nulla di vago insomma così da ovviare ad ogni possibile fraintendimento.

All’inizio, quando si comincia a programmare, ci si sente un po’ impacciati: ci sono nuove parole da imparare e nuove regole per organizzarle e dare forma al testo del programma. Stiamo in fin dei conti imparando a farci capire dal computer, una macchina particolarmente stupida e ottusa, la quale metterà duramente alla prova la nostra pazienza.

L’importante è non scoraggiarsi alle prime difficoltà e procedere gradatamente, un passo alla volta. Come con tutte le cose, la perfezione viene con l’esercizio: più programmeremo più tutto questo diventerà semplice.

Carta e Matita

Prima di cominciare ad immettere testo all’interno dell’IDE di Arduino, potrebbe essere una buona idea quella di usare carta e matita! Personalmente l’ho sempre trovato un ottimo sistema per imparare, perchè mi aiuta a fissare meglio nella memoria le parole e la sintassi del linguaggio.

Con il programma riportato su carta inoltre è più facile visualizzarlo per intero, un metodo utilissimo per farsi una idea precisa del suo funzionamento.

Usando carta e matita non siamo obbligati a stare di fronte al computer per scrivere o studiare, possiamo esaminare il codice e goderci al contempo una bella giornata di sole!

Pronti? Si comincia!

Ecco il nostro primo programma: mentre lo leggiamo e lo trascriviamo, facciamo particolare attenzione alle parentesi, ai segni di punteggiatura e alle lettere minuscole e maiuscole (il linguaggio di programmazione Arduino è infatti case sensitive, ovvero fa distinzione tra le due forme).

void setup()
{
    pinMode(13, OUTPUT);
}

void loop()
{
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
    delay(1000);
}

A cosa serve questo programma? Lasciamo la risposta per dopo e nel frattempo concentriamoci sul linguaggio, esaminando il programma da un punto di vista macroscopico.

Non preoccupiamoci se alcune delle cose che diremo risulteranno poco chiare. La cosa è perfettamente normale quando ci si avvicina per la prima volta ad un nuovo argomento. In breve tempo tutto diverrà sempre più chiaro.

Blocchi di codice

A prima vista si possono notare due strutture principali: si tratta di 2 porzioni di testo, ciascuna in qualche modo associata ad un coppia di parentesi graffe.

Queste strutture prendono il nome di blocchi di codice, una parentesi graffa aperta ne sancisce l’inizio mentre una chiusa ne determina la conclusione.

Al loro interno sono raggruppate una serie di righe di testo terminate dal carattere terminatorepunto e virgola”: ogni riga costituisce una singola istruzione!

blocco di codice

Setup e Loop

Guardiamo nuovamente il nostro codice e ora associamo ad ogni riga un numero progressivo così che sia più facile esaminarlo:

1
2
3
4
5
6
7
8
9
10
11
12
void setup()
{
    pinMode(13, OUTPUT);
}

void loop()
{
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
    delay(1000);
}

Osserviamo la riga 1 che contiene il testo void setup(). In qualche modo assomiglia alla riga 6 che invece recita void loop().

Anche se non possiedono il carattere terminatore come le altre, anche queste sono istruzioni ed entrambe hanno la medesima funzione: assegnare un nome, per così dire, ai blocchi di codice sottostanti!

setup & loop

Il blocco setup contiene 1 istruzione:

pinMode(13, OUTPUT);

mentre il blocco loop ne contiene 4:

digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);

Tutte le istruzioni contenute all’interno dei blocchi di questo nostro programma sono istruzioni del tipo chiamata a funzione.

Che cosa fa una istruzione di questo tipo? Una chiamata a funzione nel linguaggio Arduino, e in tutti i linguaggi di programmazione più in generale, serve per fare uso di una particolare capacità del linguaggio o della scheda Arduino nel nostro caso.

Le righe 9 e 11 del programma ad esempio chiamano la funzione denominata delay per servirsi della capacità della scheda di aspettare.

Aspettare cosa? Aspettare quanto?

Scrivere solo delay non è sufficiente infatti; per usare questa funzionalità non basta solo invocarla ma occorre aggiungere una ulteriore informazione, non tanto il cosa aspettare, piuttosto il quanto aspettare.

Ecco quindi spiegato il numero 1000 indicato tra parentesi tonde: 1000 è un parametro e rappresenta il quantitativo di millisecondi (1 secondo) che la scheda Arduino dovrà aspettare una volta giunta ad eseguire questa particolare istruzione!

Facciamo un altro esempio, ed esaminiamo ora altre due istruzioni del blocco loop, quelle alla riga 8 e 10.

Anche in questo caso si tratta di istruzioni del tipo chiamata a funzione e la funzione interessata ha nome digitalWrite.

Quando la scheda Arduino esegue una digitalWrite, scrive un valore di tensione elettrica su uno dei suoi pin digitali. Per essere eseguita correttamente, la funzione digitalWrite ha bisogno di sapere:

  1. su quale pin digitale andare ad agire;
  2. quale tensione elettrica utilizzare;

Nel capitolo precedente abbiamo accennato ai pin digitali della scheda Arduino; sono 14 in tutto, indicati sulla scheda con un indice crescente dal numero 0 al 13:

pin digitali

Senza entrare nel dettaglio, ci basti sapere che su questo tipo di pin è possibile scrivere (o leggere) solo 2 valori di tensione elettrica, alta oppure bassa, rispettivamente associati alle parole chiave inglesi HIGH e LOW.

la nostra

digitalWrite( 13, HIGH );

quindi, quando eseguita dalla scheda Arduino, causa l’impostazione di una tensione alta sul pin numero 13! In modo del tutto speculare, l’istruzione

digitalWrite( 13, LOW );

scrive” sul pin 13 il valore di tensione elettrica basso.

Lo studio del programma si completa con l’esame di un’ultima istruzione, l’unica del blocco di codice setup. La riga 3 del nostro programma recita:

pinMode( 13, OUTPUT );

Anche questa è una chiamata a funzione e questa volta è pinMode la funzione ad essere invocata.

A cosa serve? Ha bisogno di qualche parametro per operare correttammente e se sì, quanti e quali?

La funzione pinMode serve per impostare la modalità di utilizzo di un particolare pin. La sua utilità ci sarà più chiara nei prossimi capitoli ma per ora ci basta sapere che ha bisogno di due parametri:

  1. a quale pin fare riferimento;
  2. quale modalità impostare per il pin;

Nel nostro caso la

pinMode( 13, OUTPUT );

imposta il pin digitale numero 13 come OUTPUT il che ci consentirà di utilizzarlo in seguito come destinazione per la “scrittura” di valori di tensione.

Un altra modalità interessante, e che vedremo nei prossimi capitoli, è quella di INPUT per usare il pin digitale in modo duale, consentendo operazioni di “lettura”.

Flusso del programma

Non dobbiamo dimenticare che questo nostro programma è la traduzione in un linguaggio ad alto livello di un algoritmo pensato per la risoluzione di un particolare problema.

Il programma verrà poi convertito in eseguibile (linguaggio a basso livello) e quindi caricato sulla memoria della scheda Arduino e solo qui messo in esecuzione.

compilazione-caricamento

Una volta immagazzinato nella memoria della scheda, il microcontrollore lo legge a partire dal blocco setup, eseguendo le istruzioni in esso contenute, una alla volta, dalla prima all’ultima fino a completarle tutte.

Dopodichè passa alla lettura del blocco loop e fa lo stesso per le sue istruzioni.

Giunto al termine del blocco, l’esecuzione non si interrompe ma riprende dalla prima istruzione del blocco loop e continua in un ciclo infinito, fintanto che la scheda continua ad essere alimentata.

Ecco come si potrebbe sintetizzare il flusso del programma:

program flow

In altre parole il blocco setup contiene istruzioni che vogliamo vengano eseguite una ed una sola volta, mentra il blocco loop (come il nome stesso suggerisce) contiene le istruzioni che vogliamo continuare a ripetere.

Ordine

Pensando al programma come ad un flusso di azioni consecutive, si capisce quanto sia importante che le istruzioni siano disposte secondo un ordine preciso.

Cosa succederebbe se invertissimo l’ordine di alcune di esse? Molto probabilmente non riusciremmo a risolvere il nostro problema e potremmo causare degli errori.

L’errore (pt.1)

Acquisiremo prestissimo dimestichezza con diversi tipi di errore: come abbiamo detto l’elaboratore è una macchina stupida e non ci dovremo quindi stupire se talvolta si lamenterà del nostro codice.

Specie all’inizio, la cosa potrebbe avvenire con una certa frequenza. E’ sufficiente una piccola disattenzione, una lettera dimenticata oppure digitata minuscola anzichè maiuscola, un punto e virgola o una parentesi in meno o in più per causare un errore.

In questi casi il mio consiglio è quello di non perdere la calma: fare un respiro profondo e ritornare sui propri passi con un atteggiamento zen.

Lo stesso IDE di Arduino, lo vedremo meglio tra poco, può esserci di grande aiuto in questi casi grazie ai messaggi mostrati a console.

Nell’IDE

E’ giunto finalmente il momento di usare l’IDE Arduino per scrivere, compilare e infine caricare il nostro programma sulla scheda e vederlo finalmente in azione!

Dopo averlo scaricato ed installato seguendo le istruzioni del capitolo precedente, apriamo l’IDE e cominciamo a trascrivere il nostro programma: creiamo un nuovo file usando la voce di menu File/New o la combinazione di tasti Ctrl+n, e riportiamo all’interno dell’editor il corpo del programma.

Una volta fatto dovreste ottenere qualcosa di simile a quanto mostrato nella figura seguente:

IDE

Nello scrivere il codice all’interno dell’editor abbiamo anche già scoperto alcune delle comodità fornite da un ambiente di sviluppo integrato (IDE in inglese) come questo.

Synthax Highlight

Ad esempio è interessante notare come le diverse parole del linguaggio abbiano assunto colorazioni differenti: basta osservare i parametri HIGH, LOW ed anche OUTPUT che sono stati colorati di blu, oppure void e ancora setup e loop o tutti i nomi delle istruzioni all’interno dei blocchi, colorati in arancio.

Questa funzionalità dell’IDE si chiama synthax highlighting e permette di individuare rapidamente la varie parti del codice e, dal momento che si occupa di colorare tutte le “parole riservate” del linguaggio Arduino, permette di capire velocemente se le si sta scrivendo nel modo lessicamente corretto.

Chiusura automatica del blocco e indentazione

Quando creiamo un nuovo blocco di codice e digitiamo una parentesi graffa per poi andare a capo ad inserire istruzioni al suo interno, l’IDE chiude il blocco al posto nostro inserendo la parentesi graffa chiusa una riga più sotto.

Altra cosa interessante da notare è che le istruzioni che vengono inserite all’interno del blocco vengono indentate automaticamente.

L’indentazione non è indispensabile ma è molto utile per formattare il codice e renderlo più facilmente leggibile: l’IDE provvede a farlo in modo automatico mentre stiamo scrivendo.

Tutte queste impostazione possono essere comunque modificate attraverso il menu File/Preferences.

Salvare

Prima di procedere salviamo il nostro programma facendo click sulla voce File/Save As…, assegnando un nome allo sketch e selezionando la cartella sketchbook (o qualsiasi altra cartella preferiamo) come destinazione.


Verifica

E’ il momento di verificare il nostro codice per vedere se contiene qualche errore. E’ proprio questa la famosa fase di compilazione della quale abbiamo tanto parlato: il codice viene compilato e così facendo ne viene verificata l’effettiva eseguibilità.

Se l’esito sarà positivo, il nostro programma, ormai trasformato in file eseguibile, sarà pronto per essere caricato sulla scheda!

Torniamo ad esaminare l’interfaccia dell’IDE per parlare dei primi due pulsanti sulla sinistra, fino ad ora rimasti in sospeso.

IDE

Si tratta rispettivamente di:

  • Verify, che lancia la compilazione e la verifica del programma;
  • Upload, da usare per effettuare il trasferimento del file eseguibile dalla memoria del computer a quella della scheda Arduino.

Come abbiamo detto più volte, il codice sorgente ad alto livello è fondamentalmente un’astrazione: perchè possa essere eseguito dall’elaboratore, deve prima essere convertito in un equivalente a basso livello, l’eseguibile.

Mentre il codice ad alto livello è indipendente dalla piattaforma, non lo è l’eseguibile che differisce a seconda del tipo di elaboratore sul quale il programma deve essere eseguito.

In altre parole, il nostro programma scritto in linguaggio Arduino resta invariato sia che lo si voglia infine eseguire su di una scheda di tipo UNO oppure Mega, Nano o Micro; quello che cambia sarà invece l’eseguibile, compilato specificatamente per la piattaforma prescelta.


Come fa l’IDE a sapere che il nostro codice sorgente deve essere compilato specificatamente per la scheda Arduino UNO, quella che stiamo utilizzando?

Siamo noi a doverglielo dire, selezionando il nostro modello di scheda dal menu a tendina Tools/Board. Una volta fatto è arrivato infine il momento di fare click sul pulsante Verify!!

Se tutto va bene, visualizzeremo una barra di progressione sul margine inferiore dell’editor e infine due messaggi. Il primo, sempre sul margine inferiore, riporta Done compiling. e il secondo, mostrato all’interno della console, sarà simile a quello mostrato dalla figura seguente

messaggio a console

L’errore (pt.2)

In caso di errore invece potremmo ritrovarci in una sitiazione come questa

errore

Respiro profondo, niente paura. Pur non particolarmente simpatica, questa situazione ci permette di scoprire un altro grande pregio dell’IDE: quello di segnalarci, in certi casi con una certa precisione, quale sia l’errore e dove si trovi all’interno del nostro codice.

In particolare vediamo dapprima la parte inferiore dell’editor:

errore

Semplificando un poco, il messaggio significa che il compilatore non è stato in grado di tradurre il nostro programma in un file eseguibile, in particolare perchè non sa tradurre la parola “digitalwrite”.

Lo stesso messaggio è riportaro, in modo un po’ più dettagliato, anche a console:

errore

l’IDE ci indica anche a quale riga del nostro codice il compilatore ha riscontrato l’errore:

errore

Grazie a tutti questi indizi e riflettendo un poco, è facile capire quale ne sia la causa e come risolverlo: ho scritto male una lettera dell’istruzione digitalWrite!

A questo punto basta agire modificando la lettera w, da minuscola a maiuscola, cliccare nuovamente sul pulsante Verify e il gioco è fatto.

Errori come questo sono del tutto normali, possono capitare ed è facile individuarli e risolverli grazie all’aiuto dell’IDE.

Caricamento

A verifica completata con successo, è ora il momento di caricare l’eseguibile sulla scheda e per farlo bastano pochi semplici passaggi.

Dapprima connettiamo la scheda Arduino UNO al PC usando un semplice cavo USB A-B (il classico cavo USB da stampante).

Quindi, dal menu a tendina Tools/Ports selezioniamo l’identificativo della porta USB alla quale la scheda Arduino UNO è stata connessa.

Questa sigla differisce a seconda del sistema operativo e dalla porta USB impiegata. Nel mio caso, ad esempio, usando un sistema operativo GNU/Linux Debian, la sigla che seleziono è la dev/ttyACM0 che nella lista delle varie porte disponibili, riporta l’ulteriore stringa (Arduino/Genuino UNO).

Su sistemi operativi Windows, il nome della porta dovrebbe essere qualcosa del tipo COMx, dove x sta ad indicare una cifra. Per maggiori informazioni su come connettere la scheda UNO al proprio computer vi rimando a questo link, dal sito ufficiale di Arduino.

Infine basta fare click sul pulsante Upload.

Anche in tale caso l’IDE mostra una barra di progressione e, ad operazione completata, un messaggio Done uploading.

Se tutto è andato come previsto, dando uno sguardo alla scheda, dovremmo vedere il LED di bordo accendersi e spegnersi alternativamente ogni secondo!

L’Errore (pt.3)

Se qualcosa è andato storto invece, probabilmente è perchè si è verificato un problema in fase di caricamento dell’eseguibile. In tale caso la console potrebbe presentare un messaggio d’errore come questo:

errore

Come si evince dal messaggio, l’IDE non è stato in grado di accedere alla scheda, data per connessa alla porta dev/ttyACM0, nè di copiarvi alcunchè. L’errore si spiega facilmente: in questo caso ho semplicemente scordato di connettere la scheda Arduino UNO al PC prima di fare click sul pulsante Upload, ops!

Se l’errore che vi si presenta dovesse essere di tipo diverso e non bastasse una disconnessione/riconnessione della scheda al PC, vi consiglio di leggere con attenzione i vari passaggi riportati in questa pagina o di chiedere eventualmente aiuto sul forum.

Ricapitolando

Nel vedere il nostro programma in esecuzione sulla scheda Arduino UNO, risulta semplice ricavare a ritroso l’algoritmo di partenza dal quale il programma è stato ricavato.

algoritmo

Al termine del caricamento dell’eseguibile sulla memoria del microcontrollore, l’esecuzione parte immediatamente e le prime istruzioni ad essere eseguite sono quelle del blocco setup.

Nel nostro caso l’unica istruzione pinMode(13, OUTPUT) imposta il pin digitale 13 della scheda, al quale è connesso il LED di bordo, in modalità di OUTPUT per poterci successivamente “scrivere” valori di tensione alto o basso.

Terminate le istruzioni del blocco setup l’esecuzione passa al blocco loop e alla prima di quelle in esso contenute. La prima istruzione “scrive” sul pin numero 13 un valore di tensione alto, conseguentemente il LED si accende e resta acceso per 1 secondo, tempo durante il quale il microcontrollore non fa nulla, semplicemente aspetta.

L’esecuzione continua con la terza istruzione del blocco loop con la quale scriviamo sul pin 13 un valore di tensione basso questa volta. Così facendo il LED si spegne e l’esecuzione, dopo un’ulteriore attesa della durata di 1 secondo, riprende dal principio del blocco. Il processo si ripete infinite volte.


Complimenti per aver scritto, compilato ed infine eseguito il nostro primissimo programma in linguaggio Arduino.

Questo è un primissimo passo ma di importanza fondamentale per il futuro percorso che ci attende.

Un passo altrettanto importante perchè ci consente di comprendere quale sia l’importanza del codice e le sue immense potenzialità perchè, con poche e semplici parole, ci fa ottenere risultati sorprendenti!

Per approfondire

La chiamata a funzione è un particolare tipo di istruzione che si presenta nella forma

nome_di_funzione ( parametro/i );

Questa istruzione, quando eseguita, invoca una particolare funzionalità del linguaggio. Se per operare correttamente la funzionalità ha bisogno che le vengano fornite alcune informazioni, queste possono esserle passate sottoforma di parametri usando le parentesi rotonde.

Tra le parentesi tonde di una chiamata a funzione si possono trovare uno o più parametri, come abbiamo visto, e può trattarsi di numeri, lettere o parole a seconda dei casi.

La chiamata a funzione non è l’unico tipo di istruzione che possiamo trovare nel linguaggio Arduino. Abbiamo già visto ad esempio le istruzioni void setup() e void loop() che hanno il compito di definire i nomi di blocchi di codice. Ne esistono anche altri tipi e li vedremo man mano che compariranno nei futuri programmi che scriveremo.


Abbiamo detto che il pulsante Upload si occupa del caricamento del file eseguibile sulla scheda. Quanto detto in realtà è solo parzialmente corretto, infatti prima di caricare, Upload compila il programma, esattamente come fa Verify.

In altre parole, quando vogliamo velocizzare il nostro processo di scrittura/compilazione/caricamento/esecuzione, possiamo pensare di premere direttamente il pulsante Upload! Nel caso di errori di compilazione o di caricamento, il processo specifico si interromperà e l’IDE ci mostrerà i consueti messaggi a console.

Reference

Per chi fosse curioso e volesse sin da subito raccogliere ancora più informazioni in merito alle istruzioni che abbiamo visto in questo nostro primo programma (o magari cominciare ad esplorare altri aspetti del linguaggio Arduino), lascio qui il link alla Reference del linguaggio, un vero e proprio vocabolario del programmatore!