Control de Temperatura con ESP32, LCD I2C y Dimmer Digital

 Materiales Necesarios

  • 1 × ESP32 (NodeMCU ESP32 o similar)

  • 1 × Display LCD 16×2 con módulo I2C

  • 4 × Botones pulsadores

  • 1 × Sensor de temperatura (LM35, NTC o DS18B20)

  • 1 × MOC3031 (Optoacoplador triac)

  • 1 × Triac (BT136 o similar, según potencia requerida)

  • 1 × Resistencia de 180Ω 1/4W

  • 1 × Resistencia de 330Ω 1/4W

  • 1 × Carga resistiva (calefactor, foco incandescente, etc.)

  • 1 × Protoboard y cables

  • 1 × Disipador de calor para el triac (opcional, según potencia)

Esquema de Conexiones

Conexiones ESP32:

  • LCD I2C:

    • SDA → GPIO 21

    • SCL → GPIO 22

    • VCC → 3.3V

    • GND → GND

  • Botones (con pull-up interno):

    • UP → GPIO 12

    • DOWN → GPIO 13

    • PLAY → GPIO 14

    • SETTING → GPIO 27

    • Todos los botones conectados también a GND

  • Sensor de Temperatura (LM35):

    • VCC → 3.3V

    • OUT → GPIO 35 (ADC1_CH7)

    • GND → GND

  • Salida Dimmer:

    • CONTROL → GPIO 26 (Salida PWM)

Circuito de Potencia con MOC3031 y Triac:

ESP32 GPIO26 → Resistencia 330Ω → Pin 1 MOC3031
Pin 2 MOC3031 → GND
Pin 6 MOC3031 → Resistencia 180Ω → Compuerta Triac
MT1 Triac → Línea AC
MT2 Triac → Carga
La otra terminal de la carga → Línea AC neutral

Código Adaptado para ESP32

cpp
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>

// Configuración del LCD I2C
LiquidCrystal_I2C lcd(0x27, 16, 2); // Dirección I2C 0x27, display 16x2

// Definición de pines
const int up = 12;
const int down = 13;
const int play = 14;
const int setting = 27;
const int salidaPWM = 26;
const int sensorTemp = 35;

// Variables de control
int var_modo = 1; // modo de control (0: on/off, 1: PID)
double temp;  // temperatura medida
double Output; // Salida PWM
double error;  // error setpoint-temp

double p = 1;
double i = 1;
double d = 1;
double tdes = 25;

int tmin = 25;
int tmax = 27;

// Crear objeto PID
PID myPID(&temp, &Output, &tdes, p, i, d, DIRECT);

// Estados del sistema
#define modo 0
#define ganancia_P 1
#define ganancia_I 2
#define ganancia_D 3
#define temp_des 4
#define pid 5
#define temp_min 6
#define temp_max 7
#define on_off 8

int estado = modo; // Estado actual del sistema

// Configuración PWM para ESP32
const int freq = 1000;
const int pwmChannel = 0;
const int resolution = 8;

void setup() {
  Serial.begin(115200);
  
  // Inicializar LCD
  lcd.init();
  lcd.backlight();
  lcd.clear();
  
  // Configurar pines
  pinMode(up, INPUT_PULLUP);
  pinMode(down, INPUT_PULLUP);
  pinMode(play, INPUT_PULLUP);
  pinMode(setting, INPUT_PULLUP);
  pinMode(sensorTemp, INPUT);
  
  // Configurar PWM para el dimmer
  ledcSetup(pwmChannel, freq, resolution);
  ledcAttachPin(salidaPWM, pwmChannel);
  ledcWrite(pwmChannel, 0);
  
  // Configurar PID
  myPID.SetSampleTime(20);
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(0, 255);
  
  mostrarMensajeInicial();
}

void loop() {
  // Leer temperatura (LM35: 10mV/°C)
  int lectura = analogRead(sensorTemp);
  temp = (lectura * 3.3 * 100) / 4096.0; // Convertir a °C para ESP32 (3.3V reference)
  
  switch (estado) {
    case modo:
      manejarModo();
      break;
    case ganancia_P:
      manejarGananciaP();
      break;
    case ganancia_I:
      manejarGananciaI();
      break;
    case ganancia_D:
      manejarGananciaD();
      break;
    case temp_des:
      manejarTempDeseada();
      break;
    case pid:
      manejarPID();
      break;
    case temp_min:
      manejarTempMin();
      break;
    case temp_max:
      manejarTempMax();
      break;
    case on_off:
      manejarOnOff();
      break;
  }
  
  delay(10);
}

