Schema circuito progetto Arduino Uno Temperatura e Luce

Arduino Uno LCD Display Temperatura e Luce

Da tempo avevo eseguito l’esempio dello StarterKit di Arduino Uno con le spiegazioni di come collegare un LCD Display 16×2 con l’uso di un potenziometro. Nel poco tempo a mia disposizione per giocherellare con Arduino, ogni tanto provavo ad applicare qualche modifica all’esempio già fatto, inserendo dei sensori, bottoni e modificando lo sketch, cioè il software da caricare in Arduino contenente le istruzioni che esso deve compiere. Ho quindi deciso di applicare all’esempio iniziale, un sensore di luce, un sensore per la temperatura e un bottone. Tutto il materiale è presente nella confezione dello StarterKit e già utilizzati da me negli altri esempi del book.

Avendo gli esempi del libro, pensavo agevolmente di fare questo progettino e pubblicarlo qui sul sito, ma non è stato proprio così facile a dirla tutta. A livello hardware la parte più complicata, forse perchè ha bisogno di più attenzione e di un attento controllo è stato collegare il Display LCD a 16 colonne e 2 righe. Ho riscontrato invece problemi nella gestione del bottone, in quanto il mio obbiettivo era ottenere uno switch fra le funzioni che gestiscono il sensore della luce e il sensore della temperatura. In oltre il sensore della temperatura il TMP36, risente di disturbi che possono esserci nell’alimentazione o nei cablaggi stessi sulla breadboard, complicazione che mi ha comportato dei ritardi nell’esecuzione del progetto. Dopo un primo tentativo ero riuscito a far funzionare il tutto con qualche pausa Delay() che però non solo rallentava di molto il sistema, ma lo rendeva poco fluido e non sempre il bottone risultava pronto per switchare fra le due funzioni che avevo impostato. C’era quindi bisogno di rivedere lo sketch rendendolo adatto al mio progetto. In realtà avevo preso in considerazione l’uso dell’Interrupt per gestire il bottone, ma il Pin 2 a cui corrisponde in Arduino Uno  è assegnato al LCD. Devo ancora analizzare bene la possibilità di poter liberare il PIN 2 e di conseguenza spostare su altro PIN il collegamento del piedino 14 (D7) dell LCD per poter poi avere la possibilità nei prossimi progetti l’Interrupt a disposizione. Con queste problematiche, tra cui anche, evitare il continuo aggiornamento del LCD anche quando non serve, che crea un refresh visibile e fastidioso, ho inserito delle condizioni e dei timer che regolassero il tutto.

Potete visualizzare il video del progetto qui: video
Progetto Arduino luce temperatura video

 

Delay e multitasking

Eliminando tutte o quasi le pause delay(), sostituendole molto spesso con un contatore timer basato sulla funzione millis(), ho ottenuto, non solo  un ciclo più fluido e pulito, ma lo sketch risulta una specie di insieme di istruzioni multitasking. Premettendo che a livello di Arduino Uno, il microcontrollore di cui è dotato esegue un ciclo di operazioni sequenziali e mai parallele. Il multitasking reale non si può fare in quanto le operazioni vengono eseguite sempre una alla volta, sempre in un unico ciclo. Anche utilizzando l’Interrupt, l’evento generato dalla messa in attività di quest’ultimo, porterebbe al blocco del ciclo di istruzioni predefinito mettendolo in pausa, riattivandolo solo al termine dell’esecuzione delle istruzioni dell’interrupt. In pratica inserendo dei contatori timer, facciamo eseguire un certo numero di funzioni o istruzioni , solo nel momento in cui vengono verificati attraverso delle condizioni, gli intervalli di esecuzione da noi voluti. Inserendo più contatori timer, che gestiscono l’esecuzione temporale delle istruzioni avremo un effetto alternato e più efficace dell’esecuzione delle istruzioni all’interno dello stesso ciclo. Potremmo ad esempio non volere che un sensore venga letto migliaia di volte al secondo, ma solo 10 volte e magari vorremmo impedire che il display LCD fosse aggiornato di continuo.

Preparazione circuito del progetto su breadboard

