Credo che voi come me abbiate incontrato durante la vostra vita insegnanti o amici che vi hanno donato un’idea o un modo di operare che vi ha arricchito intellettualmente e migliorato la vostra vita lavorativa. Io ne ho molti e tra questi sicuramente l’amico Alessandro Rodella (Alex per gli amici) è l’esempio per me di creatività tecnica/elettronica. Alessandro è un software engineer in una grande azienda che produce software di Borsa per l’Italia e per mercati borsistici esteri, a lui si deve la direzione di importantissimi progetti. Con lui condivido la stessa passione per l’elettronica e fin da bambini ci portiamo dentro la voglia di smontare dispositivi elettronici per scoprirne il funzionamento. Una delle ultime passioni di Alex è Arduino con cui sta realizzando apparati interessantissimi, in questo ultimo periodo si sta occupando di domotica e finalmente ha deciso di incomiciare a pubblicare i suoi esperimenti.
Le soluzioni che Alex sta pensando hanno, secondo me, valenza industriale ed il primo dei tutorial, suddiviso in tre parti ne è un esempio: un termostato GSM.
Il termostato è stato ultimato e messo in funzione oggi, inutile dirvi che funziona perfettamente!
Certamente una bella esperienza che potrò realizzare con i miei allievi.
Su Play With Arduino troverete nelle prossime settimane altri interessantissimi progetti non mancate di visitare il sito… stay tuned.
Inolte ho deciso di incominciare questa nuova serie di lezioni perché sollecitato anche dalle mail di diversi utenti che mi hanno chiesto più volte dettagli sulla programmazione… e poi visto che devo insegnare programmazione in C, tanto vale usare il C usato in Arduino che mi permette di far percepire “fisicamente” il risultato della programmazione e quindi maggior gratificazione da parte dello studente. Ho constatato che la voglia di studiare aumenta se la programmazione ha effetto su una struttura fisica (led, motori, relè ecc….) si contestualizza sul pratico e lo studente comprende che ciò che fa a scuola serve (a molti ancora non è chiaro questo aspetto…)
Molto più difficile sarebbe se restassi sul virtuale e insegnassi il C facendo progetti che non hanno un riscontro sul mondo fisico… provare per credere dopo più di 20 anni di insegnamento ne sono convinto.
Fatta la premessa… lo scopo utilizzare, come indice degli argomenti da trattare, il libro di Brian W. Evans: Arduino programming notebook, che ricordo essere sotto licenza Creative Commons Attribution-Noncommercial-Share Alike 3.0 License (che è la stessa di questo sito), per strutturare un nuovo libro on-line in cui aggiungere gli appunti del mio corso. Cercherò di dare al tutto una struttura “scolastica” in modo da renderla più semplice per lo studente.
Il libro subirà variazioni e correzioni, quindi anche ad opera conclusa, nei mesi che seguiranno effettuerò variazioni ed integrazioni che evidenzierò con data e versione.
Spero che queste lezioni possano servire e se durante l’esposizione trovate errori o incongruenze o avete suggerimenti non esitate a darmene comunicazione, pubblicherò volentieri i vostri contributi.
Grazie.
Strutture
La struttura base di un programma Arduino è abbastanza semplice e si sviluppa in almeno due parti.
Queste due parti, o funzioni, necessarie racchiudono parti di istruzioni.
Dove setup() indica il blocco di settaggio e loop() è il blocco che viene eseguito. Entrambe le sezioni sono necessarie per far si che un programma funzioni.
setup() è la prima funzione ad essere invocata verrà eseguita una volta sola e in essa vengono dichiarate le variabili usate nel programma, è usata per impostare il pinMode o inizializzare la comunicazione seriale.
La funzione loop() contiene il codice che deve essere eseguito ripetutamente, in essa vengono letti gli input, i segnali di output ecc…
Questa funzione è la parte principale di un programma Arduino (sketch), esegue la maggior parte del lavoro.
setup()
La funzione setup() è chiamata una volta sola quando il programma viene fatto funzionare. E’ usata per inizializzare il pinMode e la seriale e deve essere incluso in un programma, anche se non ci sono istruzioni da eseguire.
void setup()
{
pinMode(pin, OUTPUT); //inposta il 'pin' come output
}
loop()
Dopo che è stata eseguita la chiamata alla funzione setup(), la funzione loop() fa esattamente quello che suggerisce il suo nome, esegue ripetutamente un loop, permettendo al programma di modificare, rispondere e controllare la scheda Arduino.
void loop()
{
digitalWrite(pin, HIGH); // imposta 'pin' ad on
delay(1000); // effettua una pausa di 1 secondo
digitalWrite(pin, LOW); // imposta 'pin' ad off
delay(1000); // effettua una pausa di 1 secondo
}
funzioni
Una funzione è un blocco di codice a cui è attribuito un nome, è da intendersi come un blocco di istruzioni che vengono eseguite quando viene invocata la funzione.
Delle funzioni void setup () e void loop () abbiamo già discusso, parleremo di altre funzioni più avanti.
Le funzioni personalizzate possono essere scritti per eseguire compiti ripetitivi e ridurre confusione in un programma. Quando si dichiara una funzione in primo luogo bisogna dichiarare il tipo della funzione, cioè il tipo di valore restituito dalla funzione, quindi se la funzione è di tipo ‘int’ (intero), vorrà dire che restituirà un valore intero.
type functionName(parameters)
{
statements;
}
La funzione di tipo intero: delayVal() è utilizzata per fissare un valore di ritardo in un programma che legge un valore da un potenziometro. Per prima cosa dichiariamo una variabile locale v di tipo intero, impostiamo v al valore restituito dalla funzione analogRead(pot), che può restituire un valore compreso tra 0 e 1023, dividiamo il valore ottenuto per 4 per ottenere un valore compreso tra 0 e 255 e infine restituiamo questo valore al programma principale (quello che ha invocato delayVal() ).
int delayVal()
{
int v; // varibile temporanea intera 'v'
v = analogRead(pot); // lettura del valore del potenziometro
v /= 4; // conversione da 0-1023 a 0-255
return v; // restituisce il valore finale
}
{} Parentesi graffe
Le parentesi graffe (dette anche solamente “parentesi” o “parentesi graffe”) definiscono l’inizio e la fine di un blocco funzione e blocchi istruzione così come la funzione void loop() e le istruzioni for e if
type function()
{
statements;
}
Una parentesi graffa aperta deve essere sempre seguita da una parentesi graffa chiusa. Questo è spesso indicato come bilanciamento delle parentesi. Parentesi non bilanciate possono creare diversi problemi al compilatore e talvolta possono essere difficili da rintracciare in un programma molto esteso.
L’ambiente Arduino include una funzione utile per controllare il bilanciamento delle parentesi graffe. E’ sufficiente selezionare una parentesi o fare click immediatamente dopo la parentesi affinchè venga evidenziata la parentesi logicamente corrispondente.
; punto e virgola
Il punto e virgola deve essere usato al termine di un’istruzione e separa gli elementi di un programma. Il punto e virgola è usato per separare elementi in un ciclo for.
int x = 13; // dichiara che la variabile ‘x’ è un intero
dimenticare un punto e virgola al termine di una riga produrrà un errore di compilazione. La rilevazione di un punto e virgola mancante non è sempre semplice da rilevare, alcune volte il compilatore potrebbe darvi dei messaggi di errore che possono sembrare illogici, in questo caso la prima cosa da fare è controllare la mancanza di un punto e virgola nei pressi della linea di codice dove il compilatore ha evidenziato l’anomalia.
/*…*/ blocco commenti
I blocchi commenti, o commenti multi-linea, sono aree di testo che sono ignorate dal programma e sono usate per una descrizione lunga del codice oppure commenti che aiutano la comprensione di parti del programma. Il bloccco commento incomincia con /* e termina con */ e può occupare più righe.
/* questo è un blocco commento chiuso
non dimenticare di chiudere il commento
anche i segni di blocco commento sono bilanciati
*/
poiché i commenti vengono ignorati dal programma, essi non occupano spazio di memoria, quindi è opportuno usarli frequentemente, abbondando il più possibile nello specificare le azioni dei vari blocchi del programma, agendo in questo modo sarà anche più semplice effettuare il debug del programma.
Nota: non è possibile annidare blocchi di commenti, cioè inserire un blocco commento all’interno di un altro blocco commento.
// commenti in singola linea
I commenti in singola linea incominciano con // e terminano con la successiva linea di codice. Come per il blocco commento, anche i commenti in singola linea sono ignorati dal programma e non occupano spazio di memoria.
// questo è un commento su una sola linea
I commenti su un’unica linea sono spesso usati dopo un’istruzione per fornire maggiori informazioni sull’azione che compie e per futura memoria.
Tutti gli appunti realizzati potete trovarli nalla sezione: Appunti di programmazione nella sezione Arduino di questo sito.
Nella precedente lezione abbiamo visto come progettare un controllo presenza in due stanze adiacenti in cui abbiamo utilizzato due pulsanti per simulare due sensori PIR (uno per ogni stanza) e due led per simulare l’accensione delle lampade nelle due stanze.
L’ultimo sketch consentiva di silmulare la seguente situazione per entrambe le stanze:
entro nella stanza
PIR avverte la mia presenza
si accende la luce
ritardo lo spegnimento della luce per darmi il tempo di uscire dalla stanza
In questa e nella successiva lezione vorrei giungere alla realizzazione di un comportamento più vicino alla realtà:
entro nella stanza
PIR avverte la mia presenza
si accende in fade la luce
esco dalla stanza
il PIR non rileva più la mia presenza
si spegne in fade la luce
Suddivido la soluzione del problema in due sottoproblemi che risolverò in questa e nella successiva lezione:
funzione fade
funzione controllo presenza
Realizziamo la funzione fade
Se ricordate nella lezione 2 abbiamo realizzato il famoso “blink” lo sketch che accendeva e spegneva in modo continuativo un LED.
Realizziamo nuovamente il circuito ed eseguite lo sketch allegato:
// Esempio 01: fare lampeggiare un LED
#define LED 13 // LED collegato al pin digitale 13
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
digitalWrite(LED, HIGH); // accende il LED
delay(1000); // aspetta 1 secondo
digitalWrite(LED, LOW); // spegne il LED
delay(1000); // aspetta 1 secondo
}
Provate a ridurre drasticamente il ritardo di accensione e spegnimento, arrivate a 10 millisecondi, quasi non dovreste più pecepire lampeggiare il LED e inoltre dovreste aver notato che la luminosità del LED è diminuita.
// Esempio 02: modulazione di larghezza di impulso (PWM)
#define LED 13 // LED collegato al pin digitale 13
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
digitalWrite(LED, HIGH); // accende il LED
delay(10); // aspetta 10 millisecondi
digitalWrite(LED, LOW); // spegne il LED
delay(10); // aspetta 10 millisecondi
}
Il motivo per cui si vede illuminare di meno il diodo LED è dovuta alla modulazione di larghezza di impulso in inglese Pulse Width Modulation – PWM, che detta in modo meno tecnico vuol dire che se facciamo lampeggiare un diodo LED ad una frequenza sufficientemente elevata e se cambiamo il rapporto tra il tempo in cui sta acceso ed il tempo in cui sta spento, il nostro occhio non percepirà il lampeggiare del LED ed inoltre a secondo del rapporto del tempo di accensione e spegnimento potremo regolare la luminosità del LED.
Possiamo dire che il PWM è una tecnica per ottenere risultati analogici con mezzi digitali.
Un po’ di teoria: il Duty cycle
Il duty cycle di un onda quadra/rettangolare e il rapporto tra la durata (in secondi) del segnale quando è “alto” ed il periodo totale del segnale. In altre parole è un numero che esprime quant’è la parte di periodo in cui il segnale è alto.
Facendo riferimento al disegno la formula che esprime il duty cycle è:
τ/T
dove T è il periodo e τ la parte di periodo in cui il segnale è alto.
Dalla formula potete subito notare che τ può variare da un valore minimo di 0 a un valore massimo pari a T, ciò implica che il valore del duty cycle varia da 0 a 1:
in entrambi i casi siamo in presenza di segnali continui.
Dalla formula possiamo comprendere quindi che il duty cycle è sempre un valore che varia tra 0 e 1.
Il duty cycle è spesso rappresentato in percentuale, D% e per ottenere la percentuale è sufficiente moltiplicare per 100 il rapporto τ/T, dire quindi che il D%=30% vuol dire che per il 30% del periodo totale il segnale si trova a livello alto, come conseguenza possiamo subito dire che il segnale sarà a livello basso per il restante 70% del periodo.
Dire quindi che il duty cycle è del 50% vuol dire che nel periodo T il segnale si mantiene alto per T/2 e per il restante T/2 a livello basso in questo caso siamo quindi in presenza di un’onda quadra.
Passiamo ora alla pratica
Poniamoci nelle seguenti 3 condizioni:
50% LED acceso e 50% LED spento
luminosità al 50%
25% LED acceso e 75% LED spento
luminosità al 25%
75% LED acceso e 25% LED spento
luminosità al 75%
Per realizzare le tre condizioni impostate scegliamo un periodo sufficientemente breve tale da non percepire il lampeggiare del LED:
Poniamo un periodo T = 20ms
10ms acceso e 10ms spento
5 ms acceso e 15ms spento
75 ms acceso e 5ms spento
// Esempio 03: modulazione di larghezza di impulso (PWM) - on: 10ms - off: 10ms
#define LED 13 // LED collegato al pin digitale 13
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
digitalWrite(LED, HIGH); // accende il LED
delay(10); // aspetta 10 millisecondi
digitalWrite(LED, LOW); // spegne il LED
delay(10); // aspetta 10 millisecondi
}
// Esempio 04: modulazione di larghezza di impulso (PWM) - on: 5ms - off: 15ms
#define LED 13 // LED collegato al pin digitale 13
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
digitalWrite(LED, HIGH); // accende il LED
delay(5); // aspetta 5 millisecondi
digitalWrite(LED, LOW); // spegne il LED
delay(15); // aspetta 15 millisecondi
}
// Esempio 05: modulazione di larghezza di impulso (PWM) - on: 15ms - off: 5ms
#define LED 13 // LED collegato al pin digitale 13
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
digitalWrite(LED, HIGH); // accende il LED
delay(15); // aspetta 15 millisecondi
digitalWrite(LED, LOW); // spegne il LED
delay(5); // aspetta 5 millisecondi
}
Dal filmato potete notare la variazione di luminosità nelle tre condizioni:
Con un po’ di esperimenti noterete che la tecnica di variazione della luminosità, utilizzando il ritardo “delay()”, non è il metodo migliore in quanto, non appena inseite altri sensori ad Arduino, oppure inviate dei dati alla seriale, il LED tremolerà nell’attesa che termini la lettura del sensore o la scrittura sulla seriale.
Come evitare questo problema?
Arduino UNO offre la possibilità di usare i pin 3, 5, 6, 9, 10, 11 l’istruzione: analogWrite(), istruzione che consente appunto di far lampeggiare il LED o governare un motore elettrico mentre lo sketch esegue altre istruzioni.
Sintassi:
analogWrite(pin, valore)
dove:
pin: è il piedino su cui inviamo il segnale, per Arduino UNO i pin 3, 5, 6, 9, 10, 11
valore: è il duty cycle compreso tra 0 (sempre off) a 255 (sempre on)
La funzione non restituisce nessun valore.
Quindi se utilizziamo la funzione analogWrite() per il controllo della luminosità del LED e scriviamo:
analogWrite(11, 0)
il LED collegato al pin 11 avrà una luminosità dello 0% (duty cycle 0%)
// Esempio 06: utilizzo della funzione analgoWrite() - LED spento - (duty cycle 0%)
#define LED 11 // LED collegato al pin digitale 11
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
analogWrite(LED, 0); // accende il LED
}
analogWrite(11, 64)
il LED collegato al pin 11 avrà una luminosità del 25% (duty cycle 25%)
// Esempio 07: utilizzo della funzione analgoWrite() - LED spento - (duty cycle 25%)
#define LED 11 // LED collegato al pin digitale 11
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
analogWrite(LED, 64); // accende il LED
}
analogWrite(11, 128)
il LED collegato al pin 11 avrà una luminosità del 50% (duty cycle 50%)
// Esempio 08: utilizzo della funzione analgoWrite() - LED spento - (duty cycle 50%)
#define LED 11 // LED collegato al pin digitale 11
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
analogWrite(LED, 128); // accende il LED
}
analogWrite(11, 191)
il LED collegato al pin 11 avrà una luminosità del 75% (duty cycle 75%)
// Esempio 09: utilizzo della funzione analgoWrite() - LED spento - (duty cycle 75%)
#define LED 11 // LED collegato al pin digitale 11
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
analogWrite(LED, 191); // accende il LED
}
analogWrite(11, 255)
il LED collegato al pin 11 avrà una luminosità del 100% (duty cycle 100%)
// Esempio 10: utilizzo della funzione analgoWrite() - LED spento - (duty cycle 100%)
#define LED 11 // LED collegato al pin digitale 11
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
analogWrite(LED, 255); // accende il LED
}
Nel filmato allegato potete notare la differenza di luminosità nelle 5 condizioni sopra illustrate.
Imparato come variare la luminosità del LED usando la funzione analogWrite(), vediamo come realizzare il fade del LED ovvero l’accensione e lo spegnimento graduale, attenzione che questo modo di procedere sarà utile anche quando dovremo imparare a variare la velocità di un motorino elettrico.
Lo schetch che vi allego è già presente negli esempi disponibili dal menù: File -> Examples -> 3.Analog -> Fading ne ho variato alcune parti:
// Esempio 11: Fading
#define LED 11 // LED collegato al pin digitale 11
int valoreFade = 0; // variabile usata per contare in avanti e indietro
void setup() {
pinMode(LED, OUTPUT); // imposta il pin digitale come output
}
void loop() {
// procede ciclicamente da 0 a 254 (fade in -> aumento luminosità)
for (valoreFade = 0 ; valoreFade < 255; valoreFade++) { analogWrite(LED, valoreFade); //impostiamo la luminosità del LED delay(10); // aspettiamo 10ms per percepire la viariazione di luminosità, //perché analogWrite è istantaneo } // procede ciclicamente da 255 a 1 (fade out -> diminuzione della luminosità)
for(valoreFade = 255 ; valoreFade > 0; valoreFade--) {
analogWrite(LED, valoreFade); //impostiamo la luminosità del LED
delay(10);
// aspettiamo 10ms per percepire la viariazione di luminosità,
//perché analogWrite è istantaneo
}
}
Analizzaimo il codice.
Prendiamo in analisi la prima parte del loop(). All’interno troviamo un primo ciclo for:
...
// procede ciclicamente da 0 a 254 (fade in -> aumento luminosità)
for (valoreFade = 0 ; valoreFade < 255; valoreFade++) {
analogWrite(LED, valoreFade); //impostiamo la luminosità del LED
delay(10);
// aspettiamo 10ms per percepire la viariazione di luminosità,
//perché analogWrite è istantaneo
}
...
Ad ogni ciclo incrementiamo la variabile valoreFade di 1 (valoreFade++) partendo da 0 fino a 254. valoreFade viene utilizzata in analogWrite(LED, valoreFade) per variare il valore del duty cycle ed incrementare la luminosità del LED. Poichè l’azione di analogWrite(LED, valoreFade) è immediata per percepire visivamente la variazione di luminosità introduciamo un piccolo ritardo di 10ms con delay(10). Il ciclo terminerà non appena la condizione valoreFade < 255 non è più vera, cioè valoreFade non più minore di 255.
Il secondo ciclo for consente di diminuire la luminosità:
...
// procede ciclicamente da 255 a 1 (fade out -> diminuzione della luminosità)
for(valoreFade = 255 ; valoreFade > 0; valoreFade--) {
analogWrite(LED, valoreFade); //impostiamo la luminosità del LED
delay(10);
// aspettiamo 10ms per percepire la viariazione di luminosità,
//perché analogWrite è istantaneo
}
...
Ad ogni ciclo la variabie valoreFade viene decrementata di 1 (valoreFade–) facendo decrescere valoreFade da 255 a 1 e di conseguenza la luminosità del LED. Il ciclo terminerà quando la condizione valoreFade > 0 non è più vera.
Usciti da questo secondo ciclo si ripartirà con il primo ciclo for che permetterà nuovamente l’aumento della luminosità del LED.
Nella prossima lezione vedreme come interagire mediante pulsanti sull’intensità luminosità del LED.
Sto ricevendo diverse mail di utenti che non riescono a prelevare il corso gratuito di Arduino realizzato da Elettronica In di cui avevo dato notizia il 10 di settembre scorso.
Per poter prelevare il corso è necessario effettuare il login, se non si è registrati procedere con la registrazione, seguendo questa procedura:
[wpspoiler name=”Come prelevare il corso”]
Dopo aver effettuato il Login seguite il link per andare alla pagina da cui scaricare il corso.
[/wpspoiler]
solo in questo modo potete prelevare il file .zip che contiene il pdf e i sorgenti degli sketch usati nel corso.
Una volta effettuato il login sul sito seguite il link per andare sulla pagina da cui scaricare il corso.
Ho appena segnalato su vocescuola.it la nuova ed utilissima funzionalità di delicious: Stacks:
Non solo collezioni testuali di link, ma vere è proprie pile di link con immagini e filmati da collezionare e condividere con chi volete. Certamente un modo rapidissimo di collezionare informazioni da condividere rapidamente con i vostri allievi. Immagino ad esempio alla realizzazione di cacce al tesoro per i vostri allievi, oppure ad una collezione di volumi di link suddivisi per argomento da utilizzare come sitografia di studio da proporre in modo più interessante ai propri allievi.
E quindi non potevo non realizzare, per i miei studenti e per i moltissimi che utilizzano le mie lezioni su questo sito uno Stak su delicious tutto dedicato ad Arduino dal titolo:
Ho collezionato quelle che ritengo le migliori risorse didattiche per imparare ad utilizzare Arduino. Cercherò di mantenere aggiornato questo Stack e lo utilizzerò come punto di riferimento per la realizzazione di corsi on-line, approfondimenti e consigli di studio per i miei studenti.
Per rimanere aggiornati sugli aggiornamenti del mio stak su delicious fate click sul pulsante
follow staks
nella colonna destra della mia pagina delicious.
Oppure per vedere gli staks che sto creando seguite il link.