#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Configuración OLED (0.42" = 72x40 píxeles típicamente)
#define SCREEN_WIDTH 72
#define SCREEN_HEIGHT 40
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Pines
#define BTN_PIN 7 // Pin del pulsador (ajusta según tu conexión)
#define BUZZER_PIN 10 // Pin del buzzer opcional
// Estados del sistema
enum Estado { MENU, TRABAJO, DESCANSO, PAUSA };
Estado estadoActual = MENU;
// Configuración de tiempos (en minutos)
int tiempoTrabajo = 25;
int tiempoDescanso = 5;
int opcionMenu = 0; // 0=trabajo, 1=descanso, 2=iniciar
// Variables del temporizador
unsigned long tiempoInicio = 0;
unsigned long tiempoRestante = 0;
bool pausado = false;
// Control del botón
unsigned long ultimaPulsacion = 0;
unsigned long tiempoPresionado = 0;
bool botonPresionado = false;
const int DEBOUNCE = 50;
const int TIEMPO_LARGO = 1000; // 1 segundo para pulsación larga
void setup() {
Serial.begin(115200);
// Inicializar pulsador
pinMode(BTN_PIN, INPUT_PULLUP);
pinMode(BUZZER_PIN, OUTPUT);
// Inicializar OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("Error al inicializar OLED"));
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Pomodoro");
display.println("Listo!");
display.display();
delay(2000);
mostrarMenu();
}
void loop() {
manejarBoton();
switch(estadoActual) {
case MENU:
// El menú se actualiza solo con las pulsaciones
break;
case TRABAJO:
case DESCANSO:
if (!pausado) {
actualizarTemporizador();
}
break;
case PAUSA:
// Esperando a reanudar
break;
}
}
void manejarBoton() {
bool estadoBoton = digitalRead(BTN_PIN) == LOW;
unsigned long ahora = millis();
// Detectar flanco de bajada (inicio de pulsación)
if (estadoBoton && !botonPresionado && (ahora - ultimaPulsacion > DEBOUNCE)) {
botonPresionado = true;
tiempoPresionado = ahora;
}
// Detectar flanco de subida (fin de pulsación)
if (!estadoBoton && botonPresionado) {
botonPresionado = false;
unsigned long duracion = ahora - tiempoPresionado;
ultimaPulsacion = ahora;
if (duracion > TIEMPO_LARGO) {
// Pulsación larga
manejarPulsacionLarga();
} else {
// Pulsación corta
manejarPulsacionCorta();
}
}
}
void manejarPulsacionCorta() {
if (estadoActual == MENU) {
// Navegar por el menú
opcionMenu = (opcionMenu + 1) % 3;
mostrarMenu();
} else if (estadoActual == TRABAJO || estadoActual == DESCANSO) {
// Pausar/Reanudar
pausado = !pausado;
if (pausado) {
estadoActual = PAUSA;
mostrarPausa();
} else {
tiempoInicio = millis() - (tiempoRestante * 1000);
mostrarTemporizador();
}
} else if (estadoActual == PAUSA) {
// Reanudar
pausado = false;
estadoActual = (tiempoRestante > tiempoDescanso * 60) ? TRABAJO : DESCANSO;
tiempoInicio = millis() - (tiempoRestante * 1000);
mostrarTemporizador();
}
}
void manejarPulsacionLarga() {
if (estadoActual == MENU) {
if (opcionMenu == 0) {
// Ajustar tiempo de trabajo
tiempoTrabajo = (tiempoTrabajo % 60) + 5; // 5, 10, 15...60
if (tiempoTrabajo > 60) tiempoTrabajo = 5;
mostrarMenu();
} else if (opcionMenu == 1) {
// Ajustar tiempo de descanso
tiempoDescanso = (tiempoDescanso % 30) + 5; // 5, 10, 15...30
if (tiempoDescanso > 30) tiempoDescanso = 5;
mostrarMenu();
} else if (opcionMenu == 2) {
// Iniciar Pomodoro
iniciarPomodoro();
}
} else {
// Detener y volver al menú
animacionDetener();
estadoActual = MENU;
pausado = false;
opcionMenu = 0;
mostrarMenu();
}
}
void mostrarMenu() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
// Mostrar opciones
display.print(opcionMenu == 0 ? ">" : " ");
display.print("Trab:");
display.print(tiempoTrabajo);
display.println("m");
display.print(opcionMenu == 1 ? ">" : " ");
display.print("Desc:");
display.print(tiempoDescanso);
display.println("m");
display.println();
display.print(opcionMenu == 2 ? ">" : " ");
display.println("INICIAR");
display.display();
}
void iniciarPomodoro() {
animacionInicio();
estadoActual = TRABAJO;
tiempoInicio = millis();
tiempoRestante = tiempoTrabajo * 60;
pausado = false;
mostrarTemporizador();
}
void actualizarTemporizador() {
unsigned long transcurrido = (millis() - tiempoInicio) / 1000;
int tiempoTotal = (estadoActual == TRABAJO) ? tiempoTrabajo * 60 : tiempoDescanso * 60;
tiempoRestante = tiempoTotal - transcurrido;
if (tiempoRestante <= 0) {
// Tiempo completado
sonarAlarma();
if (estadoActual == TRABAJO) {
// Cambiar a descanso
estadoActual = DESCANSO;
tiempoInicio = millis();
tiempoRestante = tiempoDescanso * 60;
} else {
// Fin del Pomodoro
estadoActual = MENU;
opcionMenu = 0;
mostrarMenu();
return;
}
}
mostrarTemporizador();
delay(500); // Actualizar cada medio segundo
}
void mostrarTemporizador() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
// Mostrar estado
if (estadoActual == TRABAJO) {
display.println("TRABAJO");
} else {
display.println("DESCANSO");
}
// Mostrar tiempo
int minutos = tiempoRestante / 60;
int segundos = tiempoRestante % 60;
display.setTextSize(1);
display.setCursor(10, 16);
if (minutos < 10) display.print("0");
display.print(minutos);
display.print(":");
if (segundos < 10) display.print("0");
display.print(segundos);
display.display();
}
void mostrarPausa() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(5, 12);
display.println("PAUSA");
int minutos = tiempoRestante / 60;
int segundos = tiempoRestante % 60;
display.setCursor(10, 24);
if (minutos < 10) display.print("0");
display.print(minutos);
display.print(":");
if (segundos < 10) display.print("0");
display.print(segundos);
display.display();
}
void sonarAlarma() {
// Tono de alarma (3 pitidos)
for(int i = 0; i < 3; i++) {
tone(BUZZER_PIN, 1000, 200);
delay(300);
}
}
void animacionInicio() {
// Animación de círculo expandiéndose
display.clearDisplay();
for(int r = 1; r <= 20; r += 2) {
display.clearDisplay();
display.fillCircle(SCREEN_WIDTH/2, SCREEN_HEIGHT/2, r, SSD1306_WHITE);
display.display();
delay(50);
}
// Flash de texto "GO!"
for(int i = 0; i < 3; i++) {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(20, 15);
display.println("GO!");
display.display();
tone(BUZZER_PIN, 800, 100);
delay(200);
display.clearDisplay();
display.display();
delay(100);
}
delay(300);
}
void animacionDetener() {
// Animación de cruz/X expandiéndose
display.clearDisplay();
for(int i = 0; i <= 15; i++) {
display.clearDisplay();
// Dibujar X
display.drawLine(SCREEN_WIDTH/2 - i, SCREEN_HEIGHT/2 - i,
SCREEN_WIDTH/2 + i, SCREEN_HEIGHT/2 + i, SSD1306_WHITE);
display.drawLine(SCREEN_WIDTH/2 + i, SCREEN_HEIGHT/2 - i,
SCREEN_WIDTH/2 - i, SCREEN_HEIGHT/2 + i, SSD1306_WHITE);
display.display();
delay(40);
}
// Mostrar "STOP"
display.clearDisplay();
display.setTextSize(1);
display.setCursor(15, 15);
display.println("STOP");
display.display();
tone(BUZZER_PIN, 400, 300);
delay(800);
// Efecto de desvanecimiento (simulado con parpadeo)
for(int i = 0; i < 4; i++) {
display.clearDisplay();
display.display();
delay(100);
display.setCursor(15, 15);
display.println("STOP");
display.display();
delay(100);
}
display.clearDisplay();
display.display();
delay(200);
}Loading
esp32-c3-devkitm-1
esp32-c3-devkitm-1
Loading
ssd1306
ssd1306