Reaktionsprobleme Arduino Leonardo

Hi, ich habe Probleme mit nem Code von meinem Arduino Leonardo. Ich verbinde dieses zusätzlich mit einem Arduino Nano über RX/TX, um Taster zu nutzen.

Folgendes: Meine 5 Drehwinkelgeber funktionieren durch irgendwelche Sachen in dem Code nicht richtig, heißt: Die Eingänge erfassen die Stromunterbrechung nicht korrekt. Am Anfang hat alles funktioniert, aber durch irgendwas jetzt nicht mehr.

Kann irgendjemand da nen Fehler erkennen oder hat einen besseren Vorschlag?

Danke schonmal und viele Grüße :smiley:

#include <Arduino.h>
#include <RotaryEncoder.h>
#include <Joystick.h>

byte val;

#define PIN_IN1 2
#define PIN_IN2 3
#define PIN_IN3 4
#define PIN_IN4 5
#define PIN_IN5 6
#define PIN_IN6 7
#define PIN_IN7 8
#define PIN_IN8 9
#define PIN_IN9 10
#define PIN_IN10 11

#define key_switch A0
#define AFB A1
#define Licht A2

#define serialprint 1 //Serielle Ausgaben "1" oder nicht "0"

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD,
  16,      // Anzahl Tasten
  0,      // Hat Switch Count
  true,   // X Achse
  true,   // Y Achse
  true,   // Z Achse
  false,  // Rx
  false,  // Ry
  false,  // Rz
  false,  // Ruder
  true,   // Throttle
  false,  // Accelerator
  true,   // Brake
  false); // Steering

RotaryEncoder *encoder1 = nullptr;
RotaryEncoder *encoder2 = nullptr;
RotaryEncoder *encoder3 = nullptr;
RotaryEncoder *encoder4 = nullptr;
RotaryEncoder *encoder5 = nullptr;

void checkPosition()
{
  encoder1->tick();
  encoder2->tick();
  encoder3->tick();
  encoder4->tick();
  encoder5->tick();
}

void setup()
{
  Serial.begin(9600);
  Serial1.begin(9600);
  while (!Serial)
    ;
  Serial.println("Programm startet...");

  pinMode(key_switch, INPUT_PULLUP);
  pinMode(AFB, INPUT_PULLUP);
  pinMode(Licht, INPUT_PULLUP);

  // use FOUR3 mode when PIN_IN1, PIN_IN2 signals are always HIGH in latch position.
  // encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);

  // use FOUR0 mode when PIN_IN1, PIN_IN2 signals are always LOW in latch position.

  // use TWO03 mode when PIN_IN1, PIN_IN2 signals are both LOW or HIGH in latch position.
  encoder1 = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);
  encoder2 = new RotaryEncoder(PIN_IN3, PIN_IN4, RotaryEncoder::LatchMode::FOUR3);
  encoder3 = new RotaryEncoder(PIN_IN5, PIN_IN6, RotaryEncoder::LatchMode::FOUR3);
  encoder4 = new RotaryEncoder(PIN_IN7, PIN_IN8, RotaryEncoder::LatchMode::FOUR3);
  encoder5 = new RotaryEncoder(PIN_IN9, PIN_IN10, RotaryEncoder::LatchMode::FOUR3);

  // register interrupt routine
  attachInterrupt(digitalPinToInterrupt(PIN_IN1), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN3), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN4), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN5), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN6), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN7), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN8), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN9), checkPosition, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_IN10), checkPosition, CHANGE);

  Joystick.begin();
  Joystick.setThrottleRange(-20, 20); //Gashebel(Fahrschalter)
  Joystick.setBrakeRange(-20, 20); //Bremse(Zugbremse))
  Joystick.setXAxisRange(-20, 20); //X-Achse(Führerbremsventil)
  Joystick.setYAxisRange(-20, 20); //Y-Achse(AFB)
  Joystick.setZAxisRange(-20, 20); //Z-Achse(Richtungsschalter)
} // setup()

