Tastenabfrage mehrerer Tasten inkl. Entprellung

Hallo , mein Name ist Volker und ich beschäftige mich erst seit kurzem mit dem Arduino.
Kleine Projekte funktionieren bereits ganz gut och bei der Übernahme eines Sketches habe ich nun ein Problem und bitte um Hilfe.
Ein kleines Projekt mit 8 Tasten, 6 Motoren über H Shield und 8 LED für die Modellbahn.
Hier ging es mir eine um eine einfache Programmierung und Tastenabfrage mit Entprellung.

Ich fand im Forum den Sketch von Chris72622 und da er super beschrieben ist hoffte ich damit zu einer Lösung zu kommen. Leider funktioniert es nicht. Der Sketch lässt sich fehlerfrei kompilieren aber weder Motoren noch LED schalten. Arduino MEGA 2560
was mach ich falsch?

beste Grüße Volker

hier der Sketch:



/*
 *
 * Tastenauswertungsalgorithmus
 *
 * Tastenzustände können folgendermaßen abgefragt werden:
 *
 * Beispiele:
 *
 * if (bState[7] == HOLD)                                         // Wird die Taste 7 momentan gedrückt gehalten?
 * if (bCmd[3] == PUSH)                                           // Wurde die Taste 3 gedrückt?
 * if (bCmd[1] == S_HOLD)                                         // Wurde die Taste 1 pushDur ms lang gedrückt gehalten?
 * if (bCmd[2] == M_HOLD && bCmd[4] == M_HOLD)                    // Wurden die Tasten 2 und 4 pushDur ms lang gedrückt gehalten, unabhängig davon, ob weiteren Tasten gedrückt gehalten werden?
 * if (bCmd[5] == M_HOLD && bCmd[6] == M_HOLD && bCount == 2)     // Wurden die Tasten 5 und 6 pushDur ms lang gedrückt gehalten, während keine weiteren Tasten gedrückt gehalten werden?
 *                                                                // bCount sollte der Summe der abzufragenden Tasten entsprechen.
 *
 * Werden mehr als 255 Tasten benötigt, muss der Wertebereich von butPin und bCount jeweils in Integer geändert werden.
 * 
*/

#include <Bounce2.h>

unsigned long now;                  // Aktueller Zeitpunkt

// _Entprellung

#define INPUTMODE INPUT_PULLUP      // INPUT oder INPUT_PULLUP
const byte butPin[] = {             // Pin-Nummern der angeschlossenen Tasten
  2, 3, 4, 5, 6, 7, 8, 9
};
#define NUM_BUTTONS sizeof(butPin)  // Die Anzahl der Tasten durch die Anzahl der Bytes des Arrays butPin ermitteln (wird automatisch definiert)
Bounce debouncer[NUM_BUTTONS];      // Mehrere Bounce-Instanzen erstellen
bool bState[NUM_BUTTONS];           // Speichert den Zustand des Pins
enum {
  UNHOLD, HOLD
};
byte bCmd[NUM_BUTTONS];             // Speichert Pinbefehle, welche dem Sketch übergeben werden
enum {
  WAIT, PUSH, RELEASE, S_HOLD, M_HOLD
};
byte bCount;                        // Anzahl der gleichzeitig gedrückt gehaltenen Tasten
bool LED1 = 38;  //LED 1-5 LED Entkuppler, LED6-8 LED Fahrtrichtung
bool LED2 = 39;
bool LED3 = 40;
bool LED4 = 41;
bool LED5 = 42;
bool LED6 = 43;
bool LED7 = 44;
bool LED8 = 45;

int M1 = 22; // Entkuppler 1
int M2 = 23;
int M3 = 24; // Entkuppler 2
int M4 = 25;
int M5 = 26; // Entkuppler 3
int M6 = 27;
int M7 = 28; // Entkuppler 4
int M8 = 29;
int M9 = 30; // Entkuppler 5
int M10 = 31;
int M11 = 32; // Frei
int M12 = 33; // Frei
int M13 = 34; // Lok
int M14 = 35; // Lok
int M15 = 36; // Frei
int M16 = 37; // frei

int speed = 180;



