Arduino Nano Projekt: LED-Array und Tastersteuerung für magisches Quadrat funktionieren nicht wie erwartet

Hallo zusammen,

Ich arbeite gerade an einem Projekt mit einem Arduino Nano, bei dem ich ein magisches Quadrat mit 9 Zahlen in einem 3x3-Array programmieren möchte. Dabei nutze ich 9 LEDs, 4 Taster (für Navigation, Reset und Speichern), und eine RGB-LED für eine Erfolgsmeldung.

Problem:

• Zu Beginn sollen alle LEDs aus sein, und nur eine LED soll blinken, um die aktuelle Auswahl anzuzeigen. Diese LED kann mit zwei Tastern nach rechts oder unten verschoben werden.

• Wenn eine Zahl an die Position der blinkenden LED gespeichert wird, soll diese dauerhaft leuchten und nicht mehr verändert werden können. Danach springt die Auswahl automatisch zur nächsten freien LED, die wieder blinkt.

• Die Zahlen müssen so gesetzt werden, dass alle Zeilen, Spalten und Diagonalen dieselbe Summe ergeben.

Aktuelles Problem: Beim Start blinken nur zwei LEDs kurz, danach passiert nichts mehr. Die Navigation funktioniert nicht richtig und die LED wechselt nicht wie gewünscht zur nächsten freien Position.

Hardware:

• 1x Arduino Nano

• 9 weiße LEDs (Pins 2-10)

• Taster für Bewegung nach rechts (Pin D12), Bewegung nach unten (Pin D11), Speichern (Pin D13), und Reset (Pin A0)

• RGB-LED für Erfolgsmeldung (Pins A1, A2, A3)

Hier ist der relevante Teil meines Codes. Ich habe versucht, den Blink- und Speichermechanismus zu implementieren, aber irgendwas scheint nicht zu stimmen.

// LED-Pins
int ledPins[3][3] = {
  {2, 3, 4},
  {5, 6, 7},
  {8, 9, 10}
};

// Taster-Pins
const int tasterUnten = 11;
const int tasterRechts = 12;
const int tasterSpeichern = 13;
const int tasterReset = A0;

// RGB-LED-Pins
const int pinRot = A1;
const int pinGruen = A2;
const int pinBlau = A3;

// 3x3 Array für das magische Quadrat
int quadrat[3][3] = {0};

// Zahlen für das magische Quadrat
int zahlen[9] = {5, 47, 17, 29, 71, 89, 59, 113, 101};
int aktuelleZahl = 0;

// Startposition
int posX = 0, posY = 0;

void setup() {
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      pinMode(ledPins[i][j], OUTPUT);
      digitalWrite(ledPins[i][j], LOW);
    }
  }
  
  pinMode(tasterUnten, INPUT_PULLUP);
  pinMode(tasterRechts, INPUT_PULLUP);
  pinMode(tasterSpeichern, INPUT_PULLUP);
  pinMode(tasterReset, INPUT_PULLUP);
  
  pinMode(pinRot, OUTPUT);
  pinMode(pinGruen, OUTPUT);
  pinMode(pinBlau, OUTPUT);

  digitalWrite(ledPins[posX][posY], HIGH);
}

void loop() {
  if (digitalRead(tasterUnten) == LOW) {
    bewegeUnten();
    delay(200);
  }
  if (digitalRead(tasterRechts) == LOW) {
    bewegeRechts();
    delay(200);
  }
  if (digitalRead(tasterSpeichern) == LOW) {
    speichereZahl();
    delay(200);
  }
  if (digitalRead(tasterReset) == LOW) {
    resetSpiel();
    delay(200);
  }
}

void bewegeUnten() {
  digitalWrite(ledPins[posX][posY], LOW);
  posX = (posX + 1) % 3;
  digitalWrite(ledPins[posX][posY], HIGH);
}

void bewegeRechts() {
  digitalWrite(ledPins[posX][posY], LOW);
  posY = (posY + 1) % 3;
  digitalWrite(ledPins[posX][posY], HIGH);
}

void speichereZahl() {
  quadrat[posX][posY] = zahlen[aktuelleZahl];
  aktuelleZahl++;
  digitalWrite(ledPins[posX][posY], HIGH);
}

void resetSpiel() {
  aktuelleZahl = 0;
  posX = 0;
  posY = 0;
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      quadrat[i][j] = 0;
      digitalWrite(ledPins[i][j], LOW);
    }
  }
  digitalWrite(ledPins[posX][posY], HIGH);
}

Erwartetes Verhalten:

• Nur eine LED sollte blinken, und die Auswahl soll nur durch Taster bewegt werden.