// Read the current position of the encoder and print out when changed.
void loop()
{
  static int pos1 = 0;
  static int pos2 = 0;
  static int pos3 = 0;
  static int pos4 = 0;
  static int pos5 = 0;

  encoder1->tick(); // just call tick() to check the state.
  encoder2->tick();
  encoder3->tick();
  encoder4->tick();
  encoder5->tick();

  int newPos1 = encoder1->getPosition();
  int newPos2 = encoder2->getPosition();
  int newPos3 = encoder3->getPosition();
  int newPos4 = encoder4->getPosition();
  int newPos5 = encoder5->getPosition();

  //Daten von Arduino Leonardo (Schalter)
  if (digitalRead(AFB) == LOW) {
    Joystick.setButton(0, 1);
  } else {
    Joystick.setButton(0, 0);
  }
  if (digitalRead(Licht) == LOW) {
    Joystick.setButton(1, 1);
  } else {
    Joystick.setButton(1, 0);
  }

  //Seriellen Monitor von Arduino NANO
  if (Serial1.available()) {
    val = Serial1.read();
  }
  //Daten von Arduino NANO (Taster)
  if (val == 0b00000001) {//Sand
    Joystick.setButton(2, 1);
  } else {
    Joystick.setButton(2, 0);
  }
  if (val == 0b00000010) {//Tür rechts
    Joystick.setButton(3, 1);
  } else {
    Joystick.setButton(3, 0);
  }
  if (val == 0b00000011) {//Tür links
    Joystick.setButton(4, 1);
  } else {
    Joystick.setButton(4, 0);
  }
  if (val == 0b00000100) {//Tür zu
    Joystick.setButton(5, 1);
  } else {
    Joystick.setButton(5, 0);
  }
  if (val == 0b00000101) {//Makrofon
    Joystick.setButton(6, 1);
  } else {
    Joystick.setButton(6, 0);
  }
  if (val == 0b00000110) {//Hauptschalter
    Joystick.setButton(7, 1);
  } else {
    Joystick.setButton(7, 0);
  }
  if (val == 0b00000111) {//Stromabnehmer
    Joystick.setButton(8, 1);
  } else {
    Joystick.setButton(8, 0);
  }
  if (val == 0b00001000) {//Führerstandsbeleuchtung hoch
    Joystick.setButton(9, 1);
  } else {
    Joystick.setButton(9, 0);
  }
  if (val == 0b00001001) {//Führerstandsbeleuchtung runter
    Joystick.setButton(10, 1);
  } else {
    Joystick.setButton(10, 0);
  }
  if (val == 0b00001010) {//SIFA
    Joystick.setButton(11, 1);
  } else {
    Joystick.setButton(11, 0);
  }
  if (val == 0b00001011) {//PZB Befehl
    Joystick.setButton(12, 1);
  } else {
    Joystick.setButton(12, 0);
  }
  if (val == 0b00001100) {//PZB Frei
    Joystick.setButton(13, 1);
  } else {
    Joystick.setButton(13, 0);
  }
  if (val == 0b00001101) {//PZB Wachsam
    Joystick.setButton(14, 1);
  } else {
    Joystick.setButton(14, 0);
  }
  if (val == 0b00001110) {//ETCS quittieren
    Joystick.setButton(15, 1);
  } else {
    Joystick.setButton(15, 0);
  }
  val = 0;

  if (serialprint == 1) {
    if (pos1 != newPos1) {
      Serial.print("pos1:");
      Serial.print(newPos1);
      Serial.print(" dir1:");
      Serial.println((int)(encoder1->getDirection()));
      pos1 = newPos1;
    }
    if (pos2 != newPos2) {
      Serial.print("pos2:");
      Serial.print(newPos2);
      Serial.print(" dir2:");
      Serial.println((int)(encoder2->getDirection()));
      pos2 = newPos2;
    }
    if (pos3 != newPos3) {
      Serial.print("pos3:");
      Serial.print(newPos3);
      Serial.print(" dir3:");
      Serial.println((int)(encoder3->getDirection()));
      pos3 = newPos3;
    }
    if (pos4 != newPos4) {
      Serial.print("pos4:");
      Serial.print(newPos4);
      Serial.print(" dir4:");
      Serial.println((int)(encoder4->getDirection()));
      pos4 = newPos4;
    }
    if (pos5 != newPos5) {
      Serial.print("pos5:");
      Serial.print(newPos5);
      Serial.print(" dir5:");
      Serial.println((int)(encoder5->getDirection()));
      pos5 = newPos5;
    }
  }

  if (digitalRead(key_switch) == LOW) {
    Joystick.setThrottle(newPos1);
    Joystick.setBrake(newPos2);
    Joystick.setXAxis(newPos3);
    Joystick.setYAxis(newPos4);
    Joystick.setZAxis(newPos5);
  } else {
    Joystick.setThrottle(0);
    Joystick.setBrake(0);
    Joystick.setXAxis(0);
    Joystick.setYAxis(0);
    Joystick.setZAxis(0);
  }
  delay(50);
}

Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden. Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.