void setup()
{
  for (int i = 0; i < NUM_BUTTONS; i++)
  {
    pinMode(butPin[i], INPUTMODE);
    debouncer[i].attach(butPin[i]);
    debouncer[i].interval(10);
    pinMode(M1, OUTPUT);
    pinMode(M2, OUTPUT);
    pinMode(M3, OUTPUT);
    pinMode(M4, OUTPUT);
    pinMode(M5, OUTPUT);
    pinMode(M7, OUTPUT);
    pinMode(M8, OUTPUT);
    pinMode(M9, OUTPUT);
    pinMode(M10, OUTPUT);
    pinMode(M11, OUTPUT);
    pinMode(M12, OUTPUT);
    pinMode(M13, OUTPUT);
    pinMode(M14, OUTPUT);
    pinMode(M15, OUTPUT);
    pinMode(M16, OUTPUT);
    pinMode(LED1, OUTPUT);
    pinMode(LED2, OUTPUT);
    pinMode(LED3, OUTPUT);
    pinMode(LED4, OUTPUT);
    pinMode(LED5, OUTPUT);
    pinMode(LED6, OUTPUT);
    pinMode(LED7, OUTPUT);
    pinMode(LED8, OUTPUT);
  }
}



void loop()
{
  now = millis(); // Aktueller Zeitpunkt
  debounce();
  if (bCmd[2] == PUSH)      // Entkuppler 1
    digitalWrite(LED1,HIGH);
    analogWrite(M1, speed);
    delay(2000);
    analogWrite(M1,  0); 
    delay(1000);
    analogWrite(M2, speed); 
    delay(2000);
    analogWrite(M2, 0); 
    delay (1000);  
   // digitalWrite(LED1,LOW);   
      if (bCmd[3] == PUSH)     // Entkuppler 2
    digitalWrite(LED2,HIGH);
    analogWrite(M3, speed);
    delay(2000);
    analogWrite(M3,  0); 
    delay(1000);
    analogWrite(M4, speed); 
    delay(2000);
    analogWrite(M4, 0); 
    delay (1000);     
    digitalWrite(LED1,LOW);
    
   if (bCmd[4] == PUSH)    // Entkuppler 3
    digitalWrite(LED3,HIGH);
    analogWrite(M5, speed);
    delay(2000);
    analogWrite(M5,  0); 
    delay(1000);
    analogWrite(M6, speed); 
    delay(2000);
    analogWrite(M6, 0); 
    delay (1000); 
    digitalWrite(LED3,LOW); 

    if (bCmd[5] == PUSH)    // Entkuppler 4
    digitalWrite(LED4,HIGH);
    analogWrite(M7, speed);
    delay(2000);
    analogWrite(M7,  0); 
    delay(1000);
    analogWrite(M8, speed); 
    delay(2000);
    analogWrite(M8, 0); 
    delay (1000); 
    digitalWrite(LED1,LOW); 

  if (bCmd[6] == PUSH)     // Entkuppler 5
    digitalWrite(LED5,HIGH);
    analogWrite(M8, speed);
    delay(2000);
    analogWrite(M8,  0); 
    delay(1000);
    analogWrite(M9, speed); 
    delay(2000);
    analogWrite(M9, 0); 
    delay (1000);  
    digitalWrite(LED5,LOW);

  if (bCmd[7] == PUSH)     // Lok vor
     analogWrite(M13, 0);
     delay(1000);
     analogWrite(M12, 120);
     digitalWrite(LED6,HIGH);
     digitalWrite(LED7,LOW);
     digitalWrite(LED8,LOW);
      
  if (bCmd[8] == PUSH) // Lok stop
    analogWrite(M12, 0);
    analogWrite(M13, 0);
    digitalWrite(LED7,HIGH);
    digitalWrite(LED6,LOW);
    digitalWrite(LED8,LOW);
    
  if (bCmd[9] == PUSH)     // Lok zurück
    analogWrite(M12, 0);
    delay(1000);
    analogWrite(M13, 120);
    digitalWrite(LED7,LOW);
    digitalWrite(LED6,LOW);
    digitalWrite(LED8,HIGH);  
       

}

