Errori comuni nell’uso di Arduino: nome istruzioni non corretto, terminazione istruzione, parentesi non chiuse

Gli errori più frequenti sono:

  • errori nella scrittura del nome delle istruzioni;
  • punto e virgola alla fine di un’istruzione;
  • mancanza delle parentesi graffa di apertura o chiusura di un gruppo di istruzioni;
  • uso scorretto delle parentesi.

Uno qualsiasi dei problemi indicati sopra, come avete notato a lezione, interromperà la compilazione del programma segnalandovi l’errore nell’area di status al fondo della finestra di programmazione.

Prendo come esempio il codice utilizzato questa mattina in laboratorio su cui ho aggiunto io gli errori che ho rilevato nelle scorse lezioni e questa mattina:

Codice non corretto

  • Riga 8: manca ;
  • Riga 16: uso scorretto delle parentesi graffe { } da sostituire con parentesi tonde ( )
  • Riga 19: errore nel nome dell’istruzione: digitalwrite() invece di digitalWrite()
  • Riga 21: manca parentesi } di chiusura della funzione loop()

Codice corretto

Ognuno di questi errori impedirà la compilazione del vostro programma.
So che all’inizio può essere frustrante cercare gli errori nel codice ed imparare la sintassi di programmazione, ma si tratta di un piccolo scoglio iniziale superato il quale sarete in grado di realizzare progetti sempre più complessi ed interessanti.

All’inizio copiate il codice che ho sviluppato per le lezioni, modificatelo e miglioratelo in questo modo in poco tempo riuscirete a migliorare.

Ricordo inoltre che è buona regola utilizzare le funzioni “Formattazione Automatica” che consente di indentare (far rientrare) il codice in modo da evidenziare meglio la struttura del programma migliorando la leggibilità e mettendo quindi in evidenza la struttura logica del vostro sketch.

Nel caso di dubbi sull’uso di istruzioni e sintassi, utilizzate il comando “Cerca nella Guida”, sarà sufficiente evidenziare nel codice l’istruzione di cui volete informazioni, nell’esempio che segue “digitalWrite” e dal menù “Aiuto > Cerca nella guida” vi verrà mostrato la pagina della guida che fa riferimento all’istruzione cercata.


Compito per i miei studenti:

Leggere gli articoli che seguono in riferimento agli errori comuni nell’uso di Arduino

Messaggio per i miei allivi:

non si diventa Maker facendo un blink con Arduino…
studio e sperimentazione un po’ al giorno tutti i giorni.

P.S.
se non è tuo interesse diventare Maker allora sostiuisci la frase: “non si diventa maker facendo un blink con Arduino…” con la frase “non si ottiene la sufficienza sapendo fare solo un blink con Arduino…”

😉

Arduino: chiarimenti sulla modalità di alimentazione della scheda

Per i miei allievi di 3 Automazione.
Durante le prime sperimentazioni con Arduino molto spesso si incorre in dubbi ed errori riguarda l’alimentazione della scheda, mi preme quindi fare alcune precisazioni prima che le vostre schede personali o quelle della scuola possano rovinarsi ;-).

Riprendo quanto detto a lezione mostrando le mie slide (pagina 15) e affinché ciò non venga dimenticato ricordo che esistono diverse modalità di alimentazione di Arduino:

  • cavo USB;
  • batteria esterna;
  • alimentatore esterno

Come indicato dalle specifiche tecniche della scheda:

  • la tensione di alimentazione raccomandata può variare dai 7Vcc ai 12 Vcc
  • la tensioni limite di funzionamento variano dai 6Vcc ai 20Vcc

Ovviamente lavoreremo sempre nell’intervallo raccomandato.

Nel caso si operi con un alimentatore esterno è indispensabile non solo sapere la tensione fornita dall’alimentatore, ma anche la massima corrente erogabile dall’alimentatore.

Tipicamente nelle prime sperimentazioni si utilizzano alimentatori USB per cellulari che possono erogare correnti di diversa entità, in genere si oscilla dai 0,2A ai 0,5A ma si può arrivare anche ad 1A nel caso di un caricatore per iPhone o iPad, ma è possibile trovare caricatori che erogano correnti anche superiori come ad esempio quello dell’immagine che segue di 2A per uno smartphone Asus.

Dati di targa di alcuni alimentatori:

Per alimentare la nostra scheda Arduino UNO R3 sarà sufficiente collegarlo tramite cavo USB all’alimentatore:

Arduino dispone di un Jack di collegamento esterno da 2.1×5 mm (diametro foro interno x diametro foro esterno – foro interno + e foro esterno -) a cui collegare un alimentatore esterno:

Probabilmente se avete acquistato un kit Arduino, originale o compatibile, troverete questo Jack nella vostra confezione a cui è connesso un connettore per batterie da 9V, come quello indicato nell’immagine che segue:

nel caso non fosse presente potete leggere un piccolissimo tutorial che realizzai qualche anno fa per altri studenti: Alimentare Arduino con una batteria da 9V – jack di collegamento

Nel caso non desiderate effettuare saldatura in commercio esistono jack a cui collegare fili di collegamento mediante una morsettiera in cui i cavi vengono serrati con viti oppure a pressione, come indicato nelle immagini che seguono:

Ricordate che la tensione di funzionamento dei componenti sulla scheda Arduino è di 5V, il regolatore di tensione della scheda (nell’immagine che segue indicato dalla freccia rossa) consentirà di riportare a 5V cc tensioni di alimentazione superiore che vengono fornite da un alimentatore esterno, ma questo tipo di lavoro viene trasformato dal regolatore di tensione in calore, infatti in queste condizioni noterete un aumento di temperatura del dispositivo.


In una prossima esercitazione vi mostrerò come, usando un sensore di temperatura esterno, la temperatura del regolatore aumenta all’aumentare della tensione esterna fornita alla scheda.

Tenete in conto però che tensioni di 12VCC o superiori (max 20Vcc) possono essere necessarie nel caso in cui sia necessario alimentare un dispositivo elettrico funzionante a tensioni superiori ai 5VCC che dovrà essere collegato e controllato da Arduino.

In questo caso l’alimentazione per il dispositivo esterno potrebbe essere ricavata dal pin Vin presente sulla scheda, ma ATTENZIONE questa tensione è quella che viene fornita dall’alimentatore esterno, quindi su Vin abbiamo la stessa tensione dell’alimentatore, pertanto bisogna essere certi della tensione necessaria al funzionamento del dispositivo connesso alla Vin.

Per i miei allievi: prima di procedere chiedete 🙂

Domanda“Prof. ma se non ho il Jack posso alimentare direttamente con una batteria da 9Vcc sul pin Vin?”

Sì è possibile farlo.

Domanda“Prof. ma a cosa serve il pin 5V?”

Esiste un altro modo per alimentare Arduino, lo segnalo per indicarne la possibilità ma soprattutto i rischi.
Per alimentare la scheda è possibile collegare una tensione stabilizzata di 5Vcc direttamente al pin 5V di Arduino, ma questa procedura è sconsigliata in quanto questa tensione è quella che viene direttamente applicata al microcontrollore e ad altri dispositivi sulla scheda, quindi se non siete assolutamente sicuri che la tensione di alimentazione non sia di 5Vcc evitate la connessione… meglio evitate sempre 🙂

Se per qualche motivo vi trovate in questa condizione siate certi che non sia connessa altra fonte di alimentazione alla scheda Arduino tramite jack o USB della scheda.

Per i miei allievi: prima di procedere chiedete 🙂

Ricapitolando i modi per Alimentare Arduino sono:

Domanda: “Prof. ma a cosa serve il pin 3.3V?”

Risposta: Per esercizio leggere l’articolo: leggere e studiare quanto indicato al seguente link:Livelli logici TTL e CMOS – cosa si nasconde dietro un HIGH o LOW di una digitalWrite di Arduino?

… e poi approfondiamo in classe.

Alcune precisazioni sulla corrente erogata da una fonte di alimentazione.

Domanda: “Prof. ho collegato 10 led per fare l’effetto supercar, ma le batterie si sono subito scaricate! Perché?”

La quantità di corrente erogabile da una batteria è indicata in mAh (milliampere per ora: quantità di corrente che può essere erogata in 1 ora).
Nel caso di una tipica batterie alcalina non ricaricabili da 1,5Vcc AA (modello LR6) la corrente erogata oscilla tra i 2700 e i 3400 mAh

Nel caso in cui si utilizzi una batteria da 9Vcc Alcalina di tipo 6LR61 la capacità tipica è di 565 mAh.

In modo indicativo tenendo conto di un comportamento ideale e lineare delle batterie elettriche possiamo fare le considerazioni che seguono.

Arduino per il suo funzionamento assorbe tipicamente circa 45 mA – 50mA, lo dimostreremo in laboratorio, pertanto per conoscere per quanto tempo possiamo alimentare Arduino con la batteria da 9V indicata sarà sufficiente effettuare il seguente calcolo:

t = corrente erogata dalla batteria in 1 ora/consumo = 565 mAh / 45mA = 12,56 h

Nel caso in cui si utilizzi un pacco batterie costituito da 6 batterie da 1,5V cc collegate in serie per un totale di 9V ciascuna erogante 2700 mAh si avrà un tempo di alimentazione di:

t = capacità della batteria/consumo = 2700 mAh / 45mA = 60 h

tutto ciò ovviamente nel caso in cui non si colleghino altri dispositivi alla scheda Arduino, in caso contrario bisognerà tener conto dell’assorbimento di ogni singolo componente. Ad esempio nel caso di un LED abbiamo assorbimenti che oscillano tra i 15 e i 20 mA, pertanto nel caso della domanda dello studente avremo che 10 LED assorbiranno circa:

10×15 mA = 150 mA

Quindi ai 45 mA di Arduino bisognerà aggiungere i 150 mA dei LED per un totale di 195 mA quindi la durata del pacco batterie scenderà a:

t = capacità della batteria/(consumo Arduino + consumo 10 LED) = 2700 mAh / 195mA = 14 h (circa)

e quindi aggiungendo altri dispositivi aumenterà la corrente che dovrà essere erogata dall’alimentatore.

Ovviamente utilizzando un alimentatore stabilizzato esterno collegato alla rete elettrica potremo avere costantemente alimentazione ed un’erogazione di corrente massima indicata sui dati di targa dell’alimentatore.

Esistono tecniche per porre Arduino in una modalità a basso consumo ma per questo ve ne parlerò più avanti.

Si tenga conto inoltre che nel caso in cui si alimenti Arduino e i circuiti ad esso connesso tramite USB, la corrente massima erogata dalla USB del computer se di tipo USB 1.0 o 2.0 è di 500 mA, nel caso in cui il computer sia fornito di USB 3.0 la corrente massima erogata è di 900 mA.

Domanda: “Prof. ma cosa accade se la corrente assorbita da Arduino e dei dispositivi connessi alla scheda superano i valori limiti di corrente forniti dalla USB del computer?”

