Programm hängt sich auf

Guten Tag

Ich bin aktuell an einem Programm drann für ein Simon Says mit digitalem Logbuch. Hier ist der Link zu meinem Wokwi Projekt: Wokwi - Online ESP32, STM32, Arduino Simulator

Weiss jemand wieso sich das Arduino in Step 6 (bzw. Case 6) aufhängt?? weil sobald man den button in case 5 mehr als 2 sekunden gedrückt hält sollte er eigentlich case 6 ausführen aber er macht nichts. Aktuell Passiert in case 6 nicht wirklich viel. Kommisch ist auch, dass wenn ich in case 5 anstelle von Step = 6; Step = 0; eingebe funktioniert alles ganz normal. Wenn ich jedoch über case 6 auf step 0 gehe hängt es sich einfach auf. Ist das ein Problem im Code oder ein Problem in Wokwi?

Kannst Du mal bitte den Code hier einstellen.
Danke.

Warum fängst Du für jeden Pups im gleichen Projekt einen neuen Thread an?

Gruß Tommy

/*

Simon Says Spiel für ein Geocache

Simon Says Anleitung:

Simon Says ist ein Reaktions- und Gedächtnisspiel, bei dem eine Abfolge von blinkenden LEDs gezeigt wird. 
Der Spieler muss diese Reihenfolge durch Tastendrücke korrekt wiederholen. 
Mit jeder Runde wird die Sequenz länger und dadurch schwieriger.

*/

//Bibliotheken Einbinden
#include <Wire.h>
#include <U8g2lib.h>
#include <SD.h>
#include <SPI.h>

//Eingänge
const int ButtonsX[] = {A0, A1, A2}; 
const int EncoderCLK = 6;
const int EncoderDT = 7;
const int EncoderSW = 8;

//Ausgänge
const int Buzzer = 5; //Passiver Buzzer der Passend einen Ton macht
const int ButtonsY[] = {2, 3, 4}; 
const int chipSelect = 10;

//String / Char
String Username;
char InputText[21] = "";
const char* Characters[] = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9","-","_","'"};

//Konstante Merker
const int MatrixSize = sizeof(ButtonsX) / sizeof(ButtonsX[0]);
const int NumberOfButtons = MatrixSize * MatrixSize;
const int CharactersSize = sizeof(Characters) / sizeof(Characters[0]) - 1;
const int NumberOfRounds = 1; //Anzahl der Runden
const int Time = 300; //Allgemeine Verzögerung
const int Tones[] = {262, 294, 330, 370, 415, 466, 494, 554, 622}; //Tonhöhen bei bestimmten LED's bzw Buttons
const int BoxSize = 40;
const int GridX[] = {0, 43, 86, 0, 43, 86, 0, 43, 86};
const int GridY[] = {0, 0, 0, 43, 43, 43, 86, 86, 86};

bool firstEntry = true;
bool buttonWasPressed = false;
unsigned long pressStartTime = 0;

//Merker
int Step; //Variable für Schrittkette
int PressedButton;
int LastPressedButton; //Index des Letzten Gedrückten Buttons
int InputCount; //Anzahl der Gedrücken Buttons Innerhalb einer Runde
int Round; //Aktuelle Runde
int SavedSequence[NumberOfRounds]; //Array um die Reihenfolge der LED's zu Speichern
int lastCLKState;
int CounterCharakters;
int CursorPosition;
int Attempts;

// Display Initialisieren
U8G2_SH1107_128X128_1_HW_I2C u8g2(U8G2_R0);

//Setup wird nur beim Start einmal ausgeführt
void setup() 
{
  //Eingänge / Ausgänge definieren
  pinMode(EncoderCLK, INPUT);
  pinMode(EncoderDT, INPUT);
  pinMode(EncoderSW, INPUT_PULLUP);
  pinMode(Buzzer, OUTPUT);
  for (int i = 0; i < MatrixSize; i++) 
  {
    pinMode(ButtonsX[i], INPUT_PULLUP);
    pinMode(ButtonsY[i], OUTPUT);
    digitalWrite(ButtonsY[i], HIGH);
  }

  //Ausgänge Initialisieren
  noTone(Buzzer);

  //Merker Initialisieren
  Step = 0;
  Round = 0;
  PressedButton = 0;
  LastPressedButton = 0;
  InputCount = 0;
  CounterCharakters = 0;
  CursorPosition = 0;
  Attempts = 0;
  Username = "";
  lastCLKState = digitalRead(EncoderCLK);
  for (int i = 0; i < NumberOfRounds; i++) 
  {
    SavedSequence[i] = 0;
  }

  //Display Starten
  u8g2.begin();

  //Display Initialisieren
  u8g2.firstPage();
  do {} while (u8g2.nextPage());

  //SD initialisieren
  if (!SD.begin(chipSelect)) 
  {
    u8g2.firstPage();
    do 
    {
      u8g2.setFont(u8g2_font_ncenB08_tr);
      u8g2.drawStr(0, 30, "SD Karte fehlt!");
    } while (u8g2.nextPage());
    while (1); // Stoppe das Programm
  }

  //Zufallsgenerator Initialisieren
  randomSeed(analogRead(A7));
}

