#include <LiquidCrystal.h> // richiama la libreria <LiquidCrystal.h> per la gestione del display LCD
#define NUM_READ 10 // numero di letture per il calcolo delle temperature medie
// definizione dei ritardi delay utilizzati
#define DELAY_MED 300
#define DELAY_COR 100
#define DELAY_LUN 1000
// definizione dei pin per gli ingressi digitali "pulsanti"
#define ENTER_PIN 8 // pulsante ENTER
#define SU_PIN 9 // pulsante SU
#define GIU_PIN 10 // pulsante GIU
// definizione dei pin per le uscite digitali "Led"
#define USCITA_0 22 // led azzurro
#define USCITA_1 23 // led rosa
#define USCITA_2 24 // led verde
#define USCITA_3 25 // led giallo
#define USCITA_4 26 // led rosso
#define USCITA_5 27 // led blu
#define USCITA_6 28 // led arancione
// inizializza i pin di connessione al display LCD
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
// Array che costruisce il simbolo "°"
byte degreeSymbol[8] = {0b00110, 0b01001, 0b01001, 0b00110, 0b00000, 0b00000, 0b00000, 0b00000};
// definizione della struttura "Sensor" e delle relative variabili integrate
struct Sensor {
int pin; // Pin analogico collegato al sensore
int readings[NUM_READ]; // Array per memorizzare le letture del sensore
int total; // Somma delle letture del sensore per calcolare la media
float tempMin; // Temperatura minima registrata
float tempMax; // Temperatura massima registrata
float currentTemp; // Temperatura attuale
float average; // Media delle letture
};
// inizializzazione dei valori delle variabili all'interno della struttura "sensors"
Sensor sensors[3] = {
{A0, {}, 0, 30, 10, 20, 0},
{A1, {}, 0, 30, 10, 20, 0},
{A2, {}, 0, 30, 10, 20, 0}
};
// altre variabili globali
unsigned long prevMillis = 0, previousMillis = 0, bootTime = 0; // variabili utili per i temporizzatori non bloccanti
int index = 0; // variabile in cui scorre l'Indice delle letture dei sensori
int stato = 0; // variabile in cui scorrono i livelli di "stato"
bool FIRST = true; // variabile utile per definire la prima entrata in un livello
bool isFirstBoot = true; // variabile utile per avviare all'inizio il timer per il reset dei limiti di temperatura
bool Uscite[7] = {false}; // imposta tutte le 7 uscite digitali "Led" spente al primo avviamento
// Array che comprende i 7 colori dei Led per stamparli nel display LCD
const char* coloriUscite[7] = {"Azzurro", "Rosa ", "Verde ", "Giallo ", "Rosso ", "Blu ", "Arancio"};
// Variabili per memorizzare lo stato degli ingressi digitali (pulsanti)
int ENTER = 0;
int SU = 0;
int GIU = 0;
void setup() {
pinMode(ENTER_PIN, INPUT); // inizializza l'ingresso digitale Pin 8 come INPUT
pinMode(SU_PIN, INPUT); // inizializza l'ingresso digitale Pin 9 come INPUT
pinMode(GIU_PIN, INPUT); // inizializza l'ingresso digitale Pin 10 come INPUT
for (int i = 0; i < 7; i++) {
pinMode(USCITA_0 + i, OUTPUT); // inizializza tutte le uscite digitali dal Pin 22 al Pin 28 come OUTPUT
}
lcd.begin(16, 2); // inizializza il display LCD con 16 colonne e 2 righe
lcd.createChar(1, degreeSymbol); // passa il simbolo contenuto nella variabile "degreeSymbol" sul carattere "1"
Serial.begin(9600); // Inizializza la stampante a monitor per il debug
}
void loop() {
readInputs(); // avvia la funzione "readInputs()" per la lettura dei pulsanti
if (isFirstBoot) { // controlla, se è il primo avvio,
handleFirstBoot(); // lancia la funzione "handleFirstBoot()" per resettare le temperature limite in 6 secondi
}
checkMenuChange(); // lancia la funzione "checkMenuChange();" per ciclare le temperature sul display ogni 3 secondi
readButtons(); // lancia la funzione "readButtons();" per gestire le funzioni dei pulsanti
switch (stato) { // switch che richiama i vari livelli
case 0: loopPrinc(); break; // richiama "loopPrinc();" in cui mostra su display la schermata "sistema centralizzato"
case 1: loop01(); break; // richiama "loop01();" in cui mostra su display la schermata "temperature abitazione"
case 2: displayTemperature(0, "Pian.Terra "); break; // richiama "displayTemperature();" relativo al sensore 1 e scrive "Pian.Terra"
case 3: displayTemperature(1, "Prim.Piano "); break; // richiama "displayTemperature();" relativo al sensore 1 e scrive "Prim.Piano"
case 4: displayTemperature(2, "Temp.Est. "); break; // richiama "displayTemperature();" relativo al sensore 1 e scrive "Temp.Est."
case 5: loopOutDigit(); break; // richiama "loopOutDigit();" in cui mostra su display la schermata "attivazione uscite digitali"
default: loopSubMenu(stato); break; // richiama "loopSubMenu" che gestisce l'accensione dei led e le schermate su display
}
updateSensorReadings(); // lancia la funzione "updateSensorReadings();" per rffettuare le letture dei sensori e calcolarne la media
}
// legge lo stato dei pulsanti e lo passa alle relative variabili
void readInputs() {
ENTER = digitalRead(ENTER_PIN);
SU = digitalRead(SU_PIN);
GIU = digitalRead(GIU_PIN);
}
// appena avviato il boot, attiva il reset temperature limite dopo 6 secondi
void handleFirstBoot() {
unsigned long currentTime = millis();
if (currentTime - bootTime >= 6000) {
resetTemperatureMinMax();
isFirstBoot = false;
}
}
// Avvia il timer ciclico che fa scambiare le schermate delle temperature sul display purchè lo stato sia compreso tra 0 e 4
void checkMenuChange() {
if (stato >= 0 && stato <= 4) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= 3000) {
previousMillis = currentMillis;
stato++;
if (stato > 4) stato = 2;
}
}
}
// il pulsante ENTER richiama "resetTemperatureMinMax();" e resetta le temperature limite
void readButtons() {
if (ENTER == HIGH) {
delay(DELAY_MED);
resetTemperatureMinMax();
}
// il pulsante SU aumenta di uno lo "stato" fino al livello 12
if (SU == HIGH) {
delay(DELAY_MED);
stato++;
if (stato > 12) stato = 0;
}
// il pulsante GIU diminuisce di uno lo "stato" fino al livello 0
if (GIU == HIGH) {
delay(DELAY_MED);
stato--;
if (stato < 0) stato = 12;
}
}
// funzione che mostra sullo schermo "sistema centralizzato" stato 0
void loopPrinc() {
lcd.setCursor(0, 0);
lcd.print(" Sistema ");
lcd.setCursor(0, 1);
lcd.print(" centralizzato ");
}
// funzione che mostra sullo schermo "Temperature abitazione" stato 1
void loop01() {
lcd.setCursor(0, 0);
lcd.print(" Temperature ");
lcd.setCursor(0, 1);
lcd.print(" Abitazione ");
}
// mostra su display l'ambiente e la temperatura corrispondente al livello richiamato stato 2 - 3 - 4
void displayTemperature(int sensorIndex, const char* label) {
Sensor& sensor = sensors[sensorIndex];
lcd.setCursor(0, 0);
lcd.print(label); // scrive sulla prima riga l'ambiente corrispondente allo stato attivo
lcd.print(sensor.currentTemp, 1); // scrive di seguito la temperatura corrispondente allo stato attivo, con un decimale
lcd.write(1); // scrive di seguito il carattere speciale "°"
lcd.setCursor(0, 1);
lcd.print("m."); // scrive m sulla seconda riga
lcd.print(sensor.tempMin, 1); // scrive la temperatura minima corrispondente allo stato attivo, con un decimale
lcd.write(1); // scrive di seguito il carattere speciale "°"
lcd.print(" M."); // scrive di seguito "M" sulla seconda riga
lcd.print(sensor.tempMax, 1); // scrive la temperatura massima corrispondente allo stato attivo, con un decimale
lcd.write(1); // scrive di seguito il carattere speciale "°"
}
// funzione che mostra sullo schermo "Gestione uscite digitali" stato 5
void loopOutDigit() {
lcd.setCursor(0, 0);
lcd.print("Gestione uscite ");
lcd.setCursor(0, 1);
lcd.print(" digitali ");
}
void loopSubMenu(int subMenu) { // "submenù" è una variabile il cui valore è uguale a "stato"
int idx = subMenu - 6; // "idx" è l'indice per le uscite digitali (il valore va da 0 fino a 6)
lcd.setCursor(0, 0); // predispone il cursone sulla prima riga del display LCD
lcd.print("Att.Led "); // scrive "Att.Led" sulla prima riga del display LCD
lcd.setCursor(9, 0); // predispone il cursone sulla casella 9 della prima riga del display LCD
lcd.print(coloriUscite[idx]); // scrive il colore corrispondente dall'elenco "coloriUscite" secondo l'indice "idx"
lcd.setCursor(0, 1); // predispone il cursone sulla seconda riga del display LCD
lcd.print(Uscite[idx] ? "Acceso ENT > OFF" : "Spento ENT > ON"); // scrive lo stato "Uscite" attuale del Led secondo l'indice "idx"
// Attivazione ON/OFF delle uscite digitali
if (ENTER == HIGH) { // se viene premuto il pulsante ENTER
delay(DELAY_MED);
Uscite[idx] = !Uscite[idx]; // la variabile "Uscite" dell'indice "idx" cambia stato (da OFF a ON o viceversa)
digitalWrite(USCITA_0 + idx, Uscite[idx] ? HIGH : LOW); // scrive sull'uscita relativa all'indice lo stato della variabile "Uscite"
lcd.setCursor(0, 1); // predispone il cursone sulla seconda riga del display LCD
lcd.print(Uscite[idx] ? "Acceso ENT> OFF" : "Spento ENT> ON"); // aggiorna lo stato "Uscite" del Led secondo l'indice "idx"
}
}
// effettua la lettura di 10 campioni dell'indice "index" e calcola la media del sensore relativo "Sensors"
void updateSensorReadings() {
unsigned long currMillis = millis();
if (currMillis - prevMillis >= 200) { // se sono trascorsi 0,2 secondi
for (int i = 0; i < 3; i++) { // avanza al prossimo sensore di cui fare le letture fino a 3
Sensor& sensor = sensors[i]; // passa i dati alle relative variabili nella struttura Sensors
sensor.total -= sensor.readings[index]; // sottrae le ultime letture effettuate in precedenza
sensor.readings[index] = analogRead(sensor.pin); // effettua una nuova lettura per ogni sensore
sensor.total += sensor.readings[index]; // aggiunge la nuova lettura al totale di ogni sensore
}
// avanza il registro delle 10 letture
index = (index + 1) % NUM_READ; // ogni lettura verrà ripetuta 10 volte
prevMillis = currMillis; // azzera il conteggio per avanzare alla lettura successiva
if (index == 0) { // quando ha completato tutte le letture per tutti 3 i sensori
for (int i = 0; i < 3; i++) {
updateSensorTemperature(sensors[i]); // Passa a "updateSensorTemperature" per convertire i valori medi da bits a gradi C°
}
}
}
}
// Calcola la temperatura media in gradi C° del sensore relativo
void updateSensorTemperature(Sensor& sensor) {
sensor.average = sensor.total / NUM_READ;
float voltage = (sensor.average / 1024.0) * 5.0;
float temperature = (voltage - 0.5) * 100.0;
sensor.currentTemp = temperature;
// aggiorna i valori di temperatura min. e Max. di tutti i sensori
if (sensor.currentTemp < sensor.tempMin) sensor.tempMin = sensor.currentTemp;
if (sensor.currentTemp > sensor.tempMax) sensor.tempMax = sensor.currentTemp;
}
// Resetta i valori limite forzandoli a: min 30° e Max 10° per tutti i sensori
void resetTemperatureMinMax() {
for (int i = 0; i < 3; i++) {
sensors[i].tempMin = 30;
sensors[i].tempMax = 10;
}
}