• Gespeicherte LEDs sollten dauerhaft leuchten.

• Nach dem Speichern einer Zahl soll automatisch die nächste freie LED blinken.

Frage:

Was könnte das Problem mit meinem Code sein, dass nach dem Start nur zwei LEDs kurz blinken und nichts mehr passiert? Wie kann ich den Code anpassen, damit die LEDs korrekt blinken und die Tastersteuerung wie gewünscht funktioniert?

Vielen Dank für eure Hilfe!

Bitte stellen Sie Ihre Frage auf Englisch im englischen Bereich des Forums.

Thema in den deutschen Bereich verschoben.

Bau' mal den Spagetticode in vernünfigen Code um.

  1. ich habe nicht verstanden wie Du Zahlen mit einer weißen LED darstellen willst.
  2. benutze WS2812B LED (Neopixel) da kannst Du jede LED einzeln die Farbe wählen und nur mit einem Pin ansteuern.
  3. benutze ein 3x3 Array um die Zahl bzw aus und blinkend anzuzeigen. 1 bis 9 für die Zahl, 0 aus und zB 10 für Blinken.
    Programmiere nicht blockierend.
    Informiere Dich wie ein endlicher Automat (infine state machine) und wie man mit millis() intervalle programmiert ohne den Sketch zu blockieren. Alle delay() mussen weg.

Moin @thatsme_dan ,

habe mir mal erlaubt, Deinen Sketch bei Wokwi einzustellen und die Hardware (mit einem UNO, spielt hier aber keine Rolle) nachzubilden.

Siehe https://wokwi.com/projects/412016357755096065

Zu Deinen Fragen:

Was könnte das Problem mit meinem Code sein, dass nach dem Start nur zwei LEDs kurz blinken und nichts mehr passiert?

Das sehe ich im Online-Simulator nicht, auch im Sketch finde ich keinen Code, der Leds blinken lässt. Stattdessen leuchtet zunächst die Led mit den Koordinaten (0,0).
Mit den Tasten Rechts bzw. Unten lassen sich alle Positionen anfahren.

Wie kann ich den Code anpassen, damit die LEDs korrekt blinken und die Tastersteuerung wie gewünscht funktioniert?

Eine Möglichkeit besteht darin, das Array quadrat[][] zu verwenden, um die Koordinaten der nächsten, nicht gesetzten Led zu finden und z.B. das Setzen nicht mehr zuzulassen, wo bereits ein Wert zugewiesen wurde.

Hier mal ein (noch nicht optimaler) Sketch, der aber einen Teil dessen tun dürfte, was Du beschrieben hast:
https://wokwi.com/projects/412017639012413441

Sketch
/*
  Forum: https://forum.arduino.cc/t/arduino-nano-projekt-led-array-und-tastersteuerung-fur-magisches-quadrat-funktionieren-nicht-wie-erwartet/1312361
  Wokwi: https://wokwi.com/projects/412017639012413441

  Original:
      Wokwi: https://wokwi.com/projects/412016357755096065

  Teilweise modifizierter Sketch, jedoch immer noch viel Raum für Verbesserungen!

  ec2021

*/

// LED-Pins
const byte ledPins[3][3] = {
  {2, 3, 4},
  {5, 6, 7},
  {8, 9, 10}
};

// Taster-Pins
const byte tasterUntenPin = 11;
const byte tasterRechtsPin = 12;
const byte tasterSpeichernPin = 13;
const byte tasterResetPin = A0;

// RGB-LED-Pins
const byte pinRot = A1;
const byte pinGruen = A2;
const byte pinBlau = A3;

// 3x3 Array für das magische Quadrat
byte quadrat[3][3];

// Zahlen für das magische Quadrat
byte zahlen[9] = {5, 47, 17, 29, 71, 89, 59, 113, 101};
byte aktuelleZahl = 0;

// Startposition
byte posX = 0, posY = 0;

const unsigned long SLOW = 300;
const unsigned long QUICK = 150;

unsigned long lastBlink = 0;
byte blinkState = HIGH;

class Taster {
  private:
    byte pin;
    byte state;
    byte lastState = HIGH;
    unsigned long lastChange = 0;
  public:
    Taster(byte aPin) {
      pin = aPin;
      pinMode(pin, INPUT_PULLUP);
    }
    boolean pressed() {
      byte actState = digitalRead(pin);
      if (actState != lastState) {
        lastChange = millis();
        lastState = actState;
      }
      if (state != actState && millis() - lastChange > 30) {
        state = actState;
        return (state == LOW);
      }
      return false;
    }
};