//Loop wird immer wieder wiederholt
void loop() {

  //Srittkette
  switch (Step) {

    case 0: //Initialisieren vor dem Start

      //Ausgänge Initialisieren
      noTone(Buzzer);

      //Merker Initialisieren
      Round = 0;
      PressedButton = 0;
      LastPressedButton = 0;
      InputCount = 0;
      CounterCharakters = 0;
      CursorPosition = 0;
      Attempts++;
      Username = "";
      for (int i = 0; i < NumberOfRounds; i++) 
      {
        SavedSequence[i] = 0;
      }

      //Display Initialisieren
      u8g2.firstPage();
      do {} while (u8g2.nextPage());

      //Spiel starten
      if (digitalRead(EncoderSW) == LOW) 
      {
        //Grid aufzeichnen
        u8g2.firstPage();
        do 
        {
          for (int b = 0; b < NumberOfButtons; b++) 
          {
            u8g2.drawFrame(GridX[b], GridY[b], BoxSize, BoxSize);
          }
        } while (u8g2.nextPage());

        delay(Time * 2);

        Step = 1;
      }

      //Schritt beenden
      break;

    case 1: //Bisher Gespeicherte Abfolge Abspielen

      //Variable InputCount Initialisieren
      InputCount = 0;

      //Bisher Gespeicherte Abfolge Abspielen
      for (int i = 0; i < Round; i++) 
      {
        u8g2.firstPage();
        do 
        {
          for (int b = 0; b < NumberOfButtons; b++) 
          {
            if (b == SavedSequence[i] - 1) {
              u8g2.drawBox(GridX[b], GridY[b], BoxSize, BoxSize);
            } else {
              u8g2.drawFrame(GridX[b], GridY[b], BoxSize, BoxSize);
            }
          }
        } while (u8g2.nextPage());

        tone(Buzzer, Tones[SavedSequence[i] - 1]);

        delay(Time);

        u8g2.firstPage();
        do 
        {
          for (int b = 0; b < NumberOfButtons; b++) 
          {
            u8g2.drawFrame(GridX[b], GridY[b], BoxSize, BoxSize);
          }
        } while (u8g2.nextPage());

        noTone(Buzzer);

        delay(Time);
      }

      //in Schritt 2 Wechseln
      Step = 2;

      //Schritt beenden
      break;

    case 2: //Neue Zufalls-LED Aufleuchten und Speichern lassen

      //Zufallszahl Speichern
      SavedSequence[Round] = random(1, NumberOfButtons + 1);

      //Zuffällige LED Anzeigen anhand des oben Gespeicherten Wertes
      u8g2.firstPage();
      do 
      {
        for (int b = 0; b < NumberOfButtons; b++) {
          if (b == SavedSequence[Round] - 1) {
            u8g2.drawBox(GridX[b], GridY[b], BoxSize, BoxSize);
          } else {
            u8g2.drawFrame(GridX[b], GridY[b], BoxSize, BoxSize);
          }
        }
      } while (u8g2.nextPage());

      tone(Buzzer, Tones[SavedSequence[Round] - 1]);

      delay(Time);

      u8g2.firstPage();
      do 
      {
        for (int b = 0; b < NumberOfButtons; b++) 
        {
          u8g2.drawFrame(GridX[b], GridY[b], BoxSize, BoxSize);
        }
      } while (u8g2.nextPage());
      
      noTone(Buzzer);

      //in Schritt 2 Wechseln
      Step = 3;

      //Schritt beenden
      break;

    case 3: //Überprüfen welcher Button vom Spieler gedrückt wurde und die Entsprechende LED Aufleuchten lassen

      for (int y = 0; y < MatrixSize; y++)
      {
        digitalWrite(ButtonsY[y], LOW);
        for (int x = 0; x < MatrixSize; x++)
        {
          if (digitalRead(ButtonsX[x]) == LOW)
          {
            LastPressedButton = y * MatrixSize + x + 1;
            InputCount++;

            u8g2.firstPage();
            do 
            {
              for (int b = 0; b < NumberOfButtons; b++) 
              {
                if (b == LastPressedButton - 1) {
                  u8g2.drawBox(GridX[b], GridY[b], BoxSize, BoxSize);
                } else {
                  u8g2.drawFrame(GridX[b], GridY[b], BoxSize, BoxSize);
                }
              }
            } while (u8g2.nextPage());

            tone(Buzzer, Tones[LastPressedButton - 1]);

            delay(Time);

            u8g2.firstPage();
            do 
            {
              for (int b = 0; b < NumberOfButtons; b++) 
              {
                u8g2.drawFrame(GridX[b], GridY[b], BoxSize, BoxSize);
              }
            } while (u8g2.nextPage());

            noTone(Buzzer);

            //Entprellen
            while (digitalRead(ButtonsX[x]) == LOW) 
            {
              delay(10);
            }
            delay(Time);

            //in Schritt 4 Wechseln
            Step = 4;
          }
        }
        digitalWrite(ButtonsY[y], HIGH);
      }
      //Schritt beenden
      break;

    case 4: //Überprüfen ob der Spieler den Richtigen Button gedrückt hat und demensprechend handeln

      //Falls der Richtige Button gedrückt wurde und die Anzahl der Gedrückten Buttons innerhalb der Runde der Anzahl gespielten Runden entspricht dann Leuchtet die Grüne LED kurz auf und eine neue Runde Startet
      if (LastPressedButton == SavedSequence[InputCount - 1])
      {
        if (InputCount >= Round + 1)
        {
          Round++;

          //Falls die Gewünschte Anzahl Runden Erreicht ist und der Spieler bis hier erfolgreich war, wird eine Melodie gespielt und das Logbuch freigegeben
          if (Round >= NumberOfRounds)
          {
            int Melody[]   = {523, 659, 784, 523, 523, 659, 784, 1047};
            int Duration[] = {200, 200, 200, 400, 200, 200, 200, 600};

            for (int i = 0; i < 8; i++) 
            {
              tone(Buzzer, Melody[i]);
              delay(Duration[i]);
              noTone(Buzzer);
              delay(50);  
            }
            
            Step = 5;
          }

          //Falls die Gewünschte Anzahl Runden noch nicht erreicht ist, wir eine kurze Melodie gespielt und eine Neue Runde Startet
          else
          {
            //Melodie Abspielen für Richtige Runde
            int Melody[] = {587, 698, 880};
            for (int i = 0; i < 3; i++) 
            {
              tone(Buzzer, Melody[i]);
              delay(200);
              noTone(Buzzer);
              delay(50);
            }

            Step = 1;
          }
        }

        //Falls der Richtige Button gedrückt wurde, aber die Anzahl der Gedrückten Buttons innerhalb der Runde der Anzahl gespielten Runden nicht entspricht dann wird auf eine weitere Tasteneingabe gewartet
        else
        {
          Step = 3;
        }
      }

      //Falls der Falsche Button gedrückt wird dann muss das Spiel nochmal ganz von neu gestartet werden
      else 
      {
        //Melodie Abspielen für Falsche Runde
        int melody[] = {196, 130, 98};
        for (int i = 0; i < 3; i++) 
        {
          tone(Buzzer, melody[i]);
          delay(300);
          noTone(Buzzer);
          delay(100);
        }

        Step = 0;
      }

      //Schritt beenden
      break;


    case 5: //Logbuch Freigabe mit Eingabe

      if (firstEntry) {
        firstEntry = false;

        u8g2.firstPage();
        do {
          u8g2.setFont(u8g2_font_ncenB08_tr);
          u8g2.drawStr(5, 20, "Benutzername:");
          char displayText[21];
          strncpy(displayText, InputText, CursorPosition);
          displayText[CursorPosition] = *Characters[CounterCharakters];
          displayText[CursorPosition + 1] = '\0';
          u8g2.drawStr(5, 50, displayText);
          u8g2.drawStr(5, 53, "____________________");
        } while (u8g2.nextPage());
      }

      int currentCLKState = digitalRead(EncoderCLK);

      if (lastCLKState == LOW && currentCLKState == HIGH) {
        if (digitalRead(EncoderDT) == LOW) {
          CounterCharakters++;
          if (CounterCharakters > CharactersSize) CounterCharakters = 0;
        } else {
          CounterCharakters--;
          if (CounterCharakters < 0) CounterCharakters = CharactersSize;
        }

        u8g2.firstPage();
        do {
          u8g2.setFont(u8g2_font_ncenB08_tr);
          u8g2.drawStr(5, 20, "Benutzername:");
          char displayText[21];
          strncpy(displayText, InputText, CursorPosition);
          displayText[CursorPosition] = *Characters[CounterCharakters];
          displayText[CursorPosition + 1] = '\0';
          u8g2.drawStr(5, 50, displayText);
          u8g2.drawStr(5, 53, "____________________");
        } while (u8g2.nextPage());
      }

      lastCLKState = currentCLKState;

      // Button gedrückt halten
      if (digitalRead(EncoderSW) == LOW && !buttonWasPressed) {
        buttonWasPressed = true;
        pressStartTime = millis();
      }

      // Negative Flanke erkannt (Loslassen)
      if (digitalRead(EncoderSW) == HIGH && buttonWasPressed) 
      {
        buttonWasPressed = false;
        unsigned long pressDuration = millis() - pressStartTime;

        if (pressDuration < 2000) {
          // Kurzer Druck → Zeichen übernehmen
          if (CursorPosition < 20) {
            InputText[CursorPosition] = *Characters[CounterCharakters];
            CursorPosition++;
            InputText[CursorPosition] = '\0';
          }
        } else {
          Username = String(InputText);
          Step = 6;
          return;
        }

        // Display aktualisieren
        u8g2.firstPage();
        do {
          u8g2.setFont(u8g2_font_ncenB08_tr);
          u8g2.drawStr(5, 20, "Benutzername:");
          char displayText[21];
          strncpy(displayText, InputText, CursorPosition);
          displayText[CursorPosition] = *Characters[CounterCharakters];
          displayText[CursorPosition + 1] = '\0';
          u8g2.drawStr(5, 50, displayText);
          u8g2.drawStr(5, 53, "____________________");
        } while (u8g2.nextPage());
      }
      break;

    case 6:

      // Zurücksetzen der Variablen
      firstEntry = true;
      buttonWasPressed = false;
      Step = 0;
      return;


    default: //Schrittkette Initialisieren bei enem Fehler
      Step = 0;
      break;
  }
}

