Verwendung von CLI(), SEI() und "PIND" auf GIGA R1?

Hallo Zusammen!
In einem Projekt habe ich ein Beispiel-Sketch von Nick Gammon zur Auswertung eines Rotary Encoders auf einem AVR-Board (Arduino Nano) implementiert. Der Programmschnipsel nutzt basierend auf Interrupts die "commands" CLI() und SEI() zum aktivieren/deaktivieren der Interrupts, sowie zum Auslesen von PortPin Status den Befehl PIND.

Nun würde ich diesen Sketch gerne auf den neuen GIGA übertragen. Da Mbed OS CLI() und SEI() nicht kennt, wäre meine Frage, ob ich diese Befehle einfach so wie folgt ersetzten kann:

SEI() -> interrupts (); ?
CLI() -> noInterrrupts(); ?

Und ob es beim GIGA (Mbed OS) eine Alternative zur PinStatus-Abfrage mittels PIND gibt?

Ich würde mich über eure Hilfe sehr freuen, da ich noch blutiger Anfänger bin.

Nachfolgend das Beispiel, um welches es sich handelt:

/*******Interrupt-based Rotary Encoder Sketch*******
by Simon Merrett, based on insight from Oleg Mazurov, Nick Gammon, rt, Steve Spence
*/

static int pinA = 2; // Our first hardware interrupt pin is digital pin 2
static int pinB = 3; // Our second hardware interrupt pin is digital pin 3
volatile byte aFlag = 0; // let's us know when we're expecting a rising edge on pinA to signal that the encoder has arrived at a detent
volatile byte bFlag = 0; // let's us know when we're expecting a rising edge on pinB to signal that the encoder has arrived at a detent (opposite direction to when aFlag is set)
volatile byte encoderPos = 0; //this variable stores our current value of encoder position. Change to int or uin16_t instead of byte if you want to record a larger range than 0-255
volatile byte oldEncPos = 0; //stores the last encoder position value so we can compare to the current reading and see if it has changed (so we know when to print to the serial monitor)
volatile byte reading = 0; //somewhere to store the direct values we read from our interrupt pins before checking to see if we have moved a whole detent

void setup() {
  pinMode(pinA, INPUT); // set pinA as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  pinMode(pinB, INPUT); // set pinB as an input, pulled HIGH to the logic voltage (5V or 3.3V for most cases)
  attachInterrupt(0,PinA,RISING); // set an interrupt on PinA, looking for a rising edge signal and executing the "PinA" Interrupt Service Routine (below)
  attachInterrupt(1,PinB,RISING); // set an interrupt on PinB, looking for a rising edge signal and executing the "PinB" Interrupt Service Routine (below)
  Serial.begin(115200); // start the serial monitor link
}

void PinA(){
  cli(); //stop interrupts happening before we read pin values
  reading = PIND & 0xC; // read all eight pin values then strip away all but pinA and pinB's values
  if(reading == B00001100 && aFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    if (encoderPos > 0) encoderPos=encoderPos-5; //decrement the encoder's position count
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  }
  else if (reading == B00000100) bFlag = 1; //signal that we're expecting pinB to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void PinB(){
  cli(); //stop interrupts happening before we read pin values
  reading = PIND & 0xC; //read all eight pin values then strip away all but pinA and pinB's values
  if (reading == B00001100 && bFlag) { //check that we have both pins at detent (HIGH) and that we are expecting detent on this pin's rising edge
    if (encoderPos < 180) encoderPos=encoderPos+5; //increment the encoder's position count
    bFlag = 0; //reset flags for the next turn
    aFlag = 0; //reset flags for the next turn
  }
  else if (reading == B00001000) aFlag = 1; //signal that we're expecting pinA to signal the transition to detent from free rotation
  sei(); //restart interrupts
}

void loop(){
  if(oldEncPos != encoderPos) {
    Serial.println(encoderPos);
    oldEncPos = encoderPos;
    
  }
}

Aus https://content.arduino.cc/assets/Arduino-Portenta-H7_Datasheet_stm32h747xi.pdf:

Ich denke der Chip kann das in Hardware.