mfg ein Moderator.

Mechanisch (mit Prellen) oder elektronisch (ohne Prellen)?
Wie angetrieben?

Möchtest Du den Wert jedesmal in loop() überprüfen lassen, oder nur dann, wenn ein neuer Wert eingetroffen ist?

Die Baudraten sind etwas niedrig.

Was meinst du mit "Wie angetrieben"?

Und es müsste mechanisch sein, also er rastet ein.

Und Serial1 funktioniert einwandfrei.

Ich nutze ein Nano und ein Leonardo. Das Leonardo berechnet alles, das Nano stellt nur weitere Anschlüsse zur Verfügung, die dann über Binär Zahlen per Serial ans Leonardo gegeben werden.

Mein Problem liegt aber bei den Eingängen am Leonardo, dort werden die kurzen Stromunterbrechungen der Drehwinkelgeber nicht ordentlich erkannt. Nur, wenn man ganz langsam dreht, sodass die Unterbrechung länger ist.

An den Eingängen liegt es aber nicht, weil die mit dem Example einwandfrei funktionieren und es hat sich mit 5 Drehwinkelgebern funktioniert, bis ich irgendwas falsches gemacht habe.

Moin @zugprofi,

versuche mal, das

delay(50)

aus der loop() auszukommentieren.

Wenn eine Pause von 50 ms für bestimmte Funktionen benötigt wird, würde ich das über eine millis()-Funktion realisieren und so alle zeitkritischen Abläufe davon entkoppeln.

Ich hoffe, es hilft :slight_smile:

Hi. Danke für die Idee, habe mich jetzt einfach für Potis entschieden, die 5 Drehwinkelgeber und dann noch 20 Knöpfe auslesen ist dem Arduino einfach zu viel. Bei den Potis muss das Arduino ja nicht aktiv mitzählen, sondern kann auch wenn es sich verschluckt noch die V lesen.
Vie Grüße und danke für die Hilfe. :+1:

Kein Problem, gerne.

Der Vorteil der Potis sind natürlich die "absoluten" Drehwinkel und die Belegung von nur fünf Pins. Allerdings würde ich nicht davon ausgehen, dass die Aufgaben dem Arduino zu viel sind: Mit 50 ms "Nichtstun-Dürfen" pro loop() (!!!) nimmst Du ihm die Möglichkeit, das abzuarbeiten ... :wink:

Das Grundproblem hinter delay() kann Dich immer wieder einholen, insofern lohnt es sich m.E., sich mit dem Konzept der "Zeitscheiben" per millis()-Funktion zu befassen.

Auf jeden Fall viel Erfolg weiterhin!
Gruß
ec2021

P.S.: Ein kleiner Tipp, schau Dir das mal an:

DEBO BUTTON MTX: Entwicklerboards - Button Matrix, 16 Taster bei reichelt elektronik

8 Leitungen für 16 Buttons! (Per Matrix-Auswertung)

Ich habe mir (trotz Deiner neuen Lösung) mal den Spaß gemacht, eine Tastenmatrix zusammen mit den DrehEncodern in Wokwi nachzubilden:

Sketch:

#include <RotaryEncoder.h>

constexpr byte PIN_IN1 = A1;
constexpr byte PIN_IN2 = A0;
constexpr byte PIN_IN3 = A3;
constexpr byte PIN_IN4 = A2;
constexpr byte PIN_IN5 = A5;
constexpr byte PIN_IN6 = A4;
constexpr byte PIN_IN7 = 4;
constexpr byte PIN_IN8 = 5;
constexpr byte PIN_IN9 = 2;
constexpr byte PIN_IN10 = 3;

RotaryEncoder *encoder1 = nullptr;
RotaryEncoder *encoder2 = nullptr;
RotaryEncoder *encoder3 = nullptr;
RotaryEncoder *encoder4 = nullptr;
RotaryEncoder *encoder5 = nullptr;

// Tastaturmatrix
int reihe[] = {6, 7, 8, 9};
int spalte[] = {13, 12, 11, 10};
int col_scan;
int last_scan = -1;