Sorry falls es etwas unübersichtlich ist. Da der Teil mit dem Eintragen sehr kompliziert ist habe ich nach dem Simon Says viel mithilfe von Chatgpt Gemacht.

Erstens ist das erst der zweiter und zweitens weil es beim anderen schon lange nicht mehr um die eigentliche frage gieng. Ich finde es so übersichtlicher. Kann ja jeder so machen wie er will oder? Oder wieso stört dich das so sehr?

Geh mal bitte in der IDE - > DATEI - VOREINSTELLUNGEN und dann
grafik

Dann bekommst Du schon beim kompilieren folgende Warnungen:

/tmp/arduino_modified_sketch_214777/sketch_jul02b.ino:492:10: warning: jump to case label [-fpermissive]
     case 6:
          ^
/tmp/arduino_modified_sketch_214777/sketch_jul02b.ino:404:11: note:   crosses initialization of 'int currentCLKState'
       int currentCLKState = digitalRead(EncoderCLK);
           ^~~~~~~~~~~~~~~
/tmp/arduino_modified_sketch_214777/sketch_jul02b.ino:499:5: warning: jump to case label [-fpermissive]
     default: //Schrittkette Initialisieren bei enem Fehler
     ^~~~~~~
/tmp/arduino_modified_sketch_214777/sketch_jul02b.ino:404:11: note:   crosses initialization of 'int currentCLKState'
       int currentCLKState = digitalRead(EncoderCLK);
           ^~~~~~~~~~~~~~~

