#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
#include <EEPROM.h>
// Inicializamos las variables.
LiquidCrystal_I2C lcd(0x27, 20, 4); // 0x3F 0x27
DHT dht(10, DHT22);
float temperatura ;
int humedad ;
//Rotary 1 encoder (dial) pins
#define ROT1_EN_A 4 //DT
#define ROT1_EN_B 3 //CLK
#define BTN_MENU 2
const int pumpPin = 9; //Rele nº 1
const int electrovalvula = 8; //Rele nº 2
//const int pumpPin = 7; //Rele nº 3
//const int pumpPin = 6; //Rele nº 4
//Variables para antirebote de encoder
uint8_t lrmem = 3;
int lrsum = 0;
int num = 0;
// Definimos varible de temperatura objetivo
float temperaturaObjetivo ;
// Variable para controlar la opción de forzar manualmente la bomba
bool isPumpForced = false;
// Tiempo de nebulización inicial en segundos (puedes cambiarlo según tus necesidades)
int nebulizationTime ;
// Tiempo entre nebulizaciones inicial en minutos (puedes cambiarlo según tus necesidades)
int tiempoentrenebu ;
//contador de nebulizaciones realizadas
int neburealizadas =0;
//Variables para tiempo entre nebulizacion
unsigned long tiempo1=0;
unsigned long tiempo_ultima_neb=0;
byte result_tiempo=0;
//Preparando antirrebote de boton
bool estadoPulsador, anteriorPulsador;
unsigned long db;
byte Boton=1;
//Leemos el estado de la bomba
byte estadobomba = digitalRead(pumpPin);
//Preparamos para los cambios de estado
int Estado = 1;
int Sig_Estado = 1;
int counter = 0;
int State;
int LastState;
//Configuracion del antirebote del encoder
int8_t rotary()
{
static int8_t TRANS[] = {0,-1,1,14,1,0,14,-1,-1,14,0,1,14,1,-1,0};
int8_t l, r;
l = digitalRead(ROT1_EN_B);
r = digitalRead(ROT1_EN_A);
lrmem = ((lrmem & 0x03) << 2) + 2*l + r;
lrsum = lrsum + TRANS[lrmem];
/* El encoder no esta en estado neutral */
if(lrsum % 4 != 0) return(0);
/* Encoder en el estdo neutral */
if (lrsum == 4)
{
lrsum=0;
return(1);
}
if (lrsum == -4)
{
lrsum=0;
return(-1);
}
/* lrsum > 0 if the impossible transition */
lrsum=0;
return(0);
}
void setup()
{
//leemos los valores de las variables guardados en la eeprom si son iguales de 255 significa que no ha guardado nada todavia y establecemos un valor
//solo la primera vez que se usa en un arduino nuevo luego se puede comentar
temperaturaObjetivo = EEPROM.read(0);
if (temperaturaObjetivo==255) temperaturaObjetivo=20;
nebulizationTime = EEPROM.read(10);
if (nebulizationTime==255) nebulizationTime=5;
tiempoentrenebu = EEPROM.read(20);
if (tiempoentrenebu==255) tiempoentrenebu=2;
Serial.begin(9600);
pinMode(BTN_MENU, INPUT_PULLUP);
pinMode(ROT1_EN_A,INPUT);
pinMode(ROT1_EN_B,INPUT);
pinMode(ROT1_EN_A, INPUT_PULLUP);
pinMode(ROT1_EN_B, INPUT_PULLUP);
pinMode(pumpPin, OUTPUT);//Definimos el pin de la bomba como salida
digitalWrite(pumpPin, HIGH); // Inicialmente apagamos la bomba
pinMode(electrovalvula, OUTPUT);//Definimos el pin de la elecrovalvula
digitalWrite(electrovalvula, HIGH); // Inicialmente apagamos la electrovalvula
// Inicializamos el sensor DHT.
dht.begin();
// Inicializamos la pantalla.
lcd.init();
lcd.backlight();
lcd.clear();
lcd.print("Control Nebulizador");
lcd.setCursor(0, 3);
lcd.print("Insect Killer Plants");
//Esperamos 3 segundos
delay(3000);
lcd.clear();
}
void loop()
{
tiempo1=millis();//Cogemos el valor de millis en este momento y lo asignamos a la variable tiempo 1
estadobomba = digitalRead(pumpPin); //Leemos el estado de la bomba
///ANTIRREBOTE PULSADOR
estadoPulsador=digitalRead(BTN_MENU);
if(!estadoPulsador && anteriorPulsador && millis() -db >=150UL){
Boton--;
db=millis();
}
anteriorPulsador=estadoPulsador;
Estado = Sig_Estado; //Asignamos el valor de estado a la varable sig estado
//Menu inicial....ESTADO 1...
if(Estado == 1)
{ tiempo1=millis();
// Obtenemos la temperatura y la humedad del sensor DHT.
temperatura = dht.readTemperature();
humedad = dht.readHumidity();
lcd.setCursor(0, 0);
lcd.print("Temp: ");
lcd.print(temperatura, 1);
lcd.write( (char)223);
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Hume: ");
lcd.print(humedad, 1);
lcd.print(" %");
lcd.setCursor(0, 3);
lcd.print("Neb.Realiz: ");
lcd.print(neburealizadas);
if (tiempoentrenebu <=((tiempo1-tiempo_ultima_neb)/1000)/60){
result_tiempo=0;
}
if(estadobomba == 1 && temperatura >= temperaturaObjetivo && result_tiempo == 0){
lcd.clear();
digitalWrite(electrovalvula, LOW);
delay(1000);
digitalWrite(pumpPin, LOW);
isPumpForced=1;
Sig_Estado = 43;
}
if (Boton ==0){
Boton=1;
Sig_Estado = 2;
}
}
// Estado 2....
else if(Estado == 2)
{Serial.println (Boton);
int menu;
String arrayMenu[] = {"Visualizacion","Configuracion"};
int size = sizeof(arrayMenu) / sizeof(arrayMenu[0]);
menu = menuANTIFALLOSLENTO(arrayMenu,size); // no hace falta poner el numero 6, se calcula automaticamente. Solo debes de cambiar arrayMenu
if(menu == -1)Sig_Estado = 1;
else if(menu == 1)Sig_Estado = 3;
else if(menu == 2)Sig_Estado = 4;
}
// Estado 3....
else if( Estado == 3)//Menu para enviar a visualizacion
{
lcd.clear();
lcd.setCursor(6, 0);
lcd.print("Saliendo");
lcd.setCursor(9, 1);
lcd.print("a");
lcd.setCursor(2, 2);
lcd.print(" visualizacion..");
delay(2000);
lcd.clear();
Boton=1;
Sig_Estado = 1;
}
// Estado 4....
else if( Estado == 4)
{
int menu;
String arrayMenu[] = {"Temp.Objetivo","Tiem.Nevulizacion","Tiem.Entre Nebul", "Acti. Bomba Manual","Reset contador", "Volver"};
int size = sizeof(arrayMenu) / sizeof(arrayMenu[0]);
menu = menuANTIFALLOSLENTO(arrayMenu,size);
if(menu == -1)Sig_Estado = 1;
else if(menu == 1)Sig_Estado = 40;//Temp.Objetivo
else if(menu == 2)Sig_Estado = 41;//Tiempo nebulizacion
else if(menu == 3)Sig_Estado = 42;//Tiempo entre nebulizaciones
else if(menu == 4)Sig_Estado = 8;//Activar bomba en manual
else if(menu == 5)Sig_Estado = 44;//Reset contador
else if(menu == 6)Sig_Estado = 9;//Volver
}
// Estado 5....
else if( Estado == 5)
{
int Tem_min = 0;
int Tem_Max = 50;
int8_t res;
res = rotary();
if (res!=0)
{
num = num + res;
temperaturaObjetivo = temperaturaObjetivo + res;
if (temperaturaObjetivo > Tem_Max) temperaturaObjetivo=Tem_Max;
if (temperaturaObjetivo < Tem_min) temperaturaObjetivo=Tem_min;
lcd.setCursor(7, 2);
lcd.print(" ");
lcd.setCursor(7, 2);
lcd.print(temperaturaObjetivo);
}
if (Boton ==0){
EEPROM.update(0, temperaturaObjetivo);
Boton=1;
Sig_Estado = 4;
}
}
// Estado 6....
else if( Estado == 6)
{
int Nev_min = 0;
int Nev_Max = 120;
int8_t res;
res = rotary();
if (res!=0)
{
num = num + res;
nebulizationTime = nebulizationTime + res;
if (nebulizationTime > Nev_Max) nebulizationTime=Nev_Max;
if (nebulizationTime < Nev_min) nebulizationTime=Nev_min;
lcd.setCursor(8, 2);
lcd.print(" ");
lcd.setCursor(8, 2);
lcd.print(nebulizationTime);
}
if (Boton ==0){
EEPROM.update(10, nebulizationTime);
Boton=1;
Sig_Estado = 4;
}
}
// Estado 7....
else if( Estado == 7)
{
int TiNev_min = 0;
int TiNev_Max = 30;
int8_t res;
res = rotary();
if (res!=0)
{
num = num + res;
tiempoentrenebu = tiempoentrenebu + res;
if (tiempoentrenebu > TiNev_Max) tiempoentrenebu=TiNev_Max;
if (tiempoentrenebu < TiNev_min) tiempoentrenebu=TiNev_min;
lcd.setCursor(9, 3);
lcd.print(" ");
lcd.setCursor(9, 3);
lcd.print(tiempoentrenebu);
}
if (Boton ==0){
EEPROM.update(20, tiempoentrenebu);
Boton=1;
Sig_Estado = 4;
}
}
// Estado 8....
else if( Estado == 8)
{
isPumpForced =1;
digitalWrite(electrovalvula,LOW);
delay(500);
digitalWrite(pumpPin, LOW);
lcd.clear();
lcd.setCursor(2, 0);
lcd.print("Bomba en marcha");
lcd.setCursor(1, 1);
lcd.print("Pulsa para pararla");
lcd.setCursor(6, 3);
lcd.print("Bomba:");
lcd.print(isPumpForced ? "ON " : "OFF");
while(digitalRead(BTN_MENU) == 1)
Sig_Estado = 10;
}
// Estado 9....
else if( Estado == 9)
{
lcd.clear();
Sig_Estado = 3;
}
// Estado 10....
else if( Estado == 10)
{
digitalWrite(pumpPin, HIGH);
digitalWrite(electrovalvula,HIGH);
isPumpForced =0;
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("Parando bomba");
lcd.setCursor(6, 3);
lcd.print("Bomba:");
lcd.print(isPumpForced ? "ON " : "OFF");
delay(2000);
lcd.clear();
Sig_Estado = 1;
}
// Estado 11....
else if( Estado == 11)
{
lcd.clear();
lcd.print("Desactivando bomba");
delay(3000);
Sig_Estado = 8;
}
// Estado 40....
else if( Estado == 40)
{
lcd.clear();
lcd.setCursor(0,0 );
lcd.print("Temperatura Objetivo");
lcd.setCursor(7, 2);
lcd.print(temperaturaObjetivo);
lcd.setCursor(13, 2);
lcd.write( (char)223);
lcd.print("C");
Sig_Estado = 5;
}
// Estado 41....
else if( Estado == 41)
{
lcd.clear();
lcd.print("Tiempo Nebulizacion:");
lcd.setCursor(8, 2);
lcd.print(nebulizationTime);
lcd.setCursor(11, 2);
lcd.print(" Seg.");
Sig_Estado = 6;
}
// Estado 42....
else if( Estado == 42)
{ lcd.clear();
lcd.setCursor(4, 0);
lcd.print("Tiempo Entre");
lcd.setCursor(3, 1);
lcd.print("Nebulizaciones");
lcd.setCursor(9, 3);
lcd.print(tiempoentrenebu);
lcd.setCursor(11, 3);
lcd.print(" Min.");
Sig_Estado = 7;
}
// Estado 43....
else if( Estado == 43)
{
lcd.setCursor(4, 0);
lcd.print("Nebulizando");
lcd.setCursor(0, 3);
lcd.print("Bomba:");
lcd.print(isPumpForced ? "ON " : "OFF");
delay(nebulizationTime*1000);
tiempo_ultima_neb=millis();
result_tiempo=1;
neburealizadas++;
Sig_Estado = 10;
}
// Estado 44....
else if( Estado == 44)
{ lcd.clear();
Sig_Estado = 45;
}
// Estado 45....
else if( Estado == 45)
{
lcd.setCursor(0, 0);
lcd.print("Pulsa para resetear");
lcd.setCursor(0, 3);
lcd.print("Neb.Realiz:");
lcd.print(neburealizadas);
if (Boton ==0){
Boton=1;
lcd.clear();
neburealizadas=0;
Sig_Estado = 3;
}
}
}
//Menu antifallos para selección y movimientos por el menu
int menuANTIFALLOSLENTO(String *arrayMenu,int size)
{
//Vamos a marcar en que tiempo se hizo cualquier cambio y si se hizo un cambio hace muy poco tiempo y se pulso, ese cambio le damos por malo. ok?
//Pintamos el cursor y marcamos la primera opcion
lcd.clear();
lcd.setCursor(0,0);
lcd.print("> ");
float opcion = 1; //del 1 al 1.75 Opcion 1 //Del 2 al 2.75 opcion 2
int extraOpcion = 0;
float incremento = 1;
//Pinta los 4 primeros del menu como mucho
for(int x = 0; x < size && x <= 3 ; x++) //
{
lcd.setCursor(2,x);
lcd.print(arrayMenu[x]);
}
delay(500);
byte DialPos1 = 0;
byte Last_DialPos1 = 0;
unsigned long tiempoCambioIncremento = 0;
unsigned long tiempoCambioDecremento = 0;
//Si pulsamos el boton central sale del bucle
while(digitalRead(BTN_MENU) == 1)
{
//Lee el estado del encoder
DialPos1 = (digitalRead(ROT1_EN_B) << 1) | digitalRead(ROT1_EN_A);
// Si la posicion del encoder ha cambiado
if(DialPos1 == 3 && (Last_DialPos1 == 1 ||Last_DialPos1 == 2) )
{
//Esta girarando el encoder a la derecha?
if (DialPos1 == 3 && Last_DialPos1 == 1)
{
if(opcion <size)
{
opcion += incremento;
tiempoCambioIncremento = millis();
}
}
//Is the dial being turned counter-clockwise ?
if (DialPos1 == 3 && Last_DialPos1 == 2)
{
if(opcion>1)
{
opcion -=incremento;
tiempoCambioDecremento = millis();
}
}
//Si sobrepasamos el limite por debajo
if(opcion < 1 + extraOpcion)
extraOpcion--;
//Si sobrepasamos el limite por encima
if(opcion > 4 + extraOpcion)
extraOpcion++;
//Pintamos de nuevo el menu
lcd.clear();
for(int x = extraOpcion; x < size && x <= (3+extraOpcion) ; x++) //
{
lcd.setCursor(2,x - extraOpcion);
lcd.print(arrayMenu[x]);
}
//Pintamos el cursor
lcd.setCursor(0,opcion-1-extraOpcion);
lcd.print(">");
}
//Remember the last position of the dial so we know when it has changed
Last_DialPos1 = DialPos1;
}
//Aqui hemos salido del bucle ya que hemos pulsado el boton Enter o ATRAS
//En cualquier caso no debería haberse movido ninguna tecla en 250ms?
if(millis() - tiempoCambioIncremento < 250)
opcion -= incremento;//Corregimos aunque no de tiempo a pintarla, ya que salimos del bucle y cambiamos de estado
else if(millis() - tiempoCambioDecremento < 250)
opcion += incremento;
return opcion;
}