#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <max6675.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Pines del encoder
#define ENCODER_CLK 2
#define ENCODER_DT 3
#define ENCODER_SW 4
// Pines del sensor MAX6675
int thermoDO = 7;
int thermoCS = 6;
int thermoCLK = 5;
MAX6675 sensorTemp(thermoCLK, thermoCS, thermoDO);
// Pines de los botones para iniciar y detener el conteo
#define BTN_START 8
#define BTN_STOP 9
// Pines del LED, zumbador y el relé
#define LED_PIN 10
#define BUZZER_PIN 11
#define RELAY_PIN 12
byte termo[] = { 0x04, 0x1A, 0x0A, 0x0B, 0x0A, 0x15, 0x11, 0x0E };
byte arrow[] = { 0x00, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00 };
byte reloj[] = { 0x00, 0x0E, 0x19, 0x15, 0x17, 0x11, 0x0E, 0x00 };
// Variables para controlar el estado del sistema
int ultimaPosicionClk = HIGH;
int tiempo = 5;
int temperatura = 150; // Valor inicial de la temperatura
int diferenciaTemp = 10; // Valor inicial de la diferencia de temperatura
int histeresis = 5; // Valor inicial de la histeresis
bool contadorIniciado = false;
unsigned long tiempoRestante; // En milisegundos
unsigned long tiempoAnterior = 0;
int modoSeleccion = 0; // 0: Tiempo, 1: Temperatura, 2: Diferencia de temperatura, 3: Histeresis
// Variables para manejo del debounce y lectura de botones
unsigned long ultimoBotonPressTime = 0;
unsigned long botonDelay = 300; // 300 ms
// Variables de temperatura
double temperaturaAnterior = -1; // Para comparación en tiempo real
unsigned long ultimoTiempoLectura = 0;
unsigned long intervaloLectura = 250; // Sensado cada 250ms
// Tiempo de retraso entre parametrización y mostrar temperatura actual
unsigned long tiempoEspera = 5000; // Tiempo de espera de 5 segundos
unsigned long ultimaParametrizacion = 0; // Para almacenar el último tiempo de parametrización
bool parametrizacionActiva = false; // Indica si la parametrización está activa
// Estado del relé
bool releEncendido = false;
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
pinMode(ENCODER_CLK, INPUT);
pinMode(ENCODER_DT, INPUT);
pinMode(ENCODER_SW, INPUT_PULLUP);
pinMode(BTN_START, INPUT_PULLUP);
pinMode(BTN_STOP, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(RELAY_PIN, OUTPUT);
lcd.createChar(1, termo);
lcd.createChar(2, reloj);
lcd.createChar(3, arrow);
actualizarLCD();
}
void loop() {
leerBotonEncoder();
iniciarContador();
detenerContadorSiEsNecesario();
if (contadorIniciado) {
actualizarTiempoRestante();
} else {
gestionarEncoder();
}
leerTemperaturaEnTiempoReal();
}
// Leer el botón del encoder para cambiar entre editar tiempo, temperatura, diferencia y histeresis
void leerBotonEncoder() {
if (digitalRead(ENCODER_SW) == LOW && (millis() - ultimoBotonPressTime > botonDelay)) {
modoSeleccion = (modoSeleccion + 1) % 4; // Cambia entre los modos: 0 (Tiempo), 1 (Temperatura), 2 (Diferencia), 3 (Histeresis)
actualizarLCD();
ultimoBotonPressTime = millis();
}
}
// Función para leer la temperatura en tiempo real
void leerTemperaturaEnTiempoReal() {
if (millis() - ultimoTiempoLectura >= intervaloLectura) {
ultimoTiempoLectura = millis();
double temperaturaLeida = sensorTemp.readCelsius();
if (isnan(temperaturaLeida)) {
lcd.setCursor(0, 1);
lcd.print(" Error Temp! ");
digitalWrite(LED_PIN, HIGH);
return;
}
if (parametrizacionActiva) {
if (millis() - ultimaParametrizacion >= tiempoEspera) {
parametrizacionActiva = false;
lcd.write(byte(3));
}
}
if (!parametrizacionActiva) {
if (abs(temperaturaLeida - temperaturaAnterior) >= 0.5) {
lcd.setCursor(2, 1);
lcd.print("TEMP: ");
lcd.print((int)temperaturaLeida);
lcd.print("\xDF""C ");
temperaturaAnterior = temperaturaLeida;
}
}
// Controlar el relé según la temperatura leída, la diferencia establecida y la histeresis
if (contadorIniciado) {
if (temperaturaLeida >= (temperatura + diferenciaTemp) && releEncendido) {
if (temperaturaLeida >= (temperatura + diferenciaTemp + histeresis)) {
digitalWrite(RELAY_PIN, LOW); // Apagar el relé si supera el umbral + histeresis
releEncendido = false;
lcd.setCursor(0, 1);
lcd.print(" ");
}
} else if (temperaturaLeida <= (temperatura - diferenciaTemp) && !releEncendido) {
if (temperaturaLeida <= (temperatura - diferenciaTemp - histeresis)) {
digitalWrite(RELAY_PIN, HIGH); // Encender el relé si está por debajo del umbral - histeresis
releEncendido = true;
lcd.setCursor(0, 1);
lcd.write(byte(1));
}
}
} else {
digitalWrite(RELAY_PIN, LOW);
releEncendido = false;
}
digitalWrite(LED_PIN, LOW);
}
}
void iniciarContador() {
if (digitalRead(BTN_START) == LOW && !contadorIniciado) {
contadorIniciado = true;
tiempoRestante = tiempo * 60000;
tiempoAnterior = millis();
digitalWrite(RELAY_PIN, HIGH);
actualizarLCD();
}
}
void detenerContadorSiEsNecesario() {
if (digitalRead(BTN_STOP) == LOW && contadorIniciado) {
detenerContador();
}
}
void detenerContador() {
contadorIniciado = false;
tiempoRestante = 0;
lcd.clear();
mostrarMensajeFinal();
digitalWrite(RELAY_PIN, LOW);
releEncendido = false;
}
void mostrarMensajeFinal() {
lcd.setCursor(2, 0);
lcd.print("Vulcanizado");
lcd.setCursor(3, 1);
lcd.print("Finalizado");
digitalWrite(RELAY_PIN, LOW);
tone(BUZZER_PIN, 500, 2000);
delay(3000);
lcd.clear();
actualizarLCD();
}
void actualizarTiempoRestante() {
if (tiempoRestante > 0) {
unsigned long tiempoActual = millis();
unsigned long tiempoTranscurrido = tiempoActual - tiempoAnterior;
if (tiempoTranscurrido < tiempoRestante) {
tiempoRestante -= tiempoTranscurrido;
} else {
tiempoRestante = 0;
}
tiempoAnterior = tiempoActual;
if (tiempoRestante == 0) {
detenerContador();
} else {
int minutos = tiempoRestante / 60000;
int segundos = (tiempoRestante % 60000) / 1000;
lcd.setCursor(2, 0);
lcd.print("TIEMPO: ");
if (minutos < 10) lcd.print("0");
lcd.print(minutos);
lcd.print(":");
if (segundos < 10) lcd.print("0");
lcd.print(segundos);
lcd.setCursor(15, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.write(byte(2));
}
}
}
void actualizarLCD() {
lcd.clear();
// Dependiendo del modo, actualizamos las líneas del display
switch (modoSeleccion) {
case 0: // Modo Tiempo
lcd.setCursor(0, 0);
lcd.print("TIEMPO:");
lcd.setCursor(8, 0);
lcd.print(tiempo);
lcd.print(" min");
lcd.setCursor(0, 1); // Cambiamos a la segunda línea
lcd.print("TEMP:");
lcd.setCursor(8, 1);
lcd.print(temperatura);
lcd.print(" \xDFC");
break;
case 1: // Modo Temperatura
lcd.setCursor(0, 0);
lcd.print("TEMP:");
lcd.setCursor(8, 0);
lcd.print(temperatura);
lcd.print(" \xDFC");
lcd.setCursor(0, 1); // Cambiamos a la segunda línea
lcd.print("DIF. TEMP:");
lcd.setCursor(10, 1);
lcd.print(diferenciaTemp);
break;
case 2: // Modo Diferencia de Temperatura
lcd.setCursor(0, 0);
lcd.print("DIF. TEMP:");
lcd.setCursor(10, 0);
lcd.print(diferenciaTemp);
lcd.setCursor(0, 1); // Cambiamos a la segunda línea
lcd.print("HISTERESIS:");
lcd.setCursor(12, 1);
lcd.print(histeresis);
break;
case 3: // Modo Histeresis
lcd.setCursor(0, 0);
lcd.print("HISTERESIS:");
lcd.setCursor(12, 0);
lcd.print(histeresis);
lcd.setCursor(0, 1); // Cambiamos a la segunda línea
lcd.print("TIEMPO:");
lcd.setCursor(8, 1);
lcd.print(tiempo);
lcd.print(" min");
break;
}
}
void gestionarEncoder() {
int lecturaClk = digitalRead(ENCODER_CLK);
if (lecturaClk != ultimaPosicionClk && lecturaClk == LOW) {
if (digitalRead(ENCODER_DT) == lecturaClk) {
cambiarValor(-1);
} else {
cambiarValor(1);
}
}
ultimaPosicionClk = lecturaClk;
}
void cambiarValor(int incremento) {
switch (modoSeleccion) {
case 0:
tiempo = max(1, tiempo + incremento); // No permitir menos de 1 minuto
break;
case 1:
temperatura = max(0, temperatura + incremento); // No permitir temperaturas negativas
break;
case 2:
diferenciaTemp = max(1, diferenciaTemp + incremento); // No permitir diferencia negativa
break;
case 3:
histeresis = max(0, histeresis + incremento); // Permitir 0 como valor mínimo
break;
}
actualizarLCD();
}