Was soll das return da bewirken?
Nimm das raus und dann bau das break; da rein, wo es hin gehört.

1 Like

sollte es nicht break; statt return; heißen?

Habe ich beides bereits Probiert. Das mit Return hat mir eben Chatgpt vorgeschlagen. Ich habe vergessen das wieder auf break zu ändern. Auch mit break geht es nicht.

Vielen Dank für die Antwort. Ich habe Case 5 nun komplett in geschweiften klammern gesetzt. so funktioniert es einwandfrei.

    case 5: //Logbuch Freigabe mit Eingabe
    {
      if (firstEntry) {
        firstEntry = false;

        u8g2.firstPage();
        do {
          u8g2.setFont(u8g2_font_ncenB08_tr);
          u8g2.drawStr(5, 20, "Benutzername:");
          char displayText[21];
          strncpy(displayText, InputText, CursorPosition);
          displayText[CursorPosition] = *Characters[CounterCharakters];
          displayText[CursorPosition + 1] = '\0';
          u8g2.drawStr(5, 50, displayText);
          u8g2.drawStr(5, 53, "____________________");
        } while (u8g2.nextPage());
      }

      int currentCLKState = digitalRead(EncoderCLK);

      if (lastCLKState == LOW && currentCLKState == HIGH) {
        if (digitalRead(EncoderDT) == LOW) {
          CounterCharakters++;
          if (CounterCharakters > CharactersSize) CounterCharakters = 0;
        } else {
          CounterCharakters--;
          if (CounterCharakters < 0) CounterCharakters = CharactersSize;
        }

        u8g2.firstPage();
        do {
          u8g2.setFont(u8g2_font_ncenB08_tr);
          u8g2.drawStr(5, 20, "Benutzername:");
          char displayText[21];
          strncpy(displayText, InputText, CursorPosition);
          displayText[CursorPosition] = *Characters[CounterCharakters];
          displayText[CursorPosition + 1] = '\0';
          u8g2.drawStr(5, 50, displayText);
          u8g2.drawStr(5, 53, "____________________");
        } while (u8g2.nextPage());
      }

      lastCLKState = currentCLKState;

      // Button gedrückt halten
      if (digitalRead(EncoderSW) == LOW && !buttonWasPressed) {
        buttonWasPressed = true;
        pressStartTime = millis();
      }

      // Negative Flanke erkannt (Loslassen)
      if (digitalRead(EncoderSW) == HIGH && buttonWasPressed) 
      {
        buttonWasPressed = false;
        unsigned long pressDuration = millis() - pressStartTime;

        if (pressDuration < 2000) {
          // Kurzer Druck → Zeichen übernehmen
          if (CursorPosition < 20) {
            InputText[CursorPosition] = *Characters[CounterCharakters];
            CursorPosition++;
            InputText[CursorPosition] = '\0';
          }
        } else {
          Username = String(InputText);
          Step = 6;
          return;
        }

        // Display aktualisieren
        u8g2.firstPage();
        do {
          u8g2.setFont(u8g2_font_ncenB08_tr);
          u8g2.drawStr(5, 20, "Benutzername:");
          char displayText[21];
          strncpy(displayText, InputText, CursorPosition);
          displayText[CursorPosition] = *Characters[CounterCharakters];
          displayText[CursorPosition + 1] = '\0';
          u8g2.drawStr(5, 50, displayText);
          u8g2.drawStr(5, 53, "____________________");
        } while (u8g2.nextPage());
      }
    }
    break;

