/*
Programmazione a turni con la funzione switch ..case.
Display temperature; esterna, piano terra e primo piano con registrazione di massime e minime, e data e ora.
le 4 schermate sono mostrate ciclicamente a turni di 3 secondi.
se viene premuto il tasto "Impostazione", il display mostra la schermata Impostazione: Giorno, Mese, Anno, Ore,
Minuti, Secondi, salva impostazione, ad ogni impulso del pulsante "Impostazione". per tonare a mostrare il
ciclo iniziale.
il programma prevede 4 pulsanti: "Impostazione" per entrare nella modalità impostazione e avanzare sui successivi stati
"Su" per aumentare un valore, "Giu" per diminuire un valore, "Reset Temp" per azzerare la memoria delle temperature estreme.
by Viller Broccoli
*/
#include <Wire.h> // richiama la libreria Wire che riconosce la seriale I2C
#include <RTClib.h> // richiama la libreria dell'orologio RTC
#include <LiquidCrystal.h> // richiama la libreria del display lcd
#define SET 8 // Pin per il pulsante "SET"
#define PIU 9 // Pin per il pulsante "PIU"
#define MENO 10 // Pin per il pulsante "MENO"
// Definizione del carattere personalizzato per il simbolo del grado Celsius
byte degreeSymbol[8] = {0b00110,0b01001,0b01001,0b00110,0b00000,0b00000,0b00000,0b00000};
char buffer[10]; // Buffer per la formattazione delle stringhe
int sensorPin1 = A0; // Pin analogico collegato al sensore di temperatura Piano terra
int sensorPin2 = A1; // Pin analogico collegato al sensore di temperatura primo piano
int sensorPin3 = A2; // Pin analogico collegato al sensore di temperatura esterna
const int tasto1 = 8; // Pin (8) collegato al pulsante "Impostazione"
const int tasto2 = 9; // Pin (9) collegato al pulsante "Su"
const int tasto3 = 10; // Pin (10) collegato al pulsante "Giu"
const int resetTemp = 11; // Pin (11) collegato al pulsante "reset temperature "min/Max
int tastImpost; // Variabile in cui passa il valore del pulsante "Impostazione" filtrato con Debounce
int tastSu; // Variabile in cui passa il valore del pulsante "Su" filtrato con debounce
int tastGiu; // Variabile in cui passa il valore del pulsante "Giu" filtrato con debounce
int lastButtonState1 = LOW; // Precedente lettura dell'ingresso Pin 8 (utile per il filtro debounce)
int lastButtonState2 = LOW; // Precedente lettura dell'ingresso Pin 9 (utile per il filtro debounce)
int lastButtonState3 = LOW; // Precedente lettura dell'ingresso Pin 10 (utile per il filtro debounce)
unsigned long lastDebounceTime1 = 0; // tempo dell'ultima volta che il valore del pin 8 è cambiato (per debounce)
unsigned long lastDebounceTime2 = 0; // tempo dell'ultima volta che il valore del pin 9 è cambiato (per debounce)
unsigned long lastDebounceTime3 = 0; // tempo dell'ultima volta che il valore del pin 10 è cambiato (per debounce)
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
unsigned long prevMillis = 0; // Variabile su cui memorizzare il tempo dell'ultimo cambio di stato
unsigned long currMillis = 0; // Variabile per memorizzare il tempo trascorso dopo l'ultimo cambio di stato
unsigned long t1, dt; // dichiara due variabili su cui effettuare operazioni col tempo millis()
float tempmin1 = 20; // variabile in cui viene registrato il valore più basso raggiunto di temperatura al sensore 1
float tempmin2 = 20; // variabile in cui viene registrato il valore più basso raggiunto di temperatura al sensore 1
float tempmin3 = 20; // variabile in cui viene registrato il valore più basso raggiunto di temperatura al sensore 1
float tempMax1 = 10; // variabile in cui viene registrato il valore più alto raggiunto di temperatura al sensore 1
float tempMax2 = 10; // variabile in cui viene registrato il valore più alto raggiunto di temperatura al sensore 1
float tempMax3 = 10; // variabile in cui viene registrato il valore più alto raggiunto di temperatura al sensore 1
const long interval1 = 3000; // Intervallo desiderato tra i cambi di stato (visualizza Temperatura e Data/Ora))
const float BETA = 3950; // Fattore di scala per la lettura del sensore termico
int cicloMenu = 0; // variabile che attiva la modalità "imposatazione"
int stato = 0; // variabile il cui valore permette di commutare il relativo case , parte da 0.
int limiteMassimo= 3; // variabile su cui è impostato il limite massimo di case raggiungibile
RTC_DS1307 RTC; // Inizializza l'oggetto RTC_DS1307 chiamandolo "RTC"
DateTime now; // dichiara una variabile "now" che contiene l'oggetto "DateTime" che contirnr l'stante temporale
LiquidCrystal lcd(7, 6, 5, 4, 3, 2); // inizializzazione pin dedicati al display lcd
void setup() {
pinMode (tasto1, INPUT); // Imposta il tasto "impostazione"
pinMode (tasto2, INPUT); // Imposta il tasto "Su"
pinMode (tasto3, INPUT); // Imposta il tasto "Giu"
pinMode (resetTemp, INPUT); // Imposta il tasto "Reset"
lcd.createChar(1, degreeSymbol);
Wire.begin(); // Inizializza la comunicazione I2C
RTC.begin(); // Inizializza il timer RTC
lcd.begin(16, 2); // INIZIALIZZO IL DISPLAY
Serial.begin(9600); // Inizializza la stampa su schermo a 9600 baud rate
if (!RTC.isrunning()) { // Se il RTC non sta funzionando o non è collegato,
Serial.println("RTC is NOT running!"); // scrive su stampa a schermo la scritta "RTC is NOT running!
RTC.adjust(DateTime(__DATE__, __TIME__)); // imposta la data/ora con quella dello sketch
}
}
void loop(){
// Filtro debounce di 50ms applicata al tasto "tasto1" pin 8 "Impostazione"
int reading1 = digitalRead(tasto1);
if (reading1 != lastButtonState1) {lastDebounceTime1 = millis();}
if ((millis() - lastDebounceTime1) > debounceDelay) {if (reading1 != tastImpost) {tastImpost = reading1;}}
lastButtonState1 = reading1;
// Filtro debounce di 50ms applicata al tasto "tasto2" pin 9 "Su"
int reading2 = digitalRead(tasto2);
if (reading2 != lastButtonState2) {lastDebounceTime2 = millis();}
if ((millis() - lastDebounceTime2) > debounceDelay) {if (reading2 != tastSu) {tastSu = reading2;}}
lastButtonState2 = reading2;
// Filtro debounce di 50ms applicata al tasto "tasto3" pin 10 "Giu"
int reading3 = digitalRead(tasto3);
if (reading3 != lastButtonState3) {lastDebounceTime3 = millis();}
if ((millis() - lastDebounceTime3) > debounceDelay) {if (reading3 != tastGiu) {tastGiu = reading3;}}
lastButtonState3 = reading3;
if (digitalRead(resetTemp) == HIGH) { // Se il pulsante "resetTemp" è premuto
tempmin1 = tempmin2 = tempmin3 = 30; // Reimposta i valori di tempmin
tempMax1 = tempMax2 = tempMax3 = 20; // Reimposta i valori di tempMax
}
if (cicloMenu == 0){ // se la variabile ciclomenù è 0
currMillis = millis(); // aggiorna il tempo del contatore
if (currMillis - prevMillis >= interval1) { // Verifica se è trascorso l'intervallo di tempo 2 secondi
stato = (stato + 1) % (limiteMassimo + 1); // fa aumentare la variabile "stato" di 1 ogni 2 secondi fino a 3 ciclicamente
prevMillis = currMillis; // azzera di nuovo la variabile del contatore del tempo
}
}
if (cicloMenu == 0) { // se la modalità impostazione non è attiva
if (tastImpost == HIGH) { // se il tasto "impostazione" viene premuto
stato = 4; cicloMenu = 1; // la modalita "impostazione" viene attivata e passa allo stato: 3
delay(200);
tastImpost = LOW; // per evitare livelli incerti,forza il pulsante "impostazione" basso
}
}
if (cicloMenu == 1) { // se la modalità impostazione è attiva
if (tastImpost == HIGH) { // se il tasto "impostazione" viene premuto
stato++; // stato avanza allo stato successivo
tastImpost = LOW; // per evitare livelli incerti,forza il pulsante "impostazione" basso
delay(200);
//if (stato > 9) {cicloMenu = 0; stato = 3;} // Se stato supera 6, ritorna al valore 3 ed esce dal menù impostazione
}
}
Serial.print (" stato ");
Serial.println (stato);
//Serial.print (" tastImpost ");
//Serial.print (tastImpost);
//Serial.print (" tastSu ");
//Serial.print (tastSu);
//Serial.print (" tastGiu ");
//Serial.print (tastGiu);
//Serial.print (" cicloMenu ");
//Serial.println (cicloMenu);
switch(stato){
case 0: // **************************^^***** stato 1 ***********************************
stato0(); // richiamo alla funzione "void stato0();"
break;
case 1: // ********************************* stato 2 ************************************
stato1(); // richiamo alla funzione "void stato1();"
break;
case 2: // ********************************* stato 3 ************************************
stato2(); // richiamo alla funzione "void stato2();"
break;
case 3: // ********************************* stato 4 ***********************************
stato3(); // richiamo alla funzione "void stato3();;"
break;
case 4: // ********************************* stato 5 ***********************************
stato4(); // richiamo alla funzione "void stato4();"
break;
}
}
void stato0(){ // funzione "void stato0()"
int analogValue1 = analogRead(sensorPin1); // variabile di acquisizione dell'ingresso analogico A0
float celsius1 = 1 / (log(1 / (1023. / analogValue1 - 1)) / BETA + 1.0 / 298.15) - 273.15;
// se la temperatura diminuisce, sotto al valore "tempmin" precedente Aggiorna il valore di "tempmin"
if (celsius1 < tempmin1) {tempmin1 = celsius1;}
// se la temperatura supera il valore "tempMax" precedente, Aggiorna il valore di "tempMax"
if (celsius1 > tempMax1) {tempMax1 = celsius1;}
lcd.clear(); // Cancella il display prima di stampare
lcd.print(celsius1, 1); // Stampa il valore con 1 cifra decimale
lcd.setCursor(4, 0); // Imposta il cursore al quinto spazio della prima riga
lcd.write(1); // Stampa il carattere personalizzato per il simbolo del grado Celsius
lcd.print(""); // Aggiunge un distanziale
lcd.print(" Temper. PT"); // Scrive "Temper. P1" a seguire nella prima riga
lcd.setCursor(0, 1); // Imposta il cursore all'inizio della seconda riga
lcd.print("min " ); // scrive "min" all'inizio della seconda riga
lcd.print(tempmin1, 0); // scrive la temperatura minima memorizzata
lcd.print(" Max " ); // scrive "Max" a seguire seconda riga
lcd.print(tempMax1, 1); // scrive la temperatura massima memorizzata
delay(100); // Attendi un attimo prima di aggiornare il display
}
void stato1(){ // funzione "void stato1()"
int analogValue2 = analogRead(sensorPin2); // variabile di acquisizione dell'ingresso analogico A0
float celsius2 = 1 / (log(1 / (1023. / analogValue2 - 1)) / BETA + 1.0 / 298.15) - 273.15;
// se la temperatura diminuisce, sotto al valore "tempmin" precedente Aggiorna il valore di "tempmin"
if (celsius2 < tempmin2) {tempmin2 = celsius2;}
// se la temperatura supera il valore "tempMax" precedente, Aggiorna il valore di "tempMax"
if (celsius2 > tempMax2) {tempMax2 = celsius2;}
lcd.clear(); // Cancella il display prima di stampare
lcd.print(celsius2, 1); // Stampa il valore con 1 cifra decimale
lcd.setCursor(4, 0); // Imposta il cursore al quinto spazio della prima riga
lcd.write(1); // Stampa il carattere personalizzato per il simbolo del grado Celsius
lcd.print(""); // Aggiunge un distanziale
lcd.print(" Temper. P0"); // Scrive "Temper. P1" a seguire nella prima riga
lcd.setCursor(0, 1); // Imposta il cursore all'inizio della seconda riga
lcd.print("min " ); // scrive "min" all'inizio della seconda riga
lcd.print(tempmin2, 0); // scrive la temperatura minima memorizzata
lcd.print(" Max " ); // scrive "Max" a seguire seconda riga
lcd.print(tempMax2, 1); // scrive la temperatura massima memorizzata
delay(100); // Attendi un attimo prima di aggiornare il display
}
void stato2(){ // funzione "void stato2()"
int analogValue3 = analogRead(sensorPin3); // variabile di acquisizione dell'ingresso analogico A2
float celsius3 = 1 / (log(1 / (1023. / analogValue3 - 1)) / BETA + 1.0 / 298.15) - 273.15;
// se la temperatura diminuisce, sotto al valore "tempmin" precedente Aggiorna il valore di "tempmin"
if (celsius3 < tempmin3) {tempmin3 = celsius3;}
// se la temperatura supera il valore "tempMax" precedente, Aggiorna il valore di "tempMax"
if (celsius3 > tempMax3) {tempMax3 = celsius3;}
lcd.clear(); // Cancella il display prima di stampare
lcd.print(celsius3, 1); // Stampa il valore con 1 cifra decimale
lcd.setCursor(4, 0); // Imposta il cursore al quinto spazio della prima riga
lcd.write(1); // Stampa il carattere personalizzato per il simbolo del grado Celsius
lcd.print(""); // Aggiunge un distanziale
lcd.print(" Temper. P1"); // Scrive "Temper. P1" a seguire nella prima riga
lcd.setCursor(0, 1); // Imposta il cursore all'inizio della seconda riga
lcd.print("min " ); // scrive "min" all'inizio della seconda riga
lcd.print(tempmin3, 0); // scrive la temperatura minima memorizzata
lcd.print(" Max " ); // scrive "Max" a seguire seconda riga
lcd.print(tempMax3, 1); // scrive la temperatura massima memorizzata
delay(100); // Attendi un attimo prima di aggiornare il display
}
void stato3(){ // funzione "void stato3()"
now = RTC.now(); // aggiorna la variabile "now" con il dato integrale di "tempo e data" dall'orologio "RTC"
lcd.clear(); // pulisce il display LCD per evitare sovrascritture errate
lcd.setCursor(0,0); // predispone la scrittura sulla prima riga del display
//estrae in una variabile chiamata "buffer", i dati di: giorno, mese, anno,
//dalla variabile "now" formattandoli con separatori a barrette
sprintf(buffer, "%02d/%02d/%d", now.day(), now.month(), now.year());
lcd.print( buffer); // scrive i dati formattati Giorno, Mese, Anno, nella variabile "buffer" sul display
lcd.setCursor(0,1); // predispone la scrittura dei dati sulla seconda riga del display
//estrae in una variabile chiamata "buffer", i dati di: ore, minuti, secondi,
//dalla variabile "now" formattandoli con separatori a due puntini
sprintf(buffer, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
lcd.print( buffer); // scrive i dati formattati nella variabile "buffer" sul display
t1 = millis(); // resetta il tempo "t1" registrato in precedenza
delay(100); // Attendi un attimo prima di aggiornare il display
}
void stato4(){ // funzione "void stato4()"
DateTime now = RTC.now();
boolean setMode = true; // Variabile booleana per indicare se la modalità "Impostazione" è attiva
int setModeLevel = 0; // Variabile per indicare il livello di impostazione
int _day = now.day(); // Ottiene il giorno attuale
int _month = now.month(); // Ottiene il mese attuale
int _year = now.year(); // Ottiene l'anno attuale
int _hour = now.hour(); // Ottiene l'ora attuale
int _min = now.minute(); // Ottiene il minuto attuale
int _sec = now.second(); // Ottiene il secondo attuale
lcd.clear(); // Pulisce il display LCD
lcd.setCursor(0,0); // Imposta il cursore all'inizio della prima riga
sprintf(buffer, "%s: %02d", "Giorno", _day); // Formatta il messaggio con il giorno
delay( 1000 ); // Delay per una breve pausa
timeSet = millis(); // Memorizza il tempo corrente
while ( setMode ) { // Finche si è in modalità "impostazione data/ora"
if (digitalRead(tastImpost) == HIGH || digitalRead(tastSu) == HIGH || digitalRead(tastGiu) == HIGH ) { timeSet = millis(); }
lcd.setCursor(0,0); // Imposta il cursore all'inizio della prima riga
// Imposta il giorno
if ( setModeLevel == 0 ) {
if (digitalRead(tastSu) == HIGH && _day < 31) { _day++; } // premendo "PIU" il giornoaumenta fino a 31
if (digitalRead(tastGiu) == HIGH && _day > 1) { _day--; } // premendo "MENO" il giorno diminuisce fino a 1
sprintf(buffer, "%s: %02d", "Giorno", _day); // Formatta il messaggio con il giorno e la scritta "Giorno"
}
// Imposta il mese
if ( setModeLevel == 1 ) {
if (digitalRead(tastSu) == HIGH && _month < 12) { _month++; } // premendo "PIU" il mese aumenta fino a 12
if (digitalRead(tastGiu) == HIGH && _month > 1) { _month--; } // premendo "MENO" il mese diminuisce fino a 1
sprintf(buffer, "%s: %02d", "Mese", _month); // Formatta il messaggio con il mese e la scritta "Mese"
}
// Imposta l'anno
if ( setModeLevel == 2 ) {
if (digitalRead(tastSu) == HIGH && _year < 9999) { _year++; } // premendo "PIU" l'anno aumenta fino a 9999
if (digitalRead(tastGiu) == HIGH && _year > 1900) { _year--; }// premendo "MENO" l'anno diminuisce fino 1900
sprintf(buffer, "%s: %02d", "Anno", _year); // Formatta il messaggio con l'anno e la scritta "Anno"
}
// Imposta l'ora
if ( setModeLevel == 3 ) {
if (digitalRead(tastSu) == HIGH && _hour < 24) { _hour++; } // premendo "PIU" l'ora aumenta fino a 24
if (digitalRead(tastGiu) == HIGH && _hour > 1) { _hour--; } // premendo "MENO" l'ora diminuisce fino 1
sprintf(buffer, "%s: %02d", "Ora", _hour); // Formatta il messaggio con l'ora e la scritta "ora"
}
// Imposta i minuti
if ( setModeLevel == 4 ) {
if (digitalRead(tastSu) == HIGH && _min < 60) { _min++; } // premendo "PIU" i minuti aumentano fino a 60
if (digitalRead(tastGiu) == HIGH && _min > 1) { _min--; } // premendo "MENO" i minuti diminuisce fino 1
sprintf(buffer, "%s: %02d", "Minuti", _min); // Formatta il messaggio con i minuti e la scritta "Minuti"
}
// Imposta i secondi
if ( setModeLevel == 5 ) {
if (digitalRead(tastSu) == HIGH && _sec < 60) { _sec++; } // premendo "PIU" i secondi aumentano fino a 60
if (digitalRead(tastGiu) == HIGH && _sec > 0) { _sec--; } // premendo "MENO" i secondi diminuisce fino 1
sprintf(buffer, "%s: %02d", "Secondi", _sec); // Formatta il messaggio con i secondi e la scritta "<secondi"
}
lcd.print( buffer ); // Stampa il messaggio
if (digitalRead(tastImpost) == HIGH) { lcd.clear(); setModeLevel++; }// Se il pulsante "SET" è premuto, passa al livello successivo
if (setModeLevel > 5 ) { setModeLevel=0; } // Se il livello è maggiore di 5, reimposta a 0
// Se è trascorso un certo periodo di tempo, imposta la data/ora e esci dalla modalità "Impostazione"
if (timeSet > 0 && (setModeTime*2) < (millis() - timeSet)) {
RTC.adjust(DateTime(_year, _month, _day, _hour, _min, _sec));
setMode = false;
}
delay(200);
stato = 0; // Delay per evitare letture troppo rapide dai pulsanti
}
}