Vediamo ora in dettaglio come preparare la parte hardware di questo progetto su una mini breadboard.

ATTENZIONE!!! i collegamenti mostrati nelle immagini di questo progetto sono riferiti ai componenti utilizzati! Il Display LCD a vostra disposizione potrebbe variare la disposizione dei vari PIN, non fate quindi riferimento a queste immagini per il cablaggio ma al datasheet del vostro componente elettronico!!

pins LCD screen 16x2

Sopra potete vedere lo schema dei PIN del Display LCD che ho utilizzato, presente nel mio starter Kit! NON SONO TUTTI UGUALI! Controllate bene lo schema PIN del vostro Display!!!

Se lo schema è uguale al LCD dell’immagine qui in alto, allora potete seguire i collegamenti del mio progetto.

  1. VSS su GND  negativo – della breadboard
  2. VDD su positivo + della breadboard
  3. VE sul contatto centrale del potenziometro
  4. Register Select su PIN Arduino 12
  5. Read/write su GND negativo – della breadboard
  6. Enable su PIN Arduino 11
  7. Non utilizzato
  8. Non utilizzato
  9. Non utilizzato
  10. Non utilizzato
  11. Data 4 su PIN Arduino 5
  12. Data 5 su PIN Arduino 4
  13. Data 6 su PIN Arduino 3
  14. Data 7 su PIN Arduino 2
  15. Backlight + Anodo va collegato al + della breadboard  mettendo in serie una resistenza da 220Ω (Ohm) per abbassare i Volt    in entrata ed evitare di bruciare il Led del Display.
  16. Backlight – Catodo GND, va collegato sul GND della breadboard

Se non volete utilizzare la luce posteriore dello schermo, potete tranquillamente non collegare i PIN 15 e 16.

Il mio progetto prevede un bottone, che andremo ad inserire nella breadboard e collegheremo un pin con il positivo(+), l’altro al GND(-), inserendo però fra di esso una resistenza da 10KOhm, la così detta resistenza di Pull-Down: utilizzata per evitare eventuali corto circuiti ed eliminare eventuali fluttuazioni di corrente. Tra la resistenza e il bottone collegheremo un filo che andrà al PIN 7 di Arduino. In questa situazione otterremo che lo stato del bottone sarà sempre a 0 o LOW e solamente nel momento in cui andremo a schiacciare il bottone, chiuderemo il circuito ottenendo un voltaggio di +5 o HIGH.

Per misurare la temperatura ho utilizzato come detto un sensore temperatura  [TMP36], presente anche questo nello Starter Kit. Il sensore andrà posizionato come in figura, la parte piatta che prendiamo come riferimento, andrà collegato con il pin di sinistra al positivo(+), il pin di destra al GND(-). Il Pin centrale è quello che emette il voltaggio di misurazione della temperatura e che noi dovremo leggere: va collegato al PIN analogico di Arduino UNO A0.

Se non è stato già posizionato con il LCD, bisognerà inserire il potenziometro da 10 KOhm che servirà per regolare il contrasto delle scritte del display. Il Pin a sinistra l’ho collegato al positivo (+) e il contatto a destra al negativo (-). Il PIN centrale che emette i volt desiderati girando la leva del potenziometro andrà collegato al PIN 3 del LCD (VE).

Nel poco spazio che rimane sulla piccola breadboard, si inserisce una fotoresistenza [VT90N2 LDR], in serie con una resistenza da 10 KOhm che si collegherà al negativo (-), mentre sul PIN libero della fotoresistenza si collega al positivo (+).  Nel nodo di collegamento tra fotoresistenza e resistenza collegheremo un filo che andrà al PIN analogico di Arduino UNO A1. Otterremo così un partitore di tensione: avendo collegato la fotoresistenza al positivo, all’aumentare della luce, aumenterà il voltaggio in lettura al PIN A1.

Il Software: lo sketch  per Arduino Uno