Las den chatGeist weiter vor sich her sabbeln.
Dein Problem ist case 5:

Beachte: Wenn Du eine Variable im case neu definierst, muss der Teil in einen eigenen Funktionsblock. Dann klappt da auch ohne Warnungen.

case5 und 6:

    case 5: //Logbuch Freigabe mit Eingabe
      {
        if (firstEntry)
        {
          firstEntry = false;
          u8g2.firstPage();

          do
          {
            u8g2.setFont(u8g2_font_ncenB08_tr);
            u8g2.drawStr(5, 20, "Benutzername:");
            char displayText[21];
            strncpy(displayText, InputText, CursorPosition);
            displayText[CursorPosition] = *Characters[CounterCharakters];
            displayText[CursorPosition + 1] = '\0';
            u8g2.drawStr(5, 50, displayText);
            u8g2.drawStr(5, 53, "____________________");
          } while (u8g2.nextPage());
        }

        int currentCLKState = digitalRead(EncoderCLK);

        if (lastCLKState == LOW && currentCLKState == HIGH)
        {
          if (digitalRead(EncoderDT) == LOW)
          {
            CounterCharakters++;

            if (CounterCharakters > CharactersSize)
            {
              CounterCharakters = 0;
            }
          }
          else
          {
            CounterCharakters--;

            if (CounterCharakters < 0)
            {
              CounterCharakters = CharactersSize;
            }
          }

          u8g2.firstPage();

          do
          {
            u8g2.setFont(u8g2_font_ncenB08_tr);
            u8g2.drawStr(5, 20, "Benutzername:");
            char displayText[21];
            strncpy(displayText, InputText, CursorPosition);
            displayText[CursorPosition] = *Characters[CounterCharakters];
            displayText[CursorPosition + 1] = '\0';
            u8g2.drawStr(5, 50, displayText);
            u8g2.drawStr(5, 53, "____________________");
          } while (u8g2.nextPage());
        }

        lastCLKState = currentCLKState;

        // Button gedrückt halten
        if (digitalRead(EncoderSW) == LOW && !buttonWasPressed)
        {
          buttonWasPressed = true;
          pressStartTime = millis();
        }

        // Negative Flanke erkannt (Loslassen)
        if (digitalRead(EncoderSW) == HIGH && buttonWasPressed)
        {
          buttonWasPressed = false;
          unsigned long pressDuration = millis() - pressStartTime;

          if (pressDuration < 2000)
          {
            // Kurzer Druck → Zeichen übernehmen
            if (CursorPosition < 20)
            {
              InputText[CursorPosition] = *Characters[CounterCharakters];
              CursorPosition++;
              InputText[CursorPosition] = '\0';
            }
          }
          else
          {
            Username = String(InputText);
            Step = 6;
            return;
          }

          // Display aktualisieren
          u8g2.firstPage();

          do
          {
            u8g2.setFont(u8g2_font_ncenB08_tr);
            u8g2.drawStr(5, 20, "Benutzername:");
            char displayText[21];
            strncpy(displayText, InputText, CursorPosition);
            displayText[CursorPosition] = *Characters[CounterCharakters];
            displayText[CursorPosition + 1] = '\0';
            u8g2.drawStr(5, 50, displayText);
            u8g2.drawStr(5, 53, "____________________");
          } while (u8g2.nextPage());
        }
      }
      break;

    case 6:
      // Zurücksetzen der Variablen
      firstEntry = true;
      buttonWasPressed = false;
      Step = 0;
      break;

Weil dadurch der inhaltliche Zusammenhang zerrissen wird.

Gruß Tommy

das ist ja genau das was ich jetzt gemacht habe??

dafür wird nicht auf sachen eingegangen die nicht gefragt wurden :wink:

ich hab mir Deins nicht so genau angeschaut, denke aber: ja :wink:
Wir waren zeitgleich fertig...

achso oke :slight_smile:

1 Like

Erbsenzähler....Das Haar in der Suppe finden. :wink:

Achso übrigens: Der ChatGeist hatte die Geschweiften klammern mal gestetzt aber ich dachte ich wäre schlauer und diese seien unnötig :slight_smile:

Neues Problem. Ich habe aktuell diesen Code:

/*

Simon Says Spiel für einen Geocache

Simon Says ist ein Reaktions- und Gedächtnisspiel, bei dem eine Abfolge von blinkenden LEDs gezeigt wird. 
Der Spieler muss diese Reihenfolge durch Tastendrücke korrekt wiederholen. 
Mit jeder Runde wird die Sequenz länger und dadurch schwieriger.

Geogaching ist eine Globale Schatzsuche bei dem man versuchen muss mithilfe von Beschreibungen und Koordinaten einen sogenannten Geocache suchen.
Diser Geocache ist meist eine Art Dose welche ein Logbuch enthält.

*/

//Bibliotheken Einbinden
#include <Wire.h> //I²C Bus Bibliothek
#include <SPI.h> //SPI Bus Bibliothek
#include <U8g2lib.h> //Bibliothek des Displays
#include <SD.h> //Bibliothek für den SD Karten Leser