void debounce()
{
  static unsigned long pushTime;    // Definiert, wann zuletzt eine Taste gedrückt gehalten wurde
  const  int pushDur = 700;         // Definiert die Haltedauer, im Anschluss derer eine Aktion ausgelöst werden soll
  static bool action = false;       // Definiert, ob eine Aktion bereits ausgeführt wurde
  now = millis();
  for (int i = 0; i < NUM_BUTTONS; i++)
  {
    switch (bCmd[i])
    {
      case WAIT:
        if (now - pushTime >= pushDur && action == false &&  bState[i] == HOLD)
        {
          if (bCount == 1) bCmd[i] = S_HOLD;   // Aktion fürs gedrückt halten einer Taste
          if (bCount >= 2) bCmd[i] = M_HOLD;   // Aktion fürs gedrückt halten mehrerer Tasten
        }
        break;
      case PUSH:
        if (!bCount)       // Wurde bereits noch keine Tasten weitere Taste gedrückt?
        {
          pushTime = now;  // Druck der ersten Taste
          action = false;  // Actionstatus zurücksetzen
        }
        bCount++;          // Anzahl der gleichzeitig gedrückt gehaltenen Tasten inkrementieren
        bCmd[i] = WAIT;
        break;
      case RELEASE:
        if (bCount) bCount--;         // Anzahl der gleichzeitig gedrückt gehaltenen Tasten inkrementieren, falls noch welche gedrückt gehalten werden
        if (!bCount) action = false;  // Gibt das Auslösen von Aktionen wieder frei, sobald keine Tasten mehr gedrückt gehalten werden
        bCmd[i] = M_HOLD; // An dieser Stelle wurde bewusst auf break; verzichtet
      case S_HOLD:
        bCmd[i] = M_HOLD; // An dieser Stelle wurde bewusst auf break; verzichtet
      case M_HOLD:
        action = true;  // Verhindert das mehrmalige Auslösen bereits ausgelöster Aktionen
        bCmd[i] = WAIT;
        break;
    }
    debouncer[i].update();   // Status der Tasten prüfen
    if (debouncer[i].fell())
    {
      bCmd[i] = PUSH;
      bState[i] = HOLD;
    }
    else if (debouncer[i].rose())
    {
      bCmd[i] = RELEASE;
      bState[i] = UNHOLD;
    }
  }
}

Du sollest Sketche die du findest auch verstehen. Und nicht nur kopieren. Dann passieren solche Fehler nicht.

Wieso machst du OUPUT zigmal in der for-Schleife statt nur einmal? Der Grund weshalb man das manchmal in Schleifen macht liegt an der Verwendung von Arrays. Aber das hast du hier nicht.

bool LED1 = 38;  //LED 1-5 LED Entkuppler, LED6-8 LED Fahrtrichtung
bool LED2 = 39;

Das ist Unsinn. bool ist entweder 1 oder 0 (bzw. true/false). Das verwendet man für Zustände, aber nicht für Pin-Nummern.

Und bei deinen if-Abfragen in loop() fehlen die geschweiften Klammern! Wir sind hier nicht in Python wo nur die Einrückung zählt

"now" muss in loop() nicht verwendet werden. Das könnte auch in debounce() lokal sein. Statt global. Das ist aber kein Fehler

1 Like

vielen Dank Serenifly, ich schrieb ja ich beschäftige mich erst seit kurzem mit dem Thema.
Jeep, den bool Fehler hatte ich zwischenzeitlich schon gefunden....
ich lerne erst das laufen,sorry

Moin
wenn man im Arduino Biotop laufen lernen möchte, dann hat man drei Möglichkeiten:

  • Sketche verwenden die man nicht versteht
  • Stangenware aus Bibliotheken verwenden
  • den Sketch mit einen eigenen Funktionen zusammenlöten

Wobei ich die letztere empfehle, da hier der höchste Wirkungsgrad beim Lernen erreicht wird um das Laufen zu lernen.

Hallo,

du verwendest doch die Bounce2 Lib. Die ist schon lange vorhanden und wird gepflegt. Schaue dir bitte erst dessen Bsp. an mit Taster- und Schalterfunktion usw. und probiere sie aus. Wenn verstanden -> verwenden. Irgendwas wildes vorher zu programmieren macht keinen Sinn.

ok , danke

Hallo,

wenn du damit Sattelfest bist und deine kleinste Einheit immer aus einem Taster, einem Entkuppler, einer Led etc. besteht und diese Einheit dann "nur noch" vervielfacht werden muss, dann kommen Arrays ins Spiel und ganz sicher auch eine Strucktur (struct). Das wäre der Fahrplan.

