//Copyright (c) 2024 Duțoiu Nicolae
// Mcu SLAVE
// STATIE DE EPURARE CU BAZINE IBC
/* ^
. CONDUCTE PVC |
. _______________________________________________|__________________
. | __________________|_______________ |
. | | | | |
| | __|_____|__ | __|_____|__ | | | |
| | | | | | | | | | | | | | |
| BAZIN 0 | | BAZIN 1 | | | | BAZIN 2 | | |
| | | | | | | | | |
| NU ARE POMPE | | POMPE | | | | POMPE | | |
| | | | | | EVACUARE EXT. | | |
| | | AERARE EVACUARE B2 | | AERARE RECIRCULARE B1/B0 |
|______________________| |______________________| |__________________________|
*/
/********* ATENTIE !!! **********/
// Ca Debouncer pt butoane se utilizeza CI MAX6817
// Transmisia wireles este programata direct in IDE pt asigurare comunicatie Master - Slave
// emisia se relizeaza in functia StareCiclu la o secundă si in functia Scrie_Citeste_EEPROM
// iar receptia in functia loop continu
// BAZIN 0 - separator grasimi si fermentare anaeroba
// BAZIN 1 si BAZIN 2 fermentare aeroba si au nevoie de casa bacteriilor (un grilaj de plastic + resturi teava PPR)
// BAZIN 0 descarca hidraulic-gravitational in BAZIN 1
// prea plinul in BAZIN 1 se realizeaza hidraulic
// legatura intre bazine este facuta pe principiul vaselor comunicante
// daca nu functioneaza pompele de umplere bazin 2 si evacuarea exterioara se face natural cu
// conditia ca iesirea in exterior sa fie mai jos decat intrarea canalizarii in BAZIN 0
// rezultand o fosa septica clasica
// pompele pentru setarile de mai jos au aproximativ 100 litri / minut la 1m inaltime adica 6 mc/h, valoarea reala se determina experimental
// daca pompele au debite diferite timpii de pornire evacuare si recirculare sunt diferiti
// trebuind modificate variabilele pentru pompele de EVACUARE si RECIRCULARE
// pompa standard la care se raporteaza timpii de functionare este de 6 mc/h la 5m inaltime
// cantitatea maxima evacuata este stabilita prin plutitorii de nivel minim care intrerup pompele fara comanda din partea controlerului
// daca se opreste curentul sau apare o resetare fizica controlerul revine la valorile stocate in EEPROM
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
#include <EasyTransfer.h>//transmite pe hardware serial o structura de maxim 255 octeti
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20 column and 4 rows
// adresa este pt a functiona in wokwi,
// alfel trebuie setata pe afisaj
// Transfer Serial date
EasyTransfer HC12_Transfer_TX;
EasyTransfer HC12_Transfer_RX;
uint32_t timp_RX = millis();//aseasta variabila este utilizata la verificarea receptiei
//adica daca timp de 2100 ms nu este primita corect
//structura transmisa afiseza mesajul "master nu transmite"
//Stabilire pini butoane
#define PIN_BUTON_MOD 8
#define PIN_BUTON_RST_ALARMA 7 // Pin digital 7
#define PIN_BUTON_SETUP 6 // Pin digital 6
#define PIN_BUTON_TIMP_PLUS 5 // Pin digital 5
#define PIN_BUTON_TIMP_MINUS 4 // Pin digital 4
// Pin Buzzer
#define PIN_BUZZER 13 // Pin digital 13
// Variabile Meniu
int8_t Meniu = -1; // valoarea -1 indica faptul ca nu ne aflam in meniu,
// valoarea 0 ne aflam in meniul INFO si HELP,
// restul valorilor gestioneaza afisarea meniurilor
int8_t subMeniuAERARE = -1;
int8_t subMeniuEVACUARE = -1;
int8_t subMeniuRECIRCULARE = -1;
int8_t subMeniuFLOCULANT = -1;
int8_t subMeniuRESET_ALARME = -1;
int8_t subMeniuRESET_FABRICA = -1;
int8_t subMeniuBazin_1_AERARE = -1;
int8_t subMeniuBazin_2_AERARE = -1;
bool _blink = true;
//variabila initializare ciclu cu modificarile efectuate in SETUP
bool init_SETUP = false;
// Variabile pompe
// ATENTIE ! - sa nu se schimbe pozitia variabilelor in "struct POMPE" pentru a functiona impachetarea
struct __attribute__((packed)) POMPE// Aceasta structura contine variabilele pentru pompe 6 mc/h si va fi transmisa
{ // si receptionata wireles de catre controlerul MASTER prin HC-12 433 MHz si de catre SLAVE
uint8_t Bazin_1_Aerare ; // implicit 90 de secunde min 30 sec - max 240 sec pas 10 sec
int16_t Bazin_1_Linistire ; // implicit 900 de secunde min 300 sec - max 3600 sec pas 300 sec
uint8_t Bazin_2_Aerare ; // implicit 90 de secunde min 30 sec - max 240 sec pas 10 sec
int16_t Bazin_2_Linistire ; // implicit 900 de secunde min 300 sec - max 3600 sec pas 300 sec
int16_t PornireEvacuare ; // implicit 180 de secunde min 180 sec - max 300 sec pas 10 sec - maxim 300 secunde / max 500 litri - pompa trebuie sa aiba un debit de 6 mc/h
int16_t LinistireEvacuare ; // implicit 1800 de secunde min 300 sec - max 3600 sec pas 300 sec - este folosita pentru Evacuare si Recirculare pompa 6 mc/h
uint8_t PornireRecirculare ; // implicit 60 de secunde min 15 sec - max 120 sec pas 5 sec - recircula 100 litri la debitul pompelor de 6 mc/h
uint8_t AsteptareRecirculare ; // implicit 4 ore min 3 ore max 8 ore pas 1 ora - max in secunde 28800
float PompaPeristaltica_B1 ; // implicit 10 mililitri, minim 0 mililitri - maxim 20 mililitri pt pompa utilizata
float PompaPeristaltica_B2 ; // implicit 5 mililitri, minim 0 mililitri - maxim 20 mililitri pt pompa utilizata
uint8_t Re_set ; // 0 - fara evenimente
// 1 - se reseteaza master pt. alarme de catre slave
// 2 - master transmite ca a modificat setarile
// 3 - slave transmite ca a modificat setarile
// 4 - slave transmite ca s-a resetat la setarile din fabrica
// 5 - slave a fost resetat fizic si a intrat in flux, adica a fost scos din priza, oprit sau reprogramat si transmite la master ca trebuie sa preia datatele de la master
// 6 - master solicita datele stocate in slave
// 7 - master s-a resetat la setarile de fabrica
};
struct POMPE POMPA;
//struct POMPE POMPA;
// Structura pentru afisarea ETAPEI / STARII pe LCD si transmitere date wireles prin HC-12
struct __attribute__((packed)) LCD20x4 // Aceasta structura contine textul afisat pe
{ // fiecare linie a afisajului LCD20x4
char Line[4][21]; // Aceasta structura va fi transmisa wireles
// catre controlerul SLAVE prin HC-12 433 MHz
// pt afisare pe SLAVE in inmp real
// transmiterea datelor se efectueaza in functia StareCiclu
float Temperatura[5];// = {0, 0, 0, 0, 0}; // stocheaza temperatura din Bazin 0, Bazin 1, Bazin 2, incapere, exterior
uint8_t Alarma[6];// = {0, 0, 0, 0, 0, 0b00000000}; // Stocheaza nr. de aparitii a alarmelor si numara pana la max. 255 de aparatii
// si este transmisa wireles prin HC-12
// Pt. alarma 6 se stocheaza in binar astfel
// XXX XXX XXX P2.3 P2.2 P2.1 P1.2 P1.1 - SUNT STOCATE IN ULTIMI 5 BITI
// BIT - - - 4 3 2 1 0
} ;//LCD;
//creez o structura comuna pentru transmisia seriala
union DATA
{
struct POMPE POMPA_Tx;
struct LCD20x4 LCD;
};
struct __attribute__((packed)) COMUN //aceasta structura va transmisa si receptionata
{
uint8_t tip_STR;// 1-LCD 2-POMPA
union DATA date;
} Tx_Rx;
bool primit_LCD = false;
bool setup_Tx_Rx;
int8_t alarma = 0; // stabileste tipul de alarma si ia valori
// 1 si 2 pt prea plin BAZIN 2
// 3 cand plutitorul de nivel maxim din BAZIN 2 este blocat sau pompa
// de evacuare in exterior este arsa
// 4 senzor nivel defect sau murdar si nu cupleaza in Bazin 1 sau pompa de
// evacuare in Bazin 2 este arsa
// 5 cand cel putin un bazin este sub nivelul de minim si este permanenta - adica prea gol si nu se porneste nicio pompa
// 6 cand pompa de evacuare este arsa sau senzor de prea plin defect sau murdar/lipit
// alarmele se elimina prin resetare alarma chiar daca senzorii de nivel revin la normal
// si practic pompele nu sunt arse
// resetarea alarmei se realizeaza prin resetare fizica a microcontroleru-lui
// momentan microcontrolerul nu poate determina daca o anumita pompa este arsa fizic
// alarmele se bazeaza doar pe starea senzorilor de nivel
bool _beep = true;//scoate un beep pe secunda la aparitia unei alarme
//prin apasarea butonului resetare alarme timp de 3 secunse intrerupe sunetul si viceversa
uint8_t _backlight = 1;// variabila care stinge iluminatul dupa 30
//uint8_t Reset = 0;// variabila transmisa de Mcu slave pentru resetare alarme
/******************** FUNCTIE RESETARE SOFTWARE PLACA *******************/
// resetare arduino.
// Trebuie scrisa inainte functiei loop().
// resetFunc() este chemata cand este nevoie.
void(* resetFunc) (void) = 0;
/************************************************************************/
/*********************** FUNCTIE ILUMINAT FOND LCD ***********************/
// Aceasta functie stinge lumina de fundal a afisajului LCD dupa un timp
// min 30 - max 240s
void LCD_Back_Light (uint8_t timp = 30)
{
static uint32_t volatile tmp = 0;
if (_backlight == 1) {_backlight = 2; tmp = millis(); }
if ((millis() - tmp) >= (timp * 1000) && _backlight == 2 ) { _backlight = 0; lcd.noBacklight(); }
}// end LCD_Back_Light
/************************ FUNCTII TRANSMITERE WIRELES PRIN HC12 *****************************/
// Aceste functii TX_HC12 si RX_HC12 primesc si transmit date catre slave - adica in casa
// se foloseste biblioteca EasyTRansfer deoarece stie sa transmita structuri si array
// face si un CRC de verificare a datelor primite
// se vor transmite :
// - POMPA_Set
// se receptioneaza variabilla :
// - POMPA_Set
// - structura LCD20x4
//ATENTIE !!! - transmisia nu este duplex
void tx_HC12 () // transmitere date
{
// EasyTRansfer poate trimite o singura structura de maxim 255 octeti
// este folosita cand slave transmite la master
// transmisia se face in functia loop
if (Tx_Rx.tip_STR > 1)
{
Serial.println(Tx_Rx.date.POMPA_Tx.Re_set);
HC12_Transfer_TX.sendData();// este folosit in functia StareCiclu
Serial.flush();
Tx_Rx.date.POMPA_Tx.Re_set = 0;
Tx_Rx.tip_STR = 0;
}
}// end TX_HC12
void rx_HC12 () // receptionare date
{
//if (Meniu > -1) return;
static bool primit = false;
char tmp[] = " ";
bool receptionat = false;
// se receptioneaza LCD si se verifica daca master transmite
receptionat = HC12_Transfer_RX.receiveData();
if (receptionat)
{
if (Tx_Rx.tip_STR == 1 && !setup_Tx_Rx)// afisez LCD
{
StareCiclu ();
if (!primit) {primit = !primit; lcd.clear();}
Info_Help_RstAlarm();//intra in info sau help cand este apasat butonul - sau +
LCD_Back_Light();
timp_RX = millis();
}
if (Tx_Rx.tip_STR >= 2)
{
switch (Tx_Rx.date.POMPA_Tx.Re_set)
{
// case 1: // slave transmite ca a resetat alarmele
// // nu execut nimic se seteaza Tx_Rx.date.POMPA_Tx.Re_set = 1 in Info_Help_RstAlarm()
// break;
case 2: case 5: //master a transmis ca a modificat setarile
POMPA = Tx_Rx.date.POMPA_Tx;
POMPA.Re_set = 0;//pun variabila pe zero deoarece POMPA urmeaza sa fie scris in memorie
Scrie_Citeste_EEPROM(2);//scrie datele primite
// ATENTIE MARE !!! se arde memoria
// prima data te joci cu variabila sa fi
// sigur ca transmisia se realizeaza o singura data
// Serial.println("qqqq");Serial.println(Tx_Rx.date.POMPA_Tx.Re_set);Serial.println(Tx_Rx.tip_STR);
if (Tx_Rx.date.POMPA_Tx.Re_set == 5 && Tx_Rx.tip_STR == 3)
{
lcd.setCursor(3, 2); lcd.write(uint8_t(0));
digitalWrite(PIN_BUZZER, HIGH); delay(50); digitalWrite(PIN_BUZZER, LOW);delay(500);
timp_RX = millis();
Tx_Rx.date.POMPA_Tx.Re_set = 0;
Tx_Rx.tip_STR = 0;
//return;
}
break;
// case 3: //slave transmite ca a modificat setarile
// // nu execut nimic - se seteaza Tx_Rx.date.POMPA_Tx.Re_set = 3 in sectiunea corespunzatoare
// break;
// case 4: //slave transmite ca sa resetat la setarile din fabrica
// // nu execut nimic - se seteaza Tx_Rx.date.POMPA_Tx.Re_set = 4 in sectiunea corespunzatoare
// break;
// case 5: //slave a intrat in flux si cere date de la master
// // nu execut nimic deoarece master o sa transmita ca
// // a modificat setarile si se executa instructiunile de case 2:
// break;
case 6: //master solicita date de la slave
Scrie_Citeste_EEPROM(3);//citeste datele stocat
// ATENTIE MARE !!! se arde memoria
// prima data te joci cu variabila sa fi
// sigur ca transmisia se realizeaza o singura data
Tx_Rx.date.POMPA_Tx = POMPA;
Tx_Rx.date.POMPA_Tx.Re_set = 6;//transmit ca si cum slave a modificat setarile
Tx_Rx.tip_STR = 3;// are valoarea 3 doar pt a verifica imperecherea
tx_HC12 ();
break;
case 7: // master sa resetat la setarile din fabrica
Scrie_Citeste_EEPROM(4);//pune in memorie byte-ul 1 la 0xFF sau in DEC 255
delay(2000);
resetFunc();//nu mai are ce confirmare sa transmita ca slave sa resetat
break;
// case 255: //confirmare primire date
// Tx_Rx.date.POMPA_Tx.Re_set = 0;
// Tx_Rx.tip_STR = 2;
// break;
}
return;
}
}
//Meniu == 0 ? 8000 : 2100
if ((millis() - timp_RX) >= (2500)) // verific transmisia
{
lcd.setCursor(0,0); lcd.print((char*)tmp); lcd.setCursor(0,3); lcd.print((char*)tmp);
lcd.setCursor(0,1); lcd.print(F(" ATENTIE! ")); lcd.setCursor(0,2); lcd.print(F(" MASTER NU TRANSMITE"));
digitalWrite( PIN_BUZZER, HIGH); delay(50);digitalWrite( PIN_BUZZER, LOW);
timp_RX = millis(); Meniu == 0 ? primit = false : primit = true; return;
}
} // end RX_HC12
/*********************** FUNCTII PENTRU AFISARE *********************************/
/************ FUNCTIE CARE AFISEAZA ALTERNANT STARE/ALARM IN CAZUL APARITIEI ALARMEI *************/
void Stare_Alarma ()
{
// in cazul aparitiei unei alarme se va afisa alternant STARE/ALARM
// si activez led si buzzer pe pin D13 (PB5) care sa atentioneze ca
// a aparut cel putin o alarma
bool tmp = false;
//static uint32_t timp_BUZZ = millis();
for (uint8_t i = 0; i <= 5; i++) { if (Tx_Rx.date.LCD.Alarma[i] > 0) tmp = true; }
if (tmp == true && _beep ) { digitalWrite( PIN_BUZZER, HIGH); delay(50); digitalWrite( PIN_BUZZER, LOW);}
//else {digitalWrite( PIN_BUZZER, LOW)
// if (tmp == true && _beep && mod) { if ((millis()-timp_BUZZ) > 800) {digitalWrite( PIN_BUZZER, HIGH); delay(50); digitalWrite( PIN_BUZZER, LOW);timp_BUZZ = millis();}}
// else {digitalWrite( PIN_BUZZER, LOW);timp_BUZZ = millis();}
} //End Stare_Alarma
/******************* FUNCTIE ALARME *************************/
// acesta functie scrie variabila LCD cu textul necesar afisarii alarmelor
//
void Alarme (int8_t& tipAlarma)
{
String tmp = "";
switch (tipAlarma)// elimin spatiile finale pt a elibera memorie
{
case 1: //PREA PLIN BAZIN 2
tmp = F("(A1) ALARM PREAPLIN"); strcpy(Tx_Rx.date.LCD.Line[0] , tmp.c_str());
tmp = F(" Verifica evacuarea."); strcpy(Tx_Rx.date.LCD.Line[1] , tmp.c_str());
tmp = F(" Sau debit peste"); strcpy(Tx_Rx.date.LCD.Line[2] , tmp.c_str());
tmp = F(" 100 litri / min."); strcpy(Tx_Rx.date.LCD.Line[3] , tmp.c_str());
break;
case 2: //PREA PLIN BAZIN 2
tmp = F("(A2) ALARM PREAPLIN"); strcpy(Tx_Rx.date.LCD.Line[0] , tmp.c_str());
tmp = F("Pompa Evac.P2.2 arsa"); strcpy(Tx_Rx.date.LCD.Line[1] , tmp.c_str());
tmp = F(" sau plutitor prea"); strcpy(Tx_Rx.date.LCD.Line[2] , tmp.c_str());
tmp = F("plin BAZIN 2 blocat."); strcpy(Tx_Rx.date.LCD.Line[3] , tmp.c_str());
break;
case 3: //EVACUARE
tmp = F("(A3) ALARM EVACUARE"); strcpy(Tx_Rx.date.LCD.Line[0] , tmp.c_str());
tmp = F("Pompa de evacuare in"); strcpy(Tx_Rx.date.LCD.Line[1] , tmp.c_str());
tmp = F("exterior P2.2 arsa."); strcpy(Tx_Rx.date.LCD.Line[2] , tmp.c_str());
tmp = F("Senzor nivel blocat."); strcpy(Tx_Rx.date.LCD.Line[3] , tmp.c_str());
break;
case 4: //EVACUARE
tmp = F("(A4)ALARM UMPLERE B2"); strcpy(Tx_Rx.date.LCD.Line[0] , tmp.c_str());
tmp = F("Senzorii de nivel"); strcpy(Tx_Rx.date.LCD.Line[1] , tmp.c_str());
tmp = F("defecti sau murdari/"); strcpy(Tx_Rx.date.LCD.Line[2] , tmp.c_str());
tmp = F("P1.2 umplere B2 arsa"); strcpy(Tx_Rx.date.LCD.Line[3] , tmp.c_str());
break;
case 5: //PREA GOL
tmp = F("(A5) ALARM PREA-GOL"); strcpy(Tx_Rx.date.LCD.Line[0] , tmp.c_str());
tmp = F(" ATENTIE !"); strcpy(Tx_Rx.date.LCD.Line[1] , tmp.c_str());
tmp = F(" NIVELUL APEI ESTE"); strcpy(Tx_Rx.date.LCD.Line[2] , tmp.c_str());
tmp = F(" SUB COTA ADMISA"); strcpy(Tx_Rx.date.LCD.Line[3] , tmp.c_str());
break;
case 6: //POMPE ARSE
tmp = F("(A6)ALARM POMPE ARSE"); strcpy(Tx_Rx.date.LCD.Line[0] , tmp.c_str());
tmp = F(" BAZIN 1| BAZIN 2"); strcpy(Tx_Rx.date.LCD.Line[1] , tmp.c_str());
tmp = F(" P11 P12|P21 P22 P23"); strcpy(Tx_Rx.date.LCD.Line[2] , tmp.c_str());
tmp = F("|"); strcpy(Tx_Rx.date.LCD.Line[3] , tmp.c_str()); // se va scrie in StareCiclu()
break;
}
}
/************************* FUNCTIE AFISARE STARE CICLU **************************************/
// Acesta functie afiseaza datele receptionate de la master
void StareCiclu ()
{
if (Meniu <0) Stare_Alarma();
if (Meniu > 0) return;
//delay(10);
if (Meniu == 0) return;
for ( uint8_t i = 0; i < 4; i++) {lcd.setCursor (0,i); lcd.print((char*)Tx_Rx.date.LCD.Line[i]);}
// if (alarma == 6)
// {
// for (uint8_t i = 2; i <= 18; i+=4)
// {
// lcd.setCursor (i, 3);
// if ( bitRead(Tx_Rx.date.LCD.Alarma[5], (i/4)) == 0) {lcd.write(uint8_t(0));}//afisarea se face invers stocarii
// else lcd.print("x");
// }
// }
// lcd.setCursor (0,0); lcd.print((char*)Tx_Rx.date.LCD.Line0);
// lcd.setCursor (0,1); lcd.print((char*)Tx_Rx.date.LCD.Line1);
// lcd.setCursor (0,2); lcd.print((char*)Tx_Rx.date.LCD.Line2);
// lcd.setCursor (0,3); lcd.print((char*)Tx_Rx.date.LCD.Line3);
}// end StareCiclu
/************************************************************************************/
void setup()
{
//initialize the lcd
lcd.backlight();
lcd.init();
lcd.setCursor(3,1);
lcd.print(F("xINITIALIZARE"));
// Create new characters:
uint8_t Check[] = {
B00000,
B00000,
B00001,
B00010,
B10100,
B01000,
B01000,
B00000
};
lcd.createChar(0, Check);
// Variabile Meniu
Meniu = -1;
subMeniuAERARE = -1;
subMeniuEVACUARE = -1;
subMeniuRECIRCULARE = -1;
subMeniuFLOCULANT = -1;
subMeniuRESET_ALARME = -1;
subMeniuRESET_FABRICA = -1;
subMeniuBazin_1_AERARE = -1;
subMeniuBazin_2_AERARE = -1;
_blink = true;
// Initializarea datelor implicite pentru POMPA
POMPA.Bazin_1_Aerare = 60;
POMPA.Bazin_1_Linistire = 60;
POMPA.Bazin_2_Aerare = 60;
POMPA.Bazin_2_Linistire = 60;
POMPA.PornireEvacuare = 20;
POMPA.LinistireEvacuare = 20;
POMPA.PornireRecirculare = 30;
POMPA.AsteptareRecirculare = 1;
POMPA.PompaPeristaltica_B1 = 10.0;
POMPA.PompaPeristaltica_B2 = 5.0;
POMPA.Re_set = 0;
// // POMPA_Tx ar trebui sa fie initializata la fel sau copiata din POMPA
Tx_Rx.date.POMPA_Tx = POMPA;
// Initializarea datelor pentru LCD (daca e cazul)
String tmp = F(" ");
for(int i = 0; i < 4; i++) {
strcpy(Tx_Rx.date.LCD.Line[i],tmp.c_str()); // Inițializare cu spații
}
for(int i = 0; i < 5; i++) {
Tx_Rx.date.LCD.Temperatura[i] = 0.0;
}
for(int i = 0; i < 6; i++) {
Tx_Rx.date.LCD.Alarma[i] = 0;
}
Serial.begin(9600);//initialize the serial
// lcd.setCursor(4,1);
// lcd.print(F("INITIALIZARE"));
// initializare pin buzzer
pinMode(PIN_BUZZER, OUTPUT);// se foloseste pentru dispozitivul SLAVE
digitalWrite(PIN_BUZZER, LOW);
pinMode(PIN_BUTON_SETUP, INPUT_PULLUP);
pinMode(PIN_BUTON_TIMP_MINUS, INPUT_PULLUP);
pinMode(PIN_BUTON_TIMP_PLUS, INPUT_PULLUP);
pinMode(PIN_BUTON_RST_ALARMA, INPUT_PULLUP);
pinMode(PIN_BUTON_MOD, INPUT_PULLUP);
Scrie_Citeste_EEPROM(0);// aici trebuie sa fie apelata inainte de functia
// Initializare_Ciclu() pt a fi stocate valorile
// de initializare a variabilelor la prima scriere
// a programului pe Mcu
// printez check
delay(500);
lcd.setCursor(3, 1);
lcd.write(uint8_t (0));
digitalWrite(PIN_BUZZER, HIGH);
delay(50);
digitalWrite(PIN_BUZZER, LOW);
delay(1000);
lcd.setCursor(3,2);
lcd.print(F("xIMPERECHERE"));
// transfer date wireles HC12
HC12_Transfer_TX.begin(details(Tx_Rx), &Serial); // transmitere catre master date wireles prin portul fizic UART
HC12_Transfer_RX.begin(details(Tx_Rx), &Serial); // receptionare de la master date wireles prin portul fizic UART
//solicita date de la master
// Tx_Rx.date.POMPA_Tx = POMPA;
// Tx_Rx.date.POMPA_Tx.Re_set = 5;
// Tx_Rx.tip_STR = 2;
// tx_HC12 ();
setup_Tx_Rx = true;
digitalWrite(PIN_BUZZER, HIGH);
delay(50);
digitalWrite(PIN_BUZZER, LOW);
//delay(500);
timp_RX = millis();//este folosita pentru determinarea afisarii ca master nu transmite
}// end setup()
void loop()
{
//nu schimba ordinea liniilor in loop()
static uint32_t timp_BUZZ = millis();
if ((millis()-timp_BUZZ) >= 1000 && Meniu == 0 ) {Stare_Alarma();timp_BUZZ = millis();}
//else timp_BUZZ = millis();
Defilare_Meniu_Setup(); // intra in meniul SETUP cand buttonSETUP este apasata
if (Meniu > 0) return;
if ((PIND & (1 << PD7)) == 0 ||(PIND & (1 << PD4)) == 0 ||(PIND & (1 << PD5)) == 0 ) {Info_Help_RstAlarm();}//intra in info sau help cand este apasat butonul - sau +
for(uint8_t i = 0; i<5; i++) {rx_HC12 ();delay(10);} // receptionare date POMPA_Set
delay(10);
if (setup_Tx_Rx && Tx_Rx.tip_STR == 1)
{
Tx_Rx.date.POMPA_Tx = POMPA;
Tx_Rx.date.POMPA_Tx.Re_set = 5;
Tx_Rx.tip_STR = 2;
setup_Tx_Rx = false;
}
tx_HC12 ();// transmite catre slave POMPA_Set
}//end loop()
/************************ STOCARE SETARI IN MEMORIA EEPROM ************************/
// Acesta functie citeste sau scrie valorile variabilelor globale necesare stabilirii
// timpilor utilizati intr-un ciclu de epurare
// Aceasta functie este folosita in meniul Setup pentru stocarea modificarii variabilelor,
// in functia Initializare_Ciclu () si in functia setup()
// o scriere dureaza aproximativ 3.3 ms/octet la care se aduna si durata codului functiei
// din cate am citit EEPROM este sters odata cu instalarea unui program si toti bitii sunt 0xFF adica 1111 1111 sau 255 dec
// acest fapt este de verificat fizic
void Scrie_Citeste_EEPROM (uint8_t flag)
{
// flag = 0 functia este folosita in functia setup()
// 1 functia este folosita in functia Initializare_Ciclu ()
// 2 functia este folosita in meniul Setup si salveaza varibila
// pentru a nu se afecta ciclul in care se afla statia
// 3 se va citi continutul memoriei
// 4 scrie primul octe 0xFF adica 1111 1111 sau 255 dec
// octetul de la adresa 0 are = 0xFF adica 1111 1111 sau 255 dec, daca programul este incarcat in Mcu prima oara
// indicativul, adica valoarea = 0x80 adica 1000 0000 sau 128 dec, daca memoria contine stocate valori nemodificate
// stocata = 0x40 adica 0100 0000 sau 64 dec, daca daca memoria a fost modificata in meniul Setup
// acest octet este necesar mai ales la resetarea Mcu pt initializarea variabilelor prin pastrarea setarilor
// cu acesta functie se stocheaza primul octet si " struct POMPE " adica variabila POMPA
// initializarea de tip bloc se realizeaza in functia setup() si in functia Initializare_Ciclu ()
// pentru AERARE si RECIRCULARE initializarea se face individual la fiecare final de ciclu
// astfel incat sa nu se afecteze buna functionare a statiei in timpul setarii in meniul Setup
// daca parametrii introdusi sunt gresiti aceasta functie genereaza erori necontrolabile
return;
{
uint16_t EE_Address = 0;
uint8_t indicativ = 0;// valoarea primului octet
EEPROM.get(0, indicativ);
EE_Address += sizeof (indicativ); // calculez adresa de stocare pt. tmp_POMPA
switch (flag)
{
case 0: // functia setup()
if (indicativ == 0xFF) {indicativ = 0x80; EEPROM.put(0, indicativ); EEPROM.put(EE_Address, POMPA);}// prima rulare a programului
else {EEPROM.get(EE_Address, POMPA);}// se initializeaza la fiecare resetare
break;
//cazul 1 nu se foloseste aici // case 1: // functia Initializare_Ciclu ()
// if (indicativ == 0x40) {indicativ = 0x80; EEPROM.put(0, indicativ); EEPROM.get(EE_Address, POMPA);}
// break;
case 2: // meniul Setup - se va stoca la EXIT din setup
EEPROM.put(0, 0x40); EEPROM.put(EE_Address, POMPA);
break;
case 3: // se va citi continutul memoriei pentru reinitializare variabile în setare timp pompe
EEPROM.get(EE_Address, POMPA);
break;
case 4: // scrie primul octet 0xFF adica 1111 1111 sau 255 dec, pentru resetare fabrica se foloseste in functia Defilare_Meniu_Setup
EEPROM.put(0, 0xFF);
break;
}
}
}// end Scrie_Citeste_EEPROM
/**********************************************************************************/
/******************** FUNCTIE Button_Timp_PLUS_MINUS *****************************/
// Acesta functie adauga sau scade timp in timpul Meniului setup pentru
// modificarea parametrilor de functionare
//Intervalele min. max. si pasul de incrementre se regasesc in sectiune de declarare variabile globale
// modificat este diferit de 0 si suntem in meniul anterior se vor salva valorile modificate
void Button_Timp_PLUS_MINUS( int16_t& val_11, int16_t& val_22)
{
// val_11 si val_22 sunt adresele acelorasi variabile din functia Blink_Meniu() si nu trebuie confundate
// salvarea se realizeaza in meniul EXIT din setup
// static uint8_t modificat = 0; //daca se fac modificari se vor salva cand se paraseste meniul
// // prin SAVE&EXIT si ia urmatoarele valori
// // 1 AERARE BAZIN 1
// // 2 AERARE BAZIN 2
// // 3 EVACUARE
// // 4 RECIRCULARE
// // 5 DOZARE FLOCULANT
bool PBTplus = false;
bool PBTminus = false;
if ((PIND & (1 << PD5)) == 0) PBTplus = Timp_Apasare_BTN(PIN_BUTON_TIMP_PLUS, 200);
if ((PIND & (1 << PD4)) == 0) PBTminus = Timp_Apasare_BTN(PIN_BUTON_TIMP_MINUS, 200);
/*---------------- AERARE BAZIN 1 -------------------*/
if (subMeniuBazin_1_AERARE == 1 )// AERARE
{
if (POMPA.Bazin_1_Aerare <= 230) {if (PBTplus) POMPA.Bazin_1_Aerare += 10; /*modificat = 1;*/ init_SETUP = true;}
if (POMPA.Bazin_1_Aerare >= 40 ) {if (PBTminus) POMPA.Bazin_1_Aerare -= 10; /*modificat = 1;*/ init_SETUP = true;}
val_11 = POMPA.Bazin_1_Aerare; val_22 = POMPA.Bazin_1_Linistire / 60; return;
}
else if (subMeniuBazin_1_AERARE == 2 )// LINISTIRE
{
if (POMPA.Bazin_1_Linistire <= 3300) {if (PBTplus) POMPA.Bazin_1_Linistire += 300; /*modificat = 1;*/ init_SETUP = true;}
if (POMPA.Bazin_1_Linistire >= 600 ) {if (PBTminus) POMPA.Bazin_1_Linistire -= 300; /*modificat = 1;*/ init_SETUP = true;}
val_11 = POMPA.Bazin_1_Aerare; val_22 = POMPA.Bazin_1_Linistire / 60; return;
}
else if (subMeniuBazin_1_AERARE == 3 ) {val_11 = POMPA.Bazin_1_Aerare; val_22 = POMPA.Bazin_1_Linistire / 60; return;}
/*---------------- AERARE BAZIN 2 -------------------*/
if (subMeniuBazin_2_AERARE == 1 )//AERARE
{
if (POMPA.Bazin_2_Aerare <= 230) {if (PBTplus) POMPA.Bazin_2_Aerare += 10; /*modificat = 2;*/ init_SETUP = true;}
if (POMPA.Bazin_2_Aerare >= 40 ) {if (PBTminus) POMPA.Bazin_2_Aerare -= 10; /*modificat = 2;*/ init_SETUP = true;}
val_11 = POMPA.Bazin_2_Aerare; val_22 = POMPA.Bazin_2_Linistire / 60; return;
}
else if (subMeniuBazin_2_AERARE == 2 )//LINISTIRE
{
if (POMPA.Bazin_2_Linistire <= 3300) {if (PBTplus) POMPA.Bazin_2_Linistire += 300; /*modificat = 2;*/ init_SETUP = true;}
if (POMPA.Bazin_2_Linistire >= 600 ) {if (PBTminus) POMPA.Bazin_2_Linistire -= 300; /*modificat = 2;*/ init_SETUP = true;}
val_11 = POMPA.Bazin_2_Aerare; val_22 = POMPA.Bazin_2_Linistire/60; return;
}
else if (subMeniuBazin_2_AERARE == 3 ) {val_11 = POMPA.Bazin_2_Aerare; val_22 = POMPA.Bazin_2_Linistire / 60; return;}
/*---------------- EVACUARE -------------------*/
if (subMeniuEVACUARE == 1 )//EVACUARE
{
if (POMPA.PornireEvacuare <= 290) {if (PBTplus) POMPA.PornireEvacuare += 10; /*modificat = 3;*/ init_SETUP = true;}
if (POMPA.PornireEvacuare >= 190 ) {if (PBTminus) POMPA.PornireEvacuare -= 10; /*modificat = 3;*/ init_SETUP = true;}
val_11 = POMPA.PornireEvacuare; val_22 = POMPA.LinistireEvacuare / 60; return;
}
else if (subMeniuEVACUARE == 2 )//LINISTIRE evacuare
{
if (POMPA.LinistireEvacuare <= 3600) {if (PBTplus) POMPA.LinistireEvacuare += 300; /*modificat = 3;*/ init_SETUP = true;}
if (POMPA.LinistireEvacuare >= 600 ) {if (PBTminus) POMPA.LinistireEvacuare -= 300; /*modificat = 3;*/ init_SETUP = true;}
val_11 = POMPA.PornireEvacuare; val_22 = POMPA.LinistireEvacuare/60; return;
}
else if (subMeniuEVACUARE == 3 ) {val_11 = POMPA.PornireEvacuare; val_22 = POMPA.LinistireEvacuare/60; return;}
/*---------------- RECIRCULARE -------------------*/
if (subMeniuRECIRCULARE == 1 )//RECIRCULARE amestec
{
if (POMPA.PornireRecirculare <= 115) {if (PBTplus) POMPA.PornireRecirculare += 5; /*modificat = 4;*/ init_SETUP = true;}
if (POMPA.PornireRecirculare >= 20 ) {if (PBTminus) POMPA.PornireRecirculare -= 5; /*modificat = 4;*/ init_SETUP = true;}
val_11 = POMPA.PornireRecirculare; val_22 = POMPA.AsteptareRecirculare; return;
}
else if (subMeniuRECIRCULARE == 2 )//INTERVAL RECIRCULARE perioada de timp la care se realizeaza
{
if (POMPA.AsteptareRecirculare <= 7) {if (PBTplus) POMPA.AsteptareRecirculare += 1; /*modificat = 4;*/ init_SETUP = true;}
if (POMPA.AsteptareRecirculare >= 4 ) {if (PBTminus) POMPA.AsteptareRecirculare -= 1; /*modificat = 4;*/ init_SETUP = true;}
val_11 = POMPA.PornireRecirculare; val_22 = POMPA.AsteptareRecirculare; return;
}
else if (subMeniuRECIRCULARE == 3 ) {val_11 = POMPA.PornireRecirculare; val_22 = POMPA.AsteptareRecirculare; return;}
/*----------------- FLOCULANT ---------------------*/
if (subMeniuFLOCULANT == 1 )//DOZARE BAZIN 1
{
if (POMPA.PompaPeristaltica_B1 <= 19) {if (PBTplus) POMPA.PompaPeristaltica_B1 += 1; /*modificat = 5;*/ init_SETUP = true;}
if (POMPA.PompaPeristaltica_B1 >= 1 ) {if (PBTminus) POMPA.PompaPeristaltica_B1 -= 1; /*modificat = 5;*/ init_SETUP = true;}
val_11 = POMPA.PompaPeristaltica_B1; val_22 = POMPA.PompaPeristaltica_B2; return;
}
else if (subMeniuFLOCULANT == 2 )//DOZARE BAZIN 2
{
if (POMPA.PompaPeristaltica_B2 <= 19) {if (PBTplus) POMPA.PompaPeristaltica_B2 += 1; /*modificat = 5;*/ init_SETUP = true;}
if (POMPA.PompaPeristaltica_B2 >= 1 ) {if (PBTminus) POMPA.PompaPeristaltica_B2 -= 1; /*modificat = 5;*/ init_SETUP = true;}
val_11 = POMPA.PompaPeristaltica_B1; val_22 = POMPA.PompaPeristaltica_B2; return;
}
else if (subMeniuFLOCULANT == 3 ) {val_11 = POMPA.PompaPeristaltica_B1; val_22 = POMPA.PompaPeristaltica_B2; return;}
}// end Button_Timp_PLUS_MINUS
/*************************************************************************************/
/************ FUNCTIE CARE DETERMINA CAT TIMP ESTE APASAT UN BUTON *******************/
// Aceasta fuctie determina cat timp este apasat butonul
// Daca timpAPASARE este egal cu zero returneaza
// TIMPUL MAXIM DE APASARE ESTE 2^32-1 MILISECUNDE APROXIMATIV 50 ZILE APOI SE RESETEAZA
// Variabila " start " reprezinta timpul la care a fost apasat butonul si se determina
// cu functia arduino " millis() "
// Variabila " timpAPASARE " reprezinta timpul necesar de apasare ca butonul sa produca efect si este dat in milisecude,
// In interiorul functiei calculul se realizeaza in milisecunde deoarece valoarea " start " este data de functia " millis() "
// ATENTIE!!! - ACEASTA FUNCTIE NU ESTE IDENTICA CU CEA DE LA MASTER
// LA MASTER SE BAZEAZA PE INTARZIEREA TRANSMISIEI PE I2C
bool Timp_Apasare_BTN (const uint8_t btnPIN, const uint16_t timpAPASARE)
{
uint32_t blink = millis();
uint32_t start = millis();
if ((PIND & (1 << btnPIN)) != 0) {return false;}
lcd.backlight(); _backlight = 1;//aprinde afisajul LCD cand este apasat orice buton
while((PIND & (1 << btnPIN)) == 0)
{
if ((millis() - start) <= timpAPASARE) digitalWrite( 12, HIGH);
else
{
//creaza efectul de palpaire al ledului corespunzator butonului apasat
digitalWrite( 12, LOW);
if (timpAPASARE != 1000) {timp_RX = millis(); return true;}
blink = millis();
while((millis() - blink) < 200) {}
blink = millis();
digitalWrite( 12, HIGH);
while((millis() - blink) < 200 ) {}//nu se foloseste la incrementare/decrementare
if (btnPIN == PIN_BUTON_RST_ALARMA && ((millis() - start) >= timpAPASARE * 3)) //activeaza sau dezactiveaza buzzer-ul
{
_beep = !_beep;
lcd.clear(); lcd.setCursor(2, 0); lcd.print(F("< Sunet Alarma >"));lcd.setCursor(9, 2);lcd.print(_beep == true ? F("ON") : F("OFF"));
digitalWrite( 12, HIGH);
while((PIND & (1 << btnPIN)) == 0){}
lcd.clear();
}
}
}
digitalWrite( 12, LOW);
if (btnPIN == PIN_BUTON_RST_ALARMA && ((millis() - start) >= timpAPASARE * 3)) {timp_RX = millis(); return false;}//nu anuleaza alarmele cand este activat sau dezactivat buzzer-ul
else if ((millis() - start) >= (timpAPASARE == 1000 ? timpAPASARE : timpAPASARE/4)) //timpAPASARE/4 este folosit pentru incrementare valori setari
{
if (btnPIN == PIN_BUTON_RST_ALARMA) {lcd.clear(); lcd.setCursor(0, 1); lcd.print(F("* ALARME RESETATE *")); delay(1500); lcd.clear();}
timp_RX = millis(); return true;
}
else {timp_RX = millis(); return false;}
}//end Timp_Apasare_BTN
/**********************************************************************/
/*********************** FUNCTIE Blink_Meniu ***********************/
// Acesata functie afiseaza meniul pentru afisaj 20x4
// Meniul selectat va clipi
// Prima linie a afisajului este folosita pentru titlu
// Sunt afisate doar trei linii de meniu
// Denumirea meniului nu trebuie sa fie mai mare de 14 caractere daca este
// necesara introducere de date, altfel sa nu depasasca 18 caractere
// sel reprezinta pozitia meniului selectat
// sel reprezinta linia de afisare cu valori 1, 2 sau 3
// val_ reprezinta valorile variabilelor care se vor afisa modificate prin introducere de date
// UM_ reprezinta unitatea de masura
void Blink_Meniu ( uint8_t sel, String meniu_1 = "", String meniu_2 = "", String meniu_3 = "",
int16_t val_1 = -1, int16_t val_2 = -1,
String UM_1 = "", String UM_2 = "" )
{
String PU = F("< >");
String PUM = F(">>");
String SP1 = F(" ");
String SP2 = F(" ");
String SP3 = F(" ");
static uint32_t previousMillis = millis();
if ( _blink )
{
switch (sel) // stabileste meniul selectat
{
case 1: meniu_1 = (subMeniuRESET_FABRICA != -1 ? "" : (PUM + SP1)) + meniu_1; meniu_2 = (subMeniuRESET_FABRICA != -1 ? "" : SP2) + meniu_2 ; meniu_3 = (subMeniuRESET_FABRICA != -1 ? "" : SP2) + meniu_3 ; break;
case 2: meniu_1 = (subMeniuRESET_FABRICA != -1 ? "" : SP2) + meniu_1 ; meniu_2 = (subMeniuRESET_FABRICA != -1 ? "" : (PUM + SP1)) + meniu_2; meniu_3 = (subMeniuRESET_FABRICA != -1 ? "" : SP2) + meniu_3 ; break;
case 3: meniu_1 = (subMeniuRESET_FABRICA != -1 ? "" : SP2) + meniu_1 ; meniu_2 = (subMeniuRESET_FABRICA != -1 ? "" : SP2) + meniu_2 ; meniu_3 = (subMeniuRESET_FABRICA != -1 ? "" : (PUM + SP1)) + meniu_3; break;
}
for ( uint8_t i = 1; i <= (UM_1 != "" ? 13:20); i++ ) {if (meniu_1.length() < (UM_1 != "" ? 13:20)) {meniu_1 += SP1;} } // se adauga spatii
for ( uint8_t i = 1; i <= (UM_2 != "" ? 13:20); i++ ) {if (meniu_2.length() < (UM_2 != "" ? 13:20)) {meniu_2 += SP1;} } // se adauga spatii
for ( uint8_t i = 1; i <= 20; i++ ) {if (meniu_3.length() < 20) {meniu_3 += SP1;} } // se adauga spatii
lcd.setCursor(0, 1); lcd.print( meniu_1 );
lcd.setCursor(0, 2); lcd.print( meniu_2 );
lcd.setCursor(0, 3); lcd.print( meniu_3 );
if (UM_1 != "") { lcd.setCursor(17, 1); lcd.print(UM_1);}
if (UM_2 != "") { lcd.setCursor(17, 2); lcd.print(UM_2);}
_blink = false;
}
//lcd.backlight(); _backlight = 1; // cand se afla in setare nu se stinge afisajul
if (((Meniu >= 8 && Meniu <= 10) || subMeniuAERARE >=4 ) && sel != 3 ) Button_Timp_PLUS_MINUS( val_1, val_2);
uint32_t currentMillis = millis();
if ( ((PIND & (1 << PD4)) == 0 || (PIND & (1 << PD5)) == 0) && ((Meniu >= 8 && Meniu <= 10) || subMeniuAERARE >=4 ) && sel != 3) {previousMillis = currentMillis;}//cand sunt apasate butoanele Plus Minus nu mai palpaie
delay(100);//teoretic aceasta intarziere este necesara doar pt wokwi, fara ea se reseteaza
//trebuie verificat fizic pe controler
if ((currentMillis - previousMillis) <= 350)
{
lcd.setCursor(0, sel); lcd.print(subMeniuRESET_FABRICA != -1 ? meniu_2 : PUM);
if (val_1 != -1) { lcd.setCursor(14, 1); lcd.print(val_1); if (val_1 < 10) lcd.print(SP1); if (val_1 < 100) lcd.print(SP1); }
if (val_2 != -1) { lcd.setCursor(14, 2); lcd.print(val_2); if (val_2 < 10) lcd.print(SP1); if (val_2 < 100) lcd.print(SP1); }
}
else if ((currentMillis - previousMillis) <= 600 )
{
if (val_1 != -1 && sel == 1) { lcd.setCursor(14, sel); lcd.print(SP3);}// afiseaza 3 spatii si creaza efectul de clipire citire date
else if (val_2 != -1 && sel == 2) { lcd.setCursor(14, sel); lcd.print(SP3);}// afiseaza 3 spatii si creaza efectul de clipire citire date
else if (subMeniuRESET_FABRICA == 1) { lcd.setCursor(3, 2 ); lcd.print(PU);}
else if (subMeniuRESET_FABRICA == 2) { lcd.setCursor(11, 2); lcd.print(PU);}
else { lcd.setCursor(0, sel); lcd.print(SP2); }//afiseaza 2 spatii si creaza efectul de clipire meniu
}
else {previousMillis = millis();}
}//end Blink_Meniu
/***************** FUNCTIE Afisare_Meniu ********************/
// Aceasta functie afiseaza Meniul si Meniul selectat prin licarire si marcat cu caracterul ">"
// Functia este utilizata in interiorul functiei Defilare_Meniu ()
void Afisare_Meniu_Setup ()
{
String AERARE = F("AERARE");
String EVACUARE = F("EVACUARE");
String RECIRCULARE = F("RECIRCULARE");
String BAZIN_1 = F("BAZIN 1");
String BAZIN_2 = F("BAZIN 2");
String EXIT = F("EXIT");
String PORNIRE = F("PORNIRE");
String LINISTIRE = F("LINISTIRE");
String ASTEPTARE = F("ASTEPTARE");
String SAVE_EXIT = F("SAVE & EXIT");
String ORE = F("ore");
String MIN = F("min");
String SEC = F("sec");
String RESET_FABRICA = F("RESETARE FABRICA");
//String DA = F("DA");
//String NU = F("NU");
String FLOCULANT = F("DOZARE FLOCULANT");
String DOZAJ_BAZIN_1 = F("BAZIN 1");
String DOZAJ_BAZIN_2 = F("BAZIN 2");
String ML = F("ml");
if (Meniu >= 1 && Meniu <= 6) { lcd.setCursor(0, 0); lcd.print(F("------ SETARE ------"));}
// Meniu principal 1 - AERARE
if (Meniu == 1) {Blink_Meniu ( 1, AERARE, EVACUARE, RECIRCULARE );}
// Meniu principal 2 - EVACUARE
else if (Meniu == 2) {Blink_Meniu ( 2, AERARE, EVACUARE, RECIRCULARE );}
// Meniu principal 3 - RECIRCULARE
else if (Meniu == 3) {Blink_Meniu ( 3, AERARE, EVACUARE, RECIRCULARE );}
// Meniu principal 4 - DOZARE FLOCULANT
else if (Meniu == 4) {Blink_Meniu ( 3, EVACUARE, RECIRCULARE, FLOCULANT );}
// Meniu principal 5 - RESET FABRICA
else if (Meniu == 5) {Blink_Meniu ( 3, RECIRCULARE, FLOCULANT, RESET_FABRICA );}
// Meniu principal 6 - EXIT
else if (Meniu == 6) {Blink_Meniu ( 3, FLOCULANT, RESET_FABRICA, EXIT );}
// Meniu AERARE
else if (Meniu == 7)
{
if (subMeniuAERARE >= 1 && subMeniuAERARE <= 3) { lcd.setCursor(0, 0); lcd.print(F("-- SETARE: AERARE --"));}
// subMeniuAERARE
if (subMeniuAERARE == 1) {Blink_Meniu ( 1, BAZIN_1, BAZIN_2, EXIT ); }
else if (subMeniuAERARE == 2) {Blink_Meniu ( 2, BAZIN_1, BAZIN_2, EXIT ); }
else if (subMeniuAERARE == 3) {Blink_Meniu ( 3, BAZIN_1, BAZIN_2, EXIT ); }
//Aerare BAZIN 1
else if (subMeniuAERARE == 4)
{
lcd.setCursor(0, 0); lcd.print(F("-- AERARE BAZIN 1 --"));
//AERARE
if (subMeniuBazin_1_AERARE == 1) {Blink_Meniu ( 1, AERARE, LINISTIRE, SAVE_EXIT,POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60, SEC, MIN ); }
//LINISTIRE
else if (subMeniuBazin_1_AERARE == 2) {Blink_Meniu ( 2, AERARE, LINISTIRE, SAVE_EXIT,POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60, SEC, MIN ); }
//SAVE & EXIT
else if (subMeniuBazin_1_AERARE == 3) {Blink_Meniu ( 3, AERARE, LINISTIRE, SAVE_EXIT,POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60, SEC, MIN ); }
}
// Aerare BAZIN 2
else if (subMeniuAERARE == 5)
{
lcd.setCursor(0, 0); lcd.print(F("-- AERARE BAZIN 2 --"));
//AERARE
if (subMeniuBazin_2_AERARE == 1) {Blink_Meniu ( 1, AERARE, LINISTIRE, SAVE_EXIT,POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60, SEC, MIN ); }
//LINISTIRE
else if (subMeniuBazin_2_AERARE == 2) {Blink_Meniu ( 2, AERARE, LINISTIRE, SAVE_EXIT,POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60, SEC, MIN ); }
//SAVE & EXIT
else if (subMeniuBazin_2_AERARE == 3) {Blink_Meniu ( 3, AERARE, LINISTIRE, SAVE_EXIT,POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire/60, SEC, MIN ); }
}
}
// Meniu EVACUARE
else if (Meniu == 8)
{
// subMeniuEVACUARE
lcd.setCursor(0, 0); lcd.print(F("----- EVACUARE -----"));
//EVACUARE
if (subMeniuEVACUARE == 1) Blink_Meniu ( 1, EVACUARE, LINISTIRE, SAVE_EXIT, POMPA.PornireEvacuare, POMPA.LinistireEvacuare/60, SEC, MIN );
//LINISTIRE
else if (subMeniuEVACUARE == 2) Blink_Meniu ( 2, EVACUARE, LINISTIRE, SAVE_EXIT, POMPA.PornireEvacuare, POMPA.LinistireEvacuare/60, SEC, MIN );
//SAVE & EXIT
else if (subMeniuEVACUARE == 3) Blink_Meniu ( 3, EVACUARE, LINISTIRE, SAVE_EXIT, POMPA.PornireEvacuare, POMPA.LinistireEvacuare/60, SEC, MIN );
}
// Meniu RECIRCULRE
else if (Meniu == 9)
{
// subMeniuRECIRCULARE
lcd.setCursor(0, 0); lcd.print(F("---- RECIRCULARE ---"));
//PORNIRE
if (subMeniuRECIRCULARE == 1) Blink_Meniu ( 1, PORNIRE, ASTEPTARE , SAVE_EXIT, POMPA.PornireRecirculare, POMPA.AsteptareRecirculare, SEC , ORE );
//ASTEPTARE
else if (subMeniuRECIRCULARE == 2) Blink_Meniu ( 2, PORNIRE, ASTEPTARE , SAVE_EXIT, POMPA.PornireRecirculare, POMPA.AsteptareRecirculare, SEC , ORE );
// SAVE & EXIT
else if (subMeniuRECIRCULARE == 3) Blink_Meniu ( 3, PORNIRE, ASTEPTARE , SAVE_EXIT, POMPA.PornireRecirculare, POMPA.AsteptareRecirculare, SEC , ORE );
}
// Meniu DOZARE FLOCULANT
else if (Meniu == 10)
{
// subMeniuFLOCULANT
lcd.setCursor(0, 0); lcd.print(F("- DOZARE FLOCULANT -"));
//DOZAJ BAZIN 1
if (subMeniuFLOCULANT == 1) Blink_Meniu ( 1, DOZAJ_BAZIN_1, DOZAJ_BAZIN_2 , SAVE_EXIT, POMPA.PompaPeristaltica_B1, POMPA.PompaPeristaltica_B2, ML, ML);
//DOZAJ BAZIN 2
else if (subMeniuFLOCULANT == 2) Blink_Meniu ( 2, DOZAJ_BAZIN_1, DOZAJ_BAZIN_2 , SAVE_EXIT, POMPA.PompaPeristaltica_B1, POMPA.PompaPeristaltica_B2, ML, ML);
//SAVE & EXIT
else if (subMeniuFLOCULANT == 3) Blink_Meniu ( 3, DOZAJ_BAZIN_1, DOZAJ_BAZIN_2 , SAVE_EXIT, POMPA.PompaPeristaltica_B1, POMPA.PompaPeristaltica_B2, ML, ML);
}
// Meniu RESET FABRICA
else if (Meniu == 11)
{
//RESETARE FABRICA
lcd.setCursor(0, 0); lcd.print(F("- RESETARE FABRICA -"));
//NU
if (subMeniuRESET_FABRICA == 1) Blink_Meniu ( 2, F(""), F(" < NU > DA") );
//DA
else if (subMeniuRESET_FABRICA == 2) Blink_Meniu ( 2, F(""), F(" NU < DA >") );
}
}// end Afisare_Meniu_Setup
/**********************************************************************************************/
/***************** FUNCTIE CARE DEFILEZA MeniuL SETARE CU UN SINGUR BUTON ********************/
// Cand este chemata modifica valoare variabilei " Meniu ".
// Functia este executata numai cand valorea variabilei " Meniu " este >= 1
// Cand variabila " Meniu = -1 " microcontroler-ul executa alte operatii
// Daca butonul SETARE este apasat >= 1 secunda programul intra in modul setare
// Daca butonul SETARE este apasat >= 1 secunda pe subMeniu se intra in subMeniuri
// Daca butonul SETARE este apasat 0.45 - 0.9 secunde defileaza intre meniuri
void Defilare_Meniu_Setup ()
{
if (Meniu == 0 ) return;
Afisare_Meniu_Setup();
if (Meniu <= 0 && init_SETUP) {init_SETUP = false;}
if (Meniu == -1 && (PIND & (1 << PD6)) != 0) return;//digitalRead(PIN_BUTON_SETUP)) return;
//if (Meniu == -1 && digitalRead(PIN_BUTON_SETUP)) return;
//if (digitalRead(PIN_BUTON_SETUP)) return;
if ((PIND & (1 << PD6)) != 0) return;//daca nu este apasat butonul SETUP
bool timp = Timp_Apasare_BTN ( PIN_BUTON_SETUP, 1000 );// returneaza intotdeauna TRUE sau FALSE
// deoarece timpAPASARE este diferit de zero
_blink = true;
switch (Meniu) { // Meniul principal are 4 submeniuri
case -1: // intra in modul SETARE
if (timp) { Meniu = 1; lcd.clear (); Scrie_Citeste_EEPROM(3);}//sa intrat in setari si se citeste POMPA_Set
break;
case 1: // Meniu principal 1 - AERARE
if (!timp) { Meniu ++; }
else { Meniu = 1 + 6; subMeniuAERARE = 1; lcd.clear(); }
break;
case 2: // Meniu principal 2 - EVACUARE
if (!timp) { Meniu ++; }
else { Meniu = 2 + 6; subMeniuEVACUARE = 1; lcd.clear(); }
break;
case 3: // Meniu principal 3 - RECIRCULARE
if (!timp) { Meniu ++; }
else { Meniu = 3 + 6; subMeniuRECIRCULARE = 1; lcd.clear(); }
break;
case 4: // Meniu principal 4 - DOZAJ FLOCULANT
if (!timp) { Meniu ++; }
else { Meniu = 4 + 6 ; subMeniuFLOCULANT = 1; lcd.clear(); }
break;
case 5: // Meniu principal 4 - RESET FABRICA
if (!timp) { Meniu ++; }
else { Meniu = 5 + 6 ; subMeniuRESET_FABRICA = 1; lcd.clear(); }
break;
case 6: // Meniu principal 4 - EXIT
if (!timp) { Meniu = 1; }
else
{
Meniu = -1 ; subMeniuAERARE = -1; subMeniuEVACUARE = -1; subMeniuRECIRCULARE = -1; subMeniuRESET_FABRICA = -1;
POMPA.Re_set = 0;
Scrie_Citeste_EEPROM(2);//salveaza modificarile efectuate in setup
lcd.clear();
init_SETUP = false;
Tx_Rx.tip_STR = 2;//transmite Tx_Rx
Tx_Rx.date.POMPA_Tx = POMPA;
Tx_Rx.date.POMPA_Tx.Re_set = 3;//slave transmite ca amodificat setarile
tx_HC12 ();
}
break;
case 7: // Meniu secundar 1 - AERARE
switch (subMeniuAERARE) { // subMeniuAERARE are 3 subMeniuri bazin 1 bazin 2 exit
case 1: // sub Meniu BAZN 1
if (!timp) { subMeniuAERARE ++; }
else { subMeniuAERARE = 1 + 3; subMeniuBazin_1_AERARE = 1;}
break;
case 2: // sub Meniu BAZN 2
if (!timp) { subMeniuAERARE ++; }
else { subMeniuAERARE = 2 + 3; subMeniuBazin_2_AERARE = 1;}
break;
case 3: // sub Meniu EXIT
if (!timp ) { subMeniuAERARE = 1; }
else { Meniu = 1; subMeniuAERARE = -1; lcd.clear ();}
break;
case 4: //sub Meniu Bazin 1 AERARE // are 3 submeniuri PORNIRE , LINISTIRE si SAVE & EXIT
switch (subMeniuBazin_1_AERARE) {
case 1: //PORNIRE
if (!timp ) { subMeniuBazin_1_AERARE++; }
break;
case 2: //LINISTIRE
if (!timp ) { subMeniuBazin_1_AERARE++; }
break;
case 3: //SAVE & EXIT
if (!timp ) { subMeniuBazin_1_AERARE = 1; }
else { subMeniuAERARE = 1; subMeniuBazin_1_AERARE = -1; subMeniuBazin_2_AERARE = -1; lcd.clear (); }
break;
}// end switch (subMeniuBazin_1_AERARE)
break;
case 5: //sub Meniu Bazin 2 AERARE // are 3 submeniuri PORNIRE , LINISTIRE si SAVE & EXIT
switch (subMeniuBazin_2_AERARE) {
case 1: //PORNIRE
if (!timp ) { subMeniuBazin_2_AERARE++; }
break;
case 2: //LINISTIRE
if (!timp ) { subMeniuBazin_2_AERARE++; }
break;
case 3: //SAVE & EXIT
if (!timp ) { subMeniuBazin_2_AERARE = 1; }
else { subMeniuAERARE = 2; subMeniuBazin_1_AERARE = -1; subMeniuBazin_2_AERARE = -1; lcd.clear (); }
break;
}// end switch (subMeniuBazin_2_AERARE)
break;
}// end switch (subMeniuAERARE)
break;
case 8: // sub Meniu EVACUARE // are 3 sub Meniuri PORNIRE, LINISTIRE si SAVE & EXIT
switch (subMeniuEVACUARE) {
case 1: //PORNIRE
if (!timp ) { subMeniuEVACUARE++; }
break;
case 2: //LINISTIRE
if (!timp ) { subMeniuEVACUARE++; }
break;
case 3: //SAVE & EXIT
if (!timp ) { subMeniuEVACUARE = 1; }
else { Meniu = 2; subMeniuEVACUARE = -1; lcd.clear (); }
break;
}// end switch (subMeniuEVACUARE)
break;
case 9: // RECIRCULARE // are 3 sub Meniuri PORNIRE, ASTEPTARE si SAVE & EXIT
switch (subMeniuRECIRCULARE) {
case 1: //PORNIRE
if (!timp ) { subMeniuRECIRCULARE++; }
break;
case 2: //ASTEPTARE
if (!timp ) { subMeniuRECIRCULARE++; }
break;
case 3: //SAVE & EXIT
if (!timp ) { subMeniuRECIRCULARE = 1; }
else { Meniu = 3; subMeniuRECIRCULARE = -1; lcd.clear (); }
break;
}// end switch (subMeniuRECIRCULARE)
break;
case 10: // DOZAJ FLOCULANT // are 3 sub Meniuri DOZAJ BAZIN 1, DOZAJ BAZIN 2 si SAVE & EXIT
switch (subMeniuFLOCULANT) {
case 1: //DOZAJ BAZIN 1
if (!timp ) { subMeniuFLOCULANT++; }
break;
case 2: //DOZAJ BAZIN 2
if (!timp ) { subMeniuFLOCULANT++; }
break;
case 3: //SAVE & EXIT
if (!timp ) { subMeniuFLOCULANT = 1; }
else { Meniu = 4; subMeniuFLOCULANT = -1; lcd.clear (); }
break;
}// end switch (subMeniuFLOCULANT)
break;
case 11: // RESET FABRICA // are 2 sub meniuri NU si DA
switch (subMeniuRESET_FABRICA){
case 1: // NU
if (!timp ) { subMeniuRESET_FABRICA++; }
else { Meniu = 5; subMeniuRESET_FABRICA = -1; lcd.clear (); }
break;
case 2: // DA
if (!timp ) { subMeniuRESET_FABRICA = 1; }
else { Meniu = 5; subMeniuRESET_FABRICA = -1; lcd.clear (); Tx_Rx.date.POMPA_Tx.Re_set = 4; Tx_Rx.tip_STR = 2; tx_HC12 (); delay(50);/*transmite ca se reseteaza*/ Scrie_Citeste_EEPROM(4); resetFunc();}
break;
}// end switch (subMeniuRESET_FABRICA)
break;
}// end switch (Meniu)
}//end Defilare_Meniu_Setup
/************** FUNCTIE INFO-HELP *******************/
// Aceasta functie afiseaza informatii privind temperatura si alarmele aparute
// Partea de help textul alarmelor pt a se cunoaste ce reprezinta fiecare alarma
// Alarmele sunt in numar de sase si se afiseaza (Ax) - yyy , Ax inseamna A1, A2,...A6
// iar yyy insemna numarul de aparitii a alarmei, maxim stocate 255
// aparitiile alarmelor nu sunt stocate in memoria EEPROM, la fiecare resetare sau
// intreruperea curentului nr. aparitiei alarmelor se vor reseta la zero
void Info_Help_RstAlarm()
{
static int8_t info_help = 0;// var. pt afisare info despre temperatura si alarme sau help afisand textul alarmei
uint8_t tmp = 0;
bool timp_help = false;
bool timp_info = false;
bool rst_alarma = false;
String tmp_STR = "";
if (Meniu > 0) return;
if ((PIND & (1 << PD7)) == 0 )//|| Tx_Rx.date.POMPA_Tx.Re_set == 1)//!digitalRead(PIN_BUTON_RST_ALARMA)
{
rst_alarma = Timp_Apasare_BTN (PIN_BUTON_RST_ALARMA, 1000);
if (rst_alarma)// || Tx_Rx.date.POMPA_Tx.Re_set == 1)
{
Tx_Rx.tip_STR = 2;
Tx_Rx.date.POMPA_Tx.Re_set = 1;
Tx_Rx.date.LCD.Alarma[0] = 0;
Tx_Rx.date.LCD.Alarma[1] = 0;
Tx_Rx.date.LCD.Alarma[2] = 0;
Tx_Rx.date.LCD.Alarma[3] = 0;
Tx_Rx.date.LCD.Alarma[4] = 0;//alarma == 5 ? 1 : 0;// in timpul alarma bazin prea gol pastreaza o singura aparitie
Tx_Rx.date.LCD.Alarma[5] = 0;
}
}
if ((PIND & (1 << PD4)) == 0 && info_help <= 0)//!digitalRead(PIN_BUTON_TIMP_MINUS)
{timp_info = Timp_Apasare_BTN ( PIN_BUTON_TIMP_MINUS, 1000 ); tmp = 102;}// returneaza intotdeauna TRUE sau FALSE
else if ((PIND & (1 << PD5)) == 0 && info_help >= 0)//!digitalRead(PIN_BUTON_TIMP_PLUS)
{timp_help = Timp_Apasare_BTN ( PIN_BUTON_TIMP_PLUS, 1000 ); tmp = 101;}// returneaza intotdeauna TRUE sau FALSE
//else {return;} // deoarece timpAPASARE este diferit de zero
if (Meniu == -1 && timp_info && info_help == 0) {Meniu = 0; info_help = -1; lcd.clear();}// afiseaza info
else if (Meniu == 0 && timp_info && info_help < 0) {Meniu = -1; info_help = 0; lcd.clear(); StareCiclu(); return;}// iese din info si afiseaza starea curenta
if (Meniu == -1 && timp_help && info_help == 0) {Meniu = 0; info_help = 1; lcd.clear();}// afiseaza help
else if (Meniu == 0 && timp_help && info_help > 0) {Meniu = -1; info_help = 0; lcd.clear(); for (uint8_t i = 0; i <=3; i++) {strcpy(Tx_Rx.date.LCD.Line[i] , tmp_STR.c_str());} StareCiclu(); return;}// iese din help si afiseaza starea curenta
//if (Meniu == 0 && !primit_LCD) {lcd.clear(); primit_LCD = true;}
if (Meniu != 0) return;
if (info_help != 0 && tmp !=0) {lcd.clear();}
if (!timp_info && tmp == 102)
{
if (info_help == -2) info_help = -1;
else info_help = -2;
}
//lcd.setCursor (0,0); lcd.print(bitRead(Tx_Rx.date.LCD.Alarma[5], 0));
//temperatureSensors.update();
//temperatureSensors.requestTemperature();// de vazut daca este necesara dupa compilare
// in montajul electronic
switch (info_help) {
case -2: // info alarme
lcd.setCursor (0,0); lcd.print(F("< APARITII ALARME >"));
for (uint8_t i = 1; i <= 6; i++)//aici scriu A(1) ... A(6)
{
// if (i <= 3) tmp = 1;
// else tmp = 11;
lcd.setCursor ((i <= 3 ? 0 : 10 ), (i <= 3 ? i : i - 3));lcd.print(F("A("));lcd.print(i);
lcd.print(F(") ")); if (i != 6 ) {lcd.print( Tx_Rx.date.LCD.Alarma[i-1]);}
//lcd.setCursor ((i <= 3 ? i : i - 3), (i <= 3 ? i : i - 3));lcd.print(Tx_Rx.date.LCD.Alarma[i-1]);
}
lcd.setCursor(15,3);
for (uint8_t i = 0; i <= 4; i++)
{
if ( bitRead(Tx_Rx.date.LCD.Alarma[5], i) == 0) {lcd.write(uint8_t(0));}//afisarea se face invers stocarii
else lcd.print("x");
}
break;
case -1: // info teperatura
//if (!timp_info && (PIND & (1 << PD4)) == 0) { info_help --; }
lcd.setCursor (0,0); lcd.print(F("<TEMPERATURA STATIE>"));
lcd.setCursor (10,1); lcd.print(F("EXT"));
lcd.setCursor (10,2); lcd.print(F("INT"));
for (uint8_t i = 1; i <= 5; i++)
{
if (i <= 3)
{
tmp = 0;
lcd.setCursor (0, i);lcd.print(F("B"));lcd.print(i-1);// aici scriu B0 ... B2
}
else tmp = 11;
lcd.setCursor (3 + tmp, (i <= 3 ? i : i - 3));
if (Tx_Rx.date.LCD.Temperatura[i-1] > 0)// aici scriu temperaturile cu semn - 0 +
{
lcd.print("+");
}
else if (Tx_Rx.date.LCD.Temperatura[i-1] < 0)
{
lcd.print("-");
}
else
{
lcd.print(" ");
}
if (Tx_Rx.date.LCD.Temperatura[i-1] > -10 && Tx_Rx.date.LCD.Temperatura[i-1] < 10) lcd.print("0"); //: lcd.print("");
Tx_Rx.date.LCD.Temperatura[i-1] < 0 ? lcd.print(-1*Tx_Rx.date.LCD.Temperatura[i-1]) : lcd.print(Tx_Rx.date.LCD.Temperatura[i-1]);
//lcd.print((char)223);
}
break;
case 1 ... 5: // alarma 1 ... 5
if (!timp_help && tmp == 101) { info_help ++; }
break;
case 6: // alarma 6
if (!timp_help && tmp == 101) { info_help = 1; }
break;
}
if (info_help >= 1)
{
Alarme (info_help);
for ( uint8_t i = 0; i < 4; i++) {lcd.setCursor (((i == 3 && info_help == 6) ? 8 : 0) ,i); lcd.print((char*)Tx_Rx.date.LCD.Line[i]);}
if (info_help == 6)
{
for (uint8_t i = 2; i <= 18; i+=4)
{
lcd.setCursor (i, 3);
if ( bitRead(Tx_Rx.date.LCD.Alarma[5], (i/4)) == 0) {lcd.write(uint8_t(0));}//afisarea se face invers stocarii
else lcd.print("x");
}
}
// lcd.setCursor (0,0); lcd.print((char*)Tx_Rx.date.LCD.Line[0]);
// lcd.setCursor (0,1); lcd.print((char*)Tx_Rx.date.LCD.Line[1]);
// lcd.setCursor (0,2); lcd.print((char*)Tx_Rx.date.LCD.Line[2]);
// lcd.setCursor (0,3); lcd.print((char*)Tx_Rx.date.LCD.Line[3]);
}
}// end Info_HelpALARMA
CONTROLER SLAVE STATIE DE EPURARE HOME MADE RELIZATA DIN REZERVOARE IBC
NOTA : - Acest controler primeste date de la master si le afiseaza in casa
. . . . . . .- Modulul HC-12 de comunicare wireles nu este reprezentat in aceasta schema
MOD DE UTILIZARE
- Prin apasarea butonului SETUP mai mult de o secunda se intra in meniul setup sau in sub meniuri
- Prin apasarea butoanelor Timp- si Timp+ se ajusteza timpii in submeniuri
- Prin apasarea butonului Timp- mai mult de o secunda se afiseaza succesiv informatii despre temperatura si numarul de apariții al alarmelor
- Prin apasarea butonului Timp+ mai mult de o secunda se afiseaza succesiv continutul alarmelor - cauza care a generat alama
- Prin apasarea butonului MOD mai mult de o secunda se schimba afisarea "Statie de Epurare" sau alte dispozitive