//Initialisierungen
U8G2_SSD1327_MIDAS_128X128_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); // Display Festlegen

//Eingänge
const int ButtonsX[] = {A0, A1, A2}; //Pins der Buttonmatrix auf der X Achse
const int EncoderCLK = 6; //CLK Pin des Encoders
const int EncoderDT = 7; //DT Pin des Encoders
const int EncoderSW = 8; //SW Pin des Encoders
const int SDInserted = 9; //SD Karte eingelegt

//Ausgänge
const int ButtonsY[] = {2, 3, 4}; //Pins der Buttonmatrix auf der Y Achse
const int Buzzer = 5; //Passiver Buzzer der Passend einen Ton macht
const int SDSelect = 10; //SD Karte auswählen

//Textvariablen
String Username; //Endgültiger Benutzernamen
char InputText[21] = ""; //Aktuell ausgewähltes Zeichen bei der Benutzereingabe
char DisplayText[21] = ""; //Bisher eingetragene Zeichen bei der Benutzereingabe
const char* Characters[] = //Erlaubte Zeichen für die Benutzereingabe
{
  "a","b","c","d","e","f","g","h","i","j","k","l","m",
  "n","o","p","q","r","s","t","u","v","w","x","y","z",
  "0","1","2","3","4","5","6","7","8","9","-","_","'", 
  "<"
};

//Array Grössen
const int MatrixSize = sizeof(ButtonsX) / sizeof(ButtonsX[0]); //Anzahl der Button in eine Richtung -> Funktioniert nur Richig bei gleichmässiger Verteilung auf X und Y
const int NumberOfButtons = sizeof(ButtonsX) / sizeof(ButtonsX[0]) * sizeof(ButtonsY) / sizeof(ButtonsY[0]); // Anzahl der Buttons
const int CharactersSize = sizeof(Characters) / sizeof(Characters[0]) - 1; //Grösse des Array für die Zeichen bei der Benutzereingabe

//Allgemeine Parameter
const int NumberOfRounds = 1; //Anzahl der Runden
const int Time = 300; //Allgemeine Verzögerung

//Paramter für die Melodien des Buzzers
const int Tones[] = {262, 294, 330, 370, 415, 466, 494, 554, 622}; //Tonhöhen bei bestimmten LED's bzw Buttons
const int RightMelody[] = {587, 698, 880}; //Tonhöhen bei der Melodie die Mitteilt das eine Runde Richtig war
const int RightMelodyDuration[] = {200, 50}; //Verzögerung bei der Melodie die Mitteilt das eine Runde Richtig war
const int LoseMelody[] = {196, 130, 98}; //Tonhöhen bei der Melodie die Mitteilt das etwas falsches gedrückt wurde
const int LoseMelodyDuration[] = {300, 100}; //Verzögerungen bei der Melodie die Mitteilt das etwas falsches gedrückt wurde
const int WinMelody[]   = {523, 659, 784, 523, 523, 659, 784, 1047}; //Tonhöhen bei der Melodie die Mitteilt das das Spiel eroflgreich abgeschlossen wurde
const int WinMelodyDuration[] = {175, 175, 175, 350, 175, 175, 175, 525}; //Verzögerungen bei der Melodie die Mitteilt das das Spiel eroflgreich abgeschlossen wurde

//Parameter für das Aufzeichnen des Simon Says Feld
const int GridSize = 40; //Grösse der Felder
const int GridX[] = {0, 43, 86, 0, 43, 86, 0, 43, 86}; //Position der Felder auf der X Achse
const int GridY[] = {0, 0, 0, 43, 43, 43, 86, 86, 86}; //Position der Felder auf der Y Achse

//Variablen
int Step; //Variable für Schrittkette
int PressedButton;
int LastPressedButton; //Index des Letzten Gedrückten Buttons
int InputCount; //Anzahl der Gedrücken Buttons Innerhalb einer Runde
int Round; //Aktuelle Runde
int SavedSequence[NumberOfRounds]; //Array um die Reihenfolge der LED's zu Speichern
int CurrentCLKState; //Aktueller Status des CLK Pins am Encoder
int LastCLKState; //Letzter Status des CLK Pins am Encoder
int LastSWState; //Letzer Status des SW Pins am Encoder
int CounterCharakters; //Anzahl bisher eingetragenen Zeichen (maximal 20)
int CursorPosition; //Cursor Position auf dem Disply -> Benutzername eingabe
int Attempts; //Anzahl Versuche des Spielers bis (wird nachdem es geschafft wurde zurückgesetzt)
unsigned long Lastmillis1; //Variable für die millis() funktion


