![08 Numerazione capitolo](08-num-capitolo.png) ## 08 - CLESSIDRA DIGITALE **IN QUESTO PROGETTO, COSTRUIRAI UNA CLESSIDRA DIGITALE CHE ACCENDE UN LED OGNI DIECI MINUTI. SAPRAI PER QUANTO TEMPO STAI LAVORANDO SUI TUOI PROGETTI USANDO IL TIMER INCORPORATO IN ARDUINO** > **Scopri:** il tipo di dati long, creare un timer > > **Tempo:** 30 MINUTI > **Livello:** ■ ■ ■ □ □ > **Basato sui progetti:** 1, 2, 3, 4 **Finora con Arduino, quando hai voluto che accadesse qualcosa in uno specifico intervallo di tempo, hai usato la funzione `delay()`: è pratica, ma un po' limitante. Quando Arduino chiama `delay()`, blocca il suo stato corrente per la durata del ritardo. Significa che non ci sono altri ingressi o uscite quando è in attesa. I ritardi non sono molto utili per tenere traccia del tempo. Se vuoi fare qualcosa ogni 10 secondi, avere un `delay()` di 10 secondi è piuttosto scomodo.** ![Ingredienti](08-ingredienti.png) >**INGREDIENTI** >* Interruttore di inclinazione (Tilt switch) >* 6 LED >* Resistenza da 10 Kilo Ohm >* 6 Resistenze da 220 Ohm La funzione `millis()` aiuta a risolvere questi problemi. Tiene traccia del tempo in cui Arduino è funzionante in millesimi di secondo. L'hai usato precedentemente nel Progetto 06 quando hai creato un timer per la calibrazione. Finora hai dichiarato le variabili come `int`. Un `int` (intero) è un numero a 16 bit, che contiene valori tra -32768 e 32767. Possono sembrare numeri grandi, ma Arduino conta 1000 volte al secondo con la funzione `millis()` e quindi esaurisci i numeri in poco tempo. Il tipo di dato `long` contiene un numero da 32 bit (tra -2147483648 e 2147483647). Dal momento che non è possibile tornare indietro per ottenere i numeri negativi, la variabile per immagazzinare il tempo `millis()` è chiamata `unsigned long`. Quando un tipo di dato è chiamato unsigned, è solo positivo. Questo ti permette di contare ancora di più. Un `unsigned long` può contare fino a 4294967295. C'è abbastanza spazio per far sì che la funzione `millis()` tenga traccia del tempo per almeno 50 giorni. Confrontando il valore attuale di `millis()` a un valore specifico, puoi vedere se è passato un certo periodo di tempo. Quando capovolgi la clessidra, un interruttore di inclinazione cambierà il suo stato e prenderà il via un nuovo ciclo di accensione dei LED. L'interruttore di inclinazione funziona come un normale interruttore nel senso che è un sensore acceso/spento. Qui lo userai come ingresso digitale. Ciò che rende unico l'interruttore di inclinazione è che rileva l'orientamento. Normalmente ha una piccola cavità all'interno del corpo che contiene una sfera di metallo. Quando è inclinato in modo corretto, la sfera rotola su un lato della cavità e collega i due terminali che sono sulla breadboard chiudendo l'interruttore. ### COSTRUISCI IL CIRCUITO ![Schema del circuito e montaggio](08-immagine_circuito_clessidra.png) 1. Collega alimentazione e massa alla breadboard. 2. Collega l'anodo (la gamba più lunga) dei sei LED ai piedini digitali 2-7. Collega i LED a massa attraverso una resistenza da 220 ohm. 3. Collega una estremità dell'interruttore di inclinazione a 5V. Collega l'altra a una resistenza da 10 kilo ohm a massa. Collega il punto dove si incontrano al piedino digitale 8. ![Schema elettrico](08-schema_elettrico_clessidra.png) ![Forbici e colla](forbici-colla.png) > *Non c'è bisogno che Arduino sia collegato al computer per funzionare. Prova a costruire un supporto con del cartoncino o del polistirolo e alimentare Arduino con una batteria per creare una clessidra portatile. Puoi creare una copertura con delle cifre a fianco delle luci.* ![Lente](lente.png) > *Gli **interruttori di inclinazione** sono strumenti ottimi ed economici per determinare l'orientamento di qualcosa.* > *Gli **accelerometri** sono altri tipi di sensori di inclinazione, ma forniscono molte più informazioni. Sono anche significativamente più costosi. Se ti serve controllare se qualcosa è su o giù, un sensore di inclinazione è più che sufficiente.* ### IL CODICE #### Dichiara una costante Hai bisogno di alcune variabili globali nel tuo programma. Per iniziare, crea una costante chiamata `switchPin`. Questo è il nome del piedino al quale è connesso l'interruttore di inclinazione. ```cpp const int switchPin = 8; ``` #### Crea una variabile per memorizzare il tempo Crea una variabile di tipo `unsigned long`. Questa memorizza il momento in cui è stato modificato l'ultimo LED. ```cpp unsigned long previousTime = 0; ``` #### Variabili per gli ingressi e le uscite Crea una variabile per lo stato dell'interruttore e un'altra per memorizzare il precedente stato dell'interruttore. Userai queste due variabili per confrontare la posizione dell'interruttore da un ciclo al successivo. Crea una variabile chiamata `led`, che verrà usata per verificare quale LED è il prossimo ad accendersi. Inizia con il piedino 2. ```cpp int switchState = 0; int prevSwitchState = 0; int led = 2; ``` #### Dichiara una variabile descrivendo l'intervallo tra gli eventi L'ultima variabile da creare è l'intervallo di accensione di ogni LED. Questo è un tipo di dato `long`. In 10 minuti (il tempo tra l'accensione di ogni LED) ci sono 600000 millesimi di secondo. Se vuoi che il ritardo tra le luci sia più lungo o corto, questo è il numero da cambiare. ```cpp long interval = 600000; ``` #### Imposta la direzione dei tuoi piedini digitali Nel `setup()`, hai bisogno di dichiarare come output i piedini dei LED 2-7. Un ciclo `for()` li dichiara tutti e sei come **OUTPUT** con solo 3 linee di codice. Hai bisogno anche di dichiarare `switchPin` come **INPUT**. ```cpp void setup() { for(int x = 2;x<8;x++){ pinMode(x, OUTPUT); } pinMode(switchPin, INPUT); } ``` #### Controlla da quanto tempo è stato avviato il programma Quando inizia il `loop()`, misura la quantità di tempo in cui Arduino è stato in funzione con `millis()` e immagazzinalo in una variabile locale chiamata `currentTime`. ```cpp void loop(){ unsigned long currentTime = millis(); ``` #### Valuta la quantità di tempo trascorso dal precedente loop() Usando un'istruzione `if()`, controlla se è passato abbastanza tempo per accendere un LED. Sottrai `currentTime` da `previousTime` e controlla se è maggiore della variabile `interval`. Se sono passati 600000 millesimi di secondo (10 minuti), imposta la variabile `previousTime` al valore di `currentTime`. ```cpp if(currentTime - previousTime > interval) { previousTime = currentTime; ``` #### Accendi un LED, prepara il prossimo Indica l'ultima volta in cui è stato acceso un LED. Quando hai impostato `previousTime`, accendi il LED e incrementa la variabile `led`. La prossima volta che passi l'intervallo di tempo, il LED successivo si accende. ```cpp digitalWrite(led, HIGH); led++; ``` #### Verifica se tutte le luci sono accese Aggiungi una istruzione `if` in più nel programma per controllare se il LED sul piedino 7 si è acceso. Non farci ancora nulla. Potrai decidere dopo cosa succede alla fine dell'ora. ```cpp if(led == 7){ } } ``` #### Leggi il valore dell'interruttore Dopo aver controllato il tempo, guarda se l'interruttore ha cambiato il suo stato. Scrivi il valore dell'interruttore nella variabile `switchState`. ```cpp switchState = digitalRead(switchPin); ``` #### Azzera le variabili se necessario Con una istruzione `if()`, verifica se l'interruttore si trova in una posizione diversa da quella precedente. Il `!=` controlla se `switchState` è diverso da `prevSwitchState`. Se sono diversi, spegni i LED, riporta la variabile `led` al primo piedino e azzera il timer per i LED impostando `previousTime` al valore di `currentTime`. ```cpp if(switchState != prevSwitchState){ for(int x = 2;x<8;x++){ digitalWrite(x, LOW); } led = 2; previousTime = currentTime; } ``` #### Imposta lo stato corrente allo stato precedente Alla fine del `loop()`, salva lo stato dell'interruttore in `prevSwitchState`, così puoi confrontarlo al valore di `switchState` nel `loop()` successivo. ```cpp prevSwitchState = switchState; } ``` ### USALO Una volta che hai programmato la scheda controlla l'ora su un orologio. Dopo che sono passati 10 minuti, il primo LED dovrebbe essersi acceso. Ogni 10 minuti si accenderà un altro LED. Alla fine di un'ora, tutte le 6 luci dovrebbero essere accese. Quando ribalti il circuito e fai cambiare stato all'interruttore di inclinazione, le luci si spegneranno e il timer ripartirà. ![Cervello](cervello.png) > *Quando l'orologio raggiunge un'ora e tutte le 6 luci sono accese, rimangono accese. Puoi pensare a un modo per attirare l'attenzione quando l'ora è passata? Suoni o il lampeggiare di luci sono entrambi buoni indicatori. La variabile led può essere controllata per vedere se tutte le luci sono accese; questo è un buon modo per catturare l'attenzione di qualcuno. Diversamente da una clessidra riempita di sabbia, le luci vanno su o giù a seconda dell'orientamento dell'interruttore. Riesci a capire come utilizzare la variabile `switchState` per indicare in quale direzione dovrebbero andare le luci?* **Per misurare il tempo tra eventi, usa la funzione `millis()`. Dato che i numeri che genera sono più grandi di quelli che puoi memorizzare in un `int`, dovresti usare il tipo di dato `unsigned long` per immagazzinarne i valori.** ### CODICE COMPLETO ```cpp /* Arduino Starter Kit example Project 8 - Digital Hourglass This sketch is written to accompany Project 8 in the Arduino Starter Kit Parts required: - 10 kilohm resistor - six 220 ohm resistors - six LEDs - tilt switch NOTE: This sketch is intentionally incomplete. Make sure to add your own code for whatever you want to happen at the end of the hour. created 13 Sep 2012 by Scott Fitzgerald https://store.arduino.cc/genuino-starter-kit This example code is part of the public domain. */ // named constant for the switch pin const int switchPin = 8; unsigned long previousTime = 0; // store the last time an LED was updated int switchState = 0; // the current switch state int prevSwitchState = 0; // the previous switch state int led = 2; // a variable to refer to the LEDs // 600000 = 10 minutes in milliseconds long interval = 600000; // interval at which to light the next LED void setup() { // set the LED pins as outputs for (int x = 2; x < 8; x++) { pinMode(x, OUTPUT); } // set the tilt switch pin as input pinMode(switchPin, INPUT); } void loop() { // store the time since the Arduino started running in a variable unsigned long currentTime = millis(); // compare the current time to the previous time an LED turned on // if it is greater than your interval, run the if statement if (currentTime - previousTime > interval) { // save the current time as the last time you changed an LED previousTime = currentTime; // Turn the LED on digitalWrite(led, HIGH); // increment the led variable // in 10 minutes the next LED will light up led++; if (led == 7) { // the hour is up // add your indicator code here } } // read the switch value switchState = digitalRead(switchPin); // if the switch has changed if (switchState != prevSwitchState) { // turn all the LEDs low for (int x = 2; x < 8; x++) { digitalWrite(x, LOW); } // reset the LED variable to the first one led = 2; //reset the timer previousTime = currentTime; } // set the previous switch state to the current state prevSwitchState = switchState; } ```