Hallo, vielen Dank für Deinen Hinweis. ich habe ja bereits beschrieben das ich noch lerne. Trotzdem möchte ich noch etwas anmerken
nun gut , ein jeder hat eine andere Auffassung wie es das besten geht. ich habe versucht zu erklären wo das Problem liegt....
Ein Grund warum ich den fertigen Sketch benutzt habe ist das er ausführlich in seinen Einzelschritten erklärt ist und siecher auch funktioniert.
Nur habe ich als Beginner Schwierigkeiten es richtig anzupassen.
Darum bin ich sehr Dankbar das Serenifly mir aufzeigte wo Fehler und meine Schwächen liegen, daraus habe ich gelernt, dass hilf mir weiter.
das war auch der Grund meiner Bitte um Hilfe.
Man kann viel experimentieren und ausprobieren . zusätzlich sollte es erlaubt sein Fragen zu stellen und um Hilfe zu.
in meinen 63 Lebensjahren habe ich immer mit offenen Augen gelernt und gefragt und meist auch viel dabei gelernt.
Es ist ja nur die was habe ich da falsch gemacht.....aber niemand sollte sich genötigt sehen.
Microsoft antwortet grundsätzlich auf Fragen mit einem Link zu Hilfeseiten/FAQ ohne sich der Frage über zu stellen. Da brütet man Tagelang über einen SQL Text
und hat nur einen falschen Zeilenumbruch......Man kann seine Zeit auch anders nutzbringender verbringen ...
Also nichts für Ungut und vielen Dank!
Beste Grüße
Volker

Hallo,

ist alles kein Problem. Lerne Schritt für Schritt. Wenn du für den nächsten Schritt bereit bist kommste wieder. Wann dieser ist bestimmts du. :wink:

Dann sind die MobaTools wie für Dich geschaffen. Da gibt es auch Tastenabfrage einschließlich Entprellung. Der Autor @MicroBahner ist hier aktiv.

Installation mittels IDE, dann kommt auch eine PDF-Datei mit deutscher Beschreibung mit.

Zu viel auf einmal, denn dann ist auch die Hilfe schwierig.

1 Like

Vielen Dank , schaue ich mir an!

Hier jetzt der fertige und getestete Sketch.
neben meinen Fehlern haben mir 3 defekte H-Shields das Leben schwer gemacht. Mit dem 4. funktionierte es dann.
Gebaut für ein Rangierspiel mit einer Lokomotive und 4 Wagons . Ziel ist es die Wagons im Rangierbahnhof mit 4 Gleisen zu vertauschen.
Vielen Dank an Chris72622 der in seinem Beispiel mit den vielen Beschreibungen es auch Dilettanten leichter macht.



/*
 *
 * Tastenauswertungsalgorithmus
 *
 * Tastenzustände können folgendermaßen abgefragt werden:
 *
 * Beispiele:
 *
 * if (bState[7] == HOLD)                                         // Wird die Taste 7 momentan gedrückt gehalten?
 * if (bCmd[0] == PUSH)                                           // Wurde die Taste 2 gedrückt?  
 * if (bCmd[1] == S_HOLD)                                         // Wurde die Taste 1 pushDur ms lang gedrückt gehalten?
 * if (bCmd[2] == M_HOLD && bCmd[4] == M_HOLD)                    // Wurden die Tasten 2 und 4 pushDur ms lang gedrückt gehalten, unabhängig davon, ob weiteren Tasten gedrückt gehalten werden?
 * if (bCmd[5] == M_HOLD && bCmd[6] == M_HOLD && bCount == 2)     // Wurden die Tasten 5 und 6 pushDur ms lang gedrückt gehalten, während keine weiteren Tasten gedrückt gehalten werden?
 *                                                                // bCount sollte der Summe der abzufragenden Tasten entsprechen.
 *
 * Werden mehr als 255 Tasten benötigt, muss der Wertebereich von butPin und bCount jeweils in Integer geändert werden.
 * 
*/

#include <Bounce2.h>

unsigned long now;                  // Aktueller Zeitpunkt

// _Entprellung

#define INPUTMODE INPUT_PULLUP      // INPUT oder INPUT_PULLUP
const byte butPin[] = {             // Pin-Nummern der angeschlossenen Tasten
  2, 3, 4, 5, 6, 7, 8, 9
};
#define NUM_BUTTONS sizeof(butPin)  // Die Anzahl der Tasten durch die Anzahl der Bytes des Arrays butPin ermitteln (wird automatisch definiert)
Bounce debouncer[NUM_BUTTONS];      // Mehrere Bounce-Instanzen erstellen
bool bState[NUM_BUTTONS];           // Speichert den Zustand des Pins
enum {
  UNHOLD, HOLD
};
byte bCmd[NUM_BUTTONS];             // Speichert Pinbefehle, welche dem Sketch übergeben werden
enum {
  WAIT, PUSH, RELEASE, S_HOLD, M_HOLD
};
byte bCount;                        // Anzahl der gleichzeitig gedrückt gehaltenen Tasten
int LED1 = 38;  //LED 1-5 LED Entkuppler, LED6-8 LED Fahrtrichtung
int LED2 = 39;
int LED3 = 40;
int LED4 = 41;
int LED5 = 42;
int LED6 = 43;
int LED7 = 44;
int LED8 = 45;