Non sono un programmatore professionista, mi sento molto un dilettante allo sbaraglio che cerca sempre di capire come realizzare un programma il più efficiente possibile e soprattutto che sia funzionante! Avendo solo studi autodidattici in materia, perdonerete, almeno spero, se il codice che posterò e che ho usato per questo progetto non sarà dei migliori. Ho deciso di presentarlo qui perché credo in questo momento sia il più funzionale che io ho abbia realizzato per questo progetto.. Inizierò ad analizzare il codice a piccoli blocchi spiegandone tutte le varie caratteristiche e a fine pagina inserirò il link per scaricare lo sketch per Arduino Uno completo.

Inizio con il farvi vedere la schermata dello sketch per questo progetto. Il software potete scaricarlo dal sito ufficiale  http://arduino.cc/en/main/software

sketch IDE arduino tab

Salto la parte introduttiva dello sketch che si vede anche nella figura sopra in quanto sono solo semplici annotazioni informative e passiamo al codice vero e proprio.


// include the library code:
#include 

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

In questo primo blocco viene inclusa la libreria LiquidCristal.h che contiene le istruzioni per far funzionare il dislay LCD e viene inizializzata inserendo i PIN collegati. Ora iniziamo a vedere la sezione in cui vengono dichiarate le variabili.

// named constant for the pin the sensor is connected to
const int sensorPin = A0; // pin with sensor temperature
const int FRSensorPin = A1; // pin with the photoresistor
const int buttonPin = 7; // the number of the pushbutton pin

In questo caso vengono definite delle variabili costanti, che non cambieranno mai. Indicano a quali PIN sono collegati i sensori e il bottone ad Arduino Uno.

// Variables will change:
int reading; // reading from the input pin
int buttonState = HIGH; // The state of the button
int lastButtonState = LOW; // the previous reading from the input pin
int FRSensorValue = 0; // variable to hold the value from fotoresistor
float temperature = 0;
float lastTemperature = 0; //variable previus read Temperature
int valTemp = 0;
int k = 0;

Qui vengono dichiarate le variabili che verranno utilizzate nelle varie funzioni  e istruzioni del programma.

 // the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
unsigned long time; // the last time the output pin was toggled
 long debounce = 100; // the debounce time, increase if the output flickers
unsigned long tmpTime; // Variables tempory event read temperature sensor
unsigned long lightTime;
unsigned long LCDTime;
unsigned long buttonTime; 

In questo blocco di codice vengono dichiarate le variabili utilizzate nelle istruzioni per i contatori del tempo.  Vedremo più avanti che queste variabili saranno utilizzate insieme alla funzione millis(), che genera un numero molto lungo. Sono variabili che occupano moltissima memoria, ma per evitare di utilizzare i delay() come ho già detto all’inizio ho preferito consumare un po’ di memoria per una esecuzione più fluida del progetto.

void setup() {
 Serial.begin(9600);
 //Initialize Time variables
 tmpTime = millis();
 lightTime = millis();
 tmpTime = millis();
 LCDTime = millis();
 buttonTime = millis();
 

Viene inizializzato il canale di comunicazione seriale con il PC tramite l’istruzione:

Serial.begin(9600);

Nella funzione di Setup, si inizializzano le variabili di tempo, assegnando il valore della funzione millis(), che non è altro che il tempo in quel determinato momento, da quando è stato messo in funzione la scheda.

// initialize pin input button
 pinMode(buttonPin, INPUT);
 // set up the number of columns and rows on the LCD
 lcd.begin(16, 2);

 //Print a messagge of Welcome
 lcd.print("MDN75 - Arduino");

 //Pause
 delay(6000);

 // clean up the screen before printing a new reply
 lcd.clear();

 // Set the cursor column 3 and line 1
 lcd.setCursor(2, 0);

 // Print on LCD
 lcd.print("Misuriamo la");
 lcd.setCursor(2, 1);
 lcd.print("Temperatura!");

 //Pause
 delay(6000);
}
 

Nel codice sopra abbiamo da prima la inizializzazione del PIN a cui è collegato il bottone e viene impostato come INPUT. Infine una serie di istruzioni che servono per mostrare su display LCD alcune parole. Ora vediamo cosa succede nella funzione loop().