Danke schonmal für dieses sehr interessanten Hinweis! Ich werde mir diese Möglichkeit auf jeden Fall mal genauer ansehen. Mein Problem ist nur, dass ich insgesamt 6 Encoder habe, welche ich mit dem GIGA betreiben möchte... da wird es dann mit der Variante wieder etwas eng.

Vom GIGA R1 hatte ich bis eben keine Ahnung, Deine Fragen kann ich Dir daher leider nicht beantworten.

Allerdings frage ich mich, ob bei so leistungsfähiger Hardware wirklich Interrupts benötigt werden. Probiere mal meine Anleitung: Drehimpulsgeber (rotary encoder) KY-040 zur Eingabe, eventuell reicht das. Bei sechs Encodern dann in eine Klasse packen und sechsmal verwenden.

Die LPTIM* sollen auch encoder können. Schau mal ins Reference Manual (RM0399). Damit dürften das genug sein oder?

Hallo Agmue,
Vielen Dank für deine Antwort!
Ich habe gerade die einleitenden Worte deines Beitrags zum Thema KY-40 gelesen und du sprichst mir aus der Seele. Ich habe soviel gesucht und herum probiert und nichts gefunden, was zuverlässig funktionierte. Irgendwann bin ich dann auch vom Typ KY-40 weg, weil mich die Hardwarequalität des Bauteils nicht überzeugt hat (sehr viel "Spiel" in der Drehachse und sehr unpräzise, aber das ist ein anderes Thema). Softwaremäßig bin ich dann irgendwann auf den Programmschnipsel von N.Gammon gestoßen und dieser war der einzige, der für mich bis dato brauchbar funktioniert hat. Deine Anleitung hatte ich in meiner Recherche bisweilen noch nicht entdeckt. Deshalb bin ich schon gespannt dein Beispiel auszuprobieren!!
Du hast recht, vielleicht bedarf es bei so hoher Taktung gar keiner Interrupts mehr - obwohl noch jede Menge an Code dazukommen wird. Der Tip mit der Klasse ist auf jeden Fall gut - ich werde es testen! Herzlichen Dank für deine Mühe und die Ideen!

Hallo

Ich habe diese Dinger irgendwo mit einem I²C Bus gesehen.

Einfach mal die Suchmaschine starten.

I

Das hier?

Da gäbe es zumindest schonmal 5 davon (LPTIM*)... Hab mir das RF0399 mal runtergeladen. Mal schauen ob ich da was finde. DANKE!

Okay, das ist auch spannend, ist auch ne überlegbare Alternative! Danke!

Ich glaube, sowas in der Art hat paulpaulson gemeint. Danke für den Link - gibt viel zu testen :slight_smile:

Bitte gerne :slightly_smiling_face:

Die Ausführungen von N. Gammon sind lesenswert, beziehen sich aber verständlicherweise auf AVRs.

Einen schlechten weil blockierenden Programmierstil durch Interrupts kaschieren zu wollen, kommt in diesem Forum leider nicht selten vor, willst Du aber nicht :wink:

Sind die sechs Encoder an einer Motorachse oder für manuelle Bedienung? Sitzen Kopffüßler davor wie bei "Man in Black" oder Humanoide mit nur zwei Händen? Für die Datenrate macht das einen entscheidenden Unterschied.

Bei meinem MP3-Player mußte ich lernen, daß IR-Fernbedienung und andere zeitkritische Programmteile nicht zusammenpassen. Daher habe ich die IR-Bibliothek in einen ATtiny85 verlegt und mittels I²C mit dem UNO verbunden. Für Dich also die Idee der verteilten Hardware.

Dazu habe ich im Thema Lichtpultsoftware Fernbedienung mit Drehencoder und Programmierbaren Tasten über USB den MCP23017 erfolgreich mit einem Drehencoder verbunden. Das Programm funktioniert mit der aktuellen Bibliothek nur nach Anpassungen und inzwischen würde ich vorrangig mit einem MCP23S17 probieren, weil schneller, aber der Interrupt ist unabhängig von "Pausen" in Deinem Programm. Mit dem MCP23S17 konnte in einem anderen Thema der kurze Kontakt eines Dartpfeils erkannt werden.