int motorPin1 = 22; // Entkuppler 1
int motorPin2 = 23;
int motorPin3 = 24; // Entkuppler 2
int motorPin4 = 25;
int motorPin5 = 26; // Entkuppler 3
int motorPin6 = 27;
int motorPin7 = 28; // Entkuppler 4
int motorPin8 = 29;
int motorPin9 = 30; // Entkuppler 5
int motorPin10 = 31;
int motorPin11 = 32; // Frei
int motorPin12 = 33; // Frei
int motorPin13 = 34; // Lok
int motorPin14 = 35; // Lok
int motorPin15 = 36; // Frei
int motorPin16 = 37; // frei

int speed = 180;



void setup()
{
  for (int i = 0; i < NUM_BUTTONS; i++)
  {
    pinMode(butPin[i], INPUTMODE);
    debouncer[i].attach(butPin[i]);
    debouncer[i].interval(10);
    
  }
    pinMode(motorPin1, OUTPUT);
    pinMode(motorPin2, OUTPUT);
    pinMode(motorPin3, OUTPUT);
    pinMode(motorPin4, OUTPUT);
    pinMode(motorPin5, OUTPUT);
    pinMode(motorPin7, OUTPUT);
    pinMode(motorPin8, OUTPUT);
    pinMode(motorPin9, OUTPUT);
    pinMode(motorPin10, OUTPUT);
    pinMode(motorPin11, OUTPUT);
    pinMode(motorPin12, OUTPUT);
    pinMode(motorPin13, OUTPUT);
    pinMode(motorPin14, OUTPUT);
    pinMode(motorPin15, OUTPUT);
    pinMode(motorPin16, OUTPUT);
    pinMode(LED1, OUTPUT);
    pinMode(LED2, OUTPUT);
    pinMode(LED3, OUTPUT);
    pinMode(LED4, OUTPUT);
    pinMode(LED5, OUTPUT);
    pinMode(LED6, OUTPUT);
    pinMode(LED7, OUTPUT);
    pinMode(LED8, OUTPUT);
}



void loop()
{

  now = millis(); // Aktueller Zeitpunkt
  debounce();
  // Entkuppler 1
  if (bCmd[0] == PUSH)  {    
    digitalWrite(LED1,HIGH);
    analogWrite(motorPin1, speed);
    delay(2000);
    analogWrite(motorPin1,  0); 
    delay(1000);
    analogWrite(motorPin2, speed); 
    delay(2000);
    analogWrite(motorPin2, 0); 
    digitalWrite(LED1,LOW);   
  }
  // Entkuppler 2
        if (bCmd[1] == PUSH)  {   
    digitalWrite(LED2,HIGH);
    analogWrite(motorPin3, speed);
    delay(2000);
    analogWrite(motorPin3,  0); 
    delay(1000);
    analogWrite(motorPin4, speed); 
    delay(2000);
    analogWrite(motorPin4, 0);      
    digitalWrite(LED2,LOW);
  }
  // Entkuppler 3
   if (bCmd[2] == PUSH)  { 
    digitalWrite(LED3,HIGH);
    analogWrite(motorPin5, speed);
    delay(2000);
    analogWrite(motorPin5,  0); 
    delay(1000);
    analogWrite(motorPin6, speed); 
    delay(2000);
    analogWrite(motorPin6, 0);  
    digitalWrite(LED3,LOW); 
   }
   // Entkuppler 4
    if (bCmd[3] == PUSH) {   
    digitalWrite(LED4,HIGH);
    analogWrite(motorPin7, speed);
    delay(2000);
    analogWrite(motorPin7,  0); 
    delay(1000);
    analogWrite(motorPin8, speed); 
    delay(2000);
    analogWrite(motorPin8, 0); 
    digitalWrite(LED4,LOW); 
    }
     // Entkuppler 5
  if (bCmd[4] == PUSH)  {   
    digitalWrite(LED5,HIGH);
    analogWrite(motorPin9, speed);
    delay(2000);
    analogWrite(motorPin9,  0); 
    delay(1000);
    analogWrite(motorPin10, speed); 
    delay(2000);
    analogWrite(motorPin10, 0);  
    digitalWrite(LED5,LOW);
  }
    // Lok vor
  if (bCmd[5] == PUSH)  {  
     analogWrite(motorPin14, 0);
     delay(1000);
     analogWrite(motorPin13, 120);
     digitalWrite(LED6,HIGH);
     digitalWrite(LED7,LOW);
     digitalWrite(LED8,LOW);
  }
      // Lok stop
   if (bCmd[6] == PUSH){ 
    analogWrite(motorPin13, 0);
    analogWrite(motorPin14, 0);
    digitalWrite(LED7,HIGH);
    digitalWrite(LED6,LOW);
    digitalWrite(LED8,LOW);
   }
      // Lok zurück
  if (bCmd[7] == PUSH)  {   
    analogWrite(motorPin13, 0);
    delay(1000);
    analogWrite(motorPin14, 120);
    digitalWrite(LED7,LOW);
    digitalWrite(LED6,LOW);
    digitalWrite(LED8,HIGH);  
  }
      
}
  

