#include <LiquidCrystal_I2C.h>
#include "EmonLib.h"
#include <EEPROM.h>
#define VOLT_PIN A0 // Pin analógico para la medición de voltaje
#define CT_PIN A1 // Pin analógico para la medición de corriente
EnergyMonitor emon1; // Create an instance
#define I2C_ADDR 0x27
#define LCD_COLUMNS 20
#define LCD_LINES 4
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define SW_ENCODER 4
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
byte caracterV[] = {
0x00,
0x00,
0x12,
0x12,
0x12,
0x12,
0x0C,
0x00
};
byte caracterA[] = {
0x00,
0x00,
0x0C,
0x12,
0x12,
0x1E,
0x12,
0x00
};
byte caracterIzq[] = {
0x00,
0x10,
0x08,
0x04,
0x08,
0x10,
0x00,
0x00
};
byte caracterDer[] = {
0x00,
0x04,
0x08,
0x10,
0x08,
0x04,
0x00,
0x00
};
byte caracterSeg[] = {
0x00,
0x00,
0x07,
0x08,
0x06,
0x01,
0x0E,
0x00
};
byte caracterBarra[] = {
0x00,
0x04,
0x04,
0x04,
0x04,
0x04,
0x04,
0x00
};
byte caracterMotor[] = {
0x00,
0x0C,
0x05,
0x11,
0x11,
0x14,
0x06,
0x00
};
char customChar[] = {
B00000,
B01000,
B01000,
B01000,
B01010,
B01111,
B00010,
B00000
};
struct Menu {
int id;
int cursorX;
int cursorY;
String mensaje;
};
Menu funciones[] = {
{1, 0, 1, "1> RANGO CORRIENTE"},
{2, 0, 1, "2> DELAY CORRIENTE"},
{3, 0, 1, "3> DELAY VOLTAJE V1"},
{4, 0, 1, "4> TEMPERATURA"},
// si se requiere... mas opciones
// iD,(x,y)
};
int numFunciones = sizeof(funciones) / sizeof(funciones[0]);
int ultimaPosicionClk = HIGH;
int SW_SELECT = 5;
int CONTACTOR = 6; //6
unsigned long toleranciaVoltaje = 0; // TIEMPO DE TOLERANCIA
unsigned long toleranciaCorriente = 0;
float corrienteProtegida = 0.0;
int EEcorrienteProtegida = 0; // eeprom
int EEtoleranciaCorriente = 20; // eeprom
int EEtoleranciaVoltaje = 30; // eeprom
int funcionActual = 0;
bool bandera = false; // Inicialmente en falso
uint32_t lowVoltageT0 = 0; // Tiempo de Tolerancia 1
uint32_t lowVoltageT1 = 0 ; // Tiempo de Reconexion General
uint32_t lowVoltageT2 = 0 ; // Tiempo de Reconexion General
unsigned long tiempoInicial;
unsigned long intervalo = 1000;// Tiempo de actualizacion de datos en pantalla
int estadoBoton1 = 0; // sw Select
int estadoBoton4 = 0; // sw Encoder
int estadoBotonAnterior1; // sw Select
int estadoBotonAnterior4; // sw Encoder
unsigned long tiempoAnterior1; // sw Select
unsigned long tiempoAnterior4; // sw Encoder
unsigned long tiempoAntirebote = 50;
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
lcd.home();
lcd.createChar(0, caracterV);
lcd.createChar(1, caracterA);
lcd.createChar(2, caracterIzq);
lcd.createChar(3, caracterDer);
lcd.createChar(4, caracterSeg);
lcd.createChar(5, caracterBarra);
lcd.createChar(6, caracterMotor);
lcd.write(0);
lcd.write(1);
lcd.write(2);
lcd.write(3);
lcd.write(4);
lcd.write(5);
lcd.write(6);
tiempoInicial = millis(); // Guardar el tiempo inicial
emon1.voltage(VOLT_PIN, 150, 1.7); // Voltage: input pin, calibration, phase_shift
emon1.current(CT_PIN, 57); // Current: input pin, calibration.
// emon1.current(CT_PIN, 45); // Current: input pin, calibration.
pinMode(SW_SELECT, INPUT_PULLUP);
pinMode(SW_ENCODER, INPUT_PULLUP);
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
pinMode(CONTACTOR, OUTPUT);
digitalWrite(CONTACTOR, HIGH);
EEPROM.get(EEcorrienteProtegida, corrienteProtegida);
EEPROM.get(EEtoleranciaCorriente , toleranciaCorriente );
EEPROM.get(EEtoleranciaVoltaje, toleranciaVoltaje );
}
uint32_t contadorDesactivaciones = 0; // Contador para las veces que se desactiva CONTACTOR cuando se cumple Rango[5]
bool excedeLimiteIntentos = false; // Bandera para indicar si se excedió el límite de intentos
bool contadorReiniciado = false; // Bandera para indicar si se reinició el contador después del límite
void displayRango(bool Rango[]) {
// Actualizar la bandera
bool bandera = (Rango[0] || Rango[1] || Rango[2] || Rango[4] || Rango[5]);
if (bandera) {
if (!excedeLimiteIntentos) { // Si no se ha excedido el límite de intentos
if (Rango[0]) { // FASE L1 FALLA VOLTAJE BAJO
uint32_t T1 = millis() - lowVoltageT0;
if (T1 > toleranciaVoltaje) {
digitalWrite(CONTACTOR, HIGH); // Detener el contactor
lcd.setCursor(2, 3);
lcd.print("______");
}
} else {
lowVoltageT0 = millis(); // Actualizar el tiempo de la última medición fuera de rango
}
if (Rango[1] && Rango[4]) { // FASE L1 VOLTAJE NORMAL
uint32_t T = millis() - lowVoltageT1;
if (T > 15000 ) { // Tiempo de reconexión 10 segundos
digitalWrite(CONTACTOR, LOW);
lcd.setCursor(0, 3);
lcd.print("NORMAL");
lcd.setCursor(12, 3);
lcd.print("MOTOR");
}
} else {
lowVoltageT1 = millis(); // Actualizar el tiempo de la última medición fuera de rango
}
if (Rango[2]) { /// FASE L1 FALLA VOLTAJE ALTO
digitalWrite(CONTACTOR, HIGH);
lcd.setCursor(0, 3);
lcd.print("______");
}
////*******************************************************************************************
if (Rango[5]) {
uint32_t T2 = millis() - lowVoltageT2;
if (T2 > toleranciaCorriente) {
digitalWrite(CONTACTOR, HIGH);
lcd.setCursor(0, 3);
lcd.print(" ");
// Incrementar el contador y verificar si excede 3 intentos
contadorDesactivaciones++;
lcd.setCursor(6, 3); // Colocar el cursor en la segunda línea y primera columna del LCD
lcd.print("F:"); // Mostrar el valor del contador en el LCD
lcd.setCursor(8, 3); // Colocar el cursor en la segunda línea y primera columna del LCD
lcd.print(contadorDesactivaciones); // Mostrar el valor del contador en el LCD
if (contadorDesactivaciones >= 3) {
excedeLimiteIntentos = true; // Establecer la bandera de exceso de intentos
digitalWrite(CONTACTOR, HIGH); // Activar el CONTACTOR
Serial.println("Se desactivó CONTACTOR más de 3 veces. Se activó la protección.");
}
}
} else {
lowVoltageT2 = millis(); // Actualizar el tiempo de la última medición fuera de rango
}
} else { // Si se ha excedido el límite de intentos
if (!contadorReiniciado) {
contadorDesactivaciones = 0; // Reiniciar el contador
contadorReiniciado = true; // Establecer la bandera de reinicio del contador
}
}
}
}
void loop() {
estadoBoton1 = digitalRead(SW_SELECT);
estadoBoton4 = digitalRead(SW_ENCODER);
unsigned int posicionActualClk = digitalRead(ENCODER_CLK); // posición actual del encoder
if (estadoBoton4 != estadoBotonAnterior4 && millis() - tiempoAnterior4 > tiempoAntirebote ) {
if (estadoBoton4 == LOW) {
funcionActual = (funcionActual % numFunciones) + 1;
lcd.clear();
lcd.setCursor(8, 0);
lcd.print("MENU");
}
for (int i = 0; i < numFunciones; i++) {
if (funcionActual == funciones[i].id) {
lcd.setCursor(funciones[i].cursorX, funciones[i].cursorY);
lcd.print(funciones[i].mensaje);
break;
}
}
tiempoAnterior4 = millis();
//
// Serial.print("FUNCION : ");
// Serial.println( funcionActual);
}
if (funcionActual == 0) {
// Pantalla Principal
emon1.calcVI(20, 2000); // Calcular todo. Número de medias ondas (cruces), tiempo de espera
float voltage = emon1.Vrms; // Extraer Vrms en una variable
float current = emon1.Irms; // Extraer Irms en una variable
// float current = emon1.Irms * 1.30;
bool Rango[5];
// FASE L1
Rango[0] = (voltage >= 0) && (voltage <= 90);
Rango[1] = (voltage >= 90) && (voltage <= 150);
Rango[2] = (voltage > 150);
// Control de corriente
// Rango[3] = (current >= corrienteProtegida);
Rango[4] = (current <= corrienteProtegida);
Rango[5] = (current >= corrienteProtegida);
displayRango(Rango);
// Mostrar voltaje
lcd.setCursor(0, 0);
lcd.print("V1:");
lcd.setCursor(7, 0); // Letra V
lcd.write(0);
// Mostrar corriente
lcd.setCursor(11, 0);
lcd.print("CT:");
// lcd.setCursor(9, 0);
// lcd.print("CARGA:");
// lcd.setCursor(10, 0);
// lcd.print("LOAD:");
lcd.setCursor(19, 0); // Letra A
lcd.write(1);
unsigned long tiempoActual = millis(); // Obtener el tiempo actual
if (tiempoActual - tiempoInicial >= intervalo) {
if (voltage > 80) {
lcd.setCursor(4, 0);
char voltageBuffer[10];
dtostrf(voltage, 3, 0, voltageBuffer); // Convertir el voltaje a cadena
lcd.print(voltageBuffer);
}
else {
lcd.setCursor(4, 0);
lcd.print("0.0");
}
//// CORRIENTE
if (current > 1) {
lcd.setCursor(15, 0);
char currentBuffer[10];
dtostrf(current, 4, 1, currentBuffer); // Convertir la corriente a cadena
lcd.print(currentBuffer);
// Muestra el carácter en la posición (18, 2)
lcd.setCursor(18, 3);
lcd.write(6); // Muestra el carácter
delay(250); // Espera 100 milisegundos
// Borra el carácter de la posición (18, 2)
lcd.setCursor(18, 3);
lcd.print(" "); // Borra el carácter
delay(250); // Espera 100 milisegundos
}
else {
lcd.setCursor(15, 0);
lcd.print("0.00");
}
tiempoInicial = tiempoActual; // Actualizar el tiempo inicial
}
Serial.print("Corriente : ");
Serial.println(current);
Serial.print("Voltaje : ");
Serial.println(voltage);
//
// Serial.print("Contador : ");
// Serial.println(intentos);
///////////////////////////////////////////////////////////////////////////////
float corrienteAnterior;
EEPROM.get(EEcorrienteProtegida, corrienteAnterior);
lcd.setCursor(0, 2);
lcd.print("Delay:");
lcd.setCursor(11, 2);
lcd.print("Delay:");
// lcd.setCursor(11, 1);
// lcd.print("CP:");
lcd.setCursor(15, 1);
char currentAntBuffer[10];
dtostrf(corrienteAnterior, 3, 1, currentAntBuffer); // Convertir la corriente a cadena
lcd.print(currentAntBuffer);
lcd.setCursor(19, 1); // SIMBOLO Letra A
lcd.write(1);
lcd.setCursor(13, 1); // SIMBOLO >>
lcd.write(2);
/////////////////////////////////////////////////////////////////////////////
unsigned long toleranciaAnterior;
EEPROM.get(EEtoleranciaCorriente, toleranciaAnterior);
// lcd.setCursor(15, 2); // SIMBOLO >>
// lcd.write(2);
lcd.setCursor(18, 2); //
lcd.print(toleranciaCorriente / 1000);
lcd.setCursor(19, 2);
lcd.write(4); // simbolo s
lcd.setCursor(9, 0); // SEPARADORES
lcd.write(5);
// lcd.setCursor(9, 1); // SEPARADORES
// lcd.write(5);
// lcd.setCursor(9, 2); // SEPARADORES
// lcd.write(5);
// lcd.setCursor(9, 3); // SEPARADORES
// lcd.write(5);
//////////////////////////////////////////////////////////
unsigned long toleranciaPico;
EEPROM.get(EEtoleranciaVoltaje, toleranciaPico );
// lcd.setCursor(5, 2); // SIMBOLO >>
// lcd.write(2);
lcd.setCursor(7, 2); //
lcd.print(toleranciaVoltaje / 1000);
lcd.setCursor(8, 2);
lcd.write(4); // simbolo s
}
// + logica aqui ....................
/////Boton de salir
if (estadoBoton1 != estadoBotonAnterior1 && millis() - tiempoAnterior1 > tiempoAntirebote ) {
if (estadoBoton1 == LOW ) {
funcionActual = 0;
lcd.clear();
}
tiempoAnterior1 = millis();
}
unsigned int dtEncoder = digitalRead(ENCODER_DT);
if (posicionActualClk != ultimaPosicionClk) {
char buffer[20]; // Mantenemos el nombre de la variable como 'buffer'
// Funcion Actual 1
if (posicionActualClk == LOW && dtEncoder == HIGH && funcionActual == 1) {
if (corrienteProtegida < 15) {
corrienteProtegida += 0.5; // Incrementa en 0.5 unidades
} else {
corrienteProtegida = 15;
}
lcd.setCursor(2, 2);
lcd.print("PGM");
lcd.setCursor(0, 3);
lcd.print("AMPERAJE CT: ");
dtostrf(corrienteProtegida, 4, 1, buffer);
lcd.print(buffer);
lcd.setCursor(13, 3); //>>
lcd.write(2);
lcd.setCursor(18, 3); // Letra A
lcd.write(1);
EEPROM.put(EEcorrienteProtegida, corrienteProtegida);
}
if (posicionActualClk == LOW && dtEncoder == LOW && funcionActual == 1) {
if (corrienteProtegida > 0) {
corrienteProtegida -= 0.5; // Decrementa en 0.5 unidades
} else {
corrienteProtegida = 0;
}
lcd.setCursor(2, 2);
lcd.print("PGM");
lcd.setCursor(0, 3);
lcd.print("AMPERAJE CT: ");
dtostrf(corrienteProtegida, 4, 1, buffer); // Reutilizamos la misma variable 'buffer'
lcd.print(buffer);
lcd.setCursor(13, 3);
lcd.write(3);
lcd.setCursor(18, 3); // Letra A
lcd.write(1);
EEPROM.put(EEcorrienteProtegida, corrienteProtegida);
}
// Funcion Actual 2 TOLERANCIA
if (posicionActualClk == LOW && dtEncoder == HIGH && funcionActual == 2 ) { // Sentido Encoder >>>
toleranciaCorriente += 1000 ;
if (toleranciaCorriente > 10000) {
toleranciaCorriente = 10000;
}
lcd.setCursor(2, 2);
lcd.print("PGM");
lcd.setCursor(1, 3);
lcd.print("DELAY: ");
dtostrf(toleranciaCorriente / 1000, 2, 0, buffer);
lcd.print(buffer);
lcd.setCursor(10, 3);
lcd.write(2);
lcd.setCursor(13, 3);
lcd.write(4); // simbolo s
EEPROM.put(EEtoleranciaCorriente, toleranciaCorriente);
}
if (posicionActualClk == LOW && dtEncoder == LOW && funcionActual == 2 ) { // Sentido Encoder <<<
if (toleranciaCorriente >= 1000) { // Asegurar que tiempoProgramado sea al menos 1000 antes de decrementar
toleranciaCorriente -= 1000 ;
} else {
toleranciaCorriente = 0; // Si tiempoProgramado es menor que 1000, establecerlo en 0
}
lcd.setCursor(2, 2);
lcd.print("PGM");
lcd.setCursor(1, 3);
lcd.print("DELAY: ");
dtostrf(toleranciaCorriente / 1000, 2, 0, buffer);
lcd.print(buffer);
lcd.setCursor(10, 3);
lcd.write(3);
lcd.setCursor(13, 3);
lcd.write(4); // simbolo s
EEPROM.put(EEtoleranciaCorriente , toleranciaCorriente);
}
// // Funcion Actual 3
if (posicionActualClk == LOW && dtEncoder == HIGH && funcionActual == 3) { // Sentido Encoder >>>
toleranciaVoltaje += 1000 ;
if (toleranciaVoltaje > 10000) {
toleranciaVoltaje = 10000;
}
lcd.setCursor(2, 2);
lcd.print("PGM");
lcd.setCursor(1, 3);
lcd.print("DELAY: ");
dtostrf(toleranciaVoltaje / 1000, 2, 0, buffer);
lcd.print(buffer);
lcd.setCursor(10, 3);
lcd.write(2);
lcd.setCursor(13, 3);
lcd.write(4); // simbolo s
EEPROM.put(EEtoleranciaVoltaje, toleranciaVoltaje);
}
if (posicionActualClk == LOW && dtEncoder == LOW && funcionActual == 3) { // Sentido Encoder <<<
if (toleranciaVoltaje >= 1000) { // Asegurar que tiempoProgramado sea al menos 1000 antes de decrementar
toleranciaVoltaje -= 1000 ;
} else {
toleranciaVoltaje = 0; // Si tiempoProgramado es menor que 1000, establecerlo en 0
}
lcd.setCursor(2, 2);
lcd.print("PGM");
lcd.setCursor(1, 3);
lcd.print("DELAY: ");
dtostrf(toleranciaVoltaje / 1000, 2, 0, buffer);
lcd.print(buffer);
lcd.setCursor(10, 3);
lcd.write(3);
lcd.setCursor(13, 3);
lcd.write(4); // simbolo s
EEPROM.put(EEtoleranciaVoltaje , toleranciaVoltaje);
}
// // Agregar mas Funcion si se requiere...
// //// ......
// // lcd.print("Nueva función F7");
}
ultimaPosicionClk = posicionActualClk;
estadoBotonAnterior1 = estadoBoton1; // Switch encoder
estadoBotonAnterior4 = estadoBoton4; // Switch Select
}