Taster tasterUnten(tasterUntenPin);
Taster tasterRechts(tasterRechtsPin);
Taster tasterReset(tasterResetPin);
Taster tasterSpeichern(tasterSpeichernPin);

void setup() {
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      pinMode(ledPins[i][j], OUTPUT);
      digitalWrite(ledPins[i][j], LOW);
    }
  }
  pinMode(pinRot, OUTPUT);
  pinMode(pinGruen, OUTPUT);
  pinMode(pinBlau, OUTPUT);
  resetSpiel();
}

void loop() {
  if (tasterUnten.pressed()) {
    bewegeUnten();
  }
  if (tasterRechts.pressed()) {
    bewegeRechts();
  }
  if (tasterSpeichern.pressed()) {
    speichereZahl();
  }
  if (tasterReset.pressed()) {
    resetSpiel();
  }
  blinken();
}

void blinken() {
  if (aktuelleZahl >= 9) {
    return;
  }
  unsigned long interval = (quadrat[posX][posY] == 0) ? SLOW : QUICK;
  if (millis() - lastBlink > interval) {
    digitalWrite(ledPins[posX][posY], blinkState);
    lastBlink = millis();
    blinkState = !blinkState;
  }
}

void bewegeUnten() {
  digitalWrite(ledPins[posX][posY], (quadrat[posX][posY] == 0) ? LOW : HIGH);
  posX = (posX + 1) % 3;
  lastBlink = 0;
}

void bewegeRechts() {
  digitalWrite(ledPins[posX][posY], (quadrat[posX][posY] == 0) ? LOW : HIGH);
  posY = (posY + 1) % 3;
  lastBlink = 0;
}

void speichereZahl() {
  if (quadrat[posX][posY] == 0) {
    quadrat[posX][posY] = zahlen[aktuelleZahl];
    aktuelleZahl++;
    digitalWrite(ledPins[posX][posY], HIGH);
  }
  sucheNaechstePosition();
}



void sucheNaechstePosition() {
  byte startX = posX;
  byte startY = posY;
  byte count = 0;
  while (quadrat[startX][startY] != 0 && count < 9) {
    count++;
    startY++;
    if (startY > 2 ) {
      startY = 0;
      startX = startX + 1;
      if (startX > 2) {
        startX = 0;
      }
    }
  }
  if (count < 9) {
    digitalWrite(ledPins[posX][posY], (quadrat[posX][posY] == 0) ? LOW : HIGH);
    posX = startX;
    posY = startY;
    digitalWrite(ledPins[posX][posY], HIGH);
  } else {
    signalRot();
  }
}

void resetSpiel() {
  aktuelleZahl = 0;
  posX = 0;
  posY = 0;
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      quadrat[i][j] = 0;
      digitalWrite(ledPins[i][j], LOW);
    }
  }
  signalGruen();
}

void signalRot() {
  setRGB(HIGH, LOW, LOW);
}

void signalGruen() {
  setRGB(LOW, HIGH, LOW);
}


void setRGB(byte r, byte g, byte b) {
  digitalWrite(pinRot, r);
  digitalWrite(pinGruen, g);
  digitalWrite(pinBlau, b);
}

Die angewählte Led blinkt langsam, wenn hier noch ein Wert gespeichert werden kann, sonst schnell. Wenn alle Felder belegt sind, leuchtet die RGB-Led rot, sonst grün.

Tasten:

  • schwarz = runter
  • blau = rechts
  • grün = speichern
  • rot = reset

Für die Taster gibt es eine kleine Klasse zum Debouncen und um nur bei Wechsel von HIGH auf LOW einmal zu reagieren.

Wenn eine Led "verlassen" wird, so wird sie ausgeschaltet, wenn der zugehörige Wert in quadrat [..][..] 0 ist, sonst wird sie eingeschaltet:

digitalWrite(ledPins[posX][posY], (quadrat[posX][posY] == 0) ? LOW : HIGH);

Ich habe mich weitgehend an Deine Programmstruktur gehalten, würde es selbst etwas anders angehen. Insbesondere sind die "magischen Zahlen" für Arrays /Grenzen (0..3) noch drin, Diese Werte zu ermitteln, würde man mit im Code ansonsten dem Compiler überlassen, damit dies bei Änderungen (z.B. Anpassung an eine 4x4 Matrix) automatisch erfolgt. Das reduziert Aufwand beim Weiterentwickeln und der Fehlersuche.

Viel Erfolg!
ec2021

1 Like

Ich habe mich auch mal mit dieser Aufgabenstellung befasst und vermeintlich nahezu gänzlich die Vorgaben des TO umgesetzt. Sofern ich diese denn richtig verstanden habe. Allerdings habe ich dabei festgestellt, dass mit den vorgegebenen Zahlenwerten keine Lösung möglich ist. Darum habe ich andere verwendet.....

Der Code
#include <Button_SL.hpp>
#include <Streaming.h>

Print &cout {Serial};
using namespace Btn;

///
/// Global Constants
///
constexpr uint8_t RGB_LED_PINS[] {A1, A2, A3};
constexpr uint8_t MATRIX_COLS {3};
constexpr uint8_t MATRIX_ROWS {MATRIX_COLS};
constexpr uint32_t BLINK_INTERVAL_MS {400};

//////////////////////////////////////////////////////////////////////////////
/// Helperclass for timer operations
///
//////////////////////////////////////////////////////////////////////////////
class Timer {
public:
  void start() { timeStamp = millis(); }
  bool operator()(const uint32_t duration) const { return (millis() - timeStamp >= duration) ? true : false; }

private:
  uint32_t timeStamp {0};
};

///
/// Own Datatypes
///
enum class Status : uint8_t { none, col, row, save, reset, result, waitForReset };
enum ColorNum { off, red, green, blue, cyan, yellow, magenta, white };

struct PlayingField {
  const uint8_t pin;
  bool saved;
  uint8_t value;
};

///
/// Used Functions
///

//
// Button query
//
template <size_t N> Status checkButtons(ButtonSL (&btns)[N]) {
  for (uint8_t i = 0; i < N; ++i) {
    if (btns[i].tick() != ButtonState::notPressed) { return static_cast<Status>(i + 1); }
  }
  return Status::none;
}

//
// toggle LEDs
//
template <size_t N> void toggleLed(PlayingField (&data)[N], uint16_t idx) {
  if (!data[idx].saved && idx < N) { digitalWrite(data[idx].pin, !digitalRead(data[idx].pin)); }
}

//
// switch  LED off
//
template <size_t N> void switchLedOff(PlayingField (&data)[N], uint16_t idx) {
  if (!data[idx].saved && idx < N) { digitalWrite(data[idx].pin, LOW); }
}

//
// switch  RGB-LED (off / color)
//
template <size_t N> void setRGBLed(const uint8_t (&pin)[N], uint8_t colorNum) {
  uint32_t colorBits {0b00000000111101110011001010100000};
  uint8_t colors = (colorBits >> (colorNum * 3)) & 0b111;
  // cout << _WIDTHZ(_BIN(colors), 32) << endl;
  // cout << _WIDTHZ(_BIN(mask), 32) << endl;
  for (size_t i {0}; i < N; ++i) { digitalWrite(pin[i], colors << i & 0b100); }
}

//
// Movement on the game matrix. Calculate the right array index
//
template <size_t N> bool doMove(PlayingField (&data)[N], uint16_t &idx, uint8_t increment) {
  bool allFieldsSet {false};
  auto start = idx;
  do {
    idx += increment;
    if (increment > 1) {
      idx = (idx > (N - 1)) ? (idx - (N - 1)) % increment : idx;
    } else {
      idx = (idx > (N - 1)) ? 0 : idx;
    }
    if (idx == start) { allFieldsSet = true; }   // Abort condition
    if (!data[idx].saved) { break; }             // Exit loop if a free field is found
  } while (!allFieldsSet);
  return allFieldsSet;
}

//
// Check the result when the input has been completed
//
template <size_t N> bool checkResult(PlayingField (&result)[N]) {
  int16_t rowSum[MATRIX_ROWS] {0, 0, 0};
  int16_t colSum[MATRIX_COLS] {0, 0, 0};
  int16_t diagSum1 {0};
  int16_t diagSum2 {0};
  for (size_t row {0}; row < MATRIX_ROWS; ++row) {
    for (size_t col {0}; col < MATRIX_COLS; ++col) {
      uint8_t idx = row * MATRIX_ROWS + col;
      cout << result[idx].value << " ";
      rowSum[row] += result[idx].value;
      colSum[col] += result[idx].value;

      if (row == col) {
        diagSum1 += result[idx].value;   // Main diagonal
      }
      if (row + col == MATRIX_COLS - 1) {
        diagSum2 += result[idx].value;   // Secondary diagonal
      }
    }
  }
  cout << endl;
  // Ausgabe der Summen
  // cout << "Reihensummen: ";
  // for (size_t i {0}; i < MATRIX_ROWS; ++i) { cout << rowSum[i] << " "; }
  // cout << endl;
  // cout << "Spaltensummen: ";
  // for (size_t i {0}; i < MATRIX_COLS; ++i) { cout << colSum[i] << " "; }
  // cout << endl;
  // cout << "Hauptdiagonale: " << diagSum1 << endl;
  // cout << "Nebendiagonale: " << diagSum2 << endl;

  bool isRowEqual {true};
  bool isColEqual {true};

  int16_t compare = rowSum[0];
  for (size_t i = 1; i < MATRIX_ROWS; ++i) {
    if (rowSum[i] != compare) {
      isRowEqual = false;
      break;
    }
  }

  for (size_t i = 0; i < MATRIX_COLS; ++i) {
    if (colSum[i] != compare) {
      isRowEqual = false;
      break;
    }
  }
  return isRowEqual & isColEqual & (diagSum1 == compare) & (diagSum2 == compare);
}

//
// Clear Data
//
template <size_t N> void resetData(PlayingField (&data)[N]) {
  for (auto &d : data) {
    digitalWrite(d.pin, LOW);
    d.saved = false;
    d.value = 0;
  }
}

///
/// Global variables / objects
///
PlayingField pfData[] {
    {2,  false, 0},
    {3,  false, 0},
    {4,  false, 0},
    {5,  false, 0},
    {6,  false, 0},
    {7,  false, 0},
    {8,  false, 0},
    {9,  false, 0},
    {10, false, 0}
};

ButtonSL bArray[] {{11}, {12}, {13}, {A0}};
Timer waitBlink;

// | 8  | 1  | 6  |
// | 3  | 5  | 7  |
// | 4  | 9  | 2  |

///
/// Main Program
///
void setup() {
  Serial.begin(115200);
  for (auto &p : pfData) { pinMode(p.pin, OUTPUT); }
  for (auto &p : RGB_LED_PINS) { pinMode(p, OUTPUT); }
  for (auto &b : bArray) {
    b.begin();
    b.setDebounceTime_ms(40);
  }
  setRGBLed(RGB_LED_PINS, blue);
}

void fsm() {
  static Status status {Status::none};
  static uint16_t index {};        // index playfield array (leds)
  static uint16_t prevIndex {};    // previos index playfield array ( for moving  - switch previous led off )
  static uint8_t saveCounter {};   // Storage counter -> index for data array (result)
  static bool isSaving {false};    // needed to prevent saving errors

  switch (status) {
    case Status::none: status = checkButtons(bArray); break;
    case Status::col:
    case Status::row:
      switchLedOff(pfData, prevIndex);
      doMove(pfData, index, (status == Status::col) ? 1 : MATRIX_COLS);
      waitBlink.start();
      status = Status::none;
      break;
    case Status::save:
      // Flag isSaving: Prevent the save function from being run again before
      // an ongoing save has been completed.
      if (isSaving) { break; }   // Exit section if the save process is already running
      isSaving = true;
      pfData[index].saved = true;
      pfData[index].value = ++saveCounter;
      cout << "Saved Nr. " << saveCounter << " at Index: " << index << endl;
      digitalWrite(pfData[index].pin, HIGH);
      if (doMove(pfData, index, 1) == true) {   // true if all fields are set
        status = Status::result;
      } else {
        waitBlink.start();
        isSaving = false;
        status = Status::none;
      }
      break;
    case Status::reset:
      resetData(pfData);
      setRGBLed(RGB_LED_PINS, blue);
      index = saveCounter = 0;
      isSaving = false;
      cout << endl << endl;
      status = Status::none;
      break;
    case Status::result:
      checkResult(pfData) ? setRGBLed(RGB_LED_PINS, green) : setRGBLed(RGB_LED_PINS, red);
      status = Status::waitForReset;
    [[falltrough]]
    case Status::waitForReset:
      if (checkButtons(bArray) == Status::reset) { status = Status::reset; }
      break;
    default: break;
  }
  if (waitBlink(BLINK_INTERVAL_MS)) {
    prevIndex = index;
    toggleLed(pfData, index);
    waitBlink.start();
  }
}

void loop() { fsm(); }

Die Simulation:

Die Lösungsreihenfolge ist
| 8 | 1 | 6 |
| 3 | 5 | 7 |
| 4 | 9 | 2 |

Die "magische Zahl" 15.

Edit: Programm nach den Erkenntnissen aus Posting #10 angepasst.

1 Like

Hallo thatsme_dan

Zeige mal die Bedienungsanleitung für dieses Spiel.

Was sind die Gewinn- bzw. Verloren-Bedingungen ?

Eigentlich hat er das ja geschrieben:

Es gibt da aber tatsächlich noch ein paar Fragen, welche mir noch so konkret in den Sinn kommen:

Sind die Zahlen dem Spieler bekannt oder drückt so lange herum, bis er zufällig die richtige Kombination findet?

Wenn die Zahlen bekannt sein sollen, wie wird die jew. Zahl, welche einer bestimmten Position in der Matrix zugewiesen ist, dem Spieler bekannt gemacht?

Soll die Zahlenreihe auch mal geändert werden (Position/ Werte)?

Hatte ich schon mal vor 3 Tagen gefragt.
Ist der To mal wieder einer der 1 (in Worten EINEN) Post schreibt und dann nie wieder?

Grüße Uwe

Es sieht ganz danach aus. Ich denke aber ich kann mir meine Fragen selber beantworten, weil ich glaube das System jetzt kapiert zu haben.

Ich habe mich von dem Code des TO etwas in eine falsche Richtung lenken lassen, nicht genug nachgedacht und die falschen Schlüsse gezogen.

Die (möglichen) Zahlen ergeben sich aus der Felderzahl der Matrix.

Bei einem magischen Quadrat von 3x3 Feldern ergibt sich die "Magische Zahl" aus der Formel 1/2 * 3 * (3²+1) = 15. Die Zahl ist fest. Daraus wiederum ergeben sich die zur Lösung möglichen Ziffern 1-9.

Ich bin davon ausgegangen, dass jedem Feld ein bestimmter Wert zugewiesen ist und dieser umsortiert werden muss. Ich gehe jetzt aber davon aus dass das falsch ist, weil das "Spiel" so eigentlich nicht spielbar ist.

Es ist wohl wie folgt richtig:

Die einzigen möglichen Zahlen die gesetzt werden können sind, wie schon erwähnt, die Ziffern 1-9 (oder 0-8). Also läuft man nach dem Programmstart die Position in der Matrix an, an welcher die Ziffer 1 zu setzen ist und drückt auf speichern. Die Zahl 1 wird an der zum Spielfeld passenden Position des Ergebnisarrays gespeichert. Dann läuft man die zweite Position an und speichert. Das wird solange wiederholt, bis alle 9 Felder angelaufen und gespeichert wurden.
Also, erstes Speichern entspricht der Zahl eins an Position X im Ergebnisarray, zweites der Zahl zwei usw. bis neun.

Hat man in der richtigen Reihenfolge den Speichern-Taster gedrückt, gilt die Aufgabe als gelöst.

Damit erübrigen sich alle meine Fragen.

1 Like

Hallo ec2021

Danke dir vielmals für die Zeit, welche du dir genommen hast. Ich musste feststellen, dass ich die falschen Zahlen mitgeteilt habe.

Ich habe den Code soeben nochmals zu den richtigen Zahlen geändert und mithilfe von ChatGPT eine Rückmeldung über die RGB eingebaut, falls das Rätsel korrekt gelöst wird.
Im Wokwi funktioniert das ganze ohne Probleme und lässt sich wie gewünscht ausführen.

Sobald ich den Code auf meine Hardware anschliesse funktioniert auch alles, ausser der Speichern Taster. Ich habe bereits durchgemessen und geschaut, ob dieser wirklich richtig verlötet ist, dass Signal sollte ankommen. Ebenfalls habe ich es bereits mit einem anderen Taster getestet, was leider auch nicht funktionierte. Zudem habe ich den Taster einmal auf Pin A4 gelegt und leider geht das Speichern dann auch nicht, zumindest blinkt die LED weiterhin, als ob nicht geschehen würde.

Hier wäre den Code, welchen ich jetzt dafür nutzte

// LED-Pins
const byte ledPins[3][3] = {
  {2, 3, 4},
  {5, 6, 7},
  {8, 9, 10}
};

// Taster-Pins
const byte tasterUntenPin = 11;
const byte tasterRechtsPin = 12;
const byte tasterSpeichernPin = 13;
const byte tasterResetPin = A0;

// RGB-LED-Pins
const byte pinRot = A1;
const byte pinGruen = A2;
const byte pinBlau = A3;

// 3x3 Array für das magische Quadrat
byte quadrat[3][3];

// Zahlen für das magische Quadrat
byte zahlen[9] = {8, 1, 6, 3, 5, 7, 4, 9, 2}; // Hier die korrekten Zahlen für das magische Quadrat
byte aktuelleZahl = 0;

// Startposition
byte posX = 0, posY = 0;

const unsigned long SLOW = 300;
const unsigned long QUICK = 150;

unsigned long lastBlink = 0;
byte blinkState = HIGH;

class Taster {
  private:
    byte pin;
    byte state;
    byte lastState = HIGH;
    unsigned long lastChange = 0;
  public:
    Taster(byte aPin) {
      pin = aPin;
      pinMode(pin, INPUT_PULLUP);
    }
    boolean pressed() {
      byte actState = digitalRead(pin);
      if (actState != lastState) {
        lastChange = millis();
        lastState = actState;
      }
      if (state != actState && millis() - lastChange > 30) {
        state = actState;
        return (state == LOW);
      }
      return false;
    }
};

Taster tasterUnten(tasterUntenPin);
Taster tasterRechts(tasterRechtsPin);
Taster tasterReset(tasterResetPin);
Taster tasterSpeichern(tasterSpeichernPin);

void setup() {
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      pinMode(ledPins[i][j], OUTPUT);
      digitalWrite(ledPins[i][j], LOW);
    }
  }
  pinMode(pinRot, OUTPUT);
  pinMode(pinGruen, OUTPUT);
  pinMode(pinBlau, OUTPUT);
  resetSpiel();
}

void loop() {
  if (tasterUnten.pressed()) {
    bewegeUnten();
  }
  if (tasterRechts.pressed()) {
    bewegeRechts();
  }
  if (tasterSpeichern.pressed()) {
    speichereZahl();
  }
  if (tasterReset.pressed()) {
    resetSpiel();
  }
  blinken();
}

void blinken() {
  if (aktuelleZahl >= 9) {
    return;
  }
  unsigned long interval = (quadrat[posX][posY] == 0) ? SLOW : QUICK;
  if (millis() - lastBlink > interval) {
    digitalWrite(ledPins[posX][posY], blinkState);
    lastBlink = millis();
    blinkState = !blinkState;
  }
}

void bewegeUnten() {
  digitalWrite(ledPins[posX][posY], (quadrat[posX][posY] == 0) ? LOW : HIGH);
  posX = (posX + 1) % 3;
  lastBlink = 0;
}

void bewegeRechts() {
  digitalWrite(ledPins[posX][posY], (quadrat[posX][posY] == 0) ? LOW : HIGH);
  posY = (posY + 1) % 3;
  lastBlink = 0;
}

void speichereZahl() {
  if (quadrat[posX][posY] == 0) {
    quadrat[posX][posY] = zahlen[aktuelleZahl];
    aktuelleZahl++;
    digitalWrite(ledPins[posX][posY], HIGH);
  }
  sucheNaechstePosition();
  
  // Überprüfen, ob das magische Quadrat korrekt ist
  if (aktuelleZahl == 9 && pruefeMagischesQuadrat()) {
    signalGruen(); // Führt die Blinksequenz aus, wenn korrekt
  }
}

void sucheNaechstePosition() {
  byte startX = posX;
  byte startY = posY;
  byte count = 0;
  while (quadrat[startX][startY] != 0 && count < 9) {
    count++;
    startY++;
    if (startY > 2) {
      startY = 0;
      startX = startX + 1;
      if (startX > 2) {
        startX = 0;
      }
    }
  }
  if (count < 9) {
    digitalWrite(ledPins[posX][posY], (quadrat[posX][posY] == 0) ? LOW : HIGH);
    posX = startX;
    posY = startY;
    digitalWrite(ledPins[posX][posY], HIGH);
  } else {
    signalRot();
  }
}

void resetSpiel() {
  aktuelleZahl = 0;
  posX = 0;
  posY = 0;
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      quadrat[i][j] = 0;
      digitalWrite(ledPins[i][j], LOW);
    }
  }
}

void signalRot() {
  setRGB(HIGH, LOW, LOW);
}

void signalGruen() {
  // Hier wird die Blinkreihenfolge ausgeführt
  for (int i = 0; i < 2; i++) {
    setRGB(LOW, HIGH, LOW); // Gelb
    delay(500);
    setRGB(LOW, LOW, LOW);
    delay(500);
  }
  for (int i = 0; i < 5; i++) {
    setRGB(HIGH, LOW, LOW); // Rot
    delay(500);
    setRGB(LOW, LOW, LOW);
    delay(500);
  }
  for (int i = 0; i < 4; i++) {
    setRGB(LOW, HIGH, LOW); // Grün
    delay(500);
    setRGB(LOW, LOW, LOW);
    delay(500);
  }
  for (int i = 0; i < 8; i++) {
    setRGB(LOW, LOW, HIGH); // Blau
    delay(500);
    setRGB(LOW, LOW, LOW);
    delay(500);
  }
}

void setRGB(byte r, byte g, byte b) {
  digitalWrite(pinRot, r);
  digitalWrite(pinGruen, g);
  digitalWrite(pinBlau, b);
}

// Funktion zur Überprüfung des magischen Quadrats
boolean pruefeMagischesQuadrat() {
  int summe = 0;

  // Berechne die Summe der ersten Reihe
  for (int j = 0; j < 3; j++) {
    summe += quadrat[0][j];
  }

  // Überprüfen der Reihen
  for (int i = 0; i < 3; i++) {
    int reiheSumme = 0;
    for (int j = 0; j < 3; j++) {
      reiheSumme += quadrat[i][j];
    }
    if (reiheSumme != summe) {
      return false; // Wenn eine Reihe nicht stimmt, gib false zurück
    }
  }

  // Überprüfen der Spalten
  for (int j = 0; j < 3; j++) {
    int spalteSumme = 0;
    for (int i = 0; i < 3; i++) {
      spalteSumme += quadrat[i][j];
    }
    if (spalteSumme != summe) {
      return false; // Wenn eine Spalte nicht stimmt, gib false zurück
    }
  }

  // Überprüfen der Diagonalen
  int diagonal1 = quadrat[0][0] + quadrat[1][1] + quadrat[2][2];
  int diagonal2 = quadrat[0][2] + quadrat[1][1] + quadrat[2][0];

  if (diagonal1 != summe || diagonal2 != summe) {
    return false; // Wenn eine Diagonale nicht stimmt, gib false zurück
  }

  return true; // Wenn alles stimmt, gib true zurück
}

Falls du Ideen hast, würde ich mich über eine Rückmeldung freuen. :slight_smile:
Danke vielmals und liebe Grüsse
guet19

Mach dir doch mal ein paar serial prints in jede Funktion damit du weißt ob er überhaupt in die Funktion hinein springt

Hallo Kai-R

Sorry für die späte Rückmeldung, leider hatte ich erste heute Zeit um das ganze zu testen.

Und als erstes auch danke vielmals an dich für das geschriebene Programm und die Zeit, welche du darin investiert hast.

Kurz zu mir und meinen Programmierkompetenzen und meinem Vorhaben.
Ich bin daran einen Adventskalender für meine Freundin zu bauen, dabei sollte sie diverse kleine Aufgaben erledigen müssen, damit ein Fach elektrisch öffnet oder sie mithilfe eines Zahlencodes 4-stellige Zahlenschlösser öffnen kann. Ich versuche euch gerne ein Bild davon anzuhängen. Selber habe ich leider keine grossen Programmierfähigkeiten. Ich habe vor 4 Wochen mein Studium als Wirtschaftsinformatiker angefangen, wobei ich seit vier Wochen daran bin die Java Basics zu erlernen, jedoch bin ich sehr Interessiert an kleinen Projekten mit Arduino.

Zum Programm:

Das Spiel sollte so aufgebaut sein, dass 9 Zahlen gegeben sind, welche der Reihe nach in einem Wert (weisse LED) gespeichert werden. Die Zahlen sind in diesem Fall meiner Freundin bekannt, da ich ihr ein Buch anfertigen lasse, in welchem zu jedem Türchen eine kurze Beschreibung steht. Dabei muss sie dann alle Werte der Reihe nach einer LED zuordnen. Sobald jede LED einen Wert zugeordnet bekommen hat wird überprüft, ob alle diagonalen, horizontalen und vertikalen Spalten die selbe Summer ergeben. Ist dies der Fall wird der Zahlencode in Form einer blinkenden RGB LED bekanntgegeben.

Zu deinem Programm: Danke dir vielmals, dein Programm macht genau das was ich wollte, zumindest so weit ich dies testen konnte. :slight_smile:

Leider besteht jedoch dabei das selbe Problem wie bei dem Programm von ec2021. Der Speichern Taster hat leider keine Funktion.

Falls du hierbei auch einen Lösungsvorschlag hättest, würde ich mich über eine Rückmeldung freuen.

Danke vielmals und liebe Grüsse
guet19

Für mich hört sich das so an, als ob der Taster fehlerhaft angeschlossen oder defekt ist. Da programmtechnisch alle vier Taster auf die gleiche Weise abgefragt werden, sehe ich momentan keinen Grund, warum nur der „Speichern“ Taster nicht funktioniert.

Danke euch allen vielmals. Ich habe nun festgestellt das der digitale und der zweite getestete analog Pin defekt war. An einem anderen Analog Pin hat das ganze funktioniert. :slight_smile:

Ich konnte nun diese Aufgabe für den Adventskalender dank eurer Hilfe abschliessen!
Danke an @Kai-R und @ec2021 für eure Programmcodes!

Danke für die Rückmeldung :slight_smile:

1 Like

Gerne :wink: Weiterhin viel Spaß und Erfolg beim Entwickeln!
ec2021

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.