void debounce()
{
  static unsigned long pushTime;    // Definiert, wann zuletzt eine Taste gedrückt gehalten wurde
  const  int pushDur = 700;         // Definiert die Haltedauer, im Anschluss derer eine Aktion ausgelöst werden soll
  static bool action = false;       // Definiert, ob eine Aktion bereits ausgeführt wurde
  now = millis();
  for (int i = 0; i < NUM_BUTTONS; i++)
  {
    switch (bCmd[i])
    {
      case WAIT:
        if (now - pushTime >= pushDur && action == false &&  bState[i] == HOLD)
        {
          if (bCount == 1) bCmd[i] = S_HOLD;   // Aktion fürs gedrückt halten einer Taste
          if (bCount >= 2) bCmd[i] = M_HOLD;   // Aktion fürs gedrückt halten mehrerer Tasten
        }
        break;
      case PUSH:
        if (!bCount)       // Wurde bereits noch keine Tasten weitere Taste gedrückt?
        {
          pushTime = now;  // Druck der ersten Taste
          action = false;  // Actionstatus zurücksetzen
        }
        bCount++;          // Anzahl der gleichzeitig gedrückt gehaltenen Tasten inkrementieren
        bCmd[i] = WAIT;
        break;
      case RELEASE:
        if (bCount) bCount--;         // Anzahl der gleichzeitig gedrückt gehaltenen Tasten inkrementieren, falls noch welche gedrückt gehalten werden
        if (!bCount) action = false;  // Gibt das Auslösen von Aktionen wieder frei, sobald keine Tasten mehr gedrückt gehalten werden
        bCmd[i] = M_HOLD; // An dieser Stelle wurde bewusst auf break; verzichtet
      case S_HOLD:
        bCmd[i] = M_HOLD; // An dieser Stelle wurde bewusst auf break; verzichtet
      case M_HOLD:
        action = true;  // Verhindert das mehrmalige Auslösen bereits ausgelöster Aktionen
        bCmd[i] = WAIT;
        break;
    }
    debouncer[i].update();   // Status der Tasten prüfen
    if (debouncer[i].fell())
    {
      bCmd[i] = PUSH;
      bState[i] = HOLD;
    }
    else if (debouncer[i].rose())
    {
      bCmd[i] = RELEASE;
      bState[i] = UNHOLD;
    }
  }
}

Danke für Deine Rückmeldung!

In Deinem Programm sehe ich noch Optimierungsmöglichkeiten. Aber nur, wenn Du magst.

PS.: Hier ist relativ viel los, da kann man nicht jedem Fragesteller gerecht werden.

Danke! Gerne, würde mich freuen wenn ich noch etwas verbessern könnte!