Ich habe keine sechs Encoder, Probieren wäre angesagt :slightly_smiling_face:

Grundsätzlich kannst Du auch einen anderen µC verwenden. Ich probiere gerade den ESP32 aus, der hat eine Menge Interrupts, ist schnell und hat ein paar Schnittstellen, beispielsweise UART2 (Serial2).

Bei ESP32 und MCP23S17 könnte ich unterstützen, die habe ich auf meinem Steckbrett. Weitere Hardware sehe ich aber nur als Plan B, C oder D.

Immer mal wieder sehe ich die Verwendung von #include <util/atomic.h>, beispielsweise im Thema Programmierfehler Zeit zwischen Interrupts , um das Zersplittern von Variablen durch Interrupts zu verhindern. Gibt es sowas auch für GIGA R1?

Im deutschsprachigen Teil tummeln sich nur ein paar Aktive aus DACH, international gibt es eventuell auch welche, die den GIGA R1 kennen. Solltest Du in den internationalen Teil wechseln, wäre eine Verweisung zwischen den Themen sinnvoll und vermeidet den Vorwurf des Doppelpostings. Sicherlich hilft man Dir bei der Wahl der richtigen Kategorie, denn manche deutschsprachigen Aktiven sind auch international aktiv.

Erstmal vielen Dank für die nützlichen Infos!

Genau das ist es, ich will auf jeden Fall einen blockierenden Programmierstil verhindern und muss es auch. Vielleicht ein paar Hintergrund-Infos zu meinem Projekt.

Zusammen mit einem Kumpel habe ich eine Tennisballmaschine gebaut, welche ein Leistungsspektrum bedient, wie uns diese vorstellen. Der Prototyp war vor etwa 2 Jahren fertig und ist auch erfolgreich im Einsatz.

Nun wollen wir aber eine verbesserte Version davon bauen.

    • Kleiner, leichter und handlicher und in vielem optimierter
    • noch präzisere Technik bei den Motoren und deren Steuerung
    • moderne tageslichttaugliche Grafikdisplays statt (LCD 20x4)
    • zusätzliche Steuerungsmöglichkeit mittels APP(IOS).
    • usw.

In der ersten Version habe ich das genau so gemacht, nämlich meine „Probleme“ in Hardware verteilt. Genau davon wollte ich eigentlich weg, da die Devise ja lautet: Abspecken! Den GIGA fand ich dafür als Eierlegendewollmilchsau sehr attraktiv. Bietet mehrere I2C Busse an (für insgesamt 2 Displays: uniTFT 2.8“) und externen FRAM.

Er bietet WIFI/BLE und quasi unbegrenzte GPIOs und Interruptpins.

Es werden insgesamt 2 DC-Motoren, 2 Servomotoren und ein Stepper angesteuert. Programmblockaden wären also Gift für die Steuerung der Servos bzw. des Steppers. Alleine die Aktivierung des Seriellen Monitors für Debuggingzwecke gefällt den Servos beispielsweise so gar nicht. Deshalb muss alles aalglatt werden. J

In der Version 1.0 unserer Maschine habe ich die Einstellungsmöglichkeiten über Potis umgesetzt. Diese möchte ich nun gerne gegen die Encoder ersetzen, zumal es ein riesen Thema war, die leichten Spannungsschwankungen am jeweiligen Analogeingang so gering wie möglich zu halten um das „Flickern“ der Potis zu minimieren (Thema: Masseschleifen, Spannungsregelerschwankungen, etc.). Hauptgrund ist aber - warum ich auf Drehgeber umsteige - dass ich die durch Encoder einstellbaren Variablen ohneweiters gut von Außen verändern kann beispielsweise über die APP. Das ist mit dem Poti natürlich nicht so schön zu lösen, weil ich die Reglereinstellung des Potis ja einen starren Wert vorgibt.

Es sollen dabei insgesamt 6 Rotary Encoder als Bedienelemente für Motoreinstellungen zum Einsatz kommen. D.h. es sitzen da keine 6-armigen Kracken, welche alle Knöpfe gleichzeitig drehen. In der Regel wird ein Regler nach dem anderen bedient um entsprechende Einstellungen vorzunehmen.