void setup()
{
  Serial.begin(9600);
  for (int i = 0; i <= 3; i++)
  {
    //Initialisierung der PINs
    pinMode(reihe[i], OUTPUT);
    pinMode(spalte[i], INPUT);
    digitalWrite(spalte[i], HIGH);
  }
  encoder1 = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);
  encoder2 = new RotaryEncoder(PIN_IN3, PIN_IN4, RotaryEncoder::LatchMode::FOUR3);
  encoder3 = new RotaryEncoder(PIN_IN5, PIN_IN6, RotaryEncoder::LatchMode::FOUR3);
  encoder4 = new RotaryEncoder(PIN_IN7, PIN_IN8, RotaryEncoder::LatchMode::FOUR3);
  encoder5 = new RotaryEncoder(PIN_IN9, PIN_IN10, RotaryEncoder::LatchMode::FOUR3);
}

int pos1 = 0;
int pos2 = 0;
int pos3 = 0;
int pos4 = 0;
int pos5 = 0;

int Reihe;
int Spalte;

void loop()
{
  if (knopfGedrueckt(Reihe, Spalte)) {
    Aktion(Reihe, Spalte);
  }

  encoder1->tick(); // just call tick() to check the state.
  encoder2->tick();
  encoder3->tick();
  encoder4->tick();
  encoder5->tick();

  int newPos1 = encoder1->getPosition();
  int newPos2 = encoder2->getPosition();
  int newPos3 = encoder3->getPosition();
  int newPos4 = encoder4->getPosition();
  int newPos5 = encoder5->getPosition();

  if (true) {
    if (pos1 != newPos1) {
      Serial.print("pos1:");
      Serial.print(newPos1);
      Serial.print(" dir1:");
      Serial.println((int)(encoder1->getDirection()));
      pos1 = newPos1;
    }
    if (pos2 != newPos2) {
      Serial.print("pos2:");
      Serial.print(newPos2);
      Serial.print(" dir2:");
      Serial.println((int)(encoder2->getDirection()));
      pos2 = newPos2;
    }
    if (pos3 != newPos3) {
      Serial.print("pos3:");
      Serial.print(newPos3);
      Serial.print(" dir3:");
      Serial.println((int)(encoder3->getDirection()));
      pos3 = newPos3;
    }
    if (pos4 != newPos4) {
      Serial.print("pos4:");
      Serial.print(newPos4);
      Serial.print(" dir4:");
      Serial.println((int)(encoder4->getDirection()));
      pos4 = newPos4;
    }
    if (pos5 != newPos5) {
      Serial.print("pos5:");
      Serial.print(newPos5);
      Serial.print(" dir5:");
      Serial.println((int)(encoder5->getDirection()));
      pos5 = newPos5;
    }
  }
}

boolean knopfGedrueckt(int &Reihe, int &Spalte) {
  //Suche nach gedrücktem Knopf
  static boolean tasteGedrueckt = false;
  static unsigned long letzterDruck = 0;
  if (tasteGedrueckt && millis()-letzterDruck < 300) {  // Diese 300 ms verhindern, dass 
                                                        // der Tastendruck "prellt" bzw.
                                                        // schnell mehrfach hintereinander
                                                        // ausgeführt wird
    return false;
  }
  tasteGedrueckt = false;
  for (int i = 0; i <= 3; i++)
  {
    if (tasteGedrueckt) break;
    digitalWrite(reihe[0], HIGH);
    digitalWrite(reihe[1], HIGH);
    digitalWrite(reihe[2], HIGH);
    digitalWrite(reihe[3], HIGH);
    digitalWrite(reihe[i], LOW);

    for (int j = 0; j <= 3; j++)
    {
      col_scan = digitalRead(spalte[j]);
      if (col_scan == LOW)
      {
        letzterDruck = millis();
        tasteGedrueckt = true;
        Reihe  = i;
        Spalte = j;
        break;
      }
    }
  }
  return tasteGedrueckt;
}


void Aktion(int i, int j)
{
  int tasterNr = i*4+j+1;
  Serial.print("Taster Nr. ");
  Serial.print(tasterNr);
  Serial.print("\t");
  switch (tasterNr){
    case 1 : // Hier die Aktion für Taster 1
             Serial.println("Aktion für Taster 1");
        break;
    case 9 : // Hier die Aktion für Taster 9
             Serial.println("Aktion für Taster 9");
        break;
    case 16 : // Hier die Aktion für Taster 16
             Serial.println("Aktion für Taster 16");
        break;
    default: // und hier für alle eventuell nicht abgefangenen Tasternummern
             Serial.println("Hier ist noch keine Aktion hinterlegt ....");
        break;
  }
}

Vielleicht nützt es Dir (oder jemand anderem) ja mal irgendwie :wink: Auf jeden Fall erkennst Du sicher das eine oder andere aus Deinem Sketch oben wieder ...

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