//Setup wird nur beim Start einmal ausgeführt
void setup() 
{
  //Eingänge / Ausgänge definieren
  pinMode(EncoderCLK, INPUT);
  pinMode(EncoderDT, INPUT);
  pinMode(EncoderSW, INPUT_PULLUP);
  pinMode(Buzzer, OUTPUT);
  for (int i = 0; i < MatrixSize; i++) 
  {
    pinMode(ButtonsX[i], INPUT_PULLUP);
    pinMode(ButtonsY[i], OUTPUT);
    digitalWrite(ButtonsY[i], HIGH);
  }

  //Ausgänge Initialisieren
  noTone(Buzzer);

  //Merker Initialisieren
  Step = 0;
  Round = 0;
  PressedButton = 0;
  LastPressedButton = 0;
  InputCount = 0;
  CounterCharakters = 0;
  CursorPosition = 0;
  Attempts = 0;
  CurrentCLKState = 0;
  Lastmillis1 = 0;
  LastSWState = false;
  Username = "";
  LastCLKState = digitalRead(EncoderCLK);
  for (int i = 0; i < NumberOfRounds; i++) 
  {
    SavedSequence[i] = 0;
  }

  //Display Starten
  u8g2.begin();

  //Display Initialisieren
  u8g2.firstPage();
  do {} while (u8g2.nextPage());

  //SD Kartenleser Initialisieren
  if (!SD.begin(SDSelect)) 
  {
    u8g2.firstPage();
    do 
    {
      u8g2.setFont(u8g2_font_ncenB08_tr);
      u8g2.drawStr(0, 20, "SD-Karte Fehler!");
    } while (u8g2.nextPage());
    delay(2000);
  }

  //Zufallsgenerator Initialisieren
  randomSeed(analogRead(A7));
}


//Loop wird immer wieder wiederholt
void loop() {
  switch (Step) {
    case 0:
      noTone(Buzzer);
      Round = 0;
      PressedButton = 0;
      LastPressedButton = 0;
      InputCount = 0;
      CounterCharakters = 0;
      CursorPosition = 0;
      Attempts++;
      CurrentCLKState = 0;
      Lastmillis1 = 0;
      LastSWState = false;
      Username = "";
      LastCLKState = digitalRead(EncoderCLK);
      for (int i = 0; i < NumberOfRounds; i++) 
      {
        SavedSequence[i] = 0;
      }

      u8g2.firstPage();
      do {} while (u8g2.nextPage());

      if (digitalRead(EncoderSW) == LOW) 
      {
        u8g2.firstPage();
        do 
        {
          for (int b = 0; b < NumberOfButtons; b++) 
          {
            u8g2.drawFrame(GridX[b], GridY[b], GridSize, GridSize);
          }
        } while (u8g2.nextPage());

        delay(Time * 2);
        Step = 1;
      }
      break;

    case 1:
      InputCount = 0;
      for (int i = 0; i < Round; i++) 
      {
        u8g2.firstPage();
        do 
        {
          for (int b = 0; b < NumberOfButtons; b++) 
          {
            if (b == SavedSequence[i] - 1) {
              u8g2.drawBox(GridX[b], GridY[b], GridSize, GridSize);
            } else {
              u8g2.drawFrame(GridX[b], GridY[b], GridSize, GridSize);
            }
          }
        } while (u8g2.nextPage());

        tone(Buzzer, Tones[SavedSequence[i] - 1]);
        delay(Time);

        u8g2.firstPage();
        do 
        {
          for (int b = 0; b < NumberOfButtons; b++) 
          {
            u8g2.drawFrame(GridX[b], GridY[b], GridSize, GridSize);
          }
        } while (u8g2.nextPage());

        noTone(Buzzer);
        delay(Time);
      }

      Step = 2;
      break;

    case 2:
      SavedSequence[Round] = random(1, NumberOfButtons + 1);

      u8g2.firstPage();
      do 
      {
        for (int b = 0; b < NumberOfButtons; b++) {
          if (b == SavedSequence[Round] - 1) {
            u8g2.drawBox(GridX[b], GridY[b], GridSize, GridSize);
          } else {
            u8g2.drawFrame(GridX[b], GridY[b], GridSize, GridSize);
          }
        }
      } while (u8g2.nextPage());

      tone(Buzzer, Tones[SavedSequence[Round] - 1]);
      delay(Time);

      u8g2.firstPage();
      do 
      {
        for (int b = 0; b < NumberOfButtons; b++) 
        {
          u8g2.drawFrame(GridX[b], GridY[b], GridSize, GridSize);
        }
      } while (u8g2.nextPage());

      noTone(Buzzer);
      Step = 3;
      break;

    case 3:
      for (int y = 0; y < MatrixSize; y++)
      {
        digitalWrite(ButtonsY[y], LOW);
        for (int x = 0; x < MatrixSize; x++)
        {
          if (digitalRead(ButtonsX[x]) == LOW)
          {
            LastPressedButton = y * MatrixSize + x + 1;
            InputCount++;

            u8g2.firstPage();
            do 
            {
              for (int b = 0; b < NumberOfButtons; b++) 
              {
                if (b == LastPressedButton - 1) {
                  u8g2.drawBox(GridX[b], GridY[b], GridSize, GridSize);
                } else {
                  u8g2.drawFrame(GridX[b], GridY[b], GridSize, GridSize);
                }
              }
            } while (u8g2.nextPage());

            tone(Buzzer, Tones[LastPressedButton - 1]);
            delay(Time);

            u8g2.firstPage();
            do 
            {
              for (int b = 0; b < NumberOfButtons; b++) 
              {
                u8g2.drawFrame(GridX[b], GridY[b], GridSize, GridSize);
              }
            } while (u8g2.nextPage());

            noTone(Buzzer);
            while (digitalRead(ButtonsX[x]) == LOW) 
            {
              delay(10);
            }
            delay(Time);
            Step = 4;
          }
        }
        digitalWrite(ButtonsY[y], HIGH);
      }
      break;

    case 4:
      if (LastPressedButton == SavedSequence[InputCount - 1])
      {
        if (InputCount >= Round + 1)
        {
          Round++;
          if (Round >= NumberOfRounds)
          {
            for (int i = 0; i < 8; i++) 
            {
              tone(Buzzer, WinMelody[i]);
              delay(WinMelodyDuration[i]);
              noTone(Buzzer);
              delay(50);  
            }
            DrawUsernameDisplay ();
            Step = 5;
          }
          else
          {
            for (int i = 0; i < 3; i++) 
            {
              tone(Buzzer, RightMelody[i]);
              delay(RightMelodyDuration[1]);
              noTone(Buzzer);
              delay(RightMelodyDuration[2]);
            }
            Step = 1;
          }
        }
        else
        {
          Step = 3;
        }
      }
      else 
      {
        for (int i = 0; i < 3; i++) 
        {
          tone(Buzzer, LoseMelody[i]);
          delay(LoseMelodyDuration[1]);
          noTone(Buzzer);
          delay(LoseMelodyDuration[2]);
        }
        Step = 0;
      }
      break;

    case 5:

      CurrentCLKState = digitalRead(EncoderCLK);

      if (LastCLKState == LOW && CurrentCLKState == HIGH) 
      {
        if (digitalRead(EncoderDT) == LOW) 
        {
          CounterCharakters++;
          if (CounterCharakters > CharactersSize)
          {
            CounterCharakters = 0;
          }
        } 
        
        else 
        {
          CounterCharakters--;
          if (CounterCharakters < 0)
          {
            CounterCharakters = CharactersSize;
          }
        }

        DrawUsernameDisplay ();
      }

      LastCLKState = CurrentCLKState;

      if (digitalRead(EncoderSW) == LOW && !LastSWState) 
      {
        LastSWState = true;
        Lastmillis1 = millis();
      }

      if (digitalRead(EncoderSW) == HIGH && LastSWState) 
      {
        LastSWState = false;

        if (millis() - Lastmillis1 < 2000) 
        {
          if (strcmp(Characters[CounterCharakters], "<") == 0) 
          {
            if (CursorPosition > 0) 
            {
              CursorPosition--;
              InputText[CursorPosition] = '\0';
            }
          } 
          
          else 
          {
            if (CursorPosition < 20) 
            {
              InputText[CursorPosition] = *Characters[CounterCharakters];
              CursorPosition++;
              InputText[CursorPosition] = '\0';
            }
          }
        } 
        
        else 
        {
          Step = 6;
        }

        DrawUsernameDisplay ();
      }

      break;

    case 6:
      Username = String(InputText);
      Step = 0;
      break;

    default:
      Step = 0;
      break;
  }
}