Ich habe erst angefangen mich mit Arduino’s zu beschäftigen, als wir zur Corona-Hochzeit die Idee hatten, so eine Ballmaschine zu bauen. Meine ersten Erfahrungen damit reiften im Zuge dessen soweit, dass ich die Maschine in Version 1.0 an‘s Laufen bekam. Das neue Vorhaben, erfordert nun aber auch meine programmiertechnische Weiterentwicklung, von daher sauge ich im Moment alles Nützliche auf. Bisher war ich stiller Leser dieses Forums. Nun musste ich aber aus meiner „Deckung“ heraus und auch mal meinen Hut in den Ring werfen. Ich werde auf jeden Fall das Thema GIGA auch nochmal in die Internationale Gruppe adressieren. Ich muss mal gucken, wie das mit der Verweisung geht, da ich mir keinen einfangen möchte. Also danke für den Tipp :slight_smile:

Einfach einen Link auf den jeweils anderen Thread setzen (Oben die 2 Kettenglieder - 4. Symbol)

Gruß Tommy

Ach klasse - super! Danke vielmals für den Hinweis :pray:

Hallo agume,

Ich hatte deinen Sketch zum Thema Rotary Encoder mal ausprobiert und ich muss sagen, ich bin begeisterst ob der guten und zuverlässigen Funktionalität, sodass ich meine bisherig favorisierte Variante (über Interrupts) gerne durch deine Lösung ersetzen möchte!

Anleitung: Drehimpulsgeber (rotary encoder) KY-040 zur Eingabe

Nun wollte ich mal testen, wie gut das klappt, wenn man bis zu 6 Rotary Encoder „gleichzeitig“ betreibt. Dafür habe ich deinen Hinweis „alles in eine Klasse packen“ versucht aufzugreifen. Da ich bisher noch nie etwas mit Klassen gemacht habe, ist dieses Unterfangen für mich leider noch etwas neu und undurchsichtig.
Um die Klasse zu testen, habe ich für den Anfang mal 2 Rotary Encoder an einen Arduino (Pro Mini) angeschlossen. Wenn ich erstmal nur Encoder_1 betreibe (also die „counterAuswertung“ meines Encoder_2 in der void loop () auskommentiert lasse) funktioniert Encoder_1 wie gehabt. Sobald ich aber Encoder_2 mit ins Spiel bringe, klappt es nicht mehr. Ich bin mir dessen bewusst, dass ich vermutlich einen katastrophalen Schnitzer drin habe, zurückzuführen auf noch vorhandene Verständnisfehler. Nur leider komme ich mit Lesen, Tutorials und Try & Error nicht mehr weiter. Vielleicht fällt dir „im Nu“ auf, wo ich versagt habe? 

Mir ist klar, dass die Routine "counterAuswertung" der einzelnen Encoder (in der void loop () ) auch noch irgendwie so verpackt werden muss, um doppelten Code zu minimieren. Das wird dann meine nächste Hürde. :sweat_smile:

Natürlich freue ich mich auch über produktive Hinweise von anderen Lesern dieses Posts.

Thanks in Advance.

// EncoderTest mit Klassen

class EncoderAuswertung
{
  private:
    const byte ENCODER_A_PIN;
    const byte ENCODER_B_PIN;
    const byte SWITCH_PIN;

  public:
    EncoderAuswertung (byte ENCODER_A_PIN, byte ENCODER_B_PIN, byte SWITCH_PIN) :
      ENCODER_A_PIN{ENCODER_A_PIN},
      ENCODER_B_PIN{ENCODER_B_PIN},
      SWITCH_PIN{SWITCH_PIN}
    {}

    void begin() {
      pinMode(ENCODER_A_PIN, INPUT);
      pinMode(ENCODER_B_PIN, INPUT);
      pinMode(SWITCH_PIN, INPUT);
  }