Beste Grüße

  1. Alle Konstanten konstant machen. Pinnummern ändern sich nicht und können auch nur Werte unter 255 annehmen, also const byte oder const uint8_t (es gibt noch mehr Möglichkeiten), spart kostbaren Speicher, wenn der selbstoptimierende Compiler das nicht selbst erledigt.
  2. Bei butPin[] nutzt Du ein Feld, bei LEDx`` und motorPinxaber nicht. DennpinMode``` geht dann so schön in einer Schleife.
  3. Leider ist delay(2000); blockierend und daher "böse" :japanese_ogre:
    Die Entkuppler und Lokaktionen blockieren sich gegenseitig. Ausweg ist die Verwendung einer Schrittkette (=finite state machine, = endlicher Automat) und millis(). Mit Schrittkette fallen viele Aufgabenstellungen sehr viel einfacher.

Das soll es erstmal sein :slightly_smiling_face:

Dankeschön!
Uih, das ist eine Menge Holz :slight_smile:
Mit Punkt 1 und 2 muss ich mich noch auseinandersetzten. das sollte ich hinbekommen.
Schrittkette Ohje da gibt es noch viel zu lernen.....

Speziell für uns Modellbahner hatte ich da mal ein Tutorial zu geschrieben. Vielleicht hilft es dir ja etwas. Allerdings zieht das Stummiforum gerade um, ich weis also nicht, wie lange der Link noch funktioniert. Tommy56 hat das in kompakter Form als PDf aber auch auf seiner Webseite gehostet. Einschießlich der Beispielsketche dazu.

hey cool, vielen Dank! :slight_smile:

Die Pins für analogWrite müssen PWM können, was aber nicht der Fall ist.

Haben die Entkuppler wirklich Motoren oder sind das nicht einfach Magneten?

Dann packe ich noch einen obendrauf und empfehle Dir Strukturen und Klassen, weil dort "zusammensteht, was zusammengehört" (Zitat @combie). Auf den ersten Blick haut einen das aus den Schuhen, aber die Mühe lohnt ebenso wie bei der Schrittkette. Ich mache die Schrittkette hier mittels switch/case. Die Methode entkuppeln() ist so geschrieben, als gäbe es nur einen Entkuppler, dennoch kann man sie innerhalb mehrerer Instanzen (Kopien der Klassen) verwenden.

Die Klasse Lok ist bei einer Lok nicht so der Brüller, aber ich war halt gerade im Schwung.

Wegen PWM habe ich alle Pins verändert (nur teilweise getestet):

#include <MobaTools.h>  // Kann mittels Arduino-IDE installiert werden. 

const byte SPEED = 120;

class Lok {
  private:  // Die folgenden Objekte sind nur innerhalb der Klasse zugänglich. Am Anfang einer Klasse überflüssig.
    enum struct Schritte {WARTEN, VOR, ZURUECK, STOPP};  // Benennung und Numerierung der Schritte der Schrittkette
    const byte tasterPinV, tasterPinS, tasterPinZ, motorPinV, motorPinZ, ledPinV, ledPinS, ledPinZ;  // V = vor; S = Stopp; Z = zurück
    Schritte schritt = Schritte::WARTEN;
    MoToTimer lokImpuls;
    const uint32_t lokPausenLaenge = 1000; // in Millisekunden
  public:
    Lok(const byte _tasterPinV, const byte _tasterPinS, const byte _tasterPinZ, const byte _motorPinV, const byte _motorPinZ, const byte _ledPinV, const byte _ledPinS, const byte _ledPinZ)
      : tasterPinV(_tasterPinV), tasterPinS(_tasterPinS), tasterPinZ(_tasterPinZ), motorPinV(_motorPinV), motorPinZ(_motorPinZ), ledPinV(_ledPinV), ledPinS(_ledPinS), ledPinZ(_ledPinZ)
    {}

    void init() {
      pinMode(tasterPinV, INPUT_PULLUP);  // gedrückt = LOW
      pinMode(tasterPinS, INPUT_PULLUP);  // gedrückt = LOW
      pinMode(tasterPinZ, INPUT_PULLUP);  // gedrückt = LOW
      pinMode(ledPinV, OUTPUT);
      pinMode(ledPinS, OUTPUT);
      pinMode(ledPinZ, OUTPUT);
    }

    void bewegen() {
      switch (schritt) {
        case Schritte::WARTEN:
          if ( !digitalRead(tasterPinV) ) {
            lokImpuls.setTime(lokPausenLaenge); // "Eieruhr" aufziehen
            analogWrite(motorPinZ, 0);
            schritt = Schritte::VOR;
          }
          if ( !digitalRead(tasterPinS) ) {
            digitalWrite(ledPinV, LOW);
            digitalWrite(ledPinS, HIGH);
            digitalWrite(ledPinZ, LOW);
            analogWrite(motorPinV, 0);
            analogWrite(motorPinZ, 0);
          }
          if ( !digitalRead(tasterPinZ) ) {
            lokImpuls.setTime(lokPausenLaenge); // "Eieruhr" aufziehen
            analogWrite(motorPinV, 0);
            schritt = Schritte::ZURUECK;
          }
          break;
        case Schritte::VOR:
          if ( lokImpuls.expired() ) {
            digitalWrite(ledPinV, HIGH);
            digitalWrite(ledPinS, LOW);
            digitalWrite(ledPinZ, LOW);
            analogWrite(motorPinV, SPEED);
            schritt = Schritte::WARTEN;
          }
          break;
        case Schritte::ZURUECK:
          if ( lokImpuls.expired() ) {
            digitalWrite(ledPinV, LOW);
            digitalWrite(ledPinS, LOW);
            digitalWrite(ledPinZ, HIGH);
            analogWrite(motorPinZ, SPEED);
            schritt = Schritte::WARTEN;
          }
          break;
      }
    }
};

Lok lok[] {  // je Lok eine Instanz der Klasse
  //_tasterPinV, _tasterPinS, _tasterPinZ, _motorPinV, _motorPinZ, _ledPinV, _ledPinS, _ledPinZ
  {44, 45, 46, 6, 7, 47, 48, 49}  // Lok 1
};

class Entkuppler {
  private:  // Die folgenden Objekte sind nur innerhalb der Klasse zugänglich. Am Anfang einer Klasse überflüssig.
    enum struct Schritte {WARTEN, ENTKUPPELN, PAUSE, AUS};  // Benennung und Numerierung der Schritte der Schrittkette
    const byte tasterPin, ledPin, motorPinE, motorPinA;  // E = entkuppeln; A = aus
    Schritte schritt = Schritte::WARTEN;
    MoToTimer kuppelImpuls;
    const uint32_t kuppelImpulsLaenge = 2000; // in Millisekunden
    const uint32_t kuppelPausenLaenge = 1000; // in Millisekunden
  public:
    Entkuppler(const byte _tasterPin, const byte _ledPin, const byte _motorPinE, const byte _motorPinA)  // Konstanten jeder Instanz
      : tasterPin(_tasterPin), ledPin(_ledPin), motorPinE(_motorPinE), motorPinA(_motorPinA)  // Startwerte, tasterPin(_tasterPin) entspricht tasterPin = _tasterPin
    {}
    void init() {
      pinMode(tasterPin, INPUT_PULLUP);  // gedrückt = LOW
      pinMode(ledPin, OUTPUT);
      pinMode(motorPinE, OUTPUT);
      pinMode(motorPinA, OUTPUT);
    }

    void entkuppeln() {
      switch (schritt) {
        case Schritte::WARTEN:
          if ( !digitalRead(tasterPin) ) {
            digitalWrite(ledPin, HIGH);
            digitalWrite(motorPinE, HIGH);
            kuppelImpuls.setTime(kuppelImpulsLaenge); // "Eieruhr" aufziehen
            schritt = Schritte::ENTKUPPELN;
          }
          break;
        case Schritte::ENTKUPPELN:
          if ( kuppelImpuls.expired() ) {
            digitalWrite(motorPinE, LOW);
            kuppelImpuls.setTime(kuppelPausenLaenge); // "Eieruhr" aufziehen
            schritt = Schritte::PAUSE;
          }
          break;
        case Schritte::PAUSE:
          if ( kuppelImpuls.expired() ) {
            digitalWrite(motorPinA, HIGH);
            kuppelImpuls.setTime(kuppelImpulsLaenge); // "Eieruhr" aufziehen
            schritt = Schritte::AUS;
          }
          break;
        case Schritte::AUS:
          if ( kuppelImpuls.expired() ) {
            digitalWrite(ledPin, LOW);
            digitalWrite(motorPinA, LOW);
            schritt = Schritte::WARTEN;
          }
          break;
      }
    }
};

Entkuppler entkuppler[] {  // je Entkuppler eine Instanz der Klasse
  //_tasterPin, _ledPin, _motorPinE, _motorPinA
  {22, 23, 24, 25}, // Entkuppler 1
  {26, 27, 28, 29}, // Entkuppler 2
  {30, 31, 32, 33}, // Entkuppler 3
  {34, 35, 36, 37}, // Entkuppler 4
  {38, 39, 40, 41}  // Entkuppler 5
};

void setup() {
  for (Entkuppler &e : entkuppler) e.init();  // alle Instanzen durchlaufen die Methode init
  for (Lok &l : lok) l.init();                // alle Instanzen durchlaufen die Methode init
}

void loop() {
  for (Entkuppler &e : entkuppler) e.entkuppeln();  // alle Instanzen durchlaufen die Methode entkuppeln
  for (Lok &l : lok) l.bewegen();                // alle Instanzen durchlaufen die Methode bewegen
}

Ich hoffe, es nützt Dir in irgendeiner Weise.

PS.: Da ich gerade die MobaTools teste, nutze ich die in diesem Beispiel. Es ginge aber auch einfach mit millis().