//Funktion um das Display zu Beschreiben bei der Benutzereingabe
void DrawUsernameDisplay ()
{
  u8g2.firstPage();

  do 
  {
    u8g2.setFont(u8g2_font_ncenB08_tr);
    u8g2.drawStr(5, 20, "Benutzername:");
    strncpy(DisplayText, InputText, CursorPosition);
    DisplayText[CursorPosition] = *Characters[CounterCharakters];
    DisplayText[CursorPosition + 1] = '\0';
    u8g2.drawStr(5, 50, DisplayText);
    u8g2.drawStr(5, 53, "__________________");
  } 
  
  while (u8g2.nextPage());
}

Ich habe nund folgendes Display gekauft: https://www.waveshare.com/wiki/1.5inch_OLED_Module

Der grund wiso ich nicht mehr das SH1107 verwende: das SH1107 habe ich nur in der Visualisierung verwendet. Ich habe nun die Ensprechende Hardware gekauft und an dieses kam ich am einfachsten bzw. habe ich als erstes gefunden.

Bei diesem muss man ja wenn man von Standard SPI auf I2C Wechseln will umlöten. Man hat ja BS1 - BS3. BS1 und BS2 muss man bei beiden den 0 OHM Wiederstand auslöten und die andern beiden pins stattdessen verbinden. Den BS3 habe ich auch mit 1 verbunden da 0X3D die Standartadresse ist. Laut Datenblatt und auf dem Display selbst benötigt man nur VCC, GND, DIN und CLK für I2C (DIN = SDA, CLK = SCL). Genau so habe ich es angeschlossen: VCC = 5V, GND = GND, DIN = A4, CLK = A5. Unten 2 Bilder von den Verbindungen.


wenn man von Standard SPI auf I2C Wechseln will

Warum sollte man die langsame Lösung wollen, wenn man sowieso schon SPI nutzt?

1 Like

Für ein OLED Mini Display reicht I²C vollkommen sogar in der langsamster Variante.