#include <TM1637Display.h>
#include "pitches.h"
// Pins for the TM1637 display
#define CLK 9
#define DIO 10
// Pins for buttons, LED, and buzzer
#define BUTTON_UP_PIN 4
#define BUTTON_DOWN_PIN 5
#define BUTTON_START_PIN 6
#define LED_PIN 11
#define MODE_SELECT1_PIN 2
#define MODE_SELECT2_PIN 3
#define BUZZER_PIN 12
// ====== TIMER ======
static int countdown_time = 300;
static int initial_countdown_time = countdown_time;
bool countdown_running = false;
bool countdown_paused = false;
unsigned long previousMillis = 0;
unsigned long buttonPressStart = 0;
const long interval = 1000;
// ====== REACTION GAME ======
bool reactionGameStarted = false;
unsigned long reactionGameStartTime;
unsigned long reactionTime;
// ====== SENSO GAME ======
const int sensoSequenceMaxLength = 99;
int sequence[sensoSequenceMaxLength];
int sensoSequenceLength = 0;
int sensoCurrentRound = 0;
bool sensoGameActive = false;
TM1637Display display(CLK, DIO);
// Noten und Dauer für die Melodien
const int melodies[2][6][2] = {
{ // Akte X
{NOTE_A3, 5},
{NOTE_E4, 5},
{NOTE_D4, 5},
{NOTE_E4, 5},
{NOTE_G4, 5},
{NOTE_E4, 15}
},
{ // Begegnung der 3. Art
{NOTE_D5, 4},
{NOTE_E5, 4},
{NOTE_C5, 4},
{NOTE_C4, 4},
{NOTE_G4, 6},
{NOTE_G4, 6}
}
};
void setup() {
// Set up the display
display.setBrightness(0x0f);
// Set up pins
pinMode(BUTTON_UP_PIN, INPUT_PULLUP);
pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP);
pinMode(BUTTON_START_PIN, INPUT_PULLUP);
pinMode(MODE_SELECT1_PIN, INPUT_PULLUP);
pinMode(MODE_SELECT2_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
Serial.begin(9600);
randomSeed(analogRead(0));
attachInterrupt(digitalPinToInterrupt(MODE_SELECT1_PIN), resetApp, CHANGE);
attachInterrupt(digitalPinToInterrupt(MODE_SELECT2_PIN), resetApp, CHANGE);
resetApp();
}
void resetApp() {
//Serial.println("resetApp");
// Initial state
digitalWrite(LED_PIN, LOW);
noTone(BUZZER_PIN);
display.clear();
}
void loop() {
if (digitalRead(MODE_SELECT1_PIN) == LOW) {
// ================================
// ====== REACTION GAME CODE ======
// ================================
if (!reactionGameStarted) {
// Wait for any button to start the game
if (digitalRead(BUTTON_UP_PIN) == LOW || digitalRead(BUTTON_DOWN_PIN) == LOW || digitalRead(BUTTON_START_PIN) == LOW) {
// start game
reactionGameStarted = true;
display.showNumberDec(0, true);
playConfirmationSound();
// Wait for a random time between 2 and 10 seconds
unsigned long waitTime = random(2000, 10000);
unsigned long blinkStartTime = millis();
bool colonState = false;
while (millis() - blinkStartTime < waitTime) {
if (millis() % 200 < 100) {
colonState = !colonState;
display.showNumberDecEx(0, colonState ? 0x80 : 0, true);
} else {
display.clear(); // Anzeige aus
}
// Hack durch gedrückt halten vermeiden
if (digitalRead(BUTTON_UP_PIN) == LOW || digitalRead(BUTTON_DOWN_PIN) == LOW || digitalRead(BUTTON_START_PIN) == LOW) {
blinkStartTime = millis();
playConfirmationSound();
}
}
display.clear(); // Anzeige aus
// Signal the player with LED and Buzzer
digitalWrite(LED_PIN, HIGH);
tone(BUZZER_PIN, NOTE_C6);
// Record the start time
reactionGameStartTime = millis();
}
} else {
reactionTime = 0;
// Wait for Button 2 to stop the timer
if (digitalRead(BUTTON_UP_PIN) == LOW || digitalRead(BUTTON_DOWN_PIN) == LOW || digitalRead(BUTTON_START_PIN) == LOW) {
// stop game
digitalWrite(LED_PIN, LOW);
noTone(BUZZER_PIN);
// Calculate reaction time
reactionTime = millis() - reactionGameStartTime;
// Display the reaction time in milliseconds
display.showNumberDec(reactionTime, true);
// Reset the game state
reactionGameStarted = false;
delay(1000);
}
}
display.showNumberDec(reactionTime, true);
} else if (digitalRead(MODE_SELECT2_PIN) == LOW) {
// =============================
// ====== SENSO GAME CODE ======
// =============================
if (sensoGameActive) {
// play sequence
digitalWrite(LED_PIN, HIGH);
for (int i = 0; i < sensoSequenceLength; i++) {
display.showNumberDec(sequence[i]);
playTone(sequence[i]);
delay(300); // game speed
display.clear();
delay(150);
}
digitalWrite(LED_PIN, LOW);
if (!getPlayerInput()) {
// game over
sensoGameActive = false;
display.showNumberDecEx(sensoCurrentRound, 0, true, 2, 2); // Display current round
digitalWrite(LED_PIN, LOW);
} else {
// next round
sensoCurrentRound++;
sequence[sensoSequenceLength] = random(1, 4);
sensoSequenceLength++;
display.showNumberDecEx(sensoCurrentRound, 0, true, 2, 2); // Display current round
delay(500);
}
} else if (digitalRead(BUTTON_UP_PIN) == LOW || digitalRead(BUTTON_DOWN_PIN) == LOW || digitalRead(BUTTON_START_PIN) == LOW) {
// Restart the game when any button is pressed
sensoSequenceLength = 1;
sensoCurrentRound = 0;
sequence[0] = random(1, 4); // Initialize the first sequence value
sensoGameActive = true;
display.showNumberDecEx(sensoCurrentRound, 0, true, 2, 2); // Display current round
digitalWrite(LED_PIN, LOW);
delay(300);
}
display.showNumberDecEx(sensoCurrentRound, 0, true, 2, 2); // Display current round
} else {
// ================================
// ========== TIMER CODE ==========
// ================================
if (!countdown_running) { // Zeit einstellen
if (digitalRead(BUTTON_UP_PIN) == LOW) {
countdown_time += 60; // Erhöht die Zeit um eine Minute
initial_countdown_time = countdown_time;
Serial.print("Countdown-Zeit: ");
Serial.print(countdown_time / 60);
Serial.println(" Minuten");
int minutes = countdown_time / 60;
int seconds = countdown_time % 60;
display.showNumberDecEx((minutes * 100) + seconds, 0b01000000, true);
playConfirmationSound();
delay(200); // Entprellung
}
if (digitalRead(BUTTON_DOWN_PIN) == LOW && countdown_time >= 60) {
countdown_time -= 60; // Verringert die Zeit um eine Minute
initial_countdown_time = countdown_time;
Serial.print("Countdown-Zeit: ");
Serial.print(countdown_time / 60);
Serial.println(" Minuten");
int minutes = countdown_time / 60;
int seconds = countdown_time % 60;
display.showNumberDecEx((minutes * 100) + seconds, 0b01000000, true);
playConfirmationSound();
delay(200); // Entprellung
}
if (digitalRead(BUTTON_START_PIN) == LOW) {
buttonPressStart = millis();
while (digitalRead(BUTTON_START_PIN) == LOW) {
if (millis() - buttonPressStart > 1000) { // Wenn der Start-Button länger als 1 Sekunde gedrückt wird
countdown_time = initial_countdown_time; // Zurück zur vorher eingestellten Zeit
Serial.println("Countdown gestoppt und zurückgesetzt!");
int minutes = countdown_time / 60;
int seconds = countdown_time % 60;
countdown_running = false;
countdown_paused = false; // Sicherstellen, dass der Countdown nicht pausiert ist, wenn er neu startet
playStopSound();
delay(200); // Entprellung
return;
}
}
Serial.println("Countdown gestartet!");
countdown_running = true;
playStartSound();
delay(1000); // Entprellung
}
}
else { // Countdown running
unsigned long currentMillis = millis();
if (digitalRead(BUTTON_START_PIN) == LOW) { // Prüfen, ob der Start-Button erneut gedrückt wird
buttonPressStart = millis();
while (digitalRead(BUTTON_START_PIN) == LOW) {
if (millis() - buttonPressStart > 1000) { // Wenn der Start-Button länger als 1 Sekunde gedrückt wird
countdown_time = initial_countdown_time; // Zurück zur vorher eingestellten Zeit
Serial.println("Countdown gestoppt und zurückgesetzt!");
int minutes = countdown_time / 60;
int seconds = countdown_time % 60;
countdown_running = false;
countdown_paused = false; // Sicherstellen, dass der Countdown nicht pausiert ist, wenn er neu startet
playStopSound();
delay(500); // Entprellung
return;
}
}
countdown_paused = !countdown_paused; // Pausieren/Fortsetzen umschalten
Serial.println(countdown_paused ? "Countdown pausiert!" : "Countdown fortgesetzt!");
playStartSound();
delay(200); // Entprellung
}
if (countdown_paused) {
// Anzeige blinken lassen
if ((currentMillis / 400) % 2 == 0) {
display.showNumberDecEx((countdown_time / 60 * 100) + countdown_time % 60, 0b01000000, true); // Anzeige an
} else {
display.clear(); // Anzeige aus
}
}
else if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
if (countdown_time > 0) {
countdown_time -= 1;
int minutes = countdown_time / 60;
int seconds = countdown_time % 60;
display.showNumberDecEx((minutes * 100) + seconds, 0b01000000, true);
} else {
// Buzzer ertönt, wenn die Zeit abgelaufen ist
Serial.println("Zeit abgelaufen!");
countdown_running = false;
countdown_paused = false; // Sicherstellen, dass der Countdown nicht in pausiertem Zustand endet
playMelody();
}
}
}
if (!countdown_paused) {
display.showNumberDecEx((countdown_time / 60 * 100) + countdown_time % 60, 0b01000000, true);
}
}
}
void playConfirmationSound() {
tone(BUZZER_PIN, NOTE_E6);
delay(2); // Pause zwischen den Noten
noTone(BUZZER_PIN);
delay(100);
}
void playStopSound() {
tone(BUZZER_PIN, NOTE_E2);
delay(100); // Pause zwischen den Noten
noTone(BUZZER_PIN);
}
void playStartSound() {
tone(BUZZER_PIN, NOTE_G4);
delay(20); // Pause zwischen den Noten
noTone(BUZZER_PIN);
}
void playTone(int number) {
int frequency = 0;
switch (number) {
case 1:
frequency = NOTE_C4; // C4
break;
case 2:
frequency = NOTE_E4; // E4
break;
case 3:
frequency = NOTE_G4; // G4
break;
}
tone(BUZZER_PIN, frequency, 150);
}
void playErrorTone() {
tone(BUZZER_PIN, 150, 500);
delay(500);
noTone(BUZZER_PIN);
}
void playMelody() {
//int melody = (digitalRead(MODE_SELECT1_PIN) == LOW) ? 0:1;
int melody = 1;
for (int i = 0; i < sizeof(melodies[melody]) / sizeof(melodies[melody][0]); i++) {
int noteDuration = 100 * melodies[melody][i][1];
tone(BUZZER_PIN, melodies[melody][i][0]);
digitalWrite(LED_PIN, HIGH); // LED blinken lassen, während die Melodie abgespielt wird
delay(noteDuration * 0.3); // Pause zwischen den Noten 1
digitalWrite(LED_PIN, LOW);
delay(noteDuration * 0.70); // Pause zwischen den Noten 2
noTone(BUZZER_PIN);
}
}
bool getPlayerInput() {
for (int i = 0; i < sensoSequenceLength; i++) {
int playerInput = 0;
unsigned long startTime = millis();
while (playerInput == 0) {
if (millis() - startTime > 3000) {
playErrorTone();
return false; // Time limit exceeded
}
if (digitalRead(BUTTON_UP_PIN) == LOW) {
playerInput = 1;
} else if (digitalRead(BUTTON_DOWN_PIN) == LOW) {
playerInput = 2;
} else if (digitalRead(BUTTON_START_PIN) == LOW) {
playerInput = 3;
}
}
display.showNumberDec(playerInput);
playTone(playerInput);
delay(300);
display.clear();
delay(150);
if (playerInput != sequence[i]) {
playErrorTone();
return false;
}
}
return true;
}