    bool rotaryEncoder(int8_t &delta) {
      delta = 0;
      enum {STATE_LOCKED, STATE_TURN_RIGHT_START, STATE_TURN_RIGHT_MIDDLE, STATE_TURN_RIGHT_END, STATE_TURN_LEFT_START, STATE_TURN_LEFT_MIDDLE, STATE_TURN_LEFT_END, STATE_UNDECIDED};
      static uint8_t encoderState = STATE_LOCKED;
      bool a = !digitalRead(ENCODER_A_PIN);
      bool b = !digitalRead(ENCODER_B_PIN);
      bool s = !digitalRead(SWITCH_PIN);
      static bool switchState = s;
      switch (encoderState) {
        case STATE_LOCKED:
          if (a && b) {
            encoderState = STATE_UNDECIDED;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_LEFT_START;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_RIGHT_START;
          }
          else {
            encoderState = STATE_LOCKED;
          };
          break;
        case STATE_TURN_RIGHT_START:
          if (a && b) {
            encoderState = STATE_TURN_RIGHT_MIDDLE;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_RIGHT_END;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_RIGHT_START;
          }
          else {
            encoderState = STATE_LOCKED;
          };
          break;
        case STATE_TURN_RIGHT_MIDDLE:
        case STATE_TURN_RIGHT_END:
          if (a && b) {
            encoderState = STATE_TURN_RIGHT_MIDDLE;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_RIGHT_END;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_RIGHT_START;
          }
          else {
            encoderState = STATE_LOCKED;
            delta = -1;
          };
          break;
        case STATE_TURN_LEFT_START:
          if (a && b) {
            encoderState = STATE_TURN_LEFT_MIDDLE;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_LEFT_START;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_LEFT_END;
          }
          else {
            encoderState = STATE_LOCKED;
          };
      break;
        case STATE_TURN_LEFT_MIDDLE:
        case STATE_TURN_LEFT_END:
          if (a && b) {
            encoderState = STATE_TURN_LEFT_MIDDLE;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_LEFT_START;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_LEFT_END;
          }
          else {
            encoderState = STATE_LOCKED;
            delta = 1;
          };
          break;
        case STATE_UNDECIDED:
          if (a && b) {
            encoderState = STATE_UNDECIDED;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_RIGHT_END;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_LEFT_END;
          }
          else {
            encoderState = STATE_LOCKED;
          };
          break;
      }

  uint32_t current_time = millis();
  static uint32_t switch_time = 0;
  const uint32_t bounce_time = 30;
  bool back = false;
  if (current_time - switch_time >= bounce_time) {
    if (switchState != s) {
      switch_time = current_time;
      back = s;
      switchState = s;
    }
  }
  return back;
}
};


int counter_DIR=90;
int counter_SPEED=90;

byte fullRange=180;
byte stepSize1=5;
byte stepSize2=10;
byte defaulPosition=90;



EncoderAuswertung encSPEED (6,5,7);
EncoderAuswertung encDIR (3,2,4);


void setup() {

  Serial.begin(115200);
  Serial.println("\nStart");

  encDIR.begin();
  encSPEED.begin();
}

void loop() {

//---------------------------------------- Beginn couterAuswertung ENCODER_1
  int8_t state_DIR = 0;
  if (encDIR.rotaryEncoder(state_DIR)) {
    counter_DIR=defaulPosition;
  }
  if (state_DIR == -1) {
    if (counter_DIR <= 0){                     
     counter_DIR = 0;
    }
    else {
    counter_DIR=counter_DIR-stepSize1;
    }
  }
  if (state_DIR == 1) {
    if (counter_DIR >= fullRange){
     counter_DIR = fullRange;
    }
    else {
    counter_DIR=counter_DIR+stepSize1;
    }
  }
//---------------------------------------- Ende counterAuswertung ENCODER_1

/*
//---------------------------------------- Beginn counterAuswertung ENCODER_2
  int8_t state_SPEED = 0;
  if (encSPEED.rotaryEncoder(state_SPEED)) {
    counter_SPEED=defaulPosition;
  }
  if (state_SPEED == -1) {
    if (counter_SPEED <= 0){
     counter_SPEED = 0;
    }
    else {
    counter_SPEED=counter_SPEED-stepSize2;
    }
  }
  if (state_SPEED == 1) {
    if (counter_SPEED >= fullRange){
     counter_SPEED = fullRange;
    }
    else {
    counter_SPEED=counter_SPEED+stepSize2;
    }
  }
//---------------------------------------- Ende couterAuswertung ENCODER_2
*/

Serial.print ("Counter_SPEED: ");
Serial.print (counter_SPEED);
Serial.print ("    Counter_DIR: ");
Serial.println (counter_DIR);
  
}