void manejarModo() {
  lcd.setCursor(0, 0);
  lcd.print("Modo:");
  lcd.setCursor(7, 0);
  
  if (var_modo == 0) {
    lcd.print("on_off");
  } else {
    lcd.print("pid");
  }
  
  lcd.setCursor(0, 1);
  lcd.print("Ti:");
  lcd.print(temp, 1);
  lcd.print("C");
  
  if (digitalRead(down) == LOW) {
    var_modo = !var_modo;
    lcd.clear();
    delay(200);
  }
  
  if (digitalRead(play) == LOW) {
    lcd.clear();
    if (var_modo == 0) {
      estado = temp_min;
    } else {
      estado = ganancia_P;
    }
    delay(200);
  }
}

void manejarGananciaP() {
  lcd.setCursor(0, 0);
  lcd.print("Ganancia P");
  lcd.setCursor(0, 1);
  lcd.print(p, 2);
  
  if (digitalRead(up) == LOW) {
    p += 0.1;
    actualizarDisplayVariable(p);
  }
  
  if (digitalRead(down) == LOW) {
    if (p > 0.1) {
      p -= 0.1;
      actualizarDisplayVariable(p);
    } else {
      lcd.setCursor(0, 1);
      lcd.print("No permitido");
      delay(200);
      lcd.setCursor(0, 1);
      lcd.print(p, 2);
    }
  }
  
  if (digitalRead(play) == LOW) {
    estado = ganancia_I;
    lcd.clear();
    delay(200);
  }
  
  if (digitalRead(setting) == LOW) {
    estado = modo;
    lcd.clear();
    delay(200);
  }
}

void manejarGananciaI() {
  lcd.setCursor(0, 0);
  lcd.print("Ganancia I");
  lcd.setCursor(0, 1);
  lcd.print(i, 2);
  
  if (digitalRead(up) == LOW) {
    i += 0.1;
    actualizarDisplayVariable(i);
  }
  
  if (digitalRead(down) == LOW) {
    if (i > 0.1) {
      i -= 0.1;
      actualizarDisplayVariable(i);
    }
  }
  
  if (digitalRead(play) == LOW) {
    estado = ganancia_D;
    lcd.clear();
    delay(200);
  }
  
  if (digitalRead(setting) == LOW) {
    estado = modo;
    lcd.clear();
    delay(200);
  }
}

void manejarGananciaD() {
  lcd.setCursor(0, 0);
  lcd.print("Ganancia D");
  lcd.setCursor(0, 1);
  lcd.print(d, 2);
  
  if (digitalRead(up) == LOW) {
    d += 0.1;
    actualizarDisplayVariable(d);
  }
  
  if (digitalRead(down) == LOW) {
    if (d > 0.1) {
      d -= 0.1;
      actualizarDisplayVariable(d);
    }
  }
  
  if (digitalRead(play) == LOW) {
    estado = temp_des;
    lcd.clear();
    delay(200);
  }
  
  if (digitalRead(setting) == LOW) {
    estado = modo;
    lcd.clear();
    delay(200);
  }
}

void manejarTempDeseada() {
  lcd.setCursor(0, 0);
  lcd.print("Temp deseada");
  lcd.setCursor(0, 1);
  lcd.print(tdes, 1);
  lcd.print("C");
  
  if (digitalRead(up) == LOW) {
    tdes += 0.5;
    actualizarDisplayVariable(tdes);
  }
  
  if (digitalRead(down) == LOW) {
    tdes -= 0.5;
    actualizarDisplayVariable(tdes);
  }
  
  if (digitalRead(play) == LOW) {
    if (p == 0 && i == 0 && d == 0) {
      estado = ganancia_P;
    } else if (tdes != 0) {
      estado = pid;
    }
    lcd.clear();
    delay(200);
  }
  
  if (digitalRead(setting) == LOW) {
    estado = modo;
    lcd.clear();
    delay(200);
  }
}

void manejarPID() {
  myPID.SetTunings(p, i, d);
  error = tdes - temp;
  myPID.Compute();
  
  // Controlar dimmer con PWM
  ledcWrite(pwmChannel, (int)Output);
  
  lcd.setCursor(0, 0);
  lcd.print("Tm:");
  lcd.print(temp, 1);
  lcd.print("C");
  
  lcd.setCursor(0, 1);
  lcd.print("Td:");
  lcd.print(tdes, 1);
  lcd.print("C Out:");
  lcd.print((int)Output);
  
  if (digitalRead(setting) == LOW) {
    estado = modo;
    lcd.clear();
    delay(200);
  }
  
  delay(200);
}