void loop() {
 time=millis();
 // read the state of the button value:
 reading = digitalRead(buttonPin);
 // compare the buttonState to its previous state

 if (reading == HIGH && lastButtonState == LOW && millis() - buttonTime > debounce) {
 if (buttonState == HIGH) {
 buttonState = LOW;
 }
 else{
 buttonState = HIGH;
 }
 // Attention position: set function debouce time
 buttonTime = millis();
 }
 // set previus state button for the loop
 lastButtonState = reading;

 // Set start function
 if (buttonState == HIGH) {
 tmpFunc();
 }
 else{
 lightFunc();
 }
}

Prima di tutto nella funzione di loop viene aggiornata la variabile “time” che prende valore della funzione millis(). Questa operazione è necessaria per far funzionare tutti i contatori delle varie funzioni che saranno attivate in questo ciclo. L’istruzione successiva si occupa di andare a leggere lo stato del bottone sul pin con nome “buttonPin”. Una serie di if valuteranno se le condizioni stabilite saranno vere e quindi imposteranno lo stato logico del “buttonState” su HIGH o LOW: il cambiamento dello stato viene valutato anche dal valore in base allo stato precedente, in modo tale che se prima lo stato era HIGH, nel momento in cui viene premuto il pulsante, diventa LOW. Anche l’azione di stato premuto o no, del pulsante viene gestito da un contatore che sfrutta la variabile “buttonTime” e va a determinare se lo stato di bottone premuto è corretto, eliminando quel lasso di tempo definito “debounce” in cui si potrebbe creare un falso contatto. Questo tipo di approccio non solo non ferma l’esecuzione del ciclo, ma fa si che si possa controllare ottimamente l’azione del pulsante, che è spesso fonte di grossi problemi. Lo stato logico del “buttonState” viene quindi sottoposto ad un “if” che valutandone la condizione stabilisce quale funzione utilizzare. E’ qui che vengono richiamate le funzioni tmpFunc() o lightFunc(): la prima va a leggere il sensore di temperatura scrivendo sul display il valore, la seconda va a leggere il sensore di luce, rielabora i dati e scrive sul display lo stato della luce. Da notare che il codice delle due funzioni non lo trovate nella scheda principale dello sketch, ma è stato separato ognuno in una sua scheda creata appositamente, che potete vedere anche nella figura dell’IDE del software di Arduino, la seconda e la terza scheda o TAB. Per creare e gestire queste schede potete andare sul bottone dell’IDE  a forma di freccia verso il basso in cui è contenuto un menu di opzioni, posto a destra dei titoli delle schede. In questo modo abbiamo reso il codice più ordinato e risulta più semplice da leggere.

Ecco qui il codice della funzione lightFunc()

// read the value fotoresistor sensor and set light state
void lightFunc()
{
 time = millis();
 //Read value fotoresistor ambient
 if(time - lightTime > 200)
 {
 FRSensorValue = analogRead(FRSensorPin);

 // clean LCD Display e print Message
 lcd.clear();
 lcd.setCursor(2, 0);
 lcd.print("Stato Luce:");
 lcd.setCursor(2, 1);
 Serial.print("Stato Luce: ");

 // switch print message from value sensor
 if (FRSensorValue < 30){
 lcd.print("Molto Buio");
 Serial.println("Molto Buio");
 }
 else if (FRSensorValue < 200){
 lcd.print("Scuro");
 Serial.println("Scuro");
 }
 else if (FRSensorValue < 500){
 lcd.print("Tenue");
 Serial.println("Tenue");
 }
 else if (FRSensorValue < 800){
 lcd.print("Medio");
 Serial.println("Medio");
 }
 else if (FRSensorValue <= 1100){ lcd.print("Luminoso"); Serial.println("Luminoso"); } else if (FRSensorValue > 1100){
 lcd.print("Intenso");
 Serial.println("Intenso");
 }

 lightTime = millis();
 } 

}

Si parte subito con le istruzioni per il contatore di tempo, quindi si valorizza la variabile “time”, si verifica con un “if”  se il tempo trascorso è di 200 millisecondi e se è vero, allora eseguirà le altre istruzioni altrimenti, verrà aggiornata la variabile “lightTime” e ripartirà il loop. Nel momento in cui la verifica risulta positiva, verrà eseguita la lettura della fotoresistenza, viene cancellato il display da tutte le scritte e viene impostata la scritta di default ” Stato luce: “. Ho inserito anche l’istruzione per scrivere tramite il seriale al monitor del PC il messaggio. Le istruzioni successive sono degli “If” concatenati che verificano il valore e in base a questo scriveranno su LCD e sul monitor del PC, lo stato della luce. Viene di nuovo aggiornata la variabile “lightTime” e riparte il loop.

Ecco qui il codice della funzione tmpFunc().

// set the temperature funciotn
void tmpFunc()
{
 time = millis();
 // Controlled Event Time Initialize
 if(time - tmpTime > 50)
 {
 // read the value of TMP36 sensor
 int sensorVal = analogRead(sensorPin);
 // set controlled counter
 k = k + 1;
 // add value K time
 valTemp= valTemp + sensorVal;

 // when K = 10 make average value
 if(k == 10){
 int valFin = valTemp / 10;
 // convert the ADC reading to voltage
 float voltage = (valFin/1024.0) * 5.0;
 temperature = (voltage - .5) * 100;
 valTemp = 0;
 k = 0;
 }
 tmpTime = millis();
 } 

 if(time - LCDTime >= 1000)
 {
 if(temperature != lastTemperature)
 {
 //Clean and Print on LCD Display a messagge of the temperature
 lcd.clear();
 lcd.setCursor(2, 0);
 lcd.print("Temperatura:");
 lcd.setCursor(4, 1);
 lcd.print("C ");
 lcd.print(temperature);
 lastTemperature = temperature;
 Serial.print("lastTemperature: ");
 Serial.println(lastTemperature);
 }
 LCDTime = millis();
 }

}
 

In questa funzione le cose si complicano un po’ per via non di un contatore ma di due. Il problema che mi si ponevano erano molteplici. Il sensore forse molto sensibile, risente di probabili disturbi presenti nel progetto e i risultati ottenuti leggendo il sensore sono spesso 2 che si alternano. In più c’è la variazione naturale della temperatura. In oltre se facessi scrivere su LCD e sul monitor a PC tutti i risultati otterrei un refresh altissimo, confuso e fastidioso. Ho quindi deciso di implementare due contatori, uno per la lettura del sensore, una per la scrittura del messaggio. In oltre per rendere il refresh ancora meno invasivo, ho deciso di cercare di ovviare agli sbalzi del sensore, facendo una media dei valori impostando un controllo ogni 10. Ecco il perchè vi è la variabile “k” che gestisce il numero di volte su cui fare la media, la variabile temporanea “valTemp” che è la sommatoria del valore letto sul sensore con la variabile “sensorVal”. Si ottiene quindi una variabile con il valore definitivo “valFin” su cui si esegue la conversione per ottenere il valore della temperatura. Ogni 10 letture, i valori delle variabili “k” e “valTemp” vengono settati a 0: permettono di ricalcolare una nuovo valore medio. Il secondo contatore con la variabile “LCDTime” porta il refresh del display LCD a 1sec e in oltre all’interno un “If” verifica se la temperatura è variata da quella scritta precedentemente. Si ottiene così che ogni secondo viene verificato il valore della temperatura e solo se questo è cambiato allora viene aggiornato il messaggio sul display LCD.

Spero vivamente che questo progetto possa essere utile a molti di voi, come lo è stato per me. Vi allego sotto lo zip da scaricare per lo sketch completo, ricordandovi che è stato realizzato per funzionare sul mio progetto e quindi prima di utilizzarlo nei vostri, modificatelo adattandolo al vostro.

Zip download mdn75

*Scompattate la cartella intera e lasciate i 3 file .ino insieme o lo sketch risulta incompleto!

Se questo articolo vi è sembrato interessante e vi è stato d’aiuto, condividetelo.
Aiutami a mantenere online il sito con un piccolo aiuto:  paypal.

Fermodellismo Elettronica Pesca e tanto altro…