/* Controllo Caldaia : V 1.0
Sketch per il controllo
delle temperature della caldaia
ed evitare il blocco per
temperatura troppo alta */
/*-----( Import Librerie )-----*/
#include <OneWire.h>
#include <DallasTemperature.h>
#include <LedControl.h>
#include <LiquidCrystal_I2C.h>
/*-----( Dichiarazione Costanti )-----*/
#define RELAY_ON 0 // Con la scheda a 8 Relè il relè è attivato quando la porta è in LOW
#define RELAY_OFF 1 // Con la scheda a 8 Relè il relè è disattivato quando la porta è in HIGH
#define RP_Risc 2 // Relè controllo pompa Riscaldamento
#define RP_Caldaia 3 // Relè controllo pompa Caldaia
#define RV_Boiler 4 // Relè controllo valvola Boiler
#define RV_Risc_ON 5 // Relè per forzare valvola riscaldamento ad aprirsi
#define RV_Risc_OFF 6 // Relè per forzare valvola riscaldamento a chiudersi
#define RV_Scarico 7 // Relè per aprire scarico acqua calda
#define Led_DIN 8 // Pin DIN display led 7 Segmenti
#define Led_CS 9 // Pin CS display led 7 Segmenti
#define Led_CLK 10 // Pin CLK display led 7 Segmenti
#define sensCald 11 // porta a cui è collegato il sensore della temperatura della caldaia
#define sensBoil 12 // porta a cui è collegato il sensore della temperatura del boiler
#define termAmbiente 13 // porta a cui è collegato il termostato ambiente
#define INPUT_PULSANTI A0 // porta a cui sono collegati i pulsanti
#define digitalLCDpower 15 // Porta a cui è collegata la retroilluminazione del display LCD
#define BUZZER_PIN 16 // Porta a cui è collegato il buzzer
#define consensoCaldaia 17 // Porta a cui è collegato il consenso caldaia
#define PIN_SDA A4 // Porta collegamento SDA per display LCD con I2C
#define PIN_SCL A5 // Porta Collegamento SCL per display LDC con I2C
#define timeLCD_ON 35000 // Quanto tempo deve rimanere accesa la retroilluminazione del display LCD
#define minimoBoiler 45 // temperatura minima sotto la quale richiede acqua calda il boiler
#define minimoCaldaia 60 // temperatura minima sotto la quale tutto si ferma
#define TMaxBoiler 85 // temperatura massima a cui può arrivare il boiler
/*-----( Dichiarazione Oggetti )-----*/
OneWire oneWireCaldaia(sensCald); // Dichiarazione per sensore lettura temperatura caldaia
DallasTemperature sensoreCaldaia(&oneWireCaldaia); // Sensore temperatura Boiler
OneWire oneWireBoiler(sensBoil); // Dichiarazione per sensore lettura temperatura Boiler
DallasTemperature sensoreBoiler(&oneWireBoiler); // Sensore lettura temperatura boiler
LiquidCrystal_I2C lcd(0x27, 20, 4); // Controllo display LCD tramite I2C
LedControl lc = LedControl(Led_DIN, Led_CLK, Led_CS, 1); // Controllo display LED 7 Segmenti
/*-----( Dichiarazione Variabili )-----*/
float tempCaldaia = 20.0; // Temperatura acqua in caldaia
float tempBoiler = 20.0; // Temperatura acqua nel boiler
float oldTempCaldaia = 20.0; // Temperatura della precedente lettura del sensore caldaia
float oldTempBoiler = 20.0; // Temperatura della precedente lettura del sensore boiler
unsigned long timeStart = millis(); // Tempo trascorso da avvio
unsigned long timeLCD = millis(); // Variabile per tempo di accensione del display LCD
unsigned long lastTime = millis(); // Tempo in cui è stata fatta l'ultima modifica di stato
long day = 86400000; // millisecondi in un giorno
long hour = 3600000; // millisecondi in un ora
long minute = 60000; // millisecondi in un minuto
long second = 1000; // millisecondi in un secondo
bool acquaBoiler = false; // Richiesta acqua calda in boiler
bool acquaRisc = false; // Richiesta acqua calda riscaldamento
bool caldaiaOk = false; // Caldaia abilita pompa
bool pmpCaldaia = false; // Pompa Caldaia (False = spenta)
bool pmpRisc = false; // Pompa Riscaldamento (False = spenta)
bool valvBoiler = false; // Valvola per acqua nel boiler (False = chiusa)
bool valvScarico = false; // Valvola per aprire scarico acqua calda
bool LCD_ON = false;
bool alertSonda = false; // Controlla che sonde temperatura siano funzionanti (false = ok)
byte valvImpianto = 0; // Valvola per acqua nell'impianto di riscaldamento (0 = auto, 1 = Apri, 2= Chiudi)
byte richiestaAcqua = 0; // variabile per definire stato richieste acqua
byte statoPrecedente = 99; // variabile per definire lo stato precedente dell'impianto
byte statoEmergenza = 0; // variabile per definire lo stato di emergenza temperatura
byte statoImpianto = 0; // variabile per stato impianto
/* Valori di statoImpianto:
0 = Tacq < 60 Temperatura Acqua inferiore a 60 Gradi - Tutto fermo
1 = Tacq >= 64 && < 85 Nessuna Richiesta acqua calda
2 = Tacq >= 64 && < 85 Richiesta Acqua Calda da Boiler
3 = Tacq >= 64 && < 85 Richiesta Acqua Calda da Riscaldamento
4 = Tacq >= 64 && < 85 Richiesta Acqua calda da Riscaldamento e Boiler
5 = 85 < Tacq < 88)
6 = 89 < Tacq < 91
7 = 92 < Tacq < 94
8 = Tacq >= 94
9 = NO Consenso Caldaia
*/
String Riga1, Riga2, Riga3, Riga4 = (" "); // Variabili per righe display
String Riga4Alert = (" ");
/*--- Variabili per test del programma ---*/
float testBoiler[15] = {40, 40, 40, 46, 43, 50, 50, 50, 60, 60, 70, 70, 60, 50, 40};
float testCaldaia[15] = {40, 60, 68, 70, 75, 75, 80, 85, 89, 93, 95, 90, 87, 80, 70};
bool testRichiesta[15] = {1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0};
bool testcaldaiaOK[15] = {0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
byte testArray = 15;
byte testCount = 0;
unsigned long testTime = millis(); // Tempo per variazione stati durante il test programma
bool testProgramma = false; // variabile per attivare test programma
/*--- --- --- --- --- --- --- --- --- --- ---*/
/*********** S E T U P ***********/
void setup()
{
Serial.begin(9600);
//-------( Inizializzazione sensori temperatura )----
sensoreCaldaia.begin();
sensoreBoiler.begin();
//-------( Inizializzazione lcd I2C )----
lcd.init();
lcd.clear();
lcd.home();
//-------( Inizializzazione led 7 Segmenti )----
lc.shutdown(0, false);
lc.setIntensity(0, 3);
lc.clearDisplay(0);
//---( Impostazione dei pin come Input o Output )----
pinMode(RP_Risc, OUTPUT); // Relè pompa riscaldamento
pinMode(RP_Caldaia, OUTPUT); // Relè pompa caldaia
pinMode(RV_Boiler, OUTPUT); // Relè Valvola acqua boiler
pinMode(RV_Risc_ON, OUTPUT); // Relè Valvola controllo temperatura acqua riscaldamento Apri
pinMode(RV_Risc_OFF, OUTPUT); // Relè Valvola controllo temperatura acqua riscaldamento Chiudi
pinMode(RV_Scarico, OUTPUT); // Relè valvola per scarico acqua calda
pinMode(digitalLCDpower, OUTPUT); // Retroilluminazione display LCD
pinMode(termAmbiente, INPUT); // Richiesta acqua da termostato ambiente
pinMode(consensoCaldaia, INPUT); // Caldaia abilita pompa
pinMode(BUZZER_PIN, OUTPUT); // Buzzer per segnalazione acustica di sovratemperatura o problema
//-------( Inizializzazione dei pin dei Relè in modo che all'avvio siano spenti )----
digitalWrite(RP_Risc, RELAY_OFF);
digitalWrite(RP_Caldaia, RELAY_OFF);
digitalWrite(RV_Boiler, RELAY_OFF);
digitalWrite(RV_Risc_ON, RELAY_OFF);
digitalWrite(RV_Risc_OFF, RELAY_OFF);
digitalWrite(RV_Scarico, RELAY_OFF);
//-------( Inizializzazione dei pin di input )----
digitalWrite(digitalLCDpower, HIGH);
digitalWrite(BUZZER_PIN, LOW);
//-------( esecuzione funzioni prima volta )-----
TempRead(true);
ReadSensor();
WriteLCD(true);
//-------( Esecuzione iniziale in caso di test del programma )---
if (testProgramma) testTime = millis();
}
/*********** L O O P ***********/
void loop()
{
if (timeStart > millis()) {
timeStart = lastTime = timeLCD = millis(); // Se millis ripartito da 0 resetto timeStart
}
if (testProgramma && (testCount <= testArray)) {
tempBoiler = testBoiler[testCount];
tempCaldaia = testCaldaia[testCount];
acquaRisc = testRichiesta[testCount];
caldaiaOk = testcaldaiaOK[testCount];
if (millis() - testTime > 10000) {
testCount++ ;
testTime = millis();
}
}
TempRead(false); // Lettura delle temperature rilevate dalle sonde
if (tempBoiler < minimoBoiler) acquaBoiler = true; // Se la temperatura del Boiler è inferiore al minimo attiva la richiesta di acqua
else acquaBoiler = false;
ReadSensor(); // Lettura dei sensori in input Richiesta acqua e ok da caldaia
int pulsante = ReadButton(); // Verifica se è stato premuto un tasto
switch (pulsante) {
case 1:
WriteLCD(true);
break;
case 2:
WriteLCD(true);
break;
case 3:
WriteLCD(true);
break;
case 4:
WriteLCD(true);
break;
case 5:
WriteLCD(true);
break;
case 6:
WriteLCD(true);
break;
case 7:
WriteLCD(true);
break;
default:
break;
}
Riga1 = ("Tc=" + String(int(tempCaldaia)) + char(223) + "C - Tb:" + String(int(tempBoiler)) + char(223) + "C");
while (Riga1.length() < 20) {
Riga1 = Riga1 + " ";
}
// Riga4 = ("Premuto tasto: " + String(pulsante));
WriteLCD(false);
WriteLED();
if (tempCaldaia <= 63) { // Temperatura in caldaia < 63 gradi: fermo tutto
pmpCaldaia = false;
pmpRisc = false;
valvBoiler = false;
valvScarico = false;
valvImpianto = 2;
statoImpianto = 0;
Riga2 = "Caldaia troppo bassa";
Riga3 = "C:OFF R:OFF B:OFF V2";
Riga4 = "Valvola imp. chiusa ";
WriteLCD(false);
SetStati(true);
}
if (tempCaldaia >= 64 && tempCaldaia < 85) { // Temperatura nel range di funzionamento
if (caldaiaOk == true) { // La caldaia ha dato il consenso
if (acquaBoiler == false && acquaRisc == false) richiestaAcqua = 1; // nessuno chiede acqua calda
if (acquaBoiler == true && acquaRisc == false) richiestaAcqua = 2; // solamente il boiler chiede acqua calda
if (acquaBoiler == false && acquaRisc == true) richiestaAcqua = 3; // solamente il riscaldamento chiede acqua calda
if (acquaBoiler == true && acquaRisc == true) richiestaAcqua = 4; // entrambi chiedono acqua calda
//Serial.print("Richiesta acqua = ");
//Serial.println(richiestaAcqua);
}
else {
richiestaAcqua = 5;
//Serial.print("Richiesta acqua = ");
//Serial.println(richiestaAcqua);
}
switch (richiestaAcqua) {
case 1:
pmpCaldaia = false;
pmpRisc = false;
valvBoiler = false;
valvScarico = false;
valvImpianto = 2;
statoImpianto = 1;
SetStati(false);
Riga2 = "T.Acqua OK - No Req.";
Riga3 = "C:OFF R:OFF B:OFF V2";
Riga4 = "Valvola imp. chiusa ";
WriteLCD(false);
Serial.println("Case 1");
break;
case 2:
pmpCaldaia = true;
pmpRisc = false;
valvBoiler = true;
valvScarico = false;
valvImpianto = 0;
statoImpianto = 2;
SetStati(false);
Riga2 = "Acqua -> Boiler ";
Riga3 = "C:ON R:OFF B:ON V:2 ";
Riga4 = "Valvola imp. chiusa ";
WriteLCD(false);
Serial.println("Case 2");
break;
case 3:
pmpCaldaia = true;
pmpRisc = true;
valvBoiler = false;
valvScarico = false;
valvImpianto = 0;
statoImpianto = 3;
SetStati(false);
Riga2 = "Acqua -> Riscaldam. ";
Riga3 = "C:ON R:ON B:OFF V:0 ";
Riga4 = "Valvola imp. autom. ";
WriteLCD(false);
Serial.println("Case 3");
break;
case 4:
pmpCaldaia = true;
pmpRisc = false;
valvBoiler = true;
valvScarico = false;
valvImpianto = 2;
statoImpianto = 4;
SetStati(false);
Riga2 = "Priorità a Boiler ";
Riga3 = "C:ON R:OFF B:ON V:2 ";
Riga4 = "Valvola imp. chiusa ";
WriteLCD(false);
Serial.println("Case 4");
break;
case 5:
pmpCaldaia = false;
pmpRisc = false;
valvBoiler = false;
valvScarico = false;
valvImpianto = 2;
statoImpianto = 9;
SetStati(false);
Riga2 = "Attesa OK da Caldaia";
Riga3 = "C:OFF R:OFF B:OFF V2";
Riga4 = "Valvola imp. chiusa ";
WriteLCD(false);
Serial.println("Case 5");
break;
default:
break;
}
}
if (tempCaldaia >= 85) {
if (tempCaldaia <= 88) statoEmergenza = 1;
if (tempCaldaia >= 89 && tempCaldaia <= 91) statoEmergenza = 2;
if (tempCaldaia >= 92 && tempCaldaia <= 93) statoEmergenza = 3;
if (tempCaldaia >= 94) statoEmergenza = 4;
pmpCaldaia = true;
valvBoiler = true;
valvScarico = false;
switch (statoEmergenza) {
case 1:
pmpRisc = false;
valvImpianto = 2;
Riga2 = "TA>85 Acqua > Boiler";
Riga3 = "C:ON R:OFF B:ON V:2 ";
Riga4 = "Valvola imp. chiusa ";
statoImpianto = 5;
break;
case 2:
pmpRisc = false;
valvImpianto = 1;
Riga2 = "TA>89 Boiler + Termo";
Riga3 = "C:ON R:OFF B:ON V:1 ";
Riga4 = "Valvola imp. aperta ";
statoImpianto = 6;
break;
case 3:
pmpRisc = true;
valvImpianto = 1;
Riga2 = "TA>92 Boiler + Risc.";
Riga3 = "C:ON R:ON B:ON V:1 ";
Riga4 = "Valvola imp. aperta ";
statoImpianto = 7;
break;
case 4:
pmpRisc = true;
valvImpianto = 1;
valvScarico = true;
Riga2 = "TA>93 Scarico Acqua!";
Riga3 = "C:ON R:ON B:ON V:1 ";
Riga4 = "Valvola imp. aperta ";
statoImpianto = 8;
break;
default:
break;
}
if (tempBoiler >= TMaxBoiler) {
valvBoiler = false;
if (valvImpianto = 2) valvImpianto = 1;
switch (statoEmergenza) {
case 1:
case 2:
Riga2 = " Acqua > Termo ";
Riga3 = "C:ON R:OFF B:OFF V:1";
Riga4 = "Temp.Boiler > T.Max ";
break;
case 3:
Riga2 = "Acqua > Termo e Risc";
Riga3 = "C:ON R:ON B:OFF V:0 ";
Riga4 = "Temp.Boiler > T.Max ";
break;
case 4:
Riga2 = "TA>93 SCARICO ACQUA!";
Riga3 = "C:ON R:ON B:OFF V:1 ";
Riga4 = "Temp.Boiler > T.Max ";
break;
default:
break;
}
}
if (acquaRisc) {
pmpRisc = true;
valvImpianto = 0;
if (statoImpianto = 8) valvImpianto = 1;
if (tempBoiler <= TMaxBoiler) {
Riga2 = "> Boiler + Risc.";
Riga3 = "C:ON R:ON B=ON V:" + String(valvImpianto) + " ";
}
else {
Riga2 = "> Riscaldamento ";
Riga3 = "C:ON R:ON B=OFF V:" + String(valvImpianto) + " ";
}
}
SetStati(false);
WriteLCD(false);
}
}
/*********** F U N Z I O N I ***********/
void TempRead(bool immed) /****** TempRead: Legge le temperature dalle sonde ******/
{
/*----- la lettura viene effettuata se sono passati più di 30 secondi dall'ultima
lettura o se immed = true -----*/
float media = 0.0; // variabile locale per calcolare la media delle letture
if (immed == true || ((millis() - timeStart) > 30000)) {
alertSonda = false;
if (testProgramma) return; // se è attivo il test del programma salta la lettura delle temperature
/*----- Lettura della temperatura dalla sonda caldaia -----*/
for (int x = 0; x < 5; x++ ) { // Esegue la lettura della sonda 5 volte per calcolare la media
sensoreCaldaia.requestTemperatures();
media = media + sensoreCaldaia.getTempCByIndex(0);
delay(100);
}
tempCaldaia = media / 5; // Calcola la media delle 5 letture e la salva nella variabile tempCaldaia
media = 0; // Resetta a zero la varabile media per le successive letture
Serial.print("Temperatura Caldaia = ");
Serial.println(tempCaldaia);
/*----- Lettura della temperatura dalla sonda boiler -----*/
for (int x = 0; x < 5; x++ ) { // Esegue la lettura della sonda 5 volte per calcolare la media
sensoreBoiler.requestTemperatures();
media = media + sensoreBoiler.getTempCByIndex(0);
delay(100);
}
tempBoiler = media / 5; // Calcola la media delle 5 letture e la salva nella variabile tempBoiler
Serial.print("Temperatura Boiler = ");
Serial.println(tempBoiler);
/*----- Controllo che le sonde siano in funzione -----*/
if (tempCaldaia == -127.00 || tempBoiler == -127.00) {
if (tempCaldaia == -127.00 && tempBoiler == -127.00) {
tempCaldaia = tempBoiler = -99;
Riga4Alert = "CONTROLLARE SONDE!!!";
alertSonda = true;
}
else if (tempCaldaia == -127.00) {
tempCaldaia = -99;
Riga4Alert = "CHECK SONDA CALDAIA!";
alertSonda = true;
}
else {
tempBoiler = -99;
Riga4Alert = "CHECK SONDA BOILER!!";
alertSonda = true;
}
}
timeStart = millis(); // la variabile timeStart viene settata al tempo corrente
}
}
void SetStati(bool immed) /****** SetStati: imposta gli stati sulle pompe e valvole ******/
{
/*-- Controllo se lo stato impianto è cambiato altrimenti esce --*/
if (statoPrecedente == statoImpianto) {
delay(5);
return;
}
// EasyBuzzer.update();
/*-- Controllo se primo avvio o se sono passati 30 secondi dall'ultima variazione --*/
if (lastTime < 5000 || (millis() - lastTime) > 30000 || immed == true || testProgramma) {
digitalWrite(RP_Risc, !pmpRisc);
digitalWrite(RP_Caldaia, !pmpCaldaia);
digitalWrite(RV_Boiler, !valvBoiler);
digitalWrite(RV_Scarico, !valvScarico);
/*-- Regola valvola impianto --*/
switch (valvImpianto)
{
case 0:
digitalWrite(RV_Risc_ON, RELAY_OFF);
digitalWrite(RV_Risc_OFF, RELAY_OFF);
break;
case 1:
digitalWrite(RV_Risc_ON, RELAY_ON);
digitalWrite(RV_Risc_OFF, RELAY_OFF);
break;
case 2:
digitalWrite(RV_Risc_ON, RELAY_OFF);
digitalWrite(RV_Risc_OFF, RELAY_ON);
break;
default:
break;
}
lastTime = millis();
statoPrecedente = statoImpianto;
}
delay (5);
}
/****** WriteLCD: Scrive le righe sul display LCD e controlla retroilluminazione ******/
void WriteLCD(bool LCD_On_Now)
{
//EasyBuzzer.update();
lcd.setCursor(0, 0);
lcd.print(Riga1);
lcd.setCursor(0, 1);
lcd.print(Riga2);
lcd.setCursor(0, 2);
lcd.print(Riga3);
lcd.setCursor(0, 3);
if (alertSonda) lcd.print(Riga4Alert);
else lcd.print(Riga4);
if (LCD_On_Now) { // Se è stato passato il valore true accende il display
timeLCD = millis() + timeLCD_ON;
LCD_ON = true;
}
if (LCD_ON) { // Se non è trascorso il tempo definito in timeLCD_ON rimango acceso
if (timeLCD - millis() > 1000) {
digitalWrite(digitalLCDpower, HIGH);
}
else {
digitalWrite(digitalLCDpower, LOW); // E' trascorso il tempo di accensione, spengo e metto a false LCD_ON
LCD_ON = false;
}
}
delay(5);
}
void ReadSensor() /****** ReadSensor: Legge lo stato dei sensori in INPUT ******/
{
if (testProgramma) return ;
acquaRisc = bool(digitalRead(termAmbiente));
caldaiaOk = bool(digitalRead(consensoCaldaia));
Serial.print("acquaRisc = ");
Serial.println(acquaRisc);
Serial.print("Caldaia OK = ");
Serial.println(caldaiaOk);
}
int ReadButton() /****** ReadButton: Verifica se sono stati premuti pulsanti e rende il numero del tasto premuto ******/
{
int Value = analogRead(INPUT_PULSANTI);
// Serial.println(Value);
if (Value > 1000) return 0; // Nessun tasto premuto
if (Value < 50) return 1; // Tasto 1 (Accensione retroilluminazione)
if (Value < 200 and Value > 150) return 2; // Tasto 2
if (Value < 350 and Value > 290) return 3; // Tasto 3
if (Value < 450 and Value > 380) return 4; // Tasto 4
if (Value < 490 and Value > 450) return 5; // Tasto 5
if (Value < 550 and Value > 500) return 6; // Tasto 6
if (Value < 590 and Value > 560) return 7; // Tasto 7
}
void WriteLED() /****** WriteLED: Scrive le temperature su i LED 7 Segmenti ******/
{
int unita, decine, centinaia, calctemp; // Variabili per il calcolo dei segmenti
bool negativo = false; // Variabile che indica se il numero è negativo
if (oldTempBoiler != tempBoiler) { // Procede se il valore della temperatura è cambiato
calctemp = int(tempBoiler);
if (tempBoiler < 0) { // Se il numero è negativo imposta la variabile e lo rende positivo
negativo = true;
calctemp = calctemp * -1;
}
unita = calctemp % 10; // Recupera la cifra delle unità
calctemp = calctemp / 10;
decine = calctemp % 10; // Recupera la cifra delle decine
calctemp = calctemp / 10;
centinaia = calctemp; // Recupera la cifra delle centinaia
if (negativo) { // Se è negativo imposta segno meno altrimenti vuoto
lc.setChar(0, 3, '-', false);
} else lc.setChar(0, 3, ' ', false);
lc.setRow(0, 0, B01100011); // imposta segno del grado
lc.setDigit(0, 1, (byte)unita, false);
lc.setDigit(0, 2, (byte)decine, false);
if (centinaia != 0) lc.setDigit(0, 3, (byte)centinaia, false);
oldTempBoiler = tempBoiler; // imposta il nuovo valore di temperatura
}
negativo = false; // ripristina negativo a false prima del nuovo calcolo
if (oldTempCaldaia != tempCaldaia) {
calctemp = int(tempCaldaia);
if (tempCaldaia < 0) {
negativo = true;
calctemp = calctemp * -1;
}
unita = calctemp % 10;
calctemp = calctemp / 10;
decine = calctemp % 10;
calctemp = calctemp / 10;
centinaia = calctemp;
if (negativo) {
lc.setChar(0, 7, '-', false);
} else lc.setChar(0, 7, ' ', false);
lc.setRow(0, 4, B01100011);
lc.setDigit(0, 5, (byte)unita, false);
lc.setDigit(0, 6, (byte)decine, false);
if (centinaia != 0) lc.setDigit(0, 7, (byte)centinaia, false);
oldTempCaldaia = tempCaldaia;
}
}
C
B
TA
OK