//Copyright (c) 2024 Duțoiu Nicolae
// Mcu MASTER
// STATIE DE EPURARE CU BAZINE IBC
/* ^
. CONDUCTE PVC |
. ________________________________________________|__________________
. | ___________________|_______________ |
. | | | | |
| | __|_____|__ | __|_____|__ | | | |
| | | | | | | | | | | | | | |
| BAZIN 0 | | BAZIN 1 | | | | BAZIN 2 | | |
| | | | | | | | | |
| NU ARE POMPE | | POMPE | | | ^ POMPE | | |
| | | | | | EVACUARE EXTERIOR | | |
| | | ^ | | P2.3 ^ ^ |
| | | AERARE RECIRCULARE B2 | | AERARE RECIRCULARE B1/B0 |
| | | P1.1 P1.2 | | P2.1 P2.2 |
|______________________| |_______________________| |__________________________|
*/
/********* ATENTIE !!! **********/
// Ca Debouncer pt plutitori si butoane se utilizeza CI MAX6818
// Pinul D8 este senzorul de nivel din BAZIN 1
// Pinul D9 este senzorul de nivel din BAZIN 2
// Pinul D10 este senzorul de prea plin BAZIN 2
// Pinul D11 este senzorul de prea gol din BAZIN 1
// Pinul D12 este senzorul de prea gol din BAZIN 2
// Pinul pcf8575 P05 comanda electrovana cu trei căi
// Pinul pcf8575 P04 este pompa de evacuare in exrterior
// Pinul pcf8575 P03 este pompa de evacuare in BAZIN 2 dupa ce s-a evacuat in exterior BAZIN 2 si se utilizeaza si la recirculare
// Pinul pcf8575 P02 este pompa de evacuare in BAZIN 0 si se utilizeaza doar la recirculare
// Pinul pcf8575 P01 este pompa de aerare Bazin 2
// Pinul pcf8575 P00 este pompa de aerare BAZIN 1
// Pinul D2 citeste senzorii de temperatura DS18B20 din fiecare bazin si din incinta
// 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 evacuarea 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.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
//#include <SerialTransfer.h>
#include <EasyTransfer.h>//transmite pe hardware serial o structura de maxim 255 octeti
//#include <util/atomic.h>
#include <PCF8575.h>//PCF8575_library Renzo Mischianti
// senzori de temperatura
#include <OneWire.h>
#include <DallasTemperature.h>
#include <NonBlockingDallas.h>
//#define RS 12
//#define EN 11
//#define D4 10
//#define D5 9
//#define D6 8
//#define D7 7
//LiquidCrystal lcd (RS, EN, D4, D5, D6, D7);
#define lcd_ADDRESS 0x27
LiquidCrystal_I2C lcd(lcd_ADDRESS, 20, 4); // I2C address 0x27, 20 column and 4 rows
// adresa este pt a functiona in wokwi,
// alfel trebuie setata pe afisaj
uint8_t _backlight = 1;// variabila care stinge iluminatul dupa 30
#define PCF8575_ADDRESS 0x20
PCF8575 pcf8575(PCF8575_ADDRESS);
//SerialTransfer HC12_Transfer;
EasyTransfer HC12_Transfer_TX;
EasyTransfer HC12_Transfer_RX;
//senzor temperatura
#define ONE_WIRE_BUS 2 // PIN of the Maxim DS18B20 temperature(s) sensor(s)
#define TIME_INTERVAL 1500 // Time interval among sensor readings [milliseconds]
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature dallasTemp(&oneWire);
NonBlockingDallas temperatureSensors(&dallasTemp);
//Stabilire pini butoane
#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 pentru intreruperea ISR() Timp
//bool volatile flag_Timer1 = false;//variabila care arata ca a aparut intreruperea Timer1
//uint32_t durata = 0;//masoara timpul fara precizie de cand a fost pornit conroler-ul
//aproximativ 136 de ani dupa care trebuie resetata
#define INTERVAL_VACANTA 180//172800 //in secunde - implicit 48 ore si reprezinta perioada la care se declanseaza vacanta
uint32_t timp_Vacanta = 0;// variabila care masoara timpul pentru a verifica daca a avut loc
// evacuarea in exterior in 48 de ore timp care reprezinta minim doua
// cicluri complete de epurare prin care se determina faptul ca
// statia nu este folosita, nu are aport de apa noua pt epurare.
// aceasta variabila stabileste cand se recircula din Bazin 2
// in Bazin 0 pentru improspatare apa
uint8_t vacanta = 1; // reduce timpul de aerare si creste timpul de linistire aerare si perioada recirculare pt economie de energie
// recircula o data la 24 de ore 100 litri din bazin 2 in bazin 0 pentru eliminarea
// mirosurilor, denitrificare si defosforizare
// este resetata in etapa de evacuare
int32_t alarma_Evacuare = -1;// calculeaza timpul de la apariatia alarmei provocata
// de blocarea senzorului de nivel din Bazin 1 astfel
// încat sa fie evitata evacuarea in exterior repetitiv
// la fiecare 15 secunde care reprezinta intarzierea
// de pornire a evacuarii
// acesta variabila este resetata la inceputul evacuarii
// adica cand senzorul de nivel B2 este cuplat
// Variabile care stocheaza pinul care a generat intreruperea ISR()
// pentru pinii IMPUT_PULLUP setati pe GND care genereaza inreruperea
// pinul D8 plutitor Bazin 1 - adica bazinul 1 sa umplut si incepe etapa de evacuare in exterior apa epurata din bazin 2
// pinul D9 plutitor Bazin 2 - adica opreste evacuarea din bazin 1 in bazinul 2
// pinul D10 plutitor prea plin - cota de avarie bazin 2 si porneste evacuarea 50 litri si
// poate emite o avarie pe afisaj pompa evacuare bazin 2 stricata
bool nivel_B1_Pin_D8 = false; //plutitor nivel BAZIN 1 declanseaza evacuarea
bool nivel_B2_Pin_D9 = false; //plutitor nivel BAZIN 2 opreste umplerea bazinului 2
bool prea_plin_B2_Pin_D10 = false; //plutitor prea plin BAZIN 2 evacueaza 100 litri in exterior
// uint8_t prea_gol = 0 // retine care bazin este prea gol si ia valori
// // 0 - nu este atins nivelul de prea gol
// // 1 - s-a atins nivelul de prea gol in Bazin 1
// // 2 - s-a atins nivelul de prea gol in Bazin 2
// // 3 - s-a atins nivelul de prea gol in Bazin 1 si 2
#define INTARZIERE_PLUTITOR 15 // implicit 15 secunde generata pentru a adauga un surplus
// de apa de 25 litri astfel incat plutitorul sa stea inundat
bool surplus_Evacuare = false; // stabileste daca a fost eliminata apa in surplus la evacuare
// fata de limit de nivel - acest surplus exita intodeauna minim 25 litri
// pentru stabilitatea contactului plutitorului sau daca in timpul linistirii
// functioneaza prea plinul hidraulic si creste nivelul
uint8_t intarziere_Pin_D8 = 0; // aceaste intarzieri sunt necesare pentru ca sa fie preluata
uint8_t intarziere_Pin_D9 = 0; // distanta de contact a plutitorilor, eliminarea semnalelor
//uint8_t intarziere_Pin_D10 = 0; // false si a semnalelor accidentale datorita efectului de val
// intarzierea este de aproximativ 15 sec. sau 25 litri,
// evenimentele declansate de plutitori apar dupa expirarea
// acestei perioade cu conditia ca plutitorul sa fie in contact
// Variabile pompe
// ATENTIE ! - sa nu se schimbe pozitia variabilelor in "struct POMPE"
// struct __attribute__((packed)) POMPE // Aceasta structura contine variabilele pentru pompe 6 mc/h si va fi transmisa
// { // wireles catre controlerul MASTER prin HC-12 433 MHz de catre SLAVE
// uint8_tBazin_1_Aerare = 90;// 60; // implicit 90 de secunde min 30 sec - max 240 sec pas 10 sec
// int16_tBazin_1_Linistire = 900;// 60; // implicit 900 de secunde min 300 sec - max 3600 sec pas 300 sec
// uint8_tBazin_2_Aerare = 90;//60; // implicit 90 de secunde min 30 sec - max 240 sec pas 10 sec
// int16_tBazin_2_Linistire = 900;//60; // implicit 900 de secunde min 300 sec - max 3600 sec pas 300 sec
// int16_tPornireEvacuare = 180;//20; // 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 = 6 mc/h
// int16_tLinistireEvacuare = 1800;//9; // implicit 1800 de secunde min 300 sec - max 3600 sec pas 300 sec - este folosita pentru Evacuare si Recirculare pompa 6 mc/h
// uint8_tPornireRecirculare = 60;//30; // implicit 60 de secunde min 15 sec - max 120 sec pas 5 sec - recircula 100 litri la debitul pompelor de 6 mc/h
// uint8_tAsteptareRecirculare = 1; // implicit 4 ore min 3 ore max 8 ore pas 1 ora - max 18 ore in secunde min 21600 - max 64800
// float PompaPeristaltica_B1 = 10; // implicit 10 mililitri, minim 0 mililitri - maxim 20 mililitri pt pompa utilizata
// float PompaPeristaltica_B2 = 5; // implicit 5 mililitri, minim 0 mililitri - maxim 20 mililitri pt pompa utilizata
// };
// 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 ;//= 60; // implicit 90 de secunde min 30 sec - max 240 sec pas 10 sec
int16_t Bazin_1_Linistire ;//= 60; // implicit 900 de secunde min 300 sec - max 3600 sec pas 300 sec
uint8_t Bazin_2_Aerare ;//= 60; // implicit 90 de secunde min 30 sec - max 240 sec pas 10 sec
int16_t Bazin_2_Linistire ;//= 60; // implicit 900 de secunde min 300 sec - max 3600 sec pas 300 sec
int16_t PornireEvacuare ;//= 20; // 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 ;//= 20; // 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 ;//= 30; // 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 ;//= 1; // implicit 4 ore min 3 ore max 8 ore pas 1 ora - max in secunde 28800
float PompaPeristaltica_B1 ;//= 10.0; // implicit 10 mililitri, minim 0 mililitri - maxim 20 mililitri pt pompa utilizata
float PompaPeristaltica_B2 ;//= 5.0; // implicit 5 mililitri, minim 0 mililitri - maxim 20 mililitri pt pompa utilizata
uint8_t Re_set ;//= 0; // 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
// 255 - confirmare receptionare date
};
struct POMPE POMPA;
struct POMPE POMPA_Set;
// 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_Set;
struct LCD20x4 LCD;
};
struct __attribute__((packed)) COMUN //aceasta structura va transmisa si receptionata
{
uint8_t tip_STR;// 1-LCD 2-POMPA_Set
union DATA date;
};
COMUN Tx_Rx;
int16_t PornireEvacuareInBazin2;// = POMPA.PornireEvacuare + INTARZIERE_PLUTITOR; //maxim 360 secunde / max 600 litri - pompa trebuie sa aiba un debit = 6 mc/h
int16_t LinistireREC;// = POMPA.LinistireEvacuare; //timpul de linistire inainte de Recirculare
#define EVACUARE_PREA_PLIN 10 // implicit 30 sec - 50 de litri pt. pompa 6 mc/h si reprezinta timpul necesar
// evacuarii unei parti din prea plin pana cand se finalizeaza etapa de evacure
// volum de prea plin Bazin 2 = 100 litri
uint16_t ORA_Recirculare = 0; // este utilizata pentru recirculare, masoara o ora pentru a decrementa Recirculare.CL
#define NR_SEC_ORA 35 //constanta care contine nr de secunde dintr-o ora adica 3600
// aceasta structura este operata in interiorul functiei call_ISR_Timer()
struct Timer_Releu // aceasta structura este un constructor pentru a putea fi initializata ca mai jos
{
Timer_Releu ( int16_t op, int16_t cl, bool ss) : OP {op}, CL {cl}, SS {ss} {}
int16_t OP = 0; //" OPEN "timpul in secunde pt. care RELEUL este normal deschis NO
int16_t CL = 0; //" CLOSE "timpul in in secunde pt. care RELEUL este normal inchis NC
bool SS = false; //" START - STOP " - 0 opreste , 1 porneste un eveniment (actioneaza un releu)
//dupa actiunea STOP/START trebuie reinitializati timpii OP, CL
};
// initializez variabilele pentru relee pompe
struct Timer_Releu AerareB1 = {POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire, true };
struct Timer_Releu AerareB2 = {POMPA.Bazin_2_Aerare, POMPA.Bazin_2_Linistire, true };
struct Timer_Releu Recirculare = {POMPA.PornireRecirculare, POMPA.AsteptareRecirculare , true };
struct Timer_Releu Evacuare = {POMPA.PornireEvacuare, POMPA.LinistireEvacuare, false };
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
bool dozareFLOCULANT = false;// variabila care devine true cand se termina umplerea bazin 2 dupa evacuare pentru a introduce floculant
uint8_t timpDozareFLOCULANT = 0;// timpul care stabileste cat floculant se dozeza - 90 ml/min
// max 255 secude sau 4.25 min
// se va verifica fizic cu pompa peristaltica in functiune
#define DEBIT_POMPA_PERISTALTICA 90.0 // 90 ml/min - se determina fizic pe pompa peristaltica
enum ACS712_PIN_Pompa
{
P1_1 = A0,// aerare B1 - PIN A0 14 nr pin
P1_2 = A1,// recirculare B1 - PIN A1 15 nr pin
P2_1 = A2,// aerare B2 - PIN A2 16 nr pin
P2_2 = A3,// recirculare B2 - PIN A3 17 nr pin
P2_3 = A0//A6 // evacuare ext. - PIN A6 20 nr pin - pt. NANO
};
uint16_t zero_ACS712[5];//stocheaza Vout ACS712 cand nu circula curent prin el
//valoarea maxima stocata ca integer este 1023/2 = 511
/******************** 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
/************************ VERIFICARE POMA ARSA ***************************/
// Aceasta functie determina daca o pompa este arsa, adica verifica intensitatea
// curentului care trece prin pompa
// Intoarce intotdeauna situatia pompelor
// mod ia valori - 1 = calibreaza toti senzorii odata
// - 2 = seteaza 1 bitul reprezentativ al pompei in variabila
// LCD.Alarma[5] daca este arsa
// Modulul utilizat este ACS71205B - poate citi max 5A la 230V pe mine ma intereseaza max 2A
// inspirat din https://github.com/muratdemirtas/ACS712-arduino-1/blob/master/ACS712.h
//ATENTIE!
// analogRead mapeaza tensiunea de referinta de 5V digital intre 0 - 1023
// ACS712 cand nu este sub sarcina scoate Vref/2, in cazul meu 5V/2 = 2.5V
// in aceasta functie compar valorile intoarse de analogRead si nu intensitatea curentului deoarece nu ma intereseaza valoarea exacta
void ACS712_POMPA(uint8_t mod = 1, ACS712_PIN_Pompa pin_Pompa = P1_1 )// are valori implicite deoarece
// calibrarea zero_ACS712 nu depinde de
// variabila pin_Pompa
// calibrare la zero se face fara sarcina adica fara pompa pornita
{
switch (mod)
{
case 1: // calibrare senzor
for(uint8_t j = A0; j<= A3/*A3 se inlocuieste cu A6 pt NANO*/; j++ )// pt A4 si A5 care este I2C nu se executa
{
if ( j != A4 && j != A5 )
{
zero_ACS712[j <= A3 ? j - A0 : 4] = 0;// teoretic 511 reprezinta 1023/2 valoarea mapata Vout ACS712
for (uint8_t i = 0; i < 20; i++ )// se face iteratia de 20 de ori pentru pt medierea valorii
{
zero_ACS712[j <= A3 ? j - A0 : 4] += analogRead(j <= A3 ? j - A0 : 4);
delay(1);//astept sa fie citit pinul
}
zero_ACS712[j <= A3 ? j - A0 : 4] /= 20;
}
}
break;
case 2: // seteaza 1 bitul pompei arse
//uint32_t period = 1000000 / frequency;
uint32_t t_start = micros();
uint32_t Isum = 0, measurements_count = 0;
int32_t Inow;
while (micros() - t_start < 10000)// 10000 reprezinta 0.5 secunde / frecventa = 50 Hz si nu execut pt un intreg ciclu de o secunda
{ // fac asta deoarece la start-soft releul ramane cuplat aproximativ 1 secunda
Inow = zero_ACS712[pin_Pompa <= A3 ? pin_Pompa - A0 : 4] - analogRead(pin_Pompa);
Isum += Inow*Inow;
measurements_count++;
}
float Irms = sqrt(Isum / measurements_count); // se face pentru precizie media patratica
if (Irms < 30)// 30 inseamna aproximativ 0.8A -valoare pt. care s-a considerat mersul
// in gol al pompei ,sub aceasta valoare se considera pompa ca fiind arsa
// popele utilizate au o putere de 250W fiecare, asta insemna aproximativ I=1.1A
{ // pentru alte pompe se va stabilii alta valoare
bitSet(LCD.Alarma[5], pin_Pompa <= A3 ? pin_Pompa - A0 : 4);// 1 pompa arsa
}
else
{
bitClear(LCD.Alarma[5], pin_Pompa <= A3 ? pin_Pompa - A0 : 4);// 0 pompa buna
}
break;
}
}// end ACS712_POMPA
/************************ FUNCTII SENZOR TEMPERATURA DS18B20 ********************************/
//Invoked ONLY when the temperature changes between two VALID sensor readings. "valid" parameter will be removed in a feature version
void handleTemperatureChange (int16_t deviceIndex, int32_t temperatureRAW)
{
temperatureRAW = temperatureRAW;//fac asta pt eliminarea atentionarii de la compilare ca acesta variabila nu este utilizata
LCD.Temperatura[deviceIndex] = temperatureSensors.getTemperatureC(deviceIndex);
//Serial.println(deviceIndex);
}// end handleTemperatureChange()
/************************ 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 :
// - structura LCD20x4
// se receptioneaza variabilla :
// - POMPA_Set
void tx_HC12 (const uint8_t& tip) // transmitere date
{
// EasyTRansfer poate trimite o singura structura de maxim 255 octeti
// tip 1 - transmite struct LCD
// tip 2 - transmite POMPA_Set
// transmisia nu se realizeaza duplex
// aceasta functie este chemata in functia loop
switch (tip)
{
case 1:
HC12_Transfer_TX.sendData();// este folosit in functia StareCiclu
Serial.flush();
break;
case 2:
// uint32_t timp_TX = millis();
// if (POMPA_Set.Re_set == 0) break;//transmite doar cand POMPA_Set.Re_set este diferit de 0
// //aici asteapta confirmarea datelor primite de la slave
// bool receptie = false;
// do{//transmite si asteapta raspuns
// HC12_Transfer_TX_POMPA_Set.sendData();// transmite catre master
// Serial.flush();//asteapta umplerea buffer-lui
// delay(20);
// receptie = HC12_Transfer_RX_POMPA_Set.receiveData();//citeste daca datele sau tranmis corec}
// if ((millis() - timp_TX) >= 500) {POMPA_Set.Re_set = 0; break;}//timp de o secunda transmite si asteapta date cred ca nu îi trebuie mai mult
// } while ((POMPA_Set.Re_set != 0) && !receptie);
if (POMPA_Set.Re_set == 0) break;
for(uint8_t i = 0; i<5; i++) {HC12_Transfer_TX.sendData();Serial.flush(); delay(10);}// transmite catre master
// Serial.flush();//asteapta umplerea buffer-lui
POMPA_Set.Re_set = 0;
break;
}
}// end tx_HC12
void rx_HC12 () // receptionare date
{
if (Meniu > 0) return;
// use this variable to keep track of how many
// bytes we've processed from the receive buffer
bool receptie = HC12_Transfer_RX.receiveData();
if (receptie == true)
{
switch (POMPA_Set.Re_set)
{
case 1: //slave a resetat alarmele
POMPA.Re_set = POMPA_Set.Re_set;
POMPA_Set.Re_set = 255;//master transmite confirmarea
break;
// case 2: //master transmite ca a modificat setarile
// // nu se executa nimic
// break;
case 3: //slave transmite ca a modificat setarile
POMPA_Set.Re_set = 0;//pun variabila pe zerodeoare POMPA_Set urmeaza sa fie scris in memorie
init_SETUP = true;//pentru initializare ciclu in Defilare_Meniu
Scrie_Citeste_EEPROM(2);//stocheaza datele primite in memorie
// ATENTIE MARE !!! se arde memoria
// prima data te joci cu variabila sa fi
// sigur ca transmisia se realizeaza o singura data
POMPA_Set.Re_set = 255;//master transmite confirmarea
break;
case 4: //slave transmite ca s-a resetat la setarile din fabrica
Scrie_Citeste_EEPROM(4);//pune in memorie byte-ul 1 la 0xFF sau in DEC 255
resetFunc();//nu mai are ce confirmare sa transmita ca slave sa resetat
break;
case 5: //slave a intrat in flux, adica slave a fost scos din priza, oprit sau reprogramat si transmite la master ca trebuie sa preia datatele de la master
Scrie_Citeste_EEPROM(3);//se citeste POMPA_Set
POMPA_Set.Re_set = 2;//pentru a transmite datele la slave ca si cum ar fi modificate setarile
break;
// case 6: //master solicita datele stocate in slave daca slave este pornit, adica master a fost scos din priza, oprit sau reprogramat
// nu se executa nimic - slave trasmite catre master ca si cum sau modificat setarile si master executa instructiunile de la case 3:
// break;
// case 7: // master sa resetat la se tarile din fabrica
// //nu execut nimic pt ca slave se va reseta
// break;
case 255: //master a primit confirmarea
POMPA_Set.Re_set = 0;
break;
}
}
} // end RX_HC12
/*********************** FUNCTII PENTRU INTRERUPERILE ISR() *********************************/
/************ FUNCTIE CARE AFISEAZA ALTERNANT STARE/ALARM IN CAZUL APARITIEI ALARMEI *************/
String 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 bool stare_Alarma = false;
for (uint8_t i = 0; i <= 5; i++) { if (LCD.Alarma[i] > 0) tmp = true; }
if (tmp == true && _beep) {pcf8575.digitalWrite( 8, LOW); delay(50);pcf8575.digitalWrite( 8, HIGH);}
else pcf8575.digitalWrite( 8, HIGH);
if (!tmp)
{return(vacanta == 1 ? F("STARE ") : F("VEGHE "));}
else if (tmp && !stare_Alarma)
{stare_Alarma = true; return (vacanta == 1 ? F("STARE ") : F("VEGHE "));}
else if (tmp && stare_Alarma)
{stare_Alarma = false; return (F("ALARMA"));}
else {return("");}// aceasta linie este introdusa pt. eliminarea mesajului de compilare
} //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(LCD.Line[0] , tmp.c_str());
tmp = F(" Verifica evacuarea."); strcpy(LCD.Line[1] , tmp.c_str());
tmp = F(" Sau debit peste"); strcpy(LCD.Line[2] , tmp.c_str());
tmp = F(" 100 litri / min."); strcpy(LCD.Line[3] , tmp.c_str());
break;
case 2: //PREA PLIN BAZIN 2
tmp = F("(A2) ALARM PREAPLIN"); strcpy(LCD.Line[0] , tmp.c_str());
tmp = F("Pompa Evac.P2.2 arsa"); strcpy(LCD.Line[1] , tmp.c_str());
tmp = F(" sau plutitor prea"); strcpy(LCD.Line[2] , tmp.c_str());
tmp = F("plin BAZIN 2 blocat."); strcpy(LCD.Line[3] , tmp.c_str());
break;
case 3: //EVACUARE
tmp = F("(A3) ALARM EVACUARE"); strcpy(LCD.Line[0] , tmp.c_str());
tmp = F("Pompa de evacuare in"); strcpy(LCD.Line[1] , tmp.c_str());
tmp = F("exterior P2.2 arsa."); strcpy(LCD.Line[2] , tmp.c_str());
tmp = F("Senzor nivel blocat."); strcpy(LCD.Line[3] , tmp.c_str());
break;
case 4: //EVACUARE
tmp = F("(A4)ALARM UMPLERE B2"); strcpy(LCD.Line[0] , tmp.c_str());
tmp = F("Senzorii de nivel"); strcpy(LCD.Line[1] , tmp.c_str());
tmp = F("defecti sau murdari/"); strcpy(LCD.Line[2] , tmp.c_str());
tmp = F("P1.2 umplere B2 arsa"); strcpy(LCD.Line[3] , tmp.c_str());
break;
case 5: //PREA GOL
tmp = F("(A5) ALARM PREA-GOL"); strcpy(LCD.Line[0] , tmp.c_str());
tmp = F(" ATENTIE !"); strcpy(LCD.Line[1] , tmp.c_str());
tmp = F(" NIVELUL APEI ESTE"); strcpy(LCD.Line[2] , tmp.c_str());
tmp = F(" SUB COTA ADMISA"); strcpy(LCD.Line[3] , tmp.c_str());
break;
case 6: //POMPE ARSE
tmp = F("(A6)ALARM POMPE ARSE"); strcpy(LCD.Line[0] , tmp.c_str());
tmp = F(" BAZIN 1| BAZIN 2"); strcpy(LCD.Line[1] , tmp.c_str());
tmp = F(" P11 P12|P21 P22 P23"); strcpy(LCD.Line[2] , tmp.c_str());
tmp = F("|"); strcpy(LCD.Line[3] , tmp.c_str()); // se va scrie in StareCiclu()
break;
}
}
/************************* FUNCTIE AFISARE STARE CICLU **************************************/
// Acesta functie afiseaza etapa in care se afla statia de epurare
void StareCiclu ( uint8_t etapa = 0)
{
//if (Meniu == 0) return;
//struct LCD20x4 LCD;
String INDENT = F("> ");
String SPATII_2 = F(" ");
String SPATII_4 = F(" ");
String SEC = F("sec");
String LINISTIRE = F("Linistire ");
String EVACUARE = F("Evacuare ");
String UMPLERE = F("Umplere ");
String AMESTEC = F("Amestec ");
String tmp = "";
static uint8_t timpAfisareAlarma = 0; // afisaza alarma timp de 10 sec la aparitia acesteia dupa care o reseteza
// pentru a nu bloca afisajul afisindu-se in continuare STAREA in care se afla statia
tmp = Stare_Alarma();
static uint8_t lcd_clear = 0;
//-----------------------------------------------------------------
// prea-plin prea-gol
if ((timpAfisareAlarma == 10) && (alarma > 2 && alarma < 6 && alarma != 5)) // afisez alarma tip 3, 4 si 5 timp de 10 sec. de la apariția acesteia dupa care se reseteaza
{ // evenimentele privind nr aparitiei alarmelor sunt stocate in variabila LCD.Alarma[0-5]
alarma = 0; timpAfisareAlarma = 0;
}
else if ((alarma > 2) && (alarma < 6) && alarma != 5) {timpAfisareAlarma++; }
// Serial.print(alarma);
// Serial.print("-----");
// Serial.println(timpAfisareAlarma);
if ( alarma ) etapa = 4;
if ( etapa != 4) lcd_clear = 0;
//------------------------------------------------------------------
//if (Meniu > 0) return;
if (Meniu > 0) etapa = 5; // nu se afiseaza etapa deoarece se seteaza Mcu MASTER
// este folosit numai pentru transmitere si afisare pe
// Mcu SLAVE faptul ca MASTER se afla in SETUP
//if (Meniu == 0) etapa = 6;//acesta etapa nu nu exista este folosita pentru a se
//pastra pe ecran info help
switch (etapa)
{
case 1: //EVACUARE
//if ( alarma ) break;
tmp += F("<< EVACUARE >>");
strcpy(LCD.Line[0] , tmp.c_str());
tmp = (Evacuare.CL); tmp += SPATII_4;
if(Evacuare.CL > 0) tmp = (INDENT + LINISTIRE + tmp.substring(0,5) + SEC);
else tmp = (SPATII_2 + LINISTIRE + tmp.substring(0,5) + SEC);
strcpy(LCD.Line[1], tmp.c_str());
tmp = (Evacuare.OP) + SPATII_4;
if(Evacuare.OP > 0 && Evacuare.CL == 0) tmp = (INDENT + EVACUARE + tmp.substring(0,5) + SEC);
else tmp = (SPATII_2 + EVACUARE + tmp.substring(0,5) + SEC);
strcpy(LCD.Line[2], tmp.c_str());
tmp = (PornireEvacuareInBazin2) +SPATII_4;
if(PornireEvacuareInBazin2 > 0 && Evacuare.OP == 0) tmp = (INDENT + UMPLERE + tmp.substring(0,5) + SEC);
else tmp = (SPATII_2 + UMPLERE + tmp.substring(0,5) + SEC);
strcpy(LCD.Line[3], tmp.c_str());
break;
case 2: //RECIRCULARE
//if ( alarma ) break;
tmp += F("<< RECIRCUL >>");
strcpy(LCD.Line[0] , tmp.c_str());
tmp = (LinistireREC) + SPATII_4 ;
if(LinistireREC > 0) tmp = (INDENT + LINISTIRE + tmp.substring(0,5) + SEC);
else tmp = (SPATII_2 + LINISTIRE + tmp.substring(0,5) + SEC);
strcpy(LCD.Line[1], tmp.c_str());
tmp = (Recirculare.OP) + SPATII_4;
if(Recirculare.OP > 0 && LinistireREC == 0) tmp = (INDENT + AMESTEC + tmp.substring(0,5) + SEC);
else tmp = (SPATII_2 + AMESTEC + tmp.substring(0,5) + SEC);
strcpy(LCD.Line[2], tmp.c_str());
tmp = F(" --------- ---- ---");
strcpy(LCD.Line[3], tmp.c_str());
break;
case 3: //AERARE
//if ( alarma ) break;
tmp += F("<< AERARE >>");
strcpy(LCD.Line[0] , tmp.c_str());
tmp = F(" Bazin 1 Bazin 2");
strcpy(LCD.Line[1] , tmp.c_str());
tmp = F("AER ");
tmp += (AerareB1.OP) + SPATII_4;
tmp = (tmp.substring(0,8) + SEC + SPATII_2 );
strcpy(LCD.Line[2] , tmp.c_str());
tmp = (AerareB2.OP) + SPATII_4;
tmp = tmp.substring(0,4) + SEC;
strcat(LCD.Line[2] , tmp.c_str());
tmp = F("LIN ");
tmp += (AerareB1.CL) + SPATII_4;
tmp = (tmp.substring(0,8) + SEC + SPATII_2);
strcpy(LCD.Line[3] , tmp.c_str());
tmp = (AerareB2.CL) + SPATII_4;
tmp = (tmp.substring(0,4) + SEC);
strcat(LCD.Line[3] , tmp.c_str());
break;
case 4: // ALARME
if (Meniu == 0) break;
if ( lcd_clear == 0) {lcd.clear(); lcd_clear = 1;}
Alarme (alarma);
break;
case 5: // MESAJ NUMAI PENTRU Mcu SLAVE
tmp = F(" ATENTIE ! "); strcpy(LCD.Line[0] , tmp.c_str());
tmp = F(" MCU MASTER SE AFLA "); strcpy(LCD.Line[1] , tmp.c_str());
tmp = F(" IN MENIUL SETUP "); strcpy(LCD.Line[2] , tmp.c_str());
tmp = F("NU UMBLATI LA SETARI"); strcpy(LCD.Line[3] , tmp.c_str());
// tx_HC12 (1); // transmitere date LCD
// return;
break;
}
Tx_Rx.tip_STR = 1;
Tx_Rx.date.LCD = LCD;
tx_HC12 (1); // transmitere date LCD
//delay(50);
//Serial.println((char*)LCD.Line[0]);
if (Meniu == 0 || etapa == 5) return;
for ( uint8_t i = 0; i < 4; i++) {lcd.setCursor (0,i); lcd.print((char*)LCD.Line[i]);}
if (alarma == 6)
{
for (uint8_t i = 2; i <= 18; i+=4)
{
lcd.setCursor (i, 3);
if ( bitRead(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*)LCD.Line[0]);
// lcd.setCursor (0,1); lcd.print((char*)LCD.Line[1]);
// lcd.setCursor (0,2); lcd.print((char*)LCD.Line[2]);
// lcd.setCursor (0,3); lcd.print((char*)LCD.Line[3]);
}// end StareCiclu
/******************** FUNCTIE INITIALIZARE CICLU ***********************/
void Initializare_Ciclu ()
{
//oprim toate pompele
for ( uint8_t x = 0; x < 5; x++ ){pcf8575.digitalWrite( x, HIGH);}
// pcf8575.digitalWrite( 4, HIGH); // opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
// pcf8575.digitalWrite( 3, HIGH); // opreste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
// pcf8575.digitalWrite( 2, HIGH); // opreste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 0
// pcf8575.digitalWrite( 1, HIGH); // opreste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
// pcf8575.digitalWrite( 0, HIGH); // opreste releul de pe pinul pcf8575 P01 care activeaza pompa de aerare bazin 2
// reseteaza intarzierea
intarziere_Pin_D8 = 0;
intarziere_Pin_D9 = 0;
//reinitializez toate variabilele pentru o etapa de epurare noua
Scrie_Citeste_EEPROM (1);
AerareB1 = {POMPA.Bazin_1_Aerare, POMPA.Bazin_1_Linistire , true };
AerareB2 = {POMPA.Bazin_2_Aerare, POMPA.Bazin_2_Linistire , true };
Recirculare = {POMPA.PornireRecirculare, POMPA.AsteptareRecirculare , true };
Evacuare = {POMPA.PornireEvacuare, POMPA.LinistireEvacuare, false};
PornireEvacuareInBazin2 = POMPA.PornireEvacuare + INTARZIERE_PLUTITOR;
ORA_Recirculare = 0; //daca apare evenimentul evacuare si recircularea nu s-a efectuat
LinistireREC = POMPA.LinistireEvacuare;
// schimb pozitia electrovanei cu trei cai penru recirculare normala
if (timp_Vacanta < INTERVAL_VACANTA) pcf8575.digitalWrite( 5, HIGH);
}
/************************ DOZARE FLOCULANT **************************/
// aceasta functie porneste pompele peristaltice pentru dozarea floculantului
// procesul are loc la finalul etapei de evacuare
// pt dizolvarea/amestecarea floculantului se realizeaza in etapa de aerare
// bazin = 0 - continua dozarea implicit
// 1 - dozeaza doar in bazin 1
// 2 - dozeaza doar in bazin 2
// 3 - dozeaza in bazin 1 si bazin 2
void Dozare_Floculant (const uint8_t& bazin = 0)
{
if (timpDozareFLOCULANT == 0)
{
dozareFLOCULANT = true;
if (bazin == 1 || bazin == 3)
{
pcf8575.digitalWrite( 0, LOW); // porneste releul de pe pinul pcf8575 P01 care activeaza pompa de aerare bazin 2
pcf8575.digitalWrite( 6, LOW); // porneste releul de pe pinul pcf8575 P06 care activeaza pompa peristaltica bazin 1
}
if (bazin == 2 || bazin == 3)
{
pcf8575.digitalWrite( 1, LOW); // porneste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
pcf8575.digitalWrite( 7, LOW); // porneste releul de pe pinul pcf8575 P07 care activeaza pompa peristaltica bazin 2
}
}
timpDozareFLOCULANT++;
if (POMPA.PompaPeristaltica_B1 > POMPA.PompaPeristaltica_B2)
{
if (timpDozareFLOCULANT > ((POMPA.PompaPeristaltica_B1 / DEBIT_POMPA_PERISTALTICA) * 60))// secunde
{
pcf8575.digitalWrite( 6, HIGH); // opreste releul de pe pinul pcf8575 P06 care activeaza pompa peristaltica bazin 1
timpDozareFLOCULANT = 0;
dozareFLOCULANT = false;
}
if (timpDozareFLOCULANT > ((POMPA.PompaPeristaltica_B2 / DEBIT_POMPA_PERISTALTICA) * 60 ))// secunde
{
pcf8575.digitalWrite( 7, HIGH); // opreste releul de pe pinul pcf8575 P06 care activeaza pompa peristaltica bazin 2
}
}
else if (POMPA.PompaPeristaltica_B2 > POMPA.PompaPeristaltica_B1)
{
if (timpDozareFLOCULANT > ((POMPA.PompaPeristaltica_B1 / DEBIT_POMPA_PERISTALTICA) * 60))// secunde
{
pcf8575.digitalWrite( 6, HIGH); // opreste releul de pe pinul pcf8575 P06 care activeaza pompa peristaltica bazin 1
}
if (timpDozareFLOCULANT > ((POMPA.PompaPeristaltica_B2 / DEBIT_POMPA_PERISTALTICA) * 60))// secunde
{
pcf8575.digitalWrite( 7, HIGH); // opreste releul de pe pinul pcf8575 P06 care activeaza pompa peristaltica bazin 2
timpDozareFLOCULANT = 0;
dozareFLOCULANT = false;
}
}
else // (POMPA.PompaPeristaltica_B1 == POMPA.PompaPeristaltica_B2)
{
if (timpDozareFLOCULANT > ((POMPA.PompaPeristaltica_B1 / DEBIT_POMPA_PERISTALTICA) * 60))// secunde
{
pcf8575.digitalWrite( 6, HIGH); // opreste releul de pe pinul pcf8575 P06 care activeaza pompa peristaltica bazin 1
pcf8575.digitalWrite( 7, HIGH); // opreste releul de pe pinul pcf8575 P06 care activeaza pompa peristaltica bazin 1
timpDozareFLOCULANT = 0;
dozareFLOCULANT = false;
}
}
}//end Dozare_Floculant()
/**************************** FUNCTIE RECUPERARE TIMP LINISTIRE *****************************************/
// Acesta functie returneaza timpul recuperat dintr-o perioada de linistire aerare sau recirculare
// si se utilizeaza pt micsorarea timpului de linistire la evacuare si recirculare
uint16_t Recuperare_Timp_Linistire()
{
int16_t RecTimpLinistire = 0;
if ((AerareB1.OP == 0 && AerareB2.OP == 0) ) // etapa de evacuare sau recirculare a aparut in perioada linistirii aerarii
{
if ((POMPA.Bazin_1_Linistire * vacanta - AerareB1.CL) >= (POMPA.Bazin_2_Linistire * vacanta - AerareB2.CL))// retine cel mai mic timp de linistire in timpul aerarii
{
RecTimpLinistire = POMPA.Bazin_2_Linistire * vacanta - AerareB2.CL;
}
else
{
RecTimpLinistire = POMPA.Bazin_1_Linistire * vacanta - AerareB1.CL;
}
if (POMPA.LinistireEvacuare > RecTimpLinistire)
{
return (POMPA.LinistireEvacuare - RecTimpLinistire);
}
else
{
return 0;
}
}
else if ((Recirculare.CL == 0 && LinistireREC != 0) && (intarziere_Pin_D8 >= INTARZIERE_PLUTITOR))// numai etapa de evacuare a aparut in perioada linistirii recircularii
{
RecTimpLinistire = LinistireREC;
return LinistireREC;
}
else//nu se afla nici in linistire aerare, nici in linistire recirculare
{
RecTimpLinistire = 0;
}
return RecTimpLinistire;
}
/************************* FUNCTIE TRATARE EVENIMENTE ISR() PINI IN ISR() TIMER **************************/
void call_ISR_Timer (void)
{
// se pastreaza ordinea if-urilor pt functionare corecta:
// 0. prea gol
// 1. prea plin
// 2. evacuare
// 3. recirculare
// 4. aerare
int16_t tmp = 0;
static uint8_t TIMP_Evacuare_PreaPlin = 0;//este utilizata pentru evacuare prea plin BAZIN 2
static uint8_t tmp_ALARMA = 0; // stocheaza temporar alarma aparuta inainte de alarma preaplin si
// este folosita strict pentru afisare
static bool stare_nivel_B2_Pin_D9 = 0; // stocheaza starea senzorului de nivel Bazin 2 dupa evauare sau
// cand apare alarma 3 si 4 si este folosit pentru evitare evacuare
// in mod continu cand senzorul de nivel din bazin 1 si/sau bazin2 raman cuplati
/**** DOZARE FLOCULANT *****/
// aici se continua procesul de dozare floculant pana la finalizare
if (dozareFLOCULANT) Dozare_Floculant();
/**** PREA GOL BAZIN 1 SI 2 IN SERIE *****/
// cand apare evenimentul prea gol nu se executa functia
// si se opresc toate pompele incercand sa echilibrez nivelul
// PIN prea_gol Bazin 1 PIN prea_gol Bazin 2
// if (((PINB & (1 << PB3)) != 0) && (alarma != 5))
// {
// if (alarma != 5) tmp_ALARMA = alarma;
// for( uint8_t x = 0; x <= 5; x++){pcf8575.digitalWrite( x, HIGH);}//opresc pompele
// // pcf8575.digitalWrite( 5, HIGH); // opreste releul de pe pinul pcf8575 P05 care activeaza electrovalva
// // pcf8575.digitalWrite( 4, HIGH); // opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
// // pcf8575.digitalWrite( 3, HIGH); // opreste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
// // pcf8575.digitalWrite( 2, HIGH); // opreste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 1 sau 0
// // pcf8575.digitalWrite( 1, HIGH); // opreste releul de pe pinul pcf8575 P01 care activeaza pompa de aerare bazin 1
// // pcf8575.digitalWrite( 0, HIGH); // opreste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 2
// LCD.Alarma[4]<255 ? LCD.Alarma[4] += 1 : LCD.Alarma[4] = 255;
// alarma = 5;// alarma prea gol
// StareCiclu (4);// afisez starea prea gol BAZIN 1 si 2
// return;
// }
// else if (((PINB & (1 << PB3)) == 0) && alarma == 5)
// {
// // restabilesc starea dinainte de prea gol
// alarma = tmp_ALARMA;
// // pornim pompele corespunzatoare etapei intrerupte de prea plin fara reluarea umplerii
// if((Evacuare.SS == true ) && (Evacuare.CL == 0) && (Evacuare.OP != 0)) pcf8575.digitalWrite( 4, LOW);// reia evacuare in exterior
// //else pcf8575.digitalWrite( 4, HIGH); //opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
// if((Evacuare.SS == true ) && (Evacuare.CL == 0) && (Evacuare.OP == 0)) pcf8575.digitalWrite( 3, LOW);// reia umplerea
// if ((Recirculare.SS == true ) && (LinistireREC == 0))
// {
// pcf8575.digitalWrite( 3, LOW); // porneste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
// pcf8575.digitalWrite( 2, LOW); // porneste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 1
// }
// if ((AerareB1.SS == true) && (AerareB1.OP != 0) && (AerareB1.CL == POMPA.Bazin_1_Linistire)) pcf8575.digitalWrite( 1, LOW); // porneste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
// if ((AerareB2.SS == true) && (AerareB2.OP != 0) && (AerareB2.CL == POMPA.Bazin_2_Linistire)) pcf8575.digitalWrite( 0, LOW); // porneste releul de pe pinul pcf8575 P01 care activeaza pompa de aerare bazin 2
// }
// else if (alarma == 5) {StareCiclu (4); return;}
/**** VACANTA *****/
// apare daca statia nu este utilizata mai mult de 48 de ore
// adica nu evacueaza in exterior
// aici calculez timpul pt vacanta
timp_Vacanta ++;// reprezinta timpul de la aparitia ultimului eveniment EVACUARE
if (alarma_Evacuare >= 0) alarma_Evacuare ++;//reprezinta timpul de la aparitia ultimei alarme provocata de blocarea senzorului de nivel din Bazin 1
if (timp_Vacanta == INTERVAL_VACANTA) // activez starea de vacanta daca timp
{ // de 48 de ore nu s-a produs evacuarea
vacanta = 2; // aceste variabile sunt resetate cand
} // apare evenimentul evacuare
/**** PREA PLIN BAZIN 2 ****/
/* 1) acest eveniment apare atunci cand plutitorul de nivel din BAZIN 1 nu este cuplat si
plutitorul de prea plin cupleaza, adica BAZIN 1 sa umplut si nu porneste evacuarea,
transferul de apa in BAZIN 2 facanduse hidraulic pana cand se ajunge la nivelul de prea plin
din BAZIN 2 fiind necesara evacuarea
2) cand plutitorului de nivel BAZIN 1 declanseaza procesul de evacuare dar pompa de evacuare
in exterior nu porneste sau este arsa si comunicarea intre bazine se realizeaza hidraulic
pana cand se atinge nivelul de prea plin din BAZIN 2
*/
if (((PINB & (1 << PB2)) != 0) && (TIMP_Evacuare_PreaPlin >= EVACUARE_PREA_PLIN ))//plutitorul a revenit la normal dupa evacuare preaplin
{
if (TIMP_Evacuare_PreaPlin <= POMPA.PornireEvacuare )// restabilesc starea dinainte de prea plin
{ // deoarece plutitorul a revenit la normal
// in timpul evacuarii prea plin
// daca sa depasit timpul POMPA.PornireEvacuare
// nu se mai restabileste starea deoarece
// s-a iesit din alarma si statia isi face ciclurile normale
(tmp_ALARMA > 2) ? alarma = tmp_ALARMA : alarma = 0;
// pornim pompele corespunzatoare etapei intrerupte de prea plin fara reluarea umplerii
if((Evacuare.SS == true ) && (Evacuare.CL == 0) && (Evacuare.OP != 0)) {/* pompa de evacuare ramane pornita*/}// ramane pornit releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
else pcf8575.digitalWrite( 4, HIGH); //opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
if((Evacuare.SS == true ) && (Evacuare.CL == 0) && (Evacuare.OP == 0)) pcf8575.digitalWrite( 3, LOW);// reia umplerea
if ((Recirculare.SS == true ) && (LinistireREC == 0))
{
pcf8575.digitalWrite( 3, LOW); // porneste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
pcf8575.digitalWrite( 2, LOW); // porneste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 1
}
if ((AerareB1.SS == true) && (AerareB1.OP != 0) && (AerareB1.CL == POMPA.Bazin_1_Linistire)) pcf8575.digitalWrite( 1, LOW); // porneste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
if ((AerareB2.SS == true) && (AerareB2.OP != 0) && (AerareB2.CL == POMPA.Bazin_2_Linistire)) pcf8575.digitalWrite( 0, LOW); // porneste releul de pe pinul pcf8575 P01 care activeaza pompa de aerare bazin 2
}
prea_plin_B2_Pin_D10 = false;
TIMP_Evacuare_PreaPlin = 0;
}
if (((PINB & (1 << PB2)) == 0) && (TIMP_Evacuare_PreaPlin == 0))
{
prea_plin_B2_Pin_D10 = true; // pin D10 este pentru prea plin din Bazin 2
// se evacueaza in exterior 50 litri
tmp_ALARMA = alarma;
for( uint8_t x = 0; x < 4; x++){pcf8575.digitalWrite( x, HIGH);}//opresc pompele
// pcf8575.digitalWrite( 3, HIGH); // opreste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
// pcf8575.digitalWrite( 2, HIGH); // opreste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 0
// pcf8575.digitalWrite( 1, HIGH); // opreste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
// pcf8575.digitalWrite( 0, HIGH); // opreste releul de pe pinul pcf8575 P01 care activeaza pompa de aerare bazin 2
pcf8575.digitalWrite( 4, LOW); // porneste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
ACS712_POMPA(2, P2_3);//verifica pompa de evacuare daca este arsa cand sa atins prea plinul
TIMP_Evacuare_PreaPlin++; alarma = 1;
LCD.Alarma[0]<255 ? LCD.Alarma[0] ++ : LCD.Alarma[0] = 255;// stochez aparitia alarmei
StareCiclu (4);// afisez starea prea plin BAZIN 2
return;
}
else if (prea_plin_B2_Pin_D10 && (TIMP_Evacuare_PreaPlin < EVACUARE_PREA_PLIN)) // evacueaza in exterior parte din prea plin
{
TIMP_Evacuare_PreaPlin++; //alarma = 1;
//StareCiclu (4);// afisez starea prea plin BAZIN 2 cat timp dureaza " EVACUARE_PREA_PLIN "
if (TIMP_Evacuare_PreaPlin <= EVACUARE_PREA_PLIN) return;
}
else if (prea_plin_B2_Pin_D10 && (TIMP_Evacuare_PreaPlin >= EVACUARE_PREA_PLIN)) // a evacuat in exterior parte din plin
{ // dar senzorul de nivel pt prea plin
// nu s-a decuplat
if ((TIMP_Evacuare_PreaPlin < POMPA.PornireEvacuare)) // preventiv continua evacuarea pana se atinge timpul " PornireEvacuare "
{ // daca contactul este activ debitul este asa de mare incat pompa de
// nu face fata (complicat sa se intample deoarece pompa din put are 3 mc/h)
// sau senzorul a ramas lipit din cauza mizeriei
alarma = 2; // declansez alarma 2, adica pompa de evacuare este arsa sau
// plutitorul prea-plin blocat, va functiona hidraulic
// pompa de evacuare se opreste in cazul plutitorului blocat cand
// este depasit timpul de evacuare intr-un ciclu normal si
// revine la ciclul normal cand se deblocheaza
if (TIMP_Evacuare_PreaPlin == EVACUARE_PREA_PLIN) LCD.Alarma[1]<255 ? LCD.Alarma[1] ++ : LCD.Alarma[1] = 255;// stochez aparitia alarmei
TIMP_Evacuare_PreaPlin++;
StareCiclu (4);// afisez starea prea-plin BAZIN 2 pana cand se termina timpul " PornireEvacuare "
return;
}
else if ((TIMP_Evacuare_PreaPlin == POMPA.PornireEvacuare ))// s-a atins timpul maxim de evacuare
{
pcf8575.digitalWrite( 4, HIGH); //opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
TIMP_Evacuare_PreaPlin++;// mai adun o unitate pt ca sa se depaseasca " PornireEvacuare "
// restabilesc starea dinainte de prea plin deoarece plutitorul plutitorul nu revine la normal
// si a fost consumat timpul de pornire evacuare insemna ca pompa de evacuare s-a ars sau plutitorul a ramas cuplat
(tmp_ALARMA > 2) ? alarma = tmp_ALARMA : alarma = 0;
// pornim pompele corespunzatoare etapei intrerupte de prea plin
if(Evacuare.SS == true ) {Evacuare.OP = 0; Evacuare.CL = 0;}// sare peste etapa de evacuare daca
// daca evenimentul de prea plin a
// aparut in timpul evacuarii
//if((Evacuare.SS == true ) && (Evacuare.CL == 0) && (Evacuare.OP != 0)) pcf8575.digitalWrite( 4, LOW);// else pcf8575.digitalWrite( 4, HIGH); //opreste / porneste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
if ((Recirculare.SS == true ) && (LinistireREC == 0))
{
pcf8575.digitalWrite( 3, LOW); // porneste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
pcf8575.digitalWrite( 2, LOW); // porneste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 0
}
if ((AerareB1.SS == true) && (AerareB1.OP != 0) && (AerareB1.CL == POMPA.Bazin_1_Linistire)) pcf8575.digitalWrite( 1, LOW); // porneste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
if ((AerareB2.SS == true) && (AerareB2.OP != 0) && (AerareB2.CL == POMPA.Bazin_2_Linistire)) pcf8575.digitalWrite( 0, LOW); // porneste releul de pe pinul pcf8575 P01 care activeaza pompa de aerare bazin 2
}
}
// end Prea Plin
/**** EVACUARE ****/
if (bitRead(LCD.Alarma[5], 4) && prea_plin_B2_Pin_D10) // pt. alarma 5 se evita evacuare continu
{ // deoarece pompa de evacuare este sigur arsa sau
goto Evita_Evacuarea; // senzorul de prea plin a ramas lipit in contact
}
else if (alarma_Evacuare >= 0 && alarma_Evacuare < INTERVAL_VACANTA / 2) // evita Evacuarea daca senzorul de nivel Bazin 1 a ramas cuplat
{ // si umplerea Bazin 2 s-a terminat - adica a aparut alarma 4
// pentru a se evita evacuarea repetitiva
// alarma_Evacuare este setata 0 cand apare alarma 4
if ((PINB & (1 << PB0)) != 0) alarma_Evacuare = -1;// evacuarea revine la normal daca senzorul de nivel Bazin 1 se decupleaza
else if (!stare_nivel_B2_Pin_D9 && (PINB & (1 << PB1)) == 0) alarma_Evacuare = -1;// se executa evacuarea daca senzorul de nivel
// Bazin 2 s-a cuplat prin echilibrare hidraulica
// si senzorul de nivel Bazin 1 este cuplat in continuare
else goto Evita_Evacuarea;
}
else if ((alarma_Evacuare == INTERVAL_VACANTA / 2))// forteaza evacuarea odata la 24 ore daca a aparut alarma 4
{ // cu conditia ca prea plinul din Bazin 2 sa nu fie cuplat
// altfel functioneaza hidraulic
// aerarea si recircularea functioneaza normal
prea_plin_B2_Pin_D10 ? alarma_Evacuare = 0 : alarma_Evacuare = -1;
}
/******* Eliminare semnale false generate de plutitorul de nivel Bazin 1 - Pin D8 *********/
//produce intarzierea pt. eliminarea semnalelor false pe senzorul de nivel bazin 1
if (((PINB & (1 << PB0)) == 0) && (intarziere_Pin_D8 < INTARZIERE_PLUTITOR))// daca plutitorul din Bazin 1 este cuplat "INTARZIERE_PLUTITOR secunde"
{ // se executa evacuarea
nivel_B1_Pin_D8 = true;
Evacuare.SS = true;
intarziere_Pin_D8++;// se produce o intarziere de "INTARZIERE_PLUTITOR secunde" necesara pentru ca plutitorul sa fie inundat
goto Evita_Evacuarea;// evita codul de evacuare
}
else if (((PINB & (1 << PB0)) != 0) && (intarziere_Pin_D8 < INTARZIERE_PLUTITOR))//daca plutitorul din Bazin 1 nu este cuplat "INTARZIERE_PLUTITOR secunde"
{ // nu se executa evacuarea
nivel_B1_Pin_D8 = false;
Evacuare.SS = false;
intarziere_Pin_D8 = 0;
goto Evita_Evacuarea;// evita codul de evacuare
}
/****************************************************************************/
/* -------aici incepe procesul de linistire, evacuare in exterior si umplere Bazin 2--------------------------------------*/
if (nivel_B1_Pin_D8 && Evacuare.SS )//eveniment pin D8 - Bazinul 1 sa umplut, opreste aerarea si
{ //recircularea pornind evacuarea,
//daca pompa de evacuare in BAZIN 1 sau BAZIN 2 s-a ars,
//functioneza ca vase comunicante
// Verifica pozitia plutitorului de nivel din Bazin 2
if ((PINB & (1 << PB1)) == 0)
{nivel_B2_Pin_D9 = true;}
else
{nivel_B2_Pin_D9 = false; }
StareCiclu (1);// afisez starea pentru evacuare cand nu avem alarme in evacuare
if (Evacuare.SS == true && Evacuare.CL == POMPA.LinistireEvacuare)// verifica daca evacuarea a aparut in timpul
{ //linistirii aerare sau recirculare
// stabileste timpul de linistire in functie de starea in care se afla statia
// adica daca se afla in perioada de linistire aerare sau recirculare
// timpul de linistire evacuare este doar diferenta de timp
tmp = Recuperare_Timp_Linistire();
if (Evacuare.CL >= tmp && tmp != 0)
{
Evacuare.CL = tmp + 1;
}
else if (Evacuare.CL < tmp && tmp != 0)
{
Evacuare.CL = 1;
}
AerareB1.SS = false; AerareB2.SS = false; Recirculare.SS = false; Evacuare.CL--;
//oprim toate pompele
for( uint8_t x = 0; x < 5; x++){pcf8575.digitalWrite( x, HIGH);}
// pcf8575.digitalWrite( 4, HIGH); // opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
// pcf8575.digitalWrite( 3, HIGH); // opreste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
// pcf8575.digitalWrite( 2, HIGH); // opreste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 0
// pcf8575.digitalWrite( 1, HIGH); // opreste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
// pcf8575.digitalWrite( 0, HIGH); // opreste releul de pe pinul pcf8575 P01 care activeaza pompa de aerare bazin 2
timp_Vacanta = 0; vacanta = 1; // resetez starea de vacanta
pcf8575.digitalWrite( 5, HIGH); // schimb pozitia electrovanei cu trei cai penru recirculare normala
return;
}
else if ((Evacuare.SS == true) && (Evacuare.CL <= POMPA.LinistireEvacuare))// incepe perioada de linistire
{
/*---------------- linistire ----------------------------------------------------------------------------------*/
// aici continua procesul de linistire
if ( Evacuare.CL != 0 ) // releul pe pinul pcf8575 P04 este Normal Close pt. perioada CL
{
Evacuare.CL--;
if ((Evacuare.CL == 0) && (Evacuare.OP == POMPA.PornireEvacuare) && nivel_B1_Pin_D8 && !nivel_B2_Pin_D9)
{
Evacuare.OP = 0;// sare peste etapa de evacuare in exterior daca plutitorul din Bazin 2 nu este la nivel
return; // prin aceasta se realizeaza echilibrarea volumetrica a statiei de epurare
}
return;
}
//------------------ evacuare -----------------------------------------------------------------------------------*/
//aici incepe evauarea in exterior
if((Evacuare.CL == 0) && (Evacuare.OP == POMPA.PornireEvacuare) && nivel_B2_Pin_D9)// sa terminat linistirea si incepe evacuarea
{
pcf8575.digitalWrite( 4, LOW);// porneste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
//delay(20);//astept sa cupleze releul pompei
ACS712_POMPA(2, P2_3);//verifica pompa de evacuare
Evacuare.OP--;
return;
}
else if ((Evacuare.OP != 0) && nivel_B2_Pin_D9 )// daca apa de evacuat este mai sus de plutiorul de nivel din BAZIN 2, adica in timpul
{ // linistirii pt. evacuare sa depasit prea plinul hidraulic din BAZIN 1, elimina
Evacuare.OP--; // surplusul si revine la PornireEvacuare in cadrul ISR pin D9 cand se modifica starea plutiorului
surplus_Evacuare = true;
if (Evacuare.OP == 0) // pompa evacuare in exterior defecta sau senzor de nivel BAZIN 2 blocat ON(cuplat)
{ // fara ca preaplinul sa fie atins
stare_nivel_B2_Pin_D9 = nivel_B2_Pin_D9;
alarma = 3; // declansez ALARMA - nu s-a decuplat senzorul de nivel in Bazin 2
LCD.Alarma[2]<255 ? LCD.Alarma[2] += 1 : LCD.Alarma[2] = 255;
//StareCiclu (4); // afisez starea cand s-a declansat alarma
//Initializare_Ciclu();
return;
}
}
else if ((Evacuare.OP != 0) && !nivel_B2_Pin_D9)// a fost eliminat surplusul de apa si evacueaza cantitatea de apa epurata
{
Evacuare.OP--;
if (surplus_Evacuare) // daca exista surplus de apa aparut in timpul linistirii
{ // reinitializeaza timpul de evacuare dupa eliminarea
Evacuare.OP = POMPA.PornireEvacuare; // surplusului pentru a se pastra timpii de epurare
surplus_Evacuare = false;
}
if (Evacuare.OP == 0) {stare_nivel_B2_Pin_D9 = nivel_B2_Pin_D9;}
return;
}
//-------------- umplere bazin 2 ---------------------------------------------------------------------------------------*/
//aici incepe umplerea bazinului 2
if (Evacuare.CL == 0 && Evacuare.OP == 0 )// s-a epuizat linistirea si evacuarea
{
//Serial.println(PornireEvacuareInBazin2);
if (PornireEvacuareInBazin2 == POMPA.PornireEvacuare + INTARZIERE_PLUTITOR)// se umple Bazinul 2 dupa ce a fost evacuat in exterior
{ // daca senzorul de nivel din Bazinul 2-pin D9 nu este decuplat
pcf8575.digitalWrite( 4, HIGH); // opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
if (!prea_plin_B2_Pin_D10 ) // porneste pompa de umplere daca preaplinul nu este cuplat,
{ // altfel transferul se realizeaza hidraulic
pcf8575.digitalWrite( 3, LOW); // porneste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
//PornireEvacuareInBazin2--;
}
PornireEvacuareInBazin2--;
return;
}
else if (PornireEvacuareInBazin2 >= 0 && PornireEvacuareInBazin2 <= POMPA.PornireEvacuare + INTARZIERE_PLUTITOR) //umple bazinul 2 dupa evacuare
{ // pompa are 100 litri/min si are
// nevoie de 180 secunde de a evacua
// 300 litri in bazinul 2
if (!nivel_B2_Pin_D9 && PornireEvacuareInBazin2 != 0 && !prea_plin_B2_Pin_D10)
{
PornireEvacuareInBazin2-- ; // continua umplerea bazin 2
return;
}
else if (PornireEvacuareInBazin2 == 0 && !prea_plin_B2_Pin_D10)
{
if (((PINB & (1 << PB0)) == 0))// senzorul de nivel bazin 1 a ramas
{ // cuplat-senzor nivel defect sau murdar
// sau pompa de umplere defecta
// se adauga floculant doar in Bazin 2
alarma = 4; // declansez ALARMA - nu s-a decuplat senzorul de nivel in bazin 1
stare_nivel_B2_Pin_D9 = nivel_B2_Pin_D9;
alarma_Evacuare++ ;
LCD.Alarma[3]<255 ? LCD.Alarma[3] += 1 : LCD.Alarma[3] = 255;
StareCiclu (4); // afisez starea cand s-a declansat alarma
Initializare_Ciclu();
Dozare_Floculant (2);// aici incepe introducerea floculantului doar in bazinul 2
// in bazinul 1 nu se introduce floculant deoarece pompa de
// umplere bazin 2 sar putea sa fie arsa si cantitatea de
// floculant dozata la suprafata in bazinul 1 sa ajunga
// hidraulic in bazin 2
return;
}
else if ((PINB & (1 << PB0)) != 0)// umplerea sa facut cu succes
{ // si se adauga floculant in ambele bazine
Initializare_Ciclu();
Dozare_Floculant (3);// aici incepe introducerea floculantului in bazin 1 si bazin 2
return;
}
}
else if (((PINB & (1 << PB0)) == 0 && nivel_B2_Pin_D9) &&
(!prea_plin_B2_Pin_D10 && stare_nivel_B2_Pin_D9))// forteaza umplerea daca senzorul de nivel din
{ // Bazin 2 nu a fost decuplat in urma evacuarii
PornireEvacuareInBazin2-- ;
return;
}
else if (nivel_B2_Pin_D9 && (PornireEvacuareInBazin2 != 0) && !prea_plin_B2_Pin_D10)// senzorul de nivel Bazin 2 s-a cuplat
{ // si nu s-a epuizat timpul de umplere
// continua umplerea 15 secunde
if (intarziere_Pin_D9 < INTARZIERE_PLUTITOR) // pompa de evacuare in Bazin 2 mai functioneaza 15 secunde
{ // aceasta situatie apare in general cand bazinul 2 nu a
// functionat plin si se produce o echilibrare de nivel
intarziere_Pin_D9++; // numara intarzierea de 15 secunde
PornireEvacuareInBazin2 = INTARZIERE_PLUTITOR - intarziere_Pin_D9;
return;
}
}
else if ((PINB & (1 << PB0)) == 0 && PornireEvacuareInBazin2 == 0 ) // s-a terminat umplerea BAZIN 2 si senzorul de nivel din BAZIN 1 este cuplat
{ // senzor nivel defect sau murdar si nu cupleaza sau pompa de umplere defecta
// se adauga floculant doar in Bazin 2
alarma = 4; // declansez ALARMA - nu s-a decuplat senzorul de nivel in bazin 1
stare_nivel_B2_Pin_D9 = nivel_B2_Pin_D9;
alarma_Evacuare++ ;
LCD.Alarma[3]<255 ? LCD.Alarma[3] += 1 : LCD.Alarma[3] = 255;
//StareCiclu (4); // afisez starea cand s-a declansat alarma
Initializare_Ciclu();
Dozare_Floculant (2);// aici incepe introducerea floculantului doar in bazinul 2
// in bazinul 1 nu se introduce floculant deoarece pompa de
// umplere bazin 2 sar putea sa fie arsa si cantitatea de
// floculant dozata la suprafata in bazinul 1 sa ajunga
// hidraulic in bazin 2
return;
}
else if (((PINB & (1 << PB0)) == 0 || nivel_B2_Pin_D9) && prea_plin_B2_Pin_D10)// apare cand senzorul de nivel Bazin 2 nu s-a decuplat dupa evacuare
{ // deoarece verificarea senzorului se face o singura data
// la inceputul umplerii, fapt care arata ca umplerea se realizeaza
// intre nivel bazin 2 si prea plin, adica bazinul 2 a ramas plin
// si prin umplere sa atins nivelul de preaplin si
// " PornireEvacuareInBazin2 " nu a ajuns la 0
// nu se adauga floculant deoarece pompa deevacuare in exterior
// s-ar putea sa fie arsa si cantitatea de floculant dozata
// la suprafata in bazinul 1 sa ajunga hidraulic in bazin 2
alarma = 6; // declansez ALARMA - pompa de evacuare in exterior sigur este arsa
bitClear(LCD.Alarma[5], 4);
//LCD.Alarma[4]<255 ? LCD.Alarma[4] += 1 : LCD.Alarma[4] = 255;
//StareCiclu (4); // afisez starea cand s-a declansat alarma
Initializare_Ciclu();
return;
}
}
}
}
return;
}// end Evacuare
Evita_Evacuarea: // saltul la aceasta eticheta pastreaza procesele
// in functiune pana se realizeaza intarzierea pe
// pinul D8 pentru eliminarea semnalelor false
/**** RECIRCULARE ****/
if (Recirculare.SS == true )//&& !nivel_B1_Pin_D8)
{
ORA_Recirculare++;
//-------------------------------------------------------------------------------
// stabilesc setari pt recirculare vacanta - are loc odata la 48 ore
if (timp_Vacanta >= INTERVAL_VACANTA && timp_Vacanta <= INTERVAL_VACANTA + 10)
{
if (timp_Vacanta == INTERVAL_VACANTA)
{
if (LinistireREC == 0)//evenimentul apare in timpul recircularii
{
//resetez recircularea
LinistireREC = POMPA.LinistireEvacuare;
Recirculare.OP = POMPA.PornireRecirculare;
}
pcf8575.digitalWrite( 3, HIGH); // opreste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
pcf8575.digitalWrite( 2, HIGH); // opreste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 1
pcf8575.digitalWrite( 5, LOW); // schimb pozitia electrovanei cu trei căi penru improspatare apa Bazin 0
}
if (timp_Vacanta == INTERVAL_VACANTA +10) // astept 10 secunde sa se comute vana cu trei căi
{
timp_Vacanta = 0;
Recirculare.CL = 0; ORA_Recirculare = 0; // fortez recircularea pentru improspatare apa Bazin 0
}
//else return;
}
//--------------------------------------------------------------------------------
//recirculare normala
if ((ORA_Recirculare == (NR_SEC_ORA * vacanta)) && (Recirculare.CL != 0)) {Recirculare.CL--; ORA_Recirculare = 0;}
if (Recirculare.CL == 0)
{
StareCiclu (2);// afisez starea pentru Recirculare
if (LinistireREC == POMPA.LinistireEvacuare)
{
// stabilesc timpul de linistire in functie de starea in care se afla statia
// adica daca se afla in perioada de linistire aerare sau recirculare
// timpul de linistire evacuare este doar diferenta de timp
tmp = Recuperare_Timp_Linistire();
if (LinistireREC >= tmp && tmp != 0)
{
LinistireREC = tmp + 1;
}
else if (LinistireREC < tmp && tmp != 0)
{
LinistireREC = 1;
}
AerareB1.OP = POMPA.Bazin_1_Aerare; AerareB2.OP = POMPA.Bazin_2_Aerare;
AerareB1.SS = false; AerareB2.SS = false; LinistireREC--;
//oprim toate pompele
for( uint8_t x = 0; x < 5; x++){pcf8575.digitalWrite( x, HIGH);}
// pcf8575.digitalWrite( 4, HIGH); // opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
// pcf8575.digitalWrite( 3, HIGH); // opreste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
// pcf8575.digitalWrite( 2, HIGH); // opreste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 0
// pcf8575.digitalWrite( 1, HIGH); // opreste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
// pcf8575.digitalWrite( 0, HIGH); // opreste releul de pe pinul pcf8575 P01 care activeaza pompa de aerare bazin 2
return;
}
if (LinistireREC != 0)
{
LinistireREC--;
//StareCiclu (2);// afisez starea pentru Recirculare
return;
}
if (LinistireREC == 0 && Recirculare.OP == POMPA.PornireRecirculare)
{
pcf8575.digitalWrite( 3, LOW); // porneste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
pcf8575.digitalWrite( 2, LOW); // porneste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 0
//delay(20);//astept sa cupleze releul pompelor
ACS712_POMPA(2, P1_2);//verifica pompa de recirculare din bazin 1
ACS712_POMPA(2, P2_2);//verifica pompa de recirculare din bazin 2
Recirculare.OP--;
//StareCiclu (2);// afisez starea pentru Recirculare
return;
}
else if ((LinistireREC == 0) && (Recirculare.OP != 0))
{
Recirculare.OP--;
//StareCiclu (2);// afisez starea pentru Recirculare
return;
}
else if ((LinistireREC == 0) && (Recirculare.OP == 0)) {Initializare_Ciclu(); return;} // s-a terminat recircularea
}
}// end Recirculare
/**** AERARE ****/
if (AerareB1.SS == true && AerareB2.SS == true)//aerarea se face in pararel la timpi diferiti pt fiecare bazin
{
if (AerareB1.OP == POMPA.Bazin_1_Aerare) {AerareB1.CL *= vacanta;}
if (AerareB2.OP == POMPA.Bazin_2_Aerare) {AerareB2.CL *= vacanta;}
StareCiclu (3);// afisez starea pentru Aerare
//aerare Bazin 1
if (AerareB1.OP == POMPA.Bazin_1_Aerare)
{
//oprim pompele de recirculare si evacuare
for( uint8_t x = 2; x < 5; x++){pcf8575.digitalWrite( x, HIGH);}
// pcf8575.digitalWrite( 4, HIGH); // opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
// pcf8575.digitalWrite( 3, HIGH); // opreste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
// pcf8575.digitalWrite( 2, HIGH); // opreste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 0
AerareB1.OP--;
pcf8575.digitalWrite( 1, LOW); // porneste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
//delay(20);//astept sa cupleze releul pompei
ACS712_POMPA(2, P1_1);//verifica pompa de aerare din bazin 1
//AerareB1.CL = AerareB1.CL * vacanta;
}
else if (AerareB1.OP != 0) AerareB1.OP--;
else if ((AerareB1.OP == 0) && (AerareB1.CL == POMPA.Bazin_1_Linistire * vacanta))
{
pcf8575.digitalWrite( 1, HIGH); // opresc releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
AerareB1.CL--;
}
else if ((AerareB1.OP == 0) && (AerareB1.CL != 0)) AerareB1.CL--;
else if ((AerareB1.OP == 0) && (AerareB1.CL == 0))
{
AerareB1.CL = POMPA.Bazin_1_Linistire * vacanta; AerareB1.OP = POMPA.Bazin_1_Aerare;
}
// aerare Bazin 2
if (AerareB2.OP == POMPA.Bazin_2_Aerare)
{
//oprim pompele de recirculare si evacuare
for( uint8_t x = 2; x < 5; x++){pcf8575.digitalWrite( x, HIGH);}
// pcf8575.digitalWrite( 4, HIGH); // opreste releul de pe pinul pcf8575 P04 care activeaza pompa de evacuare in exterior
// pcf8575.digitalWrite( 3, HIGH); // opreste releul de pe pinul pcf8575 P03 care activeaza pompa de evacuare in bazin 2
// pcf8575.digitalWrite( 2, HIGH); // opreste releul de pe pinul pcf8575 P02 care activeaza pompa de evacuare in bazin 0
AerareB2.OP--;
pcf8575.digitalWrite( 0, LOW); // porneste releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 1
//delay(20);//astept sa cupleze releul pompei
ACS712_POMPA(2, P2_1);//verifica pompa de aerare din bazin 1
//AerareB2.CL = AerareB2.CL * vacanta;
}
else if (AerareB2.OP != 0) AerareB2.OP--;
else if ((AerareB2.OP == 0) && (AerareB2.CL == POMPA.Bazin_2_Linistire * vacanta))
{
pcf8575.digitalWrite( 0, HIGH); // opresc releul de pe pinul pcf8575 P00 care activeaza pompa de aerare bazin 2
AerareB2.CL--;
}
else if ((AerareB2.OP == 0) && (AerareB2.CL != 0)) AerareB2.CL--;
else if ((AerareB2.OP == 0) && (AerareB2.CL == 0))
{
AerareB2.CL = POMPA.Bazin_2_Linistire * vacanta; AerareB2.OP = POMPA.Bazin_2_Aerare;
}
}// end Aerare
}// end call_ISR_Timer
/************************ INTRERUPERE ISR PENTRU TIMP ***************************/
// ISR(TIMER1_OVF_vect) //Intrerupere TIMER1
// {
// /************ INTRERUPERE/EVENIMENT CARE MASOARA TIMPUL IN SECUDE **********************************/
// // Acesta intrerupere este folosita pentru functii de timp prin intreruperea functiei " loop () "
// // Se poate utiliza pentru ceas, semnale pe pini, etc. care nu au nevoie de timp de precizie la microsecunda
// //ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { uint32_t temp = Durata} din lib. #include <util/atomic.h>
// // pentru a nu se transmite un rezultat eronat in timpul intreruperii
// flag_Timer1 == true ? flag_Timer1 = false : flag_Timer1 = true;
// //if (Meniu > 0 )
// // {
// // if (flag_Timer1)
// // {
// // flag_Timer1 = false;
// // //Afisare_Meniu_Setup;
// // }
// // else
// // {
// // flag_Timer1 = true;
// // //Afisare_Meniu_Setup;
// // }
// // //Serial.println(flag_Timer1 );
// // }
// }// end ISR TIMER1
/***********************************************************************************/
/************************* INTRERUPERE ISR PENTRU BUTOANE **************************/
//ATENTIE !!! pini D0 si D1 nu se utilizeaza sunt pentru transmisie seriala.
//Pentru pinii D2 si D3 se foloseste attachInterrupt() , ISR()-urile se folosesc doar pentru
//pini pe care nu se poate folosii attachInterrupt()
// ISR (PCINT0_vect)//Portul B - handle pin change interrupt for pcf8575 P00 to D13 here
// {
// nu este utilizat
// } // end of ISR PCINT0_vect
// ISR (PCINT1_vect)//Portul C - handle pin change interrupt for A0 to A5 here
// {
// nu este utilizat
// } // end of ISR PCINT1_vect
// ISR (PCINT2_vect )//Portul D - handle pin change interrupt for D4, D5 si D6 ceilalti nu se folosesc in acest caz
// {
// // //ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
// // {
// // if (((PIND & (1 << PD4)) == 0)) // butonul pe pin D4 este apasat
// // {
// // }
// // if ((PIND & (1 << PD5)) == 0 ) // butonul pe pin D5 este apasat
// // {
// // }
// // if ((PIND & (1 << PD6)) == 0 ) // butonul pe pin D6 este apasat
// // {
// // // Serial.println("DOWN");
// // start = millis();
// // }
// // //while((PIND & (1 << PD6)) != 0 ) { secundeDOWN = millis() - start;}
// // if ((PIND & (1 << PD6)) != 0 )
// // {
// // // Serial.println("UP");
// // secundeDOWN = millis() - start;// butonul pe pin D6 este apasat
// // PCIFR |= bit (PCIF2); // sterge toate intreruperile remanente;
// // }
// // // Serial.print("sec DOWN --- "); Serial.println(secundeDOWN);
// // // Serial.print("millis() --- "); Serial.println(millis());
// // // Serial.print("start --- "); Serial.println(start);
// // }
// } // end of ISR PCINT2_vect
//uint8_tnumDevices = 0;
/************************************************************************************/
void setup()
{
// 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_Set ar trebui sa fie initializata la fel sau copiata din POMPA
POMPA_Set = POMPA;
// Initializarea datelor pentru LCD (daca e cazul)
String tmp = F(" ");
for(int i = 0; i < 4; i++) {
strcpy(LCD.Line[i],tmp.c_str()); // Inițializare cu spații
}
for(int i = 0; i < 5; i++) {
LCD.Temperatura[i] = 0.0;
}
for(int i = 0; i < 6; i++) {
LCD.Alarma[i] = 0;
}
PornireEvacuareInBazin2 = POMPA.PornireEvacuare + INTARZIERE_PLUTITOR;
LinistireREC = POMPA.LinistireEvacuare;
//initialize the seria
Serial.begin(9600);
//initialize the lcd
lcd.backlight();
lcd.init();
//lcd.begin(20, 4);
// Create new characters:
uint8_t Check[] = {
B00000,
B00000,
B00001,
B00010,
B10100,
B01000,
B01000,
B00000
};
lcd.createChar(0, Check);
lcd.setCursor(4,1);
lcd.print(F("INITIALIZARE"));
// calibrez senzorii ACS712
ACS712_POMPA();
//initializare pini pcf8575
for( uint8_t x = 0; x <= 9; x++){pcf8575.pinMode(x, OUTPUT);}
// pcf8575.pinMode(P0, OUTPUT);//P00 pinii marcati pe PCB
// pcf8575.pinMode(P1, OUTPUT);//P01
// pcf8575.pinMode(P2, OUTPUT);//P02
// pcf8575.pinMode(P3, OUTPUT);//P03
// pcf8575.pinMode(P4, OUTPUT);//P04
// pcf8575.pinMode(P5, OUTPUT);//P05
// pcf8575.pinMode(P6, OUTPUT);//P06
// pcf8575.pinMode(P7, OUTPUT);//P07
// pcf8575.pinMode(P8, OUTPUT);//P10
// pcf8575.pinMode(P9, OUTPUT);//P11
pcf8575.begin();// initialize the pcf8575 si folosesc numerotarea secventiala
pcf8575.digitalWrite( 9, LOW);
// initializare pin buzzer
// pinMode(PIN_BUZZER, OUTPUT);// se foloseste pentru dispozitivul SLAVE
// initializare pini senzori de nivel (plutitori cu contacte REED montati in bazine)
for( uint8_t x = 8; x < 13; x++){pinMode(x, INPUT_PULLUP);}
// pinMode(8, INPUT_PULLUP);//senzor bazin 1
// pinMode(9, INPUT_PULLUP);//senzor bazin 2
// pinMode(10, INPUT_PULLUP);//preaplin bazin 2
// pinMode(11, INPUT_PULLUP);//prea gol bazin 1
// pinMode(12, INPUT_PULLUP);//prea gol bazin 2
// initializare pini butoane
for( uint8_t x = 4; x < 8; x++){pinMode(x, INPUT_PULLUP);}
// 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);
//senzori temperatura
//rezolutie 9, 10, 11 sau 12 biți, care corespund la 0,5 °C, 0,25 °C, 0,125 °C și, respectiv, 0,0625 °C.
temperatureSensors.begin(NonBlockingDallas::resolution_12, TIME_INTERVAL);// rezolutie senzor = 12 - adica 0.0625°C precizie
//Callbacks temperatura
//temperatureSensors.onIntervalElapsed(handleIntervalElapsed);
temperatureSensors.onTemperatureChange(handleTemperatureChange);
//temperatureSensors.onDeviceDisconnected(handleDeviceDisconnected);
//Call the following function whenever you want to request a new temperature reading without waiting for TIME_INTERVAL to elapse
// temperatureSensors.requestTemperature();
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
Initializare_Ciclu();
delay(250);
// printez check
lcd.setCursor(3, 1);
lcd.write(uint8_t (0));
delay(250);
pcf8575.digitalWrite( 8, LOW);
delay(50);
pcf8575.digitalWrite( 8, HIGH);
lcd.setCursor(4,2);
lcd.print(F("IMPERECHERE"));
// transfer date wireles HC12
HC12_Transfer_TX.begin(details(Tx_Rx), &Serial); // transmitere catre slave date wireles prin portul fizic UART
HC12_Transfer_RX.begin(details(Tx_Rx), &Serial); // receptionare de la slave date wireles prin portul fizic UART
//solicita date de slave daca slave este pornit
POMPA_Set.Re_set = 6;// adica master a fost oprit sau reprogramat si a intrat in flux
tx_HC12 (2);
delay(10);
for(uint8_t i = 0; i<10; i++) {rx_HC12 ();} // receptionare date POMPA_Set
// printez check inainte de initializare
lcd.setCursor(3, 2);
if (POMPA_Set.Re_set == 255) {lcd.write(uint8_t(0)); POMPA_Set.Re_set = 0;}//slave daca a transmis date POMPA_Set.Re_set = 255
else lcd.print("x");
pcf8575.digitalWrite( 8, LOW);
delay(50);
pcf8575.digitalWrite( 8, HIGH);
delay(50);
/******************************* Pin change interrupt BUTOANE SETARI ********************************************/
// exemplu intrerupri alti pini decat D2 si D3 pentru PORTD, se procedeaza la fel pentru PORTB si PORTC
// sunt trei porturi PORTB, PORTC, PORTD - a se vedea diagrama controlerului si tabelul porturilor;
// DDRB, DDRC, DDRD seteaza I/O pe fiecare pin din port echivalent cu pinMode() mai rapid dar fara PULLUP;
// DDRD |= ~_BV(PD2) | ~_BV(PD4); Pini D2 si D4 setati input;
// DDRD &= (1 << PD2) & (1 << PD4); Pini D2 si D4 setati output;
// PORTD |= (1 << PD2) | (1 << PD4); Pini D2 si D4 setati PULLUP dupa ce sunt setati input ca mai sus;
// pentru fiecare port exista cite o intrerupere PCMSK0, PCMSK1, PCMSK2 - PCINTxx este nr. pinului
// in vectorul de intrerupere - vezi fisa de date a controlerului
// PCMSK2 |= bit (PCINT22); // want pin D6 - stabileste intrerupere pe pinul D6;
// PCMSK2 |= bit (PCINT21); // want pin D5 - stabileste intrerupere pe pinul D5;
// .......................
// PCMSK2 |= bit (PCINT17); // want pin D1 - stabileste intrerupere pe pinul D1;
// PCMSK2 |= bit (PCINT16); // want pin D0 - stabileste intrerupere pe pinul D0;
// sau se mai pot activa toti odata. Bitul cel mai scazut este D0 si se procedeaza pentru toate porturile la fel;
// PCMSK2 |= 0b11111111; in binar
/******************** Initializare pini care activeaza intreruperea pe PORTD ****************************/
//pinii pt. butoane sunt D4, D5 si D6 si sunt initializati mai sus cu pinMode
// PCMSK2 |= 0b01110000; // seteaza D4, D5 si D6 sa activeze ISR() ;
// PCIFR |= bit (PCIF2); // sterge toate intreruperile remanente;
// PCICR |= bit (PCIE2); // activeaza intreruperile;
// initializare pini butoane
// pinMode(PIN_BUTON_SETUP, INPUT_PULLUP);
// pinMode(PIN_BUTON_TIMP_MINUS, INPUT_PULLUP);
// pinMode(PIN_BUTON_TIMP_PLUS, INPUT_PULLUP);
/********************* Initializez TIMER 1 sa cheme ISR la o secunda *************************************/
// calculul si stabilirea registrilor sa facut cu RTM TimerCalc
// TCCR1B = 0x10; // 0001 0000, Disable Timer
// TCCR1A = 0xA2; // 1010 0010
// ICR1 = 31250; // valuare TOP
// TCNT1 = 0x0; // porneste de la 0
// TCCR1B |= 3; // Prescale=64, Enable Timer in binar 0000 0100
// // sau (1<<CS10)|(0 << CS11)|(0 << CS12) prin scriere registrii
// // Set Overflow Interrupt Mask Bit
// TIMSK1 |= 1; // ISR Prototype --> ISR(TIMER1_OVF_vect){}
/*************************************************************************************************/
}// end setup()
void loop()
{
for(uint8_t i = 0; i<5; i++) { rx_HC12 (); delay(10);} // receptionare date POMPA_Set
delay(10);
tx_HC12 (2);// transmite catre slave POMPA_Set
delay(10);
static uint32_t masurare_TIMP = millis();
if ( millis() - masurare_TIMP >= 1000 )
{
masurare_TIMP = millis();
call_ISR_Timer ();
temperatureSensors.update(); // este chemata functia pt citirea temperaturilor
LCD_Back_Light (); // stinge afisajul implicit 30s max 240
}
Defilare_Meniu_Setup(); // intra in meniul SETUP cand buttonul SETUP este apasat
if (Meniu > 0) return;
Info_Help_RstAlarm();//intra in info / help cand este apasat butonul - sau + sau reseteaza alarma cand este apasat butonul RstALARM
}//end loop()
//////////////////////// FUNCTII INTRODUSE IN void 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_SET
// 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
{
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_Set);}// prima rulare a programului
else {EEPROM.get(EE_Address, POMPA);EEPROM.get(EE_Address, POMPA_Set);}// se initializeaza la fiecare resetare
break;
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_Set);
break;
case 3: // se va citi continutul memoriei pentru reinitializare variabile în setare timp pompe
EEPROM.get(EE_Address, POMPA_Set);
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 (subMeniuAERARE == 1 && modificat == 1) {Scrie_Citeste_EEPROM(2); modificat = 0;} //salveaza modificarea pt aerare Bazin 1
// if (subMeniuAERARE == 1) Scrie_Citeste_EEPROM(3);// citeste valorile existente in structura POMPA_Set
if (subMeniuBazin_1_AERARE == 1 )// AERARE
{
if (POMPA_Set.Bazin_1_Aerare <= 230) {if (PBTplus) POMPA_Set.Bazin_1_Aerare += 10; /*modificat = 1;*/ init_SETUP = true;}
if (POMPA_Set.Bazin_1_Aerare >= 40 ) {if (PBTminus) POMPA_Set.Bazin_1_Aerare -= 10; /*modificat = 1;*/ init_SETUP = true;}
val_11 = POMPA_Set.Bazin_1_Aerare; val_22 = POMPA_Set.Bazin_1_Linistire / 60; return;
}
else if (subMeniuBazin_1_AERARE == 2 )// LINISTIRE
{
if (POMPA_Set.Bazin_1_Linistire <= 3300) {if (PBTplus) POMPA_Set.Bazin_1_Linistire += 300; /*modificat = 1;*/ init_SETUP = true;}
if (POMPA_Set.Bazin_1_Linistire >= 600 ) {if (PBTminus) POMPA_Set.Bazin_1_Linistire -= 300; /*modificat = 1;*/ init_SETUP = true;}
val_11 = POMPA_Set.Bazin_1_Aerare; val_22 = POMPA_Set.Bazin_1_Linistire / 60; return;
}
else if (subMeniuBazin_1_AERARE == 3 ) {val_11 = POMPA_Set.Bazin_1_Aerare; val_22 = POMPA_Set.Bazin_1_Linistire / 60; return;}
/*---------------- AERARE BAZIN 2 -------------------*/
// if (subMeniuAERARE == 2 && modificat == 2) {Scrie_Citeste_EEPROM(2); modificat = 0;}// salveaza modificarea pt aerare Bazin 2
// if (subMeniuAERARE == 2) Scrie_Citeste_EEPROM(3);// citeste valorile existente in structura POMPA_Set
if (subMeniuBazin_2_AERARE == 1 )//AERARE
{
if (POMPA_Set.Bazin_2_Aerare <= 230) {if (PBTplus) POMPA_Set.Bazin_2_Aerare += 10; /*modificat = 2;*/ init_SETUP = true;}
if (POMPA_Set.Bazin_2_Aerare >= 40 ) {if (PBTminus) POMPA_Set.Bazin_2_Aerare -= 10; /*modificat = 2;*/ init_SETUP = true;}
val_11 = POMPA_Set.Bazin_2_Aerare; val_22 = POMPA_Set.Bazin_2_Linistire / 60; return;
}
else if (subMeniuBazin_2_AERARE == 2 )//LINISTIRE
{
if (POMPA_Set.Bazin_2_Linistire <= 3300) {if (PBTplus) POMPA_Set.Bazin_2_Linistire += 300; /*modificat = 2;*/ init_SETUP = true;}
if (POMPA_Set.Bazin_2_Linistire >= 600 ) {if (PBTminus) POMPA_Set.Bazin_2_Linistire -= 300; /*modificat = 2;*/ init_SETUP = true;}
val_11 = POMPA_Set.Bazin_2_Aerare; val_22 = POMPA_Set.Bazin_2_Linistire/60; return;
}
else if (subMeniuBazin_2_AERARE == 3 ) {val_11 = POMPA_Set.Bazin_2_Aerare; val_22 = POMPA_Set.Bazin_2_Linistire / 60; return;}
/*---------------- EVACUARE -------------------*/
// if (Meniu == 2 && modificat == 3) {Scrie_Citeste_EEPROM(2); modificat = 0;}// salveaza modificarea pt Evacuare
// if (Meniu == 2) Scrie_Citeste_EEPROM(3);// citeste valorile
if (subMeniuEVACUARE == 1 )//EVACUARE
{
if (POMPA_Set.PornireEvacuare <= 290) {if (PBTplus) POMPA_Set.PornireEvacuare += 10; /*modificat = 3;*/ init_SETUP = true;}
if (POMPA_Set.PornireEvacuare >= 190 ) {if (PBTminus) POMPA_Set.PornireEvacuare -= 10; /*modificat = 3;*/ init_SETUP = true;}
val_11 = POMPA_Set.PornireEvacuare; val_22 = POMPA_Set.LinistireEvacuare / 60; return;
}
else if (subMeniuEVACUARE == 2 )//LINISTIRE evacuare
{
if (POMPA_Set.LinistireEvacuare <= 3600) {if (PBTplus) POMPA_Set.LinistireEvacuare += 300; /*modificat = 3;*/ init_SETUP = true;}
if (POMPA_Set.LinistireEvacuare >= 600 ) {if (PBTminus) POMPA_Set.LinistireEvacuare -= 300; /*modificat = 3;*/ init_SETUP = true;}
val_11 = POMPA_Set.PornireEvacuare; val_22 = POMPA_Set.LinistireEvacuare/60; return;
}
else if (subMeniuEVACUARE == 3 ) {val_11 = POMPA_Set.PornireEvacuare; val_22 = POMPA_Set.LinistireEvacuare/60; return;}
/*---------------- RECIRCULARE -------------------*/
// if (Meniu == 3 && modificat == 4) {Scrie_Citeste_EEPROM(2); modificat = 0;}
// if (Meniu == 3 ) Scrie_Citeste_EEPROM(3);
if (subMeniuRECIRCULARE == 1 )//RECIRCULARE amestec
{
if (POMPA_Set.PornireRecirculare <= 115) {if (PBTplus) POMPA_Set.PornireRecirculare += 5; /*modificat = 4;*/ init_SETUP = true;}
if (POMPA_Set.PornireRecirculare >= 20 ) {if (PBTminus) POMPA_Set.PornireRecirculare -= 5; /*modificat = 4;*/ init_SETUP = true;}
val_11 = POMPA_Set.PornireRecirculare; val_22 = POMPA_Set.AsteptareRecirculare; return;
}
else if (subMeniuRECIRCULARE == 2 )//INTERVAL RECIRCULARE perioada de timp la care se realizeaza
{
if (POMPA_Set.AsteptareRecirculare <= 7) {if (PBTplus) POMPA_Set.AsteptareRecirculare += 1; /*modificat = 4;*/ init_SETUP = true;}
if (POMPA_Set.AsteptareRecirculare >= 4 ) {if (PBTminus) POMPA_Set.AsteptareRecirculare -= 1; /*modificat = 4;*/ init_SETUP = true;}
val_11 = POMPA_Set.PornireRecirculare; val_22 = POMPA_Set.AsteptareRecirculare; return;
}
else if (subMeniuRECIRCULARE == 3 ) {val_11 = POMPA_Set.PornireRecirculare; val_22 = POMPA_Set.AsteptareRecirculare; return;}
/*----------------- FLOCULANT ---------------------*/
// if (Meniu == 4 && modificat == 5) {Scrie_Citeste_EEPROM(2); modificat = 0;}
// if (Meniu == 4 ) Scrie_Citeste_EEPROM(3);
if (subMeniuFLOCULANT == 1 )//DOZARE BAZIN 1
{
if (POMPA_Set.PompaPeristaltica_B1 <= 19) {if (PBTplus) POMPA_Set.PompaPeristaltica_B1 += 1; /*modificat = 5;*/ init_SETUP = true;}
if (POMPA_Set.PompaPeristaltica_B1 >= 1 ) {if (PBTminus) POMPA_Set.PompaPeristaltica_B1 -= 1; /*modificat = 5;*/ init_SETUP = true;}
val_11 = POMPA_Set.PompaPeristaltica_B1; val_22 = POMPA_Set.PompaPeristaltica_B2; return;
}
else if (subMeniuFLOCULANT == 2 )//DOZARE BAZIN 2
{
if (POMPA_Set.PompaPeristaltica_B2 <= 19) {if (PBTplus) POMPA_Set.PompaPeristaltica_B2 += 1; /*modificat = 5;*/ init_SETUP = true;}
if (POMPA_Set.PompaPeristaltica_B2 >= 1 ) {if (PBTminus) POMPA_Set.PompaPeristaltica_B2 -= 1; /*modificat = 5;*/ init_SETUP = true;}
val_11 = POMPA_Set.PompaPeristaltica_B1; val_22 = POMPA_Set.PompaPeristaltica_B2; return;
}
else if (subMeniuFLOCULANT == 3 ) {val_11 = POMPA_Set.PompaPeristaltica_B1; val_22 = POMPA_Set.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- functia este blocanta
// 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() "
bool Timp_Apasare_BTN (const uint8_t btnPIN, const uint16_t timpAPASARE)
{
uint32_t start = millis();
uint16_t tmp = 0;
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)
{
pcf8575.digitalWrite( 9, HIGH);
}
else
{
//creaza efectul de palpaire al ledului corespunzator butonului apasat
while(tmp < (timpAPASARE == 1000 ? timpAPASARE/2 : timpAPASARE)) {pcf8575.digitalWrite( 9, LOW);tmp += 1;}
if (timpAPASARE != 1000) return true;
while(tmp > 0 ) {pcf8575.digitalWrite( 9, HIGH);tmp -= 1;}//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"));
while((PIND & (1 << btnPIN)) == 0){pcf8575.digitalWrite( 9, HIGH);}
lcd.clear();
}
}
}
pcf8575.digitalWrite( 9, LOW);
if (btnPIN == PIN_BUTON_RST_ALARMA && ((millis() - start) >= timpAPASARE * 3)) {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();}
return true;
}
else {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 <= 20; i++ ) {if (meniu_1.length() < 20) {meniu_1 += SP1;} } // se adauga spatii
for ( uint8_t i = 1; i <= 20; i++ ) {if (meniu_2.length() < 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
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 ()
{
//ATOMIC_BLOCK(ATOMIC_RESTORESTATE) // cu LCD_I2C se blocheaza in WOKWI
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_Set.Bazin_1_Aerare, POMPA_Set.Bazin_1_Linistire/60, SEC, MIN ); }
//LINISTIRE
else if (subMeniuBazin_1_AERARE == 2) {Blink_Meniu ( 2, AERARE, LINISTIRE, SAVE_EXIT,POMPA_Set.Bazin_1_Aerare, POMPA_Set.Bazin_1_Linistire/60, SEC, MIN ); }
//SAVE & EXIT
else if (subMeniuBazin_1_AERARE == 3) {Blink_Meniu ( 3, AERARE, LINISTIRE, SAVE_EXIT,POMPA_Set.Bazin_1_Aerare, POMPA_Set.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_Set.Bazin_1_Aerare, POMPA_Set.Bazin_1_Linistire/60, SEC, MIN ); }
//LINISTIRE
else if (subMeniuBazin_2_AERARE == 2) {Blink_Meniu ( 2, AERARE, LINISTIRE, SAVE_EXIT,POMPA_Set.Bazin_1_Aerare, POMPA_Set.Bazin_1_Linistire/60, SEC, MIN ); }
//SAVE & EXIT
else if (subMeniuBazin_2_AERARE == 3) {Blink_Meniu ( 3, AERARE, LINISTIRE, SAVE_EXIT,POMPA_Set.Bazin_1_Aerare, POMPA_Set.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_Set.PornireEvacuare, POMPA_Set.LinistireEvacuare/60, SEC, MIN );
//LINISTIRE
else if (subMeniuEVACUARE == 2) Blink_Meniu ( 2, EVACUARE, LINISTIRE, SAVE_EXIT, POMPA_Set.PornireEvacuare, POMPA_Set.LinistireEvacuare/60, SEC, MIN );
//SAVE & EXIT
else if (subMeniuEVACUARE == 3) Blink_Meniu ( 3, EVACUARE, LINISTIRE, SAVE_EXIT, POMPA_Set.PornireEvacuare, POMPA_Set.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_Set.PornireRecirculare, POMPA_Set.AsteptareRecirculare, SEC , ORE );
//ASTEPTARE
else if (subMeniuRECIRCULARE == 2) Blink_Meniu ( 2, PORNIRE, ASTEPTARE , SAVE_EXIT, POMPA_Set.PornireRecirculare, POMPA_Set.AsteptareRecirculare, SEC , ORE );
// SAVE & EXIT
else if (subMeniuRECIRCULARE == 3) Blink_Meniu ( 3, PORNIRE, ASTEPTARE , SAVE_EXIT, POMPA_Set.PornireRecirculare, POMPA_Set.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_Set.PompaPeristaltica_B1, POMPA_Set.PompaPeristaltica_B2, ML, ML);
//DOZAJ BAZIN 2
else if (subMeniuFLOCULANT == 2) Blink_Meniu ( 2, DOZAJ_BAZIN_1, DOZAJ_BAZIN_2 , SAVE_EXIT, POMPA_Set.PompaPeristaltica_B1, POMPA_Set.PompaPeristaltica_B2, ML, ML);
//SAVE & EXIT
else if (subMeniuFLOCULANT == 3) Blink_Meniu ( 3, DOZAJ_BAZIN_1, DOZAJ_BAZIN_2 , SAVE_EXIT, POMPA_Set.PompaPeristaltica_B1, POMPA_Set.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; Initializare_Ciclu();}//se intializeaza cand slave a modificat setarile
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;
Scrie_Citeste_EEPROM(2);//salveaza modificarile efectuate in setup
lcd.clear();
init_SETUP = false; Initializare_Ciclu();
POMPA_Set.Re_set = 2;// se transmite catre slave ca sau modificat setarile
// transmisia se face in functia loop
}
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 (); POMPA_Set.Re_set = 7; tx_HC12 (2);/*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;
if (Meniu > 0) return;
//Serial.println(digitalRead(PIN_BUTON_RST_ALARMA));
if ((PIND & (1 << PD7)) == 0 || POMPA.Re_set == 1)//!digitalRead(PIN_BUTON_RST_ALARMA)
{
rst_alarma = Timp_Apasare_BTN (PIN_BUTON_RST_ALARMA, 1000);
if (rst_alarma || POMPA.Re_set == 1)
{
POMPA.Re_set = 0;
alarma = 0;
LCD.Alarma[0] = 0;
LCD.Alarma[1] = 0;
LCD.Alarma[2] = 0;
LCD.Alarma[3] = 0;
LCD.Alarma[4] = 0; // alarma == 5 ? 1 : 0;// in timpul alarma bazin prea gol pastreaza o singura aparitie
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(); 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(); return;}// iese din help si afiseaza starea curenta
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;
}
//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( LCD.Alarma[i-1]);}
//lcd.setCursor ((i <= 3 ? i : i - 3), (i <= 3 ? i : i - 3));lcd.print(LCD.Alarma[i-1]);
}
lcd.setCursor(15,3);
for (uint8_t i = 0; i <= 4; i++)
{
if ( bitRead(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 <= 3; i++)
// {
// lcd.setCursor (0, i);lcd.print(F("B"));lcd.print(i-1);// aici scriu B0 ... B2
// lcd.setCursor ((LCD.Temperatura[i-1] >= 0 ? 4 : 3), i);lcd.print(LCD.Temperatura[i-1]);
// lcd.setCursor (3, i);lcd.print(LCD.Temperatura[i-1] <= 0 ? "" : "+");
// }
// for (uint8_t i = 1; i <= 2; i++)
// {
// lcd.setCursor ((LCD.Temperatura[i+2] >= 0 ? 15 : 14), i);lcd.print(LCD.Temperatura[i+2]);
// lcd.setCursor (14, i);lcd.print(LCD.Temperatura[i+2] <= 0 ? "" : "+");
// }
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;
if (LCD.Temperatura[i-1] > -10 && LCD.Temperatura[i-1] < 10) {lcd.setCursor (8 + tmp, (i <= 3 ? i : i - 3));lcd.print(" ");}
if (LCD.Temperatura[i-1] > 0)// aici scriu temperaturile cu semn - 0 +
{
lcd.setCursor (3 + tmp, (i <= 3 ? i : i - 3));lcd.print("+");//(LCD.Temperatura[i-1] <= 0 ? "" : "+");
lcd.setCursor (4 + tmp, (i <= 3 ? i : i - 3));lcd.print(LCD.Temperatura[i-1]);
}
else if (LCD.Temperatura[i-1] == 0)
{
//lcd.setCursor (3 + tmp, (i <= 3 ? i : i - 3));lcd.print(" ");
lcd.setCursor (4 + tmp, (i <= 3 ? i : i - 3));lcd.print(LCD.Temperatura[i-1]);
}
else if (LCD.Temperatura[i-1] < 0)
{
lcd.setCursor (3 + tmp, (i <= 3 ? i : i - 3));lcd.print(LCD.Temperatura[i-1]);
}
}
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*)LCD.Line[i]);}
if (info_help == 6)
{
for (uint8_t i = 2; i <= 18; i+=4)
{
lcd.setCursor (i, 3);
if ( bitRead(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*)LCD.Line[0]);
// lcd.setCursor (0,1); lcd.print((char*)LCD.Line[1]);
// lcd.setCursor (0,2); lcd.print((char*)LCD.Line[2]);
// lcd.setCursor (0,3); lcd.print((char*)LCD.Line[3]);
}
}// end Info_Help. . . . . . POMPE . . . . . . .
P2.3 P1.2 .P2.2 .P1.1 P2.1
ElectroVANĂ
. . . 3 cai . . .
------------------PLUTITORI--------------------
. . . . . . . . . . . . . Contacte Reed. . . . . . . . . . . . . .
1-Nivel B1, 2-Nivel B2, 3-PreaPLIN B2, 4-PreaGol B1-B2
POMPA Peristaltica
BAZIN 2 BAZIN 1
ALARMA
B0..... B1..... B2... int.... ext
TEMPERATURA BAZINE
- Pompele sun actionate de module start-soft
- Ledurile care reprezintă pompele în fapt sunt
relee care actioneaza modulele start-soft.
- Mini Pompele peristaltice pentru alimentare
cu floculant sunt alimentate în fapt la 12Vcc.
- Ledul de la electrovana în fapt reprezinta
releul care actioneaza elecrovana cu 3 cai
SE FOLOSESTE UNO DOAR PT SIMULARE IN WOKWI
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
- Indentificarea senzorilor se va face
înainte de intoducerea in bazine
= B0, B1 și B2 reprezinta bazinele în
care sunt introduși senzorii
- int reprezinta senzorul din
interiorul incaperii in care se afla
montate bazinele
- ext reprezinta senzorul aflat in
exteriorul incaperii
CONTROLER MASTER STATIE DE EPURARE HOME MADE RELIZATA DIN REZERVOARE IBC
NOTA : - Acest controler gestioneaza statia si transmite date către slave
. . . . . . .- Modulul HC-12 de comunicare wireles nu este reprezentat in aceasta schema