// Inclusão da biblioteca para o Anel de LED (NeoPixel)
#include <Adafruit_NeoPixel.h>
// --- MAPEAMENTO DE PINOS (baseado no diagrama) ---
// Anel de LED (NeoPixel)
#define PIN_NEOPIXEL 12 // Fio Verde no diagrama
#define NUM_PIXELS 16 // O anel no diagrama tem 16 LEDs
// Botões (INPUT_PULLUP, pois estão ligados ao GND)
#define PIN_PLAYER_BLUE 4 // Fio Azul
#define PIN_PLAYER_RED 3 // Fio Amarelo (Assumido como Vermelho para o jogo)
#define PIN_JUDGE_RESET 2 // Fio Laranja
// Buzzer
#define PIN_BUZZER 5 // Fio Vermelho para o buzzer
// --- ESTADOS DO JOGO ---
#define STATE_WAITING 0 // Aguardando um jogador apertar
#define STATE_LOCKED 1 // Um jogador apertou, sistema travado
// Inicialização do objeto NeoPixel
Adafruit_NeoPixel strip(NUM_PIXELS, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
// --- CORES ---
#define COLOR_BLUE strip.Color(0, 0, 255)
#define COLOR_RED strip.Color(255, 0, 0)
#define COLOR_OFF strip.Color(0, 0, 0)
// --- Variáveis Globais de Controle ---
// Estado do Jogo
int gameState = STATE_WAITING;
int winner = 0; // 0 = Ninguém, 1 = Azul, 2 = Vermelho
// Pontuação
// As pontuações são globais e inicializadas com 0.
// Elas não serão mais zeradas pelo Juiz.
int scoreBlue = 0;
int scoreRed = 0;
// Animação de Espera (Giratória)
unsigned long lastAnimationTime = 0;
int animationInterval = 50; // Velocidade da animação em ms
int ledPos = 0;
// Animação de Vitória (Pisca-Pisca)
unsigned long lastBlinkTime = 0;
int blinkInterval = 300; // Intervalo do pisca-pisca (300ms)
bool ledState = true; // Estado atual do LED (ligado/desligado)
void setup() {
// Inicia o Monitor Serial para depuração e placar
Serial.begin(9600);
Serial.println("Sistema 'Passa ou Repassa' Iniciado!");
Serial.println("Placar inicial: Azul 0 x 0 Vermelho");
// Configura os pinos dos botões como entrada com resistor pull-up interno
pinMode(PIN_PLAYER_BLUE, INPUT_PULLUP);
pinMode(PIN_PLAYER_RED, INPUT_PULLUP);
pinMode(PIN_JUDGE_RESET, INPUT_PULLUP);
// Configura o pino do buzzer como saída
pinMode(PIN_BUZZER, OUTPUT);
// Inicializa a biblioteca NeoPixel
strip.begin();
strip.setBrightness(255); // Define um brilho (0-255)
strip.show(); // Inicializa todos os LEDs apagados
// --- TESTE DE INICIALIZAÇÃO ---
setAllLeds(COLOR_RED);
delay(250);
setAllLeds(strip.Color(0, 255, 0)); // Verde
delay(250);
setAllLeds(COLOR_BLUE);
delay(250);
strip.clear();
strip.show();
// --- FIM DO TESTE ---
// Inicia o jogo no estado de espera
setGameState(STATE_WAITING);
}
void loop() {
// A lógica do jogo é baseada no estado atual
switch (gameState) {
case STATE_WAITING:
// 1. Gira as luzes
animateWaiting();
// 2. Verifica se algum jogador apertou
checkPlayerButtons();
break;
case STATE_LOCKED:
// 1. Faz os LEDs do vencedor piscarem
animateBlinking();
// 2. Verifica se o Juiz apertou o reset
checkJudgeReset();
break;
}
}
// Verifica os botões dos jogadores
void checkPlayerButtons() {
// Verifica o Jogador Azul
if (digitalRead(PIN_PLAYER_BLUE) == LOW) {
winner = 1; // Azul venceu a rodada de velocidade
setGameState(STATE_LOCKED);
}
// Verifica o Jogador Vermelho (só se o azul não apertou)
else if (digitalRead(PIN_PLAYER_RED) == LOW) {
winner = 2; // Vermelho venceu a rodada de velocidade
setGameState(STATE_LOCKED);
}
}
// Verifica o botão de reset do Juiz
void checkJudgeReset() {
if (digitalRead(PIN_JUDGE_RESET) == LOW) {
// Adiciona um pequeno delay para debounce (evitar múltiplos resets)
delay(50);
setGameState(STATE_WAITING); // Reinicia a rodada
}
}
// Controla o estado do jogo e as saídas
void setGameState(int newState) {
gameState = newState;
if (gameState == STATE_WAITING) {
// PREPARA PARA PRÓXIMA RODADA (RESET)
winner = 0;
strip.clear();
strip.show();
// As linhas abaixo foram removidas para tornar o placar cumulativo.
// scoreBlue = 0;
// scoreRed = 0;
// Informa no Serial
Serial.println("-------------------------");
Serial.println("JUIZ REINICIOU A RODADA!");
// Mostra o placar CUMULATIVO atual
Serial.print("Placar atual: Azul ");
Serial.print(scoreBlue);
Serial.print(" x ");
Serial.print(scoreRed);
Serial.println(" Vermelho");
Serial.println("Aguardando jogadores...");
} else if (gameState == STATE_LOCKED) {
// UM JOGADOR APERTOU (VITÓRIA)
// 1. Toca o bipe
playBeep();
// 2. Incrementa o placar e informa o vencedor
if (winner == 1) { // Azul
scoreBlue++;
Serial.println(">> Jogador AZUL apertou!");
} else if (winner == 2) { // Vermelho
scoreRed++;
Serial.println(">> Jogador VERMELHO apertou!");
}
// 3. Imprime o placar atualizado
Serial.print("Placar: Azul ");
Serial.print(scoreBlue);
Serial.print(" x ");
Serial.print(scoreRed);
Serial.println(" Vermelho");
Serial.println("Aguardando Juiz reiniciar...");
// 4. Prepara o estado inicial do pisca-pisca (começa aceso)
lastBlinkTime = millis(); // Reseta o timer do pisca-pisca
ledState = true; // Força o estado inicial para "ligado"
if (winner == 1) {
setAllLeds(COLOR_BLUE);
} else if (winner == 2) {
setAllLeds(COLOR_RED);
}
}
}
// Animação de espera (giratória, não-bloqueante)
void animateWaiting() {
if (millis() - lastAnimationTime > animationInterval) {
lastAnimationTime = millis();
strip.clear(); // Apaga todos os LEDs
// Define o pixel Azul
strip.setPixelColor(ledPos, COLOR_BLUE);
// Define o pixel Vermelho (oposto ao azul)
int redPos = (ledPos + (NUM_PIXELS / 2)) % NUM_PIXELS;
strip.setPixelColor(redPos, COLOR_RED);
strip.show(); // Atualiza o anel
// Avança a posição para a próxima iteração
ledPos = (ledPos + 1) % NUM_PIXELS;
}
}
// Animação de vitória (pisca-pisca, não-bloqueante)
void animateBlinking() {
if (millis() - lastBlinkTime > blinkInterval) {
lastBlinkTime = millis();
ledState = !ledState; // Inverte o estado (ON -> OFF, OFF -> ON)
if (ledState) {
// LIGA os LEDs na cor do vencedor
if (winner == 1) {
setAllLeds(COLOR_BLUE);
} else if (winner == 2) {
setAllLeds(COLOR_RED);
}
} else {
// DESLIGA os LEDs
strip.clear();
strip.show();
}
}
}
// Acende todos os LEDs de uma cor
void setAllLeds(uint32_t color) {
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, color);
}
strip.show();
}
// Toca um bipe curto no buzzer
void playBeep() {
tone(PIN_BUZZER, 1000, 200); // Toca um tom de 1000Hz por 200ms
}