void manejarTempMin() {
  lcd.setCursor(0, 0);
  lcd.print("Temp minima");
  lcd.setCursor(0, 1);
  lcd.print(tmin);
  lcd.print("C");
  
  if (digitalRead(up) == LOW) {
    tmin++;
    actualizarDisplayVariable(tmin);
  }
  
  if (digitalRead(down) == LOW) {
    tmin--;
    actualizarDisplayVariable(tmin);
  }
  
  if (digitalRead(play) == LOW) {
    estado = temp_max;
    lcd.clear();
    delay(200);
  }
  
  if (digitalRead(setting) == LOW) {
    estado = modo;
    lcd.clear();
    delay(200);
  }
}

void manejarTempMax() {
  lcd.setCursor(0, 0);
  lcd.print("Temp max");
  lcd.setCursor(0, 1);
  lcd.print(tmax);
  lcd.print("C");
  
  if (digitalRead(up) == LOW) {
    tmax++;
    actualizarDisplayVariable(tmax);
  }
  
  if (digitalRead(down) == LOW) {
    tmax--;
    actualizarDisplayVariable(tmax);
  }
  
  if (digitalRead(play) == LOW) {
    estado = on_off;
    lcd.clear();
    delay(200);
  }
  
  if (digitalRead(setting) == LOW) {
    estado = modo;
    lcd.clear();
    delay(200);
  }
}

void manejarOnOff() {
  lcd.setCursor(0, 0);
  lcd.print("Temp:");
  lcd.print(temp, 1);
  lcd.print("C");
  
  lcd.setCursor(0, 1);
  lcd.print("min");
  lcd.print(tmin);
  lcd.print(" max");
  lcd.print(tmax);
  
  if (temp <= tmin) {
    ledcWrite(pwmChannel, 255); // Encender completamente
  }
  if (temp >= tmax) {
    ledcWrite(pwmChannel, 0); // Apagar completamente
  }
  
  if (digitalRead(setting) == LOW) {
    estado = modo;
    lcd.clear();
    delay(200);
  }
  
  delay(200);
}

void actualizarDisplayVariable(double valor) {
  lcd.setCursor(0, 1);
  lcd.print("        ");
  lcd.setCursor(0, 1);
  lcd.print(valor, 1);
  delay(200);
}

void mostrarMensajeInicial() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Control Temp");
  lcd.setCursor(0, 1);
  lcd.print("ESP32 + PID");
  delay(2000);
  lcd.clear();
}

 Funcionamiento del Dimmer con MOC3031 y Triac

Principio de Operación:

  1. El ESP32 genera una señal PWM en el pin de control

  2. Esta señal controla el MOC3031 (optoacoplador con detector de cruce por cero)

  3. El MOC3031 activa el triac en el momento preciso del ciclo AC

  4. El triac regula la potencia entregada a la carga

Características del MOC3031:

  • Optoacoplador con detector de cruce por cero

  • Aislamiento eléctrico entre el circuito de control y la red AC

  • Diseñado específicamente para control de triacs

  • Voltaje de activación: 5-30V

Consideraciones de Seguridad:

  • AISLAMIENTO ELÉCTRICO: El MOC3031 proporciona aislamiento entre el ESP32 y la red AC

  • PROTECCIÓN: Usar un fusible en serie con la carga

  • DISIPACIÓN DE CALOR: El triac necesita disipador de calor según la potencia manejada

  • PRECAUCIÓN: La parte de potencia trabaja con voltajes peligrosos (110V/220V AC)

 Calibración y Ajustes

  1. Calibración del sensor de temperatura: Ajustar según el sensor utilizado

  2. Sintonización del PID: Ajustar las constantes P, I, D para obtener la respuesta deseada

  3. Frecuencia PWM: Ajustar según las características de la carga

  4. Límites de temperatura: Configurar según los requerimientos específicos

 Funcionalidades del Sistema

  1. Dos modos de control: PID y On/Off

  2. Ajuste de parámetros PID desde la interfaz

  3. Visualización de temperatura actual y deseada

  4. Control seguro de cargas AC mediante dimmer digital

  5. Interfaz intuitiva con botones y LCD

Este sistema permite un control preciso de temperatura con seguridad eléctrica y flexibilidad de configuración gracias al uso del ESP32 y el dimmer digital basado en MOC3031 y triac.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *