Reaktionsspiel-Programm

Hallo Leute. Ich muss in der Schule ein Reaktionsspiel bauen, da ich ein paar Probleme und Fragen habe, habe ich mich hier registriert und es wäre nett, wenn ihr mir helfen würdet. (Muss das Spiel bald fertig haben, hoffe also auf schnelle Antworten :relaxed:).
Als erstes möchte ich mal euch mein Sketch zeigen, ich habe ihn geschrieben, kann ihn jedoch nicht ausprobieren, da irgendetwas mit dem MSP-Board nicht stimmt. Wäre gut, wenn ihr ihn auf Richtigkeit überprüfen würdet.

Das Spiel ist so aufgebaut, dass es 8 LEDs und 3 Taster gibt. 7 LEDs sind grün und in einer Reihe, die 8., gelbe LED ist in der Mitte darunter. Am anfang leuchtet die mittlere LED der 7-er-Reihe. Irgendwann soll die gelbe darunter blinken. Die 2 Spieler haben jeweils einen Taster und die LED der 7-er-Reihe wandert dann in die Richtung desjenigen, der zuerst den Taster gedrückt hat.
Leuchtet die erste oder letzte LED der 7-er-Reihe, so hat der 1. beziehungsweise der 2. Spieler gewonnen und das Spiel ist beendet. Der 3.Taster soll das Spiel starten, beenden beziehungsweise neustarten.

Sketch:

int tasterpin0 = 14;
int tasterpin1 = 7;
int tasterpin2 = 15;
int lednummer = 4;
int led1 = 9;
int led2 = 5;
int led3 = 2;
int led4 = 19;
int led5 = 12;
int led6 = 13;
int led7 = 18;
int gelbeLED = 11;

void setup() {
  
 pinMode(led1,OUTPUT);
 pinMode(led2,OUTPUT);
 pinMode(led3,OUTPUT);
 pinMode(led4,OUTPUT);
 pinMode(led5,OUTPUT);
 pinMode(led6,OUTPUT);
 pinMode(led7,OUTPUT);
 pinMode(gelbeLED,OUTPUT);
 pinMode(tasterpin2, INPUT);
 pinMode(tasterpin1, INPUT);
 pinMode(tasterpin0, INPUT);
 
 }
 void loop() {
   int taster0 = digitalRead (tasterpin0);
   int taster2 = digitalRead (tasterpin2);
   int taster1 = digitalRead (tasterpin1);
   
   
   if (lednummer == 2){
   digitalWrite (led2, HIGH);
   }
   else {
   digitalWrite (led2, LOW);
   }
  
   if (lednummer == 3){
   digitalWrite (led3, HIGH);
   }
   else {
   digitalWrite (led3, LOW);
   }
 
   if (lednummer == 4){
   digitalWrite (led4,HIGH);
   }
   else {
   digitalWrite (led4,LOW);
   }
   
   if (lednummer == 5){
   digitalWrite (led5,HIGH);
   }
   else {
   digitalWrite (led5,LOW);
   }
   
   if (lednummer == 6){
   digitalWrite (led6,HIGH);
   }
   else {
   digitalWrite (led6,LOW);
   }
   
   if (lednummer == 7){  
   digitalWrite (led7,HIGH);
   delay(1000);
   digitalWrite (led7,LOW);
   delay(1000);
   digitalWrite (led7,HIGH);
   delay(1000);
   digitalWrite (led7,LOW);
   delay(1000);
   digitalWrite (led7,HIGH);
   delay(1000);
   digitalWrite (led7,LOW);
      delay(1000);
      // Hier kommt noch was, mehr dazu in der Frage
   } 
   else {
   digitalWrite (led7,LOW);
   }
   
   if (lednummer == 1){
   digitalWrite (led1,HIGH);
   delay(1000);
   digitalWrite (led1,LOW);
   delay(1000);
   digitalWrite (led1,HIGH);
   delay(1000);
   digitalWrite (led1,LOW);
   delay(1000);
   digitalWrite (led1,HIGH);
   delay(1000);
   digitalWrite (led1,LOW);
      delay(1000);
      // Hier kommt noch was, mehr dazu in der Frage
   }
   else {
   digitalWrite (led1,LOW);
   }
   
   
   if(gelbeLED == LOW){
   int rndNR = random(3000,8400);
   delay(rndNR);
   digitalWrite (gelbeLED,HIGH);
   }
   else {
   }
   
   
   if (taster1 == LOW && taster2 == HIGH && gelbeLED == HIGH) {
   lednummer = lednummer-1;
   digitalWrite (gelbeLED,LOW);
   }
   else {
   }
   
   if (taster1 == HIGH && taster2 == LOW && gelbeLED == HIGH) {
   lednummer = lednummer+1;
   digitalWrite (gelbeLED,LOW);
   }
   else {
   }
  
   if (taster1 == LOW && taster2 == LOW && gelbeLED == HIGH) {
   digitalWrite (gelbeLED,LOW);
   }
   else {
   }
   
 }

Fragen würde ich gerne, wie man ein Unterprogramm öffnet, welches sich aber immer wiederholt, also loop ist. Ich würde nämlich gerne es so programmieren, dass, wenn die 1., die 7. LED leuchtet oder der Taster0 gedrückt wird in ein Unterprogramm gewechselt wird, was nichts macht, also es den Anschein hat, dass das der Sketch "aus" und dann wieder zum void loop wechselt, wenn der Taster0 wieder gedrückt wird.
Und ansonsten, wie schon gesagt, wäre es nett, wenn ihr mir sagen könnt, ob was nicht richtig ist.

Dazu machst Du einfach eine eigene Funktion und gibst ihr einen Namen.

Beispiel void(StudentXX) :grin:
Die rufst Du dann wo immer Du sie brauchst auf.

Und setz Deinen Sketch bitte in Code-Tags, liest sich besser

Sketch markieren, Raute anklicken.

Ist der dann loop, also z.B

void (StudentXX) () {
if (taster0 == LOW){
// was schreib ich jetzt, damit es zurück zum void loop kommt?
}
}

Es wiederholt sich also immer bis ich den taster0 drücke und dann geht er wieder zum void loop?
Macht bis ich den taster0 drücke sozusagen gar nichts, wiederholt sich immer.
WIe rufe ich sie ab?
Der Rest ist richtig, oder?

Nee, Du rufst die Funktion in der Loop auf

void Loop(){
Funktion 1
Funktion 2
...

}

Es sollte so heißen:

void func()
{
}

void loop()
{
    func();
}

Keine Klammern um den Funktionsnamen selbst!

Und das hier ist wohl auch falsch:

if (taster1 == HIGH && taster2 == LOW && gelbeLED == HIGH) {
   lednummer == lednummer+1;    <-- diese Zeile
   lednummer = lednummer+1;   entweder so oder 
   lednummer++;         kürzer so 

   digitalWrite (gelbeLED,LOW);

Entsprechend auch beim Subtrahieren.

rudirabbit:
Und das hier ist wohl auch falsch:

if (taster1 == HIGH && taster2 == LOW && gelbeLED == HIGH) {

lednummer == lednummer+1;    ← diese Zeile
  lednummer = lednummer+1;  entweder so oder
  lednummer++;        kürzer so

digitalWrite (gelbeLED,LOW);



Entsprechend auch beim Subtrahieren.

Ah, stimmt. Hatte ich schon mal korrigiert, aber irgendwie nicht gespeichert. Danke, dass du mich darauf hinweist. :slight_smile:
Verbessert.

Aber bei dem Unterprogramm hätte ich noch Fragen.
Da, dass was ihr mir gezeigt hat nicht unendlich weiter läuft, sondern danach zum loop zurückkommt (,oder?), will ich es in 2 Unterprogrammen schreiben. Also:

void loop()
{
    if (taster0 == LOW){
   func ();
    }
    else {}
  }

void func()
{
  func_2 ();
  if (taster0 == LOW){
  lednummer = 3;
  // wie komme ich jetzt zum void loop zurück?
  }
  else{}
}


void func_2()
{
  func ();
  if (taster0 == LOW){
  lednummer = 3;
  // wie komme ich jetzt zum void loop zurück?
  }
  else{}
}

Soll immer zwischen func und func_2 wechseln bis ich den Taster drücke und dann wieder zu loop wechseln. Aber wie gehe ich wieder zu loop? loop(); ?
Und funktioniert es dann, wie ich mir es vorstelle?

Ist dir dabei der Controller noch nicht abgestürzt? Das produziert glaube ich ähnlich einer endlosen Rekursion einen Stack-Überlauf. Bei jedem Funktions-Aufruf wird mindestens die Rücksprung-Adresse und eventuell noch einige Register auf dem Stack gespeichert und erst wieder entfernt wenn die Funktion beendet wird. Du rufst aber vor dem Beenden immer wieder eine andere Funktion auf, die wiederum die aufrufende Funktion aufruft.

Du kannst auch die beiden Funktionen hintereinander in loop() aufrufen. Und wenn du den Taster drückst machst du was anderes.

void loop()
{
   if(Taster nicht gedrückt)
   {
       func1();
       func2();
   }
   else
   {
   }
}

Und "die void loop" gibt es nicht. Void ist lediglich der Rückgabe-Typ der Funktion. In diesem Fall nichts. Es ist kein Schlüsselwort wie "class" oder "struct", das eine Struktur definiert. Funktionen werden durch ihren Namen (und eventuell die Parameter) definiert. Nicht durch den Rückgabe-Typ.

? sorry, aber ich kapier nicht genau was du da sagst / schreibst. MIt dem, was du hingeschrieben hast, wird doch, wenn der taster nicht gedrückt ist zu func1 beziehungsweise zu func2 gewechselt, das passiert ja dann andauernd und wenn ich den taster nicht drücke, funktioniert das Spiel nicht. Ich will aber, dass void loop ganz normal abgespielt wird und erst dann, wenn ich den taster drücke, geht das Spiel "aus". Und wenn ich den wieder drücke wieder "an", also wieder zu void loop zurückgeht.

Nochmal für mich zum Verständnis, diese Unterprogramme funktionieren doch nicht in einer Endlosschleife, wie loop. Sie kehren nach dem Ablauf ihrer "Aufgaben" zurück zum loop, wo sie eingesetzt wurden und wiederholen sich nicht?

Dann bau dir eine Status-Variable vom Typ bool ein, die du mit dem Taster bei jedem Drücken hin-und-her schaltest. Und je nach dem ob die true oder false ist führst du die zwei Funktionen aus oder nicht. Und die Abfrage des Tasters kommt auch in loop().

Was du dabei aber auch beachten musst ist den Taster zu entprellen. Dafür tut es auch erst mal ein kurzes delay() von 20-50ms nach dem Abfragen des Status und bevor der Code danach ausgeführt wird. Sonst löst der Taster mehrmals aus:

Es gibt auch bessere Entprell-Routinen, aber das wird dich noch mehr verwirren.

Sie kehren nach dem Ablauf ihrer "Aufgaben" zurück zum loop, wo sie eingesetzt wurden und wiederholen sich nicht?

Sowie du das geschrieben hast schon. Du hast da zwei Funktionen die sich gegenseitig aufrufen. Das ist keine gute Idee.

Sorry, wenn ich mit meiner Unwissenheit nerve. Bin nur ein Schüler :cold_sweat: und kapiere das mit der Status-Variable des Typen bool nicht richtig, obwohl ich die Erklärung von Arduino.cc schon gelesen habe. Was muss ich an meinem Reaktionsspiel machen und wo genau muss ich die delay einfügen, damit der Taster entprellt?
Wäre dankbar, wenn du mir sagen könntest, was genau ich hinzuzufügen habe.

wo genau muss ich die delay einfügen, damit der Taster entprellt?

Eigentlich egal. Das Problem ist, dass ein Arduino viel schneller ist als ein Taster.
Das kannst du mit einem [b]delay(10); [/b]irgendwo in loop ändern: dann ist der Taster schneller, bzw der Arduino krieg das Prellen nicht mit, ist aber immer noch schnell genug um zu erkennen, dass du eine Taste gedrückt hast.

Wenn man sich merken muss, ob der Tasterzustand sich gerade erst von offen nach gedrückt (oder umgekehrt) geändert hat, oder schon in einer der vorigen loop Durchläufe, reicht es auch, wenn das delay nur bei solch einem Wechsel aufgerufen wird.

Okay, danke.
Aber wie mache ich jetzt das mit der Status-Variable vom Typ bool. Oder allgemein: wie schaffe ich das, was ich suche.

Aber wie mache ich jetzt das mit der Status-Variable vom Typ bool. Oder allgemein: wie schaffe ich das, was ich suche.

Keine Ahnung wie du das machst.
Zeig, wie du es machst, und --bei Bedarf-- , was im Ergebnis nicht so ist wie du es dir vorstellst.

Ich setze mich vor den PC und sage laut und deutlich "Mach Mal"
Aber es passiert nix.

Das liegt vermutlich nicht daran, dass das Mikrofon nicht aktiviert ist ...
(und "nix" ist auch nur ungenau beobachtet)

DAS PROBLEM liegt aber daran, dass ich nicht weiß, wie das mit dem bool funktioniert. KANN MIR ES DANN EINER MAL ERKLÄREN:

? DAS MIT DEM ZWEITEN zITAT KAPIERE ICH NICHT:

Aber so ein ganz kleines bisschen C ist kein Problem ?
Eine Variable hat einen Datentyp und einen Wert

static bool AlterZustand = LOW;

if ( digitalRead(TasterPin) == HIGH && AlterZustand == LOW)
{
   // Wechsel LOW -> HIGH
   funcLowHigh();
   AlterZustand = HIGH; 
   delay(10); // Entprellen
}

bool und boolean ist übrigens das gleiche, bis auf die Farbe in der Arduino - IDE.
Und statt static kannst du Alterzustand auch global, also ausserhalb einer Funktion wie loop() , definieren.