Nella maggior parte dei casi il controller USB viene posto, da parte del computer, in una modalità di protezione disattivando la periferica ad esso connessa (nel nostro caso Arduino), questa situazione rimane fino a quando non viene riavviato il computer.-
Nella situazione peggiore, in computer datati si rischia di bruciate il controller USB del computer o della scheda madre.

Domanda: “ Prof. ma cosa succede ad Arduino se in esso circola una corrente superiore ai 500 mA?”

Un assorbimento superiore ai 500 mA non danneggia solamente il computer ma anche Arduino che non può sopportare correnti così elevate.

Per evitare questo rischio sulla scheda Arduino è presente un fusibile termico resettabile noto anche come Termistore o PTC (Positive Temperature Coefficient: resistenza che cresce con l’aumentare della temperatura) che riduce drasticamente la corrente assorbita da Arduino nel caso in cui si superino i 500 mA ponendola quindi in protezione.
Questo fusibile è ben visibile, è collocato di fianco alla presa USB ed è costituito da terminali di color oro:

Nello schema elettrico di Arduino è indicato con F1:

Il fusibile verrà ripristinato automaticamente dopo circa 30 secondi dal momento in cui togliete alimentazione alla scheda Arduino.

Buona sperimentazione a tutti 🙂

Arduino: utilizzo del sensore di umidità e temperatura DHT11

Proseguo con le sperimentazioni di laboratorio di Sistemi dedicate alla progettazione di una semplice stazione meteorologica. In questa lezione i miei allievi di 5 Automazione dovranno gestire un sensore di umidità e temperatura DHT 11 e svolgere successivamente i tre esercizi proposti al termine di questa guida.

Il DHT11 è un sensore digitale di umidità e temperatura dell’aria costituito da una parte resistiva che si occupa della rilevazione dell’umidità e da un NTC che rileva la temperatura, queste due parti sono gestite da un microcontrollore che è parte integrante del sensore. Il DHT 11 viene pre-calibrato in fabbrica e i dati di calibrazione vengono memorizzati all’interno di una memoria di sola lettura (OPT Memory).

Caratteristiche del sensore

  • Intervallo di temperatura: da 0 a 50 ºC +/-2 ºC
  • Intervallo di umidità: da 20 a 90% +/-5%
  • Risoluzione:
    • Umidità: 1%
    • Temperatura: 1ºC
  • Tensione di alimentazione: 3 – 5.5 V DC
  • Corrente assorbita: 0.5 – 2.5 mA
  • Periodo di campionamento: 1 sec

Le dimensioni ridotte, il basso consumo energetico e la possibilità di trasmettere il segnale su cavo fino a 20 metri lo rendono interessante per diverse applicazioni sia in campo hobbistico che semiprofessionale.

Quando la lunghezza del cavo di collegamento è inferiore a 20 metri è consigliabile inserire una resistenza di pull-up da 4,7 Kohm sulla linea dati (pin 2).

Il sensore può essere acquistato in due configurazioni:

Componente singolo a 4 pin su stessa linea

Componente montato su breakout board a 3 pin (in questo caso la resistenza di pull-up interna sul pin 2 è già presente)

Pinout

Nel caso in cui si utilizzi il componente a 4 pin la corrispondenza è la seguente

  • pin 1: Vcc
  • pin 2: Out
  • pin 3: non connesso
  • pin 4: GND

Per filtrare i segnali di disturbo provenienti dall’alimentazione è consigliabile inserire un condensatore da 100nF tra Vcc e GND.

Modalità di comunicazione

La lettura dei dati rilevati dal sensore può avvenire solo dopo un tempo di 1 secondo dall’atto dell’accensione del sensore.

La comunicazione con il sensore avviene utilizzando una connessione seriale che utilizza un solo filo (Single-Wire Two-Way). Il pacchetto informativo che include i dati di temperatura ed umidità inviati dal sensore ha una lunghezza di 40 bit ed una durata di 4 ms.

Il DHT11 quando alimentato si pone in una modalità a basso consumo. Quando il microcontrollore invia un segnale di start, il DHT11 passa dalla modalità a basso consumo alla modalità di funzionamento nell’attesa che il Microcontrollore completi la fase di avvio. Completata la fase di avvio il sensore invia un pacchetto informativo di risposta al microcontrollore costituito da 40 bit al cui interno si trovano le informazioni relative a umidità e temperatura rilevate. Senza il segnale di start proveniente dal microcontrollore il DHT11 non fornirà mai i dati. Conclusa la fase di invio dati il DHT11 ritorna in una modalità a basso consumo fino a quando non rileva un nuovo segnale di start proveniente dal microcontrollore.

Schema di collegamento

Per poter utilizzare il sensore è indispensabile utilizzare una libreria specifica, utilizzeremo  la libreria DHT di Adafruit

Per poter installare la libreria andare in Sketch > Library > Include Library > Manage Libraries

Inserite nel campo di ricerca “DHT” e selezionate la libreria di Adafruit:

Procedere successivamente all’installazione della libreria “Adafruit Unified Sensor”, procedendo seguendo la medesima procedura adottata per la libreria precedente:

Per verificare il funzionamento del sensore aprite lo sketch: File > Examples > DHT Sensor library > DHTtester

Lo sketch DHTtester permetterà di stampare temperatura e umidità sulla Serial Monitor

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain

// REQUIRES the following Arduino libraries:
// - DHT Sensor Library: https://github.com/adafruit/DHT-sensor-library
// - Adafruit Unified Sensor Lib: https://github.com/adafruit/Adafruit_Sensor

#include "DHT.h"

#define DHTPIN 2     // Digital pin connected to the DHT sensor
// Feather HUZZAH ESP8266 note: use pins 3, 4, 5, 12, 13 or 14 --
// Pin 15 can work but DHT must be disconnected during program upload.