Durch einen dummen Fehler meinerseits habe ich in Deinem Programm vermutlich mehr geändert, als notwendig gewesen wäre, weshalb ich die Ursache auch nicht benennen kann, aber bei diesem Programm funktionieren nun beide Encoder.

EncoderTest mit Klassen
class EncoderAuswertung
{
  private:
    const byte ENCODER_A_PIN;
    const byte ENCODER_B_PIN;
    const byte SWITCH_PIN;
    uint8_t encoderState;
    bool switchState;
    uint32_t switch_time = 0;
  public:
    EncoderAuswertung (const byte ENCODER_A_PIN, const byte ENCODER_B_PIN, const byte SWITCH_PIN) :
      ENCODER_A_PIN(ENCODER_A_PIN),
      ENCODER_B_PIN(ENCODER_B_PIN),
      SWITCH_PIN(SWITCH_PIN),
      encoderState(0),
      switchState(HIGH),
      switch_time(0)
    {}

    void begin() {
      pinMode(ENCODER_A_PIN, INPUT);
      pinMode(ENCODER_B_PIN, INPUT);
      pinMode(SWITCH_PIN, INPUT);
    }

    bool rotaryEncoder(int8_t &delta) {
      delta = 0;
      enum {STATE_LOCKED, STATE_TURN_RIGHT_START, STATE_TURN_RIGHT_MIDDLE, STATE_TURN_RIGHT_END, STATE_TURN_LEFT_START, STATE_TURN_LEFT_MIDDLE, STATE_TURN_LEFT_END, STATE_UNDECIDED};
      bool a = !digitalRead(ENCODER_A_PIN);
      bool b = !digitalRead(ENCODER_B_PIN);
      bool s = !digitalRead(SWITCH_PIN);
      switch (encoderState) {
        case STATE_LOCKED:
          if (a && b) {
            encoderState = STATE_UNDECIDED;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_LEFT_START;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_RIGHT_START;
          }
          else {
            encoderState = STATE_LOCKED;
          };
          break;
        case STATE_TURN_RIGHT_START:
          if (a && b) {
            encoderState = STATE_TURN_RIGHT_MIDDLE;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_RIGHT_END;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_RIGHT_START;
          }
          else {
            encoderState = STATE_LOCKED;
          };
          break;
        case STATE_TURN_RIGHT_MIDDLE:
        case STATE_TURN_RIGHT_END:
          if (a && b) {
            encoderState = STATE_TURN_RIGHT_MIDDLE;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_RIGHT_END;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_RIGHT_START;
          }
          else {
            encoderState = STATE_LOCKED;
            delta = -1;
          };
          break;
        case STATE_TURN_LEFT_START:
          if (a && b) {
            encoderState = STATE_TURN_LEFT_MIDDLE;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_LEFT_START;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_LEFT_END;
          }
          else {
            encoderState = STATE_LOCKED;
          };
          break;
        case STATE_TURN_LEFT_MIDDLE:
        case STATE_TURN_LEFT_END:
          if (a && b) {
            encoderState = STATE_TURN_LEFT_MIDDLE;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_LEFT_START;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_LEFT_END;
          }
          else {
            encoderState = STATE_LOCKED;
            delta = 1;
          };
          break;
        case STATE_UNDECIDED:
          if (a && b) {
            encoderState = STATE_UNDECIDED;
          }
          else if (!a && b) {
            encoderState = STATE_TURN_RIGHT_END;
          }
          else if (a && !b) {
            encoderState = STATE_TURN_LEFT_END;
          }
          else {
            encoderState = STATE_LOCKED;
          };
          break;
      }

      uint32_t current_time = millis();
      const uint32_t bounce_time = 30;
      bool back = false;
      if (current_time - switch_time >= bounce_time) {
        if (switchState != s) {
          switch_time = current_time;
          back = s;
          switchState = s;
        }
      }
      return back;
    }
};

