#include "pitches.h"
// Definição dos pinos para LEDs, botões e alto-falante
const uint8_t pinosLED[] = {9, 10, 11, 12};
const uint8_t pinosBotao[] = {2, 3, 4, 5};
#define PINO_ALTO_FALANTE 8
// Definição dos pinos para o shift register
const int PINO_LATCH = A1;
const int PINO_DADOS = A0;
const int PINO_CLOCK = A2;
// Definição do tamanho máximo da sequência do jogo
#define TAM_MAX_JOGO 100
// Notas musicais para a sequência do jogo
const int tonsJogo[] = { NOTE_G3, NOTE_C4, NOTE_E4, NOTE_G5};
// Array para armazenar a sequência do jogo e índice atual
uint8_t sequenciaJogo[TAM_MAX_JOGO] = {0};
uint8_t indiceJogo = 0;
// Inicialização do código
void setup() {
Serial.begin(9600);
// Configuração dos pinos de LEDs como saídas e pinos de botão como entradas com pull-up
for (byte i = 0; i < 4; i++) {
pinMode(pinosLED[i], OUTPUT);
pinMode(pinosBotao[i], INPUT_PULLUP);
}
// Configuração do pino do alto-falante e dos pinos do shift register
pinMode(PINO_ALTO_FALANTE, OUTPUT);
pinMode(PINO_LATCH, OUTPUT);
pinMode(PINO_CLOCK, OUTPUT);
pinMode(PINO_DADOS, OUTPUT);
// Inicialização da semente para geração de números aleatórios
randomSeed(analogRead(A3));
}
// Tabela de segmentos para display de 7 segmentos
const uint8_t tabelaDigitos[] = {
0b11000000, 0b11111001, 0b10100100, 0b10110000,
0b10011001, 0b10010010, 0b10000010, 0b11111000,
0b10000000, 0b10010000
};
const uint8_t TRACO = 0b10111111; // Segmento para exibir um traço
// Função para enviar pontuação para o display de 7 segmentos
void enviarPontuacao(uint8_t alto, uint8_t baixo) {
digitalWrite(PINO_LATCH, LOW);
shiftOut(PINO_DADOS, PINO_CLOCK, MSBFIRST, baixo);
shiftOut(PINO_DADOS, PINO_CLOCK, MSBFIRST, alto);
digitalWrite(PINO_LATCH, HIGH);
}
// Função para exibir pontuação atual no display de 7 segmentos
void mostrarPontuacao() {
int alto = indiceJogo % 100 / 10;
int baixo = indiceJogo % 10;
enviarPontuacao(alto ? tabelaDigitos[alto] : 0xff, tabelaDigitos[baixo]);
}
// Função para acender um LED e tocar uma nota musical
void acenderLedETocarTone(byte indiceLED) {
digitalWrite(pinosLED[indiceLED], HIGH);
tone(PINO_ALTO_FALANTE, tonsJogo[indiceLED]);
delay(300);
digitalWrite(pinosLED[indiceLED], LOW);
noTone(PINO_ALTO_FALANTE);
}
// Função para tocar a sequência de notas
void tocarSequencia() {
for (int i = 0; i < indiceJogo; i++) {
byte ledAtual = sequenciaJogo[i];
acenderLedETocarTone(ledAtual);
delay(50);
}
}
// Função para ler qual botão foi pressionado
byte lerBotoes() {
while (true) {
for (byte i = 0; i < 4; i++) {
byte pinoBotao = pinosBotao[i];
if (digitalRead(pinoBotao) == LOW) {
return i;
}
}
delay(1);
}
}
// Função chamada quando o jogo termina
void fimDeJogo() {
Serial.print("Fim de jogo! Sua pontuação: ");
Serial.println(indiceJogo - 1);
indiceJogo = 0;
delay(200);
// Sequência de notas tocadas quando o jogo termina
tone(PINO_ALTO_FALANTE, NOTE_DS5);
delay(300);
tone(PINO_ALTO_FALANTE, NOTE_D5);
delay(300);
tone(PINO_ALTO_FALANTE, NOTE_CS5);
delay(300);
for (byte i = 0; i < 10; i++) {
for (int tom = -10; tom <= 10; tom++) {
tone(PINO_ALTO_FALANTE, NOTE_C5 + tom);
delay(5);
}
}
noTone(PINO_ALTO_FALANTE);
// Limpa o display de 7 segmentos
enviarPontuacao(TRACO, TRACO);
delay(500);
}
// Função para verificar se a sequência do usuário está correta
bool verificarSequenciaUsuario() {
for (int i = 0; i < indiceJogo; i++) {
byte botaoEsperado = sequenciaJogo[i];
byte botaoAtual = lerBotoes();
acenderLedETocarTone(botaoAtual);
if (botaoEsperado != botaoAtual) {
return false;
}
}
return true;
}
// Função para tocar uma melodia quando o nível sobe
void tocarSomSubidaNivel() {
tone(PINO_ALTO_FALANTE, NOTE_E4);
delay(150);
tone(PINO_ALTO_FALANTE, NOTE_G4);
delay(150);
tone(PINO_ALTO_FALANTE, NOTE_E5);
delay(150);
tone(PINO_ALTO_FALANTE, NOTE_C5);
delay(150);
tone(PINO_ALTO_FALANTE, NOTE_D5);
delay(150);
tone(PINO_ALTO_FALANTE, NOTE_G5);
delay(150);
noTone(PINO_ALTO_FALANTE);
}
// Função principal do loop
void loop() {
mostrarPontuacao();
// Adiciona uma nova nota à sequência do jogo
sequenciaJogo[indiceJogo] = random(0, 4);
indiceJogo++;
if (indiceJogo >= TAM_MAX_JOGO) {
indiceJogo = TAM_MAX_JOGO - 1;
}
// Toca a sequência atual de notas
tocarSequencia();
// Verifica se a sequência do jogador está correta
if (!verificarSequenciaUsuario()) {
fimDeJogo();
}
delay(300);
// Toca uma melodia quando o nível sobe
if (indiceJogo > 0) {
tocarSomSubidaNivel();
delay(300);
}
}