// Uncomment whatever type you're using!
#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// NOTE: If using a board with 3.3V logic like an Arduino Due connect pin 1
// to 3.3V instead of 5V!
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

// Initialize DHT sensor.
// Note that older versions of this library took an optional third parameter to
// tweak the timings for faster processors.  This parameter is no longer needed
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  Serial.println(F("DHTxx test!"));

  dht.begin();
}

void loop() {
  // Wait a few seconds between measurements.
  delay(2000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  float f = dht.readTemperature(true);

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.print(F("°C "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hic);
  Serial.print(F("°C "));
  Serial.print(hif);
  Serial.println(F("°F"));
}

Analisi del codice

Inclusione della libreria DHT

#include "DHT.h"

Definizione del pin digitale di Arduino a cui collegheremo il pin dati del DHT 11

#define DHTPIN 2     // Digital pin connected to the DHT sensor

Definizione di quale tipo di sensore DHT deve essere utilizzato, nel nostro caso il DHT 11.

#define DHTTYPE DHT11   // DHT 11

Se state utilizzando un altro sensore DHT, dovrete commentare la riga precedente e rimuovere il commento da una delle seguenti linee di codice:

//#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

Inizializza un oggetto DHT chiamato dht con il pin e digitale che avete definito in precedenza

DHT dht(DHTPIN, DHTTYPE);

Nel setup() inizializziamo la Serial Monitor con un baud rate di 9600 caratteri e scriviamo un testo per avere percezione che il sistema è avviato

  Serial.begin(9600);
  Serial.println(F("DHTxx test!"));

Inizializziamo il sensore DHT con il metodo .begin()

dht.begin();

Nel loop() viene aggiunto un ritardo di 2 secondi affinché il sensore si stabilizzi ed abbia il tempo di effettuare la lettura dei dati. La frequenza di campionamento massima è di due secondi per il DHT22 e un secondo per il DHT11.

delay(2000);

Per ottenere l’umidità, è sufficiente utilizzare il metodo readHumidity() sull’oggetto dht. Nello scketck viene salvato il valore nella variabile. Si noti che il metodo readHumidity() restituisce un valore di tipo float.

float h = dht.readHumidity();

Per ottenere leggere la temperatura bisogna utilizzare il metodo readTemperature()

float t = dht.readTemperature();

Nel caso in cui si voglia leggere la temperatura in gradi Fahrenheit è sufficiente passare il valore true al metodo readTemperature()

  float f = dht.readTemperature(true);

La libreria include anche metodi per calcolare l’indice di calore in Fahrenheit e Celsius

  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

Il codice che segue stampa sulla Serial Monitor i dati letti

  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.print(F("°C "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hic);
  Serial.print(F("°C "));
  Serial.print(hif);
  Serial.println(F("°F"));

Effettuato l’upload dello sketch sulla scheda aprendo la Serial Monitor vedere i dati letti dal sensore

Noterete che il sensore risulta molto lento nel fornire la temperatura e l’umidità reale, ha necessità di qualche minuto affinché la misura si stabilizzi su quella realmente presente nell’ambiente.

Di seguito lo sketch semplificato in più parti che fornisce solo la lettura di umidità e temperatura:

// Libreria DHT
#include "DHT.h"

// Pin digitale di arduino connesso al DHT
#define DHTPIN 2

// tipo del sensore: DHT 11
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(9600);
  Serial.println(F("DHTxx test!"));

  dht.begin();
}

void loop() {
  // Attesa di 2 secondi prima di fornire la misura.
  delay(2000);

  // Lettura dell'umidità
  float h = dht.readHumidity();
  // Lettura della temperatura in gradi Celsius
  float t = dht.readTemperature();

  // Verifica se le si presenta un errore di lettura (e riprova nuovamente)
  if (isnan(h) || isnan(t)) {
    Serial.println(F("Impossibile leggere dal sensore DHT!"));
    return;
  }

  Serial.print(F("Umidità: "));
  Serial.print(h);
  Serial.print(F("%  Temperatura: "));
  Serial.print(t);
  Serial.println(F("°C "));
}

Nota

Avrete sicuramente notato che l’istruzione Serial.print contiene al suo interno come parametro F(“testo”). La “F” indica che la stringa non utilizza la RAM della scheda.

Quando compilate uno sketch Arduino alla fine della compilazione viene indicata la quantità di memoria occupata dal programma (memorizzata nella memoria flash) che state utilizzando e la quantità di RAM dinamica che state utilizzando.

Nel caso si utilizzi un gran quantità di testo costante potreste incorrere in un messaggio di errore di “memoria insufficiente”, ciò vuol dire che si è esaurita la RAM a disposizione.

Ciò dipende dal fatto che le stringhe di testo costanti presenti nello sketch vengono sempre allocate in RAM.

Per risolvere il problema è sufficiente indicare al compilatore che tutte le stringhe di testo costanti contenute nelle Serial.print non dovranno essere allocate nella RAM.

Attenzione che ciò non potrete essere fatto per le Serial.print che contengono variabili.

Quindi

  Serial.print("Umidità: ");

può essere sostituita con

  Serial.print(F("Umidità: "));

e così anche per le altre Serial.print che contengono un testo costante.

Esercizi

Esercizio 1: inviare temperatura e umidità su un display 16×2 I2C

Esercizio 2: utilizzare due pulsanti che permetteranno rispettivamente di mostrare temperatura e pressione sul display

Esercizio 3: All’avvio dello sketch con retroilluminazione attiva, appare un messaggio di benvenuto che dura 2 secondi, successivamente un messaggio che mostra l’help di utilizzo, ad esempio:

  • P1 temperatura
  • P2 umidità

questo messaggio persiste per 5 secondi, dopo di che la retroilluminazione viene disattivata (il testo help rimane presente sul display).

Non appena si preme uno dei due pulsanti si attiva la retroilluminazione del display e compare il dato richiesto per 5 secondi, allo scadere del tempo ricompare l’help e la retroilluminazione si disattiva.

Buon making a tutti 🙂

Arduino: realizzare un menù di selezione utilizzando un Diaplay LCD 16×2 Hitachi HD44780 1602 con modulo I2C PCF8574T

Continuo la lezione cominciata la scorsa settimana con i miei studenti di 5A Automazione dell’ITIS G.B. Pininfarina di Moncalieri in merito alla gestione degli input mediante pulsanti e segnalazione stato LED sulla Serial Monitor, questa volta utilizzeremo come sistema di output un Display 16×2 con modulo I2C.

Rispetto all’esercizio svolto nella precedente lezione questa volta utilizzeremo 3 pulsanti la cui pressione provocherà l’accensione rispettivamente di un LED Rosso un  LED Verde ed un LED Giallo.

L’esercizio è suddiviso in due parti, la prima parte prevede che l’accensione dei LED avvenga premendo il pulsante ad esso associato, il rilascio provoca lo spegnimento del LED. Lo stato del LED dovrà essere segnalato con il testo ON oppure OFF e nel momento in cui lo stato risulta ON a fianco del testo ON dovrà comparire una sequenza di caratteri che simula la rotazione di un’elica, così come evidenziato dalle immagini che seguono.

Le lettere R, V, G indicano rispettivamente il colore: Rosso, Verde, Giallo dei LED la cui accensione è comandata da un pulsante NO.

La seconda parte dell’esercizio consiste nella realizzazione di uno sketch che permette il mantenimento dello stato ON oppure OFF anche al rilascio del pulsante, il cambiamento di stato avviene nella successiva pressione del pulsante.

Per i dettagli sull’uso del display 16×2 I2C vi rimando al tutorial su questo sito seguendo il link: Utilizzo dell’LCD 16×2 Hitachi HD44780 1602 con modulo I2C PCF8574T

Componenti utilizzati

  • Arduino UNO R3
  • N. 3 pulsanti NO
  • N. 3 resistori da 10 KOhm
  • N. 3 resistori da 220 Ohm
  • N. 1 LED Rosso
  • N. 1 LED Verde
  • N. 1 LED Giallo

Di seguito lo schema di collegamento:

Il funzionamento degli sketch è spiegato mediante commenti all’interno del codice.

Parte 1

/*
   Prof. Michele Maffucci
   Accensione e spegnimento led con segnalazione su Display LCD I2C
   30.09.19

   Accensione e spegnimento di LED mediante pulsanti
   con antirimbalzo e messaggio ripetuto dello stato del LED
   sul Display

   Pulsante Rosso: accensione e spegnimento LED Rosso
   (prima pressione accende, seconda pressione spegne)

   Pulsante Verde: accensione e spegnimento LED Verde
   (prima pressione accende, seconda pressione spegne)

   Pulsante Giallo: accensione e spegnimento LED Giallo
   (prima pressione accende, seconda pressione spegne)

*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// ledRosso variabile di tipo intero a cui viene assegnato 
// il valore intero 2 che sarà associato al pin digitale 2 

int ledRosso = 2;

// ledVerde variabile di tipo intero a cui viene assegnato 
// il valore intero 3 che sarà associato al pin digitale 3

int ledVerde = 3;

// ledGiallo variabile di tipo intero a cui viene assegnato 
// il valore intero 4 che sarà associato al pin digitale 4

int ledGiallo = 4;

// pulsanteRosso variabile di tipo intero a cui viene assegnato
// il valore intero 10 che sarà associato al pin digitale 10
// a cui sarà collegato il pulsante che comanda il LED Rosso 

int pulsanteRosso = 10;

// pulsanteVerde variabile di tipo intero a cui viene assegnato
// il valore intero 11 che sarà associato al pin digitale 11
// a cui sarà collegato il pulsante che comanda il LED Verde 

int pulsanteVerde = 11;

// pulsanteGiallo variabile di tipo intero a cui viene assegnato
// il valore intero 12 che sarà associato al pin digitale 12
// a cui sarà collegato il pulsante che comanda il LED Giallo 

int pulsanteGiallo = 12;

// inizializzazione della variabili in cui verrà memorizzato il valore della
// digitalRead: 0 non premuto, 1 premuto

int valRosso = 0;
int valVerde = 0;
int valGiallo = 0;

// inizializzazione della libreria in cui è descritta la modalità di utilizzo dei pin
LiquidCrystal_I2C lcd(0x27, 16, 2); // impostazione dell'indirizzo dell'LCD 0x27 di 16 caratteri e 2 linee
//-----------------------------
void setup()
{
  lcd.begin();      // inizializzazione dell'LCD
  lcd.backlight();  // attivazione della retroilluminazione

  // imposta i pin digitali a cui sono collegati i LED ad OUTPUT
  pinMode(ledRosso, OUTPUT);
  pinMode(ledVerde, OUTPUT);
  pinMode(ledGiallo, OUTPUT);

  // imposta i pin digitali a cui sono collegati i pulsanti ad OUTPUT
  pinMode(pulsanteRosso, INPUT);
  pinMode(pulsanteVerde, INPUT);
  pinMode(pulsanteGiallo, INPUT);

  // messaggio di Avvio visualizzato una sola volta
  lcd.setCursor(0, 0);      // posiziona curasore in colonna 0 e riga 0
  lcd.print("Ciao");        // stampa del testo su display
  lcd.setCursor(0, 1);      // posiziona curasore in colonna 0 e riga 1
  lcd.print("Comando LED"); // stampa del testo su display
  delay(2000);              // pausa di 2 secondi
  lcd.clear();              // cancella il contenuto del display

}
//-----------------------------

void loop()
{
  valRosso = digitalRead(pulsanteRosso);    // lettura dell'input (pulsante) e memorizzazione in valRosso
  valVerde = digitalRead(pulsanteVerde);    // lettura dell'input (pulsante) e memorizzazione in valVerde
  valGiallo = digitalRead(pulsanteGiallo);  // lettura dell'input (pulsante) e memorizzazione in valGiallo

  // ---------- Controllo pulsante LED Rosso ----------

  /* Se il pulsante viene premuto viene acceso il LED rosso
   * posizionato il cursore in colonna 0 riga 0 
   * stampato il testo: R: ON 
   * avviata l'animazione
   */
   
  if (valRosso == HIGH) {
    digitalWrite(ledRosso, HIGH);
    lcd.setCursor(0, 0);
    lcd.print("R: ON ");
    animazione(6,0);
  }

  /* Se il pulsante NON viene premuto viene spento il LED rosso
   * posizionato il cursore in colonna 0 riga 0 
   * stampato il testo: R: OFF 
   * interrotta l'animazione
   */
   
  else {
    digitalWrite(ledRosso, LOW);
    lcd.setCursor(0, 0);
    lcd.print("R: OFF ");
  }

  // ---------- Controllo pulsante LED Verde ----------

   /* Se il pulsante viene premuto viene acceso il LED verde
   * posizionato il cursore in colonna 0 riga 1 
   * stampato il testo: V: ON 
   * avviata l'animazione
   */
   
  if (valVerde == HIGH) {
    digitalWrite(ledVerde, HIGH);
    lcd.setCursor(9, 0);
    lcd.print("V: ON ");
    animazione(15,0);
  }

  /* Se il pulsante NON viene premuto viene spento il LED verde
   * posizionato il cursore in colonna 0 riga 1 
   * stampato il testo: V: OFF 
   * interrotta l'animazione
   */
   
  else {
    digitalWrite(ledVerde, LOW);
    lcd.setCursor(9, 0);
    lcd.print("V: OFF ");
  }

  // ---------- Controllo pulsante LED Giallo ----------

   /* Se il pulsante viene premuto viene acceso il LED giallo
   * posizionato il cursore in colonna 0 riga 1 
   * stampato il testo: G: ON 
   * avviata l'animazione
   */
   
  if (valGiallo == HIGH) {
    digitalWrite(ledGiallo, HIGH);
    lcd.setCursor(0, 1);
    lcd.print("G: ON ");
    animazione(6,1);
  }

  /* Se il pulsante NON viene premuto viene spento il LED giallo
   * posizionato il cursore in colonna 9 riga 0 
   * stampato il testo: G: OFF 
   * interrotta l'animazione
   */
     
  else {
    digitalWrite(ledGiallo, LOW);
    lcd.setCursor(0, 1);
    lcd.print("G: OFF ");
  }
}

// Funzione che stampa un cursore che ruota

void animazione(int colonna, int riga) {
  lcd.setCursor(colonna, riga);
  lcd.print("/");
  delay(150);
  lcd.setCursor(colonna, riga);
  lcd.print("-");
  delay(150);
  lcd.setCursor(colonna, riga);
  lcd.print("|");
  delay(150);
  lcd.setCursor(colonna, riga);
  lcd.print("/");
  delay(150);
  lcd.setCursor(colonna, riga);
  lcd.print("-");
  delay(150);
  lcd.setCursor(colonna, riga);
  lcd.print("|");
  delay(150);
}

Parte 2

/*
   Prof. Michele Maffucci
   Data: 30.09.19

   Accensione e spegnimento di LED mediante pulsanti
   con antirimbalzo e messaggio NON ripetuto dello stato del LED
   sulla su Display LCD I2C

   Stampa 1 sola volta il messaggio dello stato del LED Sul Display I2C
   (non va in loop la stampa dello stato del LED)

   Pulsante Rosso: accensione e spegnimento LED Rosso
   (prima pressione accende, seconda pressione spegne)

   Pulsante Verde: accensione e spegnimento LED Verde
   (prima pressione accende, seconda pressione spegne)

   Pulsante Giallo: accensione e spegnimento LED Giallo
   (prima pressione accende, seconda pressione spegne)

*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// ledRosso variabile di tipo intero a cui viene assegnato
// il valore intero 2 che sarà associato al pin digitale 2

int ledRosso = 2;

// ledVerde variabile di tipo intero a cui viene assegnato
// il valore intero 3 che sarà associato al pin digitale 3

int ledVerde = 3;

// ledGiallo variabile di tipo intero a cui viene assegnato
// il valore intero 4 che sarà associato al pin digitale 4

int ledGiallo = 4;

// pulsanteRosso variabile di tipo intero a cui viene assegnato
// il valore intero 10 che sarà associato al pin digitale 10
// a cui sarà collegato il pulsante che comanda il LED Rosso

int pulsanteRosso = 10;

// pulsanteVerde variabile di tipo intero a cui viene assegnato
// il valore intero 11 che sarà associato al pin digitale 11
// a cui sarà collegato il pulsante che comanda il LED Verde

int pulsanteVerde = 11;

// pulsanteGiallo variabile di tipo intero a cui viene assegnato
// il valore intero 12 che sarà associato al pin digitale 12
// a cui sarà collegato il pulsante che comanda il LED Giallo

int pulsanteGiallo = 12;

// inizializzazione della variabili in cui verrà memorizzato il valore della
// digitalRead: 0 non premuto, 1 premuto

int valRosso = 0;
int valVerde = 0;
int valGiallo = 0;

// inizializzazione della variabili in cui verrà memorizzato lo stato del pulsante
// All'avvio dello sketch i pulsanti non sono premuti

int statoRosso = 0;
int statoVerde = 0;
int statoGiallo = 0;

// inizializzazione della variabili in cui verrà memorizzato lo stato precedente del pulsante
// All'avvio dello sketch i pulsanti non sono premuti

int valRossoOld = 0;
int valVerdeOld = 0;
int valGialloOld = 0;

// inizializzazione delle variabili che consentono la stampa dello stato del LED

int stampoRossoON = 0;
int stampoRossoOFF = 0;

int stampoVerdeON = 0;
int stampoVerdeOFF = 0;

int stampoGialloON = 0;
int stampoGialloOFF = 0;

// inizializzazione della libreria in cui è descritta la modalità di utilizzo dei pin
LiquidCrystal_I2C lcd(0x27, 16, 2); // impostazione dell'indirizzo dell'LCD 0x27 di 16 caratteri e 2 linee
//-----------------------------
void setup()
{
  lcd.begin();      // inizializzazione dell'LCD
  lcd.backlight();  // attivazione della retroilluminazione

  // imposta i pin digitali a cui sono collegati i LED ad OUTPUT
  pinMode(ledRosso, OUTPUT);
  pinMode(ledVerde, OUTPUT);
  pinMode(ledGiallo, OUTPUT);

  // imposta i pin digitali a cui sono collegati i pulsanti ad OUTPUT
  pinMode(pulsanteRosso, INPUT);
  pinMode(pulsanteVerde, INPUT);
  pinMode(pulsanteGiallo, INPUT);

  // messaggio di Avvio visualizzato una sola volta
  lcd.setCursor(0, 0);      // posiziona curasore in colonna 0 e riga 0
  lcd.print("Ciao");        // stampa del testo su display
  lcd.setCursor(0, 1);      // posiziona curasore in colonna 0 e riga 1
  lcd.print("Comando LED"); // stampa del testo su display
  delay(2000);              // pausa di 2 secondi
  lcd.clear();              // cancella il contenuto del display
}
//-----------------------------


void loop()
{
  valRosso = digitalRead(pulsanteRosso);    // lettura dell'input (pulsante) e memorizzazione in valRosso
  valVerde = digitalRead(pulsanteVerde);    // lettura dell'input (pulsante) e memorizzazione in valVerde
  valGiallo = digitalRead(pulsanteGiallo);  // lettura dell'input (pulsante) e memorizzazione in valGiallo

  // ---------- Controllo pulsante LED Rosso ----------

  // viene controllato che l'input sia HIGH (pulsante premuto) e cambia lo stato del LED

  if ((valRosso == HIGH) && (valRossoOld == LOW)) {
    statoRosso = 1 - statoRosso;

    // antirimbalzo software - attesa di 15 ms per attendere che l'input si stabilizzi
    delay(15);

    // poichè il pulsante è stato premuto la variabile stampoRossoON viene posta a 0
    // per consentire la stampa del messaggio "LED Rosso ON"

    stampoRossoON = 0;
  }

  // memorizzazione del valore precedente restituito dalla digitalRead

  valRossoOld = valRosso;

  // ---------- Controllo pulsante LED Verde ----------

  // viene controllato che l'input sia HIGH (pulsante premuto) e cambia lo stato del LED

  if ((valVerde == HIGH) && (valVerdeOld == LOW)) {
    statoVerde = 1 - statoVerde;

    // antirimbalzo software - attesa di 15 ms per attendere che l'input si stabilizzi

    delay(15);

    // poichè il pulsante è stato premuto la variabile stampoVerdeON viene posta a 0
    // per consentire la stampa del messaggio "LED Verde ON"

    stampoVerdeON = 0;
  }

  // memorizzazione del valore precedente restituito dalla digitalRead

  valVerdeOld = valVerde;

  // ---------- Controllo pulsante LED Giallo ----------

  // viene controllato che l'input sia HIGH (pulsante premuto) e cambia lo stato del LED

  if ((valGiallo == HIGH) && (valGialloOld == LOW)) {
    statoGiallo = 1 - statoGiallo;

    // antirimbalzo software - attesa di 15 ms per attendere che l'input si stabilizzi

    delay(15);

    // poichè il pulsante è stato premuto la variabile stampoVerdeON viene posta a 0
    // per consentire la stampa del messaggio "LED Verde ON"

    stampoGialloON = 0;
  }

  // memorizzazione del valore precedente restituito dalla digitalRead

  valGialloOld = valGiallo;

  // ---------- Stampa sul display lo stato del LED Rosso ----------

  // Se il pulsante è stato premuto la condizione dell'if risulta vera ed il LED Rosso si accende

  if (statoRosso == 1) {
    digitalWrite(ledRosso, HIGH);

    // Se la variabile stampoRossoON è 0 allora !stampoRossoON vale 1
    // ciò consente la stampa del messaggio "LED Rosso ON"

    if (!stampoRossoON) {
      lcd.setCursor(0, 0);
      lcd.print("R: ON ");

      // Viene posto a 0 stampoRossoOFF per consentire la stampa "LED Rosso OFF"
      // nel caso si prema nuovamente il pulsante che controlla il LED Rosso.

      stampoRossoOFF = 0;
    }
  }
  // nel caso in cui il pulsante non sia premuto o nello stato precedente era stato premuto
  // allora il LED dovrà essere spento ed il messaggio sulla seriale dovrà essere "LED Rosso OFF"

  else {
    digitalWrite(ledRosso, LOW);

    if (!stampoRossoOFF) {
      lcd.setCursor(0, 0);
      lcd.print("R: OFF");             

      // Viene posto a 1 stampoRossoOFF per consentire la stampa "LED Rosso OFF"
      // nel caso si prema nuovamente il pulsante che controlla il LED Rosso.
      
      stampoRossoOFF = 1;
    }
  }

  // ---------- Stampa sul disolay lo stato del LED Verde ----------

  // Se il pulsante è stato premuto la condizione dell'if risulta vera ed il LED Verde si accende

  if (statoVerde == 1) {
    digitalWrite(ledVerde, HIGH);

    // Se la variabile stampoVerdeON è 0 allora !stampoVerdeoON vale 1
    // ciò consente la stampa del messaggio "LED verde ON"

    if (!stampoVerdeON) {
      lcd.setCursor(7, 0);
      lcd.print("V: ON ");

      // Viene posto a 0 stampoVerdeOFF per consentire la stampa "LED Verde OFF"
      // nel caso si prema nuovamente il pulsante che controlla il LED Rosso.

      stampoVerdeOFF = 0;
    }
  }

  // nel caso in cui il pulsante non sia premuto o nello stato precedente era stato premuto
  // allora il LED dovrà essere spento ed il messaggio sulla seriale dovrà essere "LED Verde OFF"

  else {
    digitalWrite(ledVerde, LOW);

    if (!stampoVerdeOFF) {
      lcd.setCursor(7, 0);
      lcd.print("V: OFF");              

      // Viene posto a 1 stampoVerdeOFF per consentire la stampa "LED Verde OFF"
      // nel caso si prema nuovamente il pulsante che controlla il LED Verde.

      stampoVerdeOFF = 1;
    }
  }

  // ---------- Stampa sul disolay lo stato del LED Giallo ----------

  // Se il pulsante è stato premuto la condizione dell'if risulta vera ed il LED Verde si accende

  if (statoGiallo == 1) {
    digitalWrite(ledGiallo, HIGH);

    // Se la variabile stampoGialloON è 0 allora !stampoGialloON vale 1
    // ciò consente la stampa del messaggio "LED giallo ON"

    if (!stampoGialloON) {
      lcd.setCursor(0, 1);     
      lcd.print("G: ON "); 
    
      // Viene posto a 0 stampoGialloOFF per consentire la stampa "LED Giallo OFF"
      // nel caso si prema nuovamente il pulsante che controlla il LED Giallo.

      stampoGialloOFF = 0;
    }
  }

  // nel caso in cui il pulsante non sia premuto o nello stato precedente era stato premuto
  // allora il LED dovrà essere spento ed il messaggio sulla seriale dovrà essere "LED Giallo OFF"

  else {
    digitalWrite(ledGiallo, LOW);

    if (!stampoGialloOFF) {
      lcd.setCursor(0, 1);     
      lcd.print("G: OFF");               
 
      // Viene posto a 1 stampoGialloOFF per consentire la stampa "LED Giallo OFF"
      // nel caso si prema nuovamente il pulsante che controlla il LED Giallo.

      //stampoGialloON = 0;
    }
  }
}

Esercizio: utilizzare gli esempi precedenti per realizzare un sistema che consente di avviare ed arrestare 2 ventole, ciascuna comandata da un pulsante. Un terzo pulsante dovrà essere utilizzato come consenso per permettere l’utilizzo del sistema, quindi:

  • Pulsante Marcia/Arresto ventola 1
  • Pulsante Marcia/Arresto ventola 2
  • Pulsante accensione spegnimento sistema

Gli stati dovranno essere indicati mediante LED e con messaggio sul display.

Buon Lavoro 🙂

Papà mi costruisci una lampada ecosostenibile?

Quando fare il Maker ti mette nei guai…

Figlia: Papà quando hai un secondo di tempo mi costruisci una lampada per la scrivania?
Però la devi fare:

  • bella
  • con oggetti di recupero, che sia ecosostenibile e quindi meglio se utilizzi materiali riciclati
  • deve essere a risparmio energetico

Io: senti signorina altre richieste?

Figlia: No no va bene così… anzi dimenticavo se la fai di legno e di colore blu così si abbina al colore della mia scrivania… grazie sei il papà più bravo dell’universo conosciuto 😊

Dopo una frase del genere come dire di no 😊

Lista materiali:

  • Avanzi stecche di legno 18×18 mm
  • Viti e dadi recuperati da un tenditore per cavi utilizzato in passato per i cavi stendibiancheria
  • Stampa 3d di un triangolo da usare come base per lampada
  • Cavo elettrico recuperato dalla precedente lampada rotta
  • Spezzone di striscia led
  • Alimentatore 12Vcc utilizzato in passato per alimentare un vecchio hard disk esterno
  • Avanzo di canalina elettrica da usare come paraluce in cui inserire la striscia led

Design essenziale, da rifinire, ma per essere stata prodotta in 1 ora di tempo credo possa andare bene.

Misure della lampada iniziando dalla base di appoggio:

  • 40 cm
  • 15 cm
  • 20 cm

Nel caso desiderate replicare il progetto le stecche di legno potete acquistarle in qualsiasi bricocenter, sono vendute a pezzi di 1m costano pochissimo.

Condivido inoltre il file per la stampa 3D della base della lampada.

Buon making a tutti 🙂