/*
int counter_DIR = 90;
int counter_SPEED = 90;

byte fullRange = 180;
byte stepSize1 = 5;
byte stepSize2 = 10;
byte defaulPosition = 90;
*/
EncoderAuswertung encSPEED (6, 5, 7);
EncoderAuswertung encDIR (3, 2, 4);

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("\nStart");

  encDIR.begin();
  encSPEED.begin();
}

void loop() {
  int8_t state_DIR = 0;
  if (encDIR.rotaryEncoder(state_DIR)) {
    Serial.println("- SWITCH_DIR -");
  }
  if (state_DIR == -1) {
    Serial.println("<--DIR ");
  }
  if (state_DIR == 1) {
    Serial.println(" DIR-->");
  }
  
  int8_t state_SPEED = 0;
  if (encSPEED.rotaryEncoder(state_SPEED)) {
    Serial.println("- SWITCH_SPEED -");
  }
  if (state_SPEED == -1) {
    Serial.println("<--SPEED ");
  }
  if (state_SPEED == 1) {
    Serial.println(" SPEED-->");
  }
}
1 Like

Hallo agmue,
erstmal sorry für meinen Fingertrouble in der Anrede meiner letzten Nachricht.

Tausend Dank für deine Mühe!!!

Ich bin wahnsinnig happy über die Lösung! Sie funktioniert wirklich astrein! Um ehrlich zu sein sogar besser als die Interrupt-Variante, welche ich bisher hatte. Werde das Programm jetzt mal ausdehnen auf meine insgesamt 6 Encoder.

Aufgrund von Problemen beim login mit meinem alten Account musste ich diesen löschen und neu anlegen. Deshalb weiß ich nicht genau, ob ich den Thread nun von meinem neuen Account als "gelöst" schließen kann. Ich versuche es auf jeden Fall.

Ich weiß eure Hilfe hier wirklich sehr zu schätzen und ich habe großes Respekt davor, dass Koryphäen wie du sich die Zeit nehmen, um Leuten wie mir auf die Beine zu helfen!
Ein ganz großes Dankeschön dafür!

LG, hg

Bitte sei so gut und berichte :slightly_smiling_face:

Eher nicht, aber eventuell kann unser hilfsbereiter Moderator @uwefed das Thema irgendwie als "gelöst" kennzeichnen.

Bitte sei so gut und berichte :slightly_smiling_face:

Soooo, ich habe den Sketch nun mit 6 Encoder penetriert und ich bin vollends begeistert! Es läuft ohne Probleme! Vermutlich könnte man gefühlt auch 30 Encoder ohne Weiteres damit betreiben und ein Mischpult daraus basteln. :slightly_smiling_face:
Zwar habe ich noch keinen weiteren Code implementiert, aber solange zusätzlicher Programmcode nichtblockierend ist, wird das die Funktionalität der Encoder vermutlich auch nicht negativ beeinflussen.

Fazit:
Jedem, der bisher an den unterschiedlichsten Drehgeber-Programmbeispielen verzweifelt ist, dem kann ich Lösung von dir agmue nur wärmstens empfehlen. Echt TOP!

https://forum.arduino.cc/t/anleitung-drehimpulsgeber-rotary-encoder-ky-040-zur-eingabe/670810

Zur Ausgangsfrage dieses Threads:

Verwendung von CLI(), SEI() und PIND auf GIGA R1?

CLI() und SEI() können nicht nur, sondern sollten sogar durch noInterrupts() und Interrupts() ersetzt werden, da diese fester Bestandteil der Arduino API sind, wie ich gelernt habe.

Für jene, die für PIND (Auslesen eines Portstatus (Port D) in AVR) nach einer Alternative in Mbed OS suchen, werden beim Befehl (GPIOD->IDR & 0xC) fündig.

Ich würde mich sehr freuen, wenn @uwefed so lieb wäre, und diesen Thread als "gelöst" kennzeichen könnte, da es mir leider nicht möglich ist. Danke!