// --- PINES DEL ESP32-C3 ---
#define DATA_PIN 4 // Va al pin DS del primer chip
#define CLOCK_PIN 5 // Va a todos los pines SHCP
#define LATCH_PIN 6 // Va a todos los pines STCP
#define LED_PIN 7 // LED del botón Arcade
#define BTN_PIN 9 // Botón Arcade
// --- ESTADOS DEL JUEGO ---
enum GameState { IDLE, RUNNING, STOPPED };
volatile GameState gameState = IDLE;
// --- VARIABLES DE TIEMPO ---
unsigned long startTime = 0;
unsigned long stopTime = 0;
unsigned long stopStateStart = 0;
volatile bool buttonPressed = false;
// --- MAPEO DE DISPLAY DE 7 SEGMENTOS (Ánodo Común) ---
const byte digitToSegment[] = {
0b11000000, // 0
0b11111001, // 1
0b10100100, // 2
0b10110000, // 3
0b10011001, // 4
0b10010010, // 5
0b10000010, // 6
0b11111000, // 7
0b10000000, // 8
0b10010000, // 9
0b11111111 // Apagado
};
// --- INTERRUPCIÓN DEL BOTÓN ---
void IRAM_ATTR handleButton() {
buttonPressed = true;
}
void setup() {
Serial.begin(115200);
pinMode(DATA_PIN, OUTPUT);
pinMode(CLOCK_PIN, OUTPUT);
pinMode(LATCH_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
pinMode(BTN_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BTN_PIN), handleButton, FALLING);
updateDisplay(0, 0, 0, 0);
digitalWrite(LED_PIN, HIGH);
Serial.println("Juego Listo. Presiona para empezar.");
}
void loop() {
// --- MÁQUINA DE ESTADOS ---
if (gameState == IDLE) {
// 1. El LED parpadea esperando que alguien juegue
digitalWrite(LED_PIN, (millis() / 500) % 2);
// 2. Todos los displays se mantienen fijos en 00.00
updateDisplay(0, 0, 0, 0);
if (buttonPressed) {
buttonPressed = false; // Limpiamos el flag del botón
startTime = millis(); // Guardamos la hora de inicio
gameState = RUNNING; // Pasamos a ejecución
digitalWrite(LED_PIN, LOW); // Apagamos el LED mientras corre el tiempo
Serial.println("¡Juego iniciado! Tiempo corriendo...");
}
}
else if (gameState == RUNNING) {
unsigned long currentElapsed = millis() - startTime;
displayTime(currentElapsed); // El display se actualiza en tiempo real
if (buttonPressed) {
buttonPressed = false; // Limpiamos el flag inmediatamente
// SOLUCIÓN AL BUG: Guardia de tiempo (Debounce de transición)
// Solo permite detener el tiempo si han pasado más de 200 milisegundos desde que inició.
// Esto evita que el mismo click de arranque detenga el cronómetro en 0.
if (currentElapsed > 200) {
stopTime = currentElapsed;
stopStateStart = millis(); // Registramos el momento exacto de la parada
gameState = STOPPED;
digitalWrite(LED_PIN, HIGH); // El LED se enciende fijo al parar
Serial.print("Tiempo congelado en: ");
Serial.println(stopTime);
}
}
}
else if (gameState == STOPPED) {
// Mantiene congelada la pantalla con el tiempo final donde se paró
displayTime(stopTime);
// Ignoramos y borramos cualquier manotazo extra durante la espera de 6 segundos
buttonPressed = false;
// Si ya transcurrieron 6000ms (6 segundos) desde que se detuvo:
if (millis() - stopStateStart >= 10000) {
gameState = IDLE; // El juego vuelve automáticamente a IDLE (displays a cero y LED parpadeando)
Serial.println("6 segundos cumplidos. Reiniciando a cero automáticamente...");
}
}
}
// --- FUNCIONES DE CONTROL DE PANTALLA ---
void displayTime(unsigned long timeInMillis) {
if (timeInMillis > 99990) timeInMillis = 99990;
unsigned int seconds = (timeInMillis / 1000) % 100;
unsigned int centiseconds = (timeInMillis / 10) % 100;
byte dig1 = seconds / 10;
byte dig2 = seconds % 10;
byte dig3 = centiseconds / 10;
byte dig4 = centiseconds % 10;
updateDisplay(dig1, dig2, dig3, dig4);
}
void updateDisplay(byte d1, byte d2, byte d3, byte d4) {
digitalWrite(LATCH_PIN, LOW);
// Comunicación en cascada (trencito) hacia los 74HC595
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, digitToSegment[d4]);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, digitToSegment[d3]);
// Forzamos el encendido del punto decimal en el segundo dígito (Unidad de segundo)
byte dig2ConPunto = digitToSegment[d2] & 0b01111111;
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, dig2ConPunto);
shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, digitToSegment[d1]);
digitalWrite(LATCH_PIN, HIGH);
}Loading
esp32-c3-devkitm-1
esp32-c3-devkitm-1