#define RS 12
#define E 10
#define D4 5
#define D5 4
#define D6 9
#define D7 13
// Dichiarazioni delle schermate e variabili
#define NUM_SCREENS 4; // Numero totale di schermate
#define DHT_PIN_EXTERNAL 2 // Collega il sensore DHT esterno al pin 2 di Arduino
#define DHT_PIN_INTERNAL 3 // Collega il sensore DHT interno al pin 3 di Arduino
//#define LEDgreen 4 //Connect Digital Pin 4 on Arduino to Green LED (+ 330 ohm resistor) and then to "NO" terminal on relay module
//#define LEDyellow 12 //Connect Digital Pin 12 on Arduino to Yellow LED (+ 330 ohm resistor) and then to "NC" terminal on relay module
#define potenziometroPin 0
#define FLUSSO_DIRETTO 6
#define CIRCUITO_RECUPERO_CALORE 8
#define buttonPin1 1 // pin del primo pulsante
#define buttonPin2 2 // pin del secondo pulsante
#define buttonPin3 3 // pin del terzo pulsante
#define buttonPin4 4 // pin del quarto pulsante
volatile int buttonState1 = LOW; // Stato del primo pulsante
volatile int buttonState2 = LOW; // Stato del secondo pulsante
volatile int buttonState3 = LOW; // Stato del terzo pulsante
volatile int buttonState4 = LOW; // Stato del quarto pulsante
unsigned long pressStartTime1 = 0;
unsigned long pressStartTime2 = 0;
unsigned long pressStartTime3 = 0;
unsigned long pressStartTime4 = 0;
float sogliaTemperaturaBenessere = 2.0; // valore (default) Differenza minima per attivare il flusso diretto (puoi regolare questo valore)
int currentScreen = 0; // Indice della schermata attuale
int CO2Value = 0;
float temperature_internal = 0;
float temperature_external = 0;
bool ventilationState = false;
//LiquidCrystal lcd(12, 10, 5, 4, 9, 13);
bool bFourBitMode = false;
char ReadSendState = -1;
unsigned char Battery_6[8] = { 0b00100, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111 };
unsigned char Battery_5[8] = { 0b00100, 0b11111, 0b10001, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111 };
unsigned char Battery_4[8] = { 0b00100, 0b11111, 0b10001, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111 };
unsigned char Battery_3[8] = { 0b00100, 0b11111, 0b10001, 0b10001, 0b11111, 0b11111, 0b11111, 0b11111 };
unsigned char Battery_2[8] = { 0b00100, 0b11111, 0b10001, 0b10001, 0b10001, 0b11111, 0b11111, 0b11111 };
unsigned char Battery_1[8] = { 0b00100, 0b11111, 0b10001, 0b10001, 0b10001, 0b10001, 0b11111, 0b11111 };
unsigned char Battery_0[8] = { 0b00100, 0b11111, 0b10001, 0b10001, 0b10001, 0b10001, 0b10001, 0b11111 };
void LcdSend(unsigned char Data)
{
if (bFourBitMode)
{
customDigitalWrite(D4, (Data >> 4) & 0x01);
customDigitalWrite(D5, (Data >> 5) & 0x01);
customDigitalWrite(D6, (Data >> 6) & 0x01);
customDigitalWrite(D7, (Data >> 7) & 0x01);
delayMicroseconds(10);
customDigitalWrite(E, HIGH);
delayMicroseconds(10);
customDigitalWrite(E, LOW);
delayMicroseconds(100);
}
customDigitalWrite(D4, (Data >> 0) & 0x01);
customDigitalWrite(D5, (Data >> 1) & 0x01);
customDigitalWrite(D6, (Data >> 2) & 0x01);
customDigitalWrite(D7, (Data >> 3) & 0x01);
delayMicroseconds(10);
customDigitalWrite(E, HIGH);
delayMicroseconds(10);
customDigitalWrite(E, LOW);
delayMicroseconds(100);
}
void LcdCommand(unsigned char Command)
{
if (ReadSendState != LOW)
{
ReadSendState = LOW;
customDigitalWrite(RS, LOW);
}
LcdSend(Command);
if (Command == 0x01) delayMicroseconds(2000);// Clear command takes more time
}
void LcdWrite(int Letter)
{
if (ReadSendState != HIGH)
{
ReadSendState = HIGH;
customDigitalWrite(RS, HIGH);
}
LcdSend(Letter);
}
void LcdWrite(const char* Text)
{
if (ReadSendState != HIGH)
{
ReadSendState = HIGH;
customDigitalWrite(RS, HIGH);
}
for (; *Text != 0; Text++)
{
char Letter = *Text;
LcdSend(Letter);
}
}
void LcdInit(bool bFirstInit)
{
if (bFirstInit)
{
// Give it time to power up
delayMicroseconds(15000);
customPinMode(RS, OUTPUT);
customPinMode(E, OUTPUT);
customPinMode(D4, OUTPUT);
customPinMode(D5, OUTPUT);
customPinMode(D6, OUTPUT);
customPinMode(D7, OUTPUT);
}
// Start
bFourBitMode = false;
LcdCommand(0x03);
delayMicroseconds(4000);
LcdCommand(0x03);
LcdCommand(0x03);
LcdCommand(0x02);
bFourBitMode = true;
LcdCommand(0x28);
LcdCommand(0x0C);
LcdCommand(0x01);// Clear
LcdCommand(0x06);
LcdCreateChar(0, Battery_0);
LcdCreateChar(1, Battery_1);
LcdCreateChar(2, Battery_2);
LcdCreateChar(3, Battery_3);
LcdCreateChar(4, Battery_4);
LcdCreateChar(5, Battery_5);
LcdCreateChar(6, Battery_6);
}
void LcdSetCursor(unsigned char Column, unsigned char Row)
{
LcdCommand(0x80 | (Column + (Row != 0 ? 0x40 : 0x00)));
}
void LcdCreateChar(unsigned char Location, unsigned char SpecialChar[8])
{
LcdCommand(0x40 | (Location << 3));
for (unsigned int i = 0; i < 8; i++)
LcdWrite(SpecialChar[i]);
}
void LcdClear() {
LcdCommand(0x01); // Clear display
delayMicroseconds(2000); // Aspetta il tempo necessario per il comando di cancellazione
}
void setup() {
LcdInit(true);
customPinMode(FLUSSO_DIRETTO, OUTPUT);
customPinMode(CIRCUITO_RECUPERO_CALORE, OUTPUT);
customPinMode(buttonPin1, INPUT);
customPinMode(buttonPin2, INPUT);
customPinMode(buttonPin3, INPUT);
customPinMode(buttonPin4, INPUT);
// Abilita l'interrupt esterno su pin 2
//EIMSK |= (1 << INT0);
/* // Imposta il trigger sull'orlo di salita
EICRA |= (1 << ISC01) | (1 << ISC00);
*/
// Change
EICRA |= (1 << ISC00);
// Abilita l'interrupt per il gruppo PCINT1 (pin 8-13)
PCICR |= (1 << PCIE1);
// Abilita il maschera interrupt per il gruppo PCINT1 (pin A0-A5)
PCMSK1 |= (1 << PC0) | (1 << PC1) | (1 << PC2) | (1 << PC3) | (1 << PC4);
//PCICR |= B00000010; // We activate the interrupts of the PC port
/* PCMSK1 |= bit (PCINT13) | bit (PCINT12) | bit (PCINT11); // want pin A5 or A4 or A3
PCIFR |= bit (PCIF1); // clear any outstanding interrupts
PCICR |= bit (PCIE1); // enable pin change interrupts for A0 to A6 and reset */
/* // Imposta il trigger sull'orlo di discesa
EICRA |= (1 << ISC01); */
// Abilita gli interrupt globali
sei();
Serial.begin(9600);
// Configura l'ADC
ADMUX = 0; // Usa il riferimento AREF, bit di sinistra a 0
ADMUX |= (1 << REFS0); // Riferimento esterno a 5V
ADCSRA |= (1 << ADEN); // Abilita l'ADC
}
void loop() {
//cli();
// TEMP +1
//if (!(((PINC & (1 << PC1))) == 0)) {
// non so perchè la temperatura continua a salire finche non ci premo un altra volta
if (!(((PINC & (1 << PC1))) == 0)) {
unsigned long pressDuration1 = millis() - pressStartTime1;
// Usa pressDuration1 per decidere quale azione intraprendere
pressDuration1 = (float)pressDuration1 / 1000.0; // Converte in secondi
Serial.println(pressDuration1);
sogliaTemperaturaBenessere += 1.0; // Incrementa la soglia di 0.5 gradi
Serial.print("temp benessere : ");
Serial.println(sogliaTemperaturaBenessere);
displaySogliaTemperaturaBenessere(sogliaTemperaturaBenessere);
// rimetto il bottone a LOW per non farlo crescere
//buttonState1 = LOW;
}
// TEMP -1
//if (!(((PINC & (1 << PC2))) == 0)) {
// non so perchè la temperatura continua a diminuire finche non ci premo un altra volta
if(!(((PINC & (1 << PC2))) == 0)){
unsigned long pressDuration2 = millis() - pressStartTime2;
// Usa pressDuration2 per decidere quale azione intraprendere
pressDuration2 = (float)pressDuration2 / 1000.0; // Converte in secondi
sogliaTemperaturaBenessere -= 1.0; // Decrementa la soglia di 1 gradi
displaySogliaTemperaturaBenessere(sogliaTemperaturaBenessere);
//buttonState2 = LOW;
}
// INFO SISTEMA eq. (buttonState3 == HIGH)
//if(!(((PINC & (1 << PC3))) == 0)) {
if(!(((PINC & (1 << PC3))) == 0)){
unsigned long pressDuration3 = millis() - pressStartTime3;
// Usa pressDuration1 per decidere quale azione intraprendere
pressDuration3 = (float)pressDuration3 / 1000.0; // Converte in secondi
currentScreen = (currentScreen + 1) % NUM_SCREENS; // Aumenta l'indice e torna a 0 se necessario
infoStatus(currentScreen); // Mostra la nuova schermata
delay(500); // Aggiungi un piccolo ritardo per evitare letture multiple
LcdClear(); // Pulisce il display
}
// SPEGNIMENTO
if (!(((PINC & (1 << PC4))) == 0)) {
unsigned long pressDuration4 = millis() - pressStartTime4;
// Usa pressDuration1 per decidere quale azione intraprendere
pressDuration4 = (float)pressDuration4 / 1000.0; // Converte in secondi
Serial.print("PRESS DURATION4 : ");
Serial.println(pressDuration4);
if(pressDuration4 >= 10){
// Spegni il sistema
spegniSistema();
}
}
/* Serial.print("Bottone 1 : ");
Serial.println(buttonState1); // Stampa lo stato del pulsante
Serial.print("Bottone 2 : ");
Serial.println(buttonState2); // Stampa lo stato del pulsante
Serial.print("Bottone 3 : ");
Serial.println(buttonState3); // Stampa lo stato del pulsante
Serial.print("Bottone 4 : ");
Serial.println(buttonState4); // Stampa lo stato del pulsante */
//sei();
//ROBA POTENZIOMETRO
int potenziometroValue = readPotentiometer(potenziometroPin);
//int asd = analogReadd(A0);
Serial.print("Valore del potenziometro : ");
Serial.println(potenziometroValue);
CO2Value = potenziometroValue * 4;
Serial.print("Livello CO2 : ");
Serial.println(CO2Value);
//delay(200); // Aggiungi un piccolo ritardo tra le letture per evitare letture multiple istantanee
customReadDHT22(DHT_PIN_INTERNAL);
Serial.print("Temperatura interna : ");
Serial.println(temperature_internal);
customReadDHT22(DHT_PIN_EXTERNAL);
Serial.print("Temperatura esterna : ");
Serial.println(temperature_external);
/*
Meno di 800 ppm: Valore ottimale per ambienti interni ben ventilati con buona qualità dell'aria.
Fino a 1000 ppm: Accettabile per ambienti interni, ma la qualità dell'aria può iniziare a diminuire e alcuni individui possono percepire una sensazione di disagio.
1000 - 2000 ppm: Valore accettabile per brevi periodi, ma la qualità dell'aria può essere compromessa, causando possibili effetti sulla concentrazione e il comfort delle persone.
Oltre 2000 ppm: Livelli elevati che indicano una ventilazione insufficiente e una scarsa qualità dell'aria. Possono causare affaticamento, mal di testa e disagio per le persone.
*/
if(CO2Value < 800){
// Livello di CO2 accettabile, spegni entrambi i sistemi di ventilazione
customDigitalWrite(FLUSSO_DIRETTO, LOW);
customDigitalWrite(CIRCUITO_RECUPERO_CALORE, LOW);
ventilationState = false;
//LcdInit(false);
if(((PINC & (1 << PC3))) == 0){
statoAria("buona");
}
} else if(CO2Value > 800 && CO2Value < 1000){
// Livello di CO2 accettabile, spegni entrambi i sistemi di ventilazione
customDigitalWrite(FLUSSO_DIRETTO, LOW);
customDigitalWrite(CIRCUITO_RECUPERO_CALORE, LOW);
ventilationState = false;
if(((PINC & (1 << PC3))) == 0){
statoAria("accettabile");
}
}else if(CO2Value > 1000){
/* // Attiva la ventilazione per abbassare il livello di CO2
customDigitalWrite(FLUSSO_DIRETTO, HIGH); // o customDigitalWrite(CIRCUITO_RECUPERO_CALORE, HIGH);
// Disattiva l'altro sistema di ventilazione
customDigitalWrite(CIRCUITO_RECUPERO_CALORE, LOW); // o customDigitalWrite(FLUSSO_DIRETTO, LOW); */
// bisogna attivare areazione
if(temperature_internal - temperature_external >= sogliaTemperaturaBenessere) {
// Attiva il relay per il flusso diretto
customDigitalWrite(FLUSSO_DIRETTO, HIGH);
customDigitalWrite(CIRCUITO_RECUPERO_CALORE, LOW);
ventilationState = true;
} else {
// Attiva il relay per il circuito di recupero del calore
customDigitalWrite(FLUSSO_DIRETTO, LOW);
customDigitalWrite(CIRCUITO_RECUPERO_CALORE, HIGH);
ventilationState = true;
} if(((PINC & (1 << PC3))) == 0){
statoAria("cattiva");
}
Serial.print("Temperatura esterna : ");
Serial.println(temperature_external);
Serial.print("Temperatura interna: ");
Serial.println(temperature_internal);
}
}
int readPotentiometer(int pin) {
ADMUX = 0x40 | (pin & 0x07); // Imposta il pin da leggere
ADCSRA |= (1 << ADSC); // Avvia la conversione
// Attendi la fine della conversione
while (ADCSRA & (1 << ADSC)) {
// Attendi
}
return ADC; // Restituisci il valore letto
}
// Funzione personalizzata per impostare la modalità del pin
void customPinMode(int pin, int mode) {
if (mode == INPUT) {
if (pin < 8) {
DDRD &= ~(1 << pin);
} else if (pin < 14) {
DDRB &= ~(1 << (pin - 8));
}
} else if (mode == OUTPUT) {
if (pin < 8) {
DDRD |= (1 << pin);
} else if (pin < 14) {
DDRB |= (1 << (pin - 8));
}
}
}
int customDigitalRead(int pin) {
if (pin < 8) {
return (PIND & (1 << pin)) ? HIGH : LOW;
} else if (pin < 14) {
return (PINB & (1 << (pin - 8))) ? HIGH : LOW;
}
return LOW;
}
void customDigitalWrite(int pin, int value) {
if (value == LOW) {
if (pin < 8) {
PORTD &= ~(1 << pin);
} else if (pin < 14) {
PORTB &= ~(1 << (pin - 8));
}
} else if (value == HIGH) {
if (pin < 8) {
PORTD |= (1 << pin);
} else if (pin < 14) {
PORTB |= (1 << (pin - 8));
}
}
}
// ISR per il gruppo PCINT1 (pin A0-A5)
ISR(PCINT1_vect) {
if (((PINC & (1 << PC1))) == 0) {
pressStartTime1 = millis();
}
if (((PINC & (1 << PC2))) == 0) {
pressStartTime2 = millis();
}
if (((PINC & (1 << PC3))) == 0) {
pressStartTime3 = millis();
}
if (((PINC & (1 << PC4))) == 0) {
pressStartTime4 = millis();
}
/* // Leggi lo stato dei bottoni
buttonState1 = (PINC & (1 << PC1)) ? HIGH : LOW;
buttonState2 = (PINC & (1 << PC2)) ? HIGH : LOW;
buttonState3 = (PINC & (1 << PC3)) ? HIGH : LOW;
buttonState4 = (PINC & (1 << PC4)) ? HIGH : LOW; */
}
float customReadDHT22(int DHTPIN) {
// Inizia la comunicazione con il sensore DHT22
int data[5];
customPinMode(DHTPIN, OUTPUT);
customDigitalWrite(DHTPIN, LOW);
//delay(20);
delayMicroseconds(1000);
customDigitalWrite(DHTPIN, HIGH);
delayMicroseconds(40);
customPinMode(DHTPIN, INPUT);
// Attendi la risposta del sensore
while (customDigitalRead(DHTPIN) == HIGH);
// Attendi che il sensore inizi la trasmissione dei dati
while (customDigitalRead(DHTPIN) == LOW);
// Attendi che il sensore finisca di trasmettere i dati
while (customDigitalRead(DHTPIN) == HIGH);
// Leggi i dati dal sensore
//int sensorData[5];
cli();
for (int i = 0; i < 5; i++) {
int value = 0;
for (int j = 0; j < 8; j++) {
while (customDigitalRead(DHTPIN) == LOW);
delayMicroseconds(50);
if (customDigitalRead(DHTPIN) == HIGH) {
value |= (1 << (7 - j));
}
while (customDigitalRead(DHTPIN) == HIGH);
}
data[i] = value;
}
// Calcola la temperatura
float temperature = ((data[2] & 0x7F) << 8 | data[3]) * 0.1;
Serial.println(temperature);
if (data[2] & 0x80) {
temperature = -temperature;
}
if(DHTPIN == 3){
temperature_internal = temperature;
}else{
temperature_external = temperature;
}
sei();
}
void displaySogliaTemperaturaBenessere(float soglia) {
LcdClear();
LcdSetCursor(0, 0);
LcdWrite("Temp. Benessere");
delay(1000);
LcdSetCursor(0, 1);
char temperatureBuffer[10];
dtostrf(soglia, 4, 1, temperatureBuffer);
char lcdText[20];
sprintf(lcdText, "%s C", temperatureBuffer);
LcdWrite(lcdText);
delay(1500);
LcdClear();
}
void stampaVar(float var) {
LcdSetCursor(0, 1);
char temperatureBuffer[10];
dtostrf(var, 4, 1, temperatureBuffer);
char lcdText[20];
sprintf(lcdText, "%s C", temperatureBuffer);
LcdWrite(lcdText);
delay(1500);
LcdClear();
}
// Funzione per la visualizzazione delle informazioni
void infoStatus(int screenIndex) {
LcdClear(); // Pulisce il display
LcdSetCursor(0, 0);
switch (screenIndex) {
case 0:
LcdWrite("Temp. Interna:");
LcdSetCursor(0, 1);
stampaVar(temperature_internal); // Mostra la temperatura interna
break;
case 1:
LcdWrite("Temp. Esterna:");
LcdSetCursor(0, 1);
stampaVar(temperature_external); // Mostra la temperatura esterna
break;
case 2:
LcdWrite("Livello CO2:");
LcdSetCursor(0, 1);
stampaVar(CO2Value); // Mostra il livello di CO2
break;
case 3:
LcdWrite("Stato Ventilaz.:");
LcdSetCursor(0, 1);
if(ventilationState = true) LcdWrite("ON");
else LcdWrite("OFF");
delay(1500);
break;
}
//PORTC &= ~(1 << PC3);
}
void spegniSistema() {
customDigitalWrite(FLUSSO_DIRETTO, LOW);
customDigitalWrite(CIRCUITO_RECUPERO_CALORE, LOW);
// Aggiungi altre azioni di spegnimento qui se necessario
while (true) {
// Blocca l'esecuzione in un ciclo infinito, il sistema è stato spento
customDigitalWrite(FLUSSO_DIRETTO, LOW);
customDigitalWrite(CIRCUITO_RECUPERO_CALORE, LOW);
}
}
void statoAria(const char* stato){
LcdClear(); // Pulisce il display
LcdSetCursor(0, 0);
LcdWrite("Qualita' aria");
//delay(1000);
LcdSetCursor(0, 1);
LcdWrite(stato);
delay(1500);
LcdClear(); // Pulisce nuovamente il display
}