Grundlagen eines Menüs

Hallo,

ich glaube man sollte das umdrehen. Erst die Steuerung programmieren und dann das Menü. Wenn man schnell zu Ergebnissen kommen möchte kann man die Bounce2 Lib für die Tasten verwenden.

Nun habe ich mich hinreißen lassen ein kleines Bsp. mit Encoder zu erstellen.
Das Ungewöhnliche ist noch bei den Encoderparametern die Port und Bit Angaben.
Mittels Pinouts sollte das jedoch kein Problem darstellen.
Da bin ich noch am überlegen wie ich die "CombiePin" am einfachsten nutzen kann.

Pinout Übersichten:
Board Pinout Überblick
UNO Pinout
Mega Pinout

In der Encoder Klasse findest du den Code von Peter Dannegger wieder aus dem Link zum Drehencoder.
Das mit der Menüauswahl und Tasterabfrage ist bewusst einfach gehalten und noch nicht perfekt. Soll nur ein Grundgedanke darstellen wie ich mir das vorstellen würde. Man könnte die Tasterabfrage noch zur Flankenerkennung umbauen oder eben Bounce2 verwenden, wem die Mehrfachausgabe während des drückens stört. Wie weit man das treibt muss jeder für sich ausmachen. Andere Menü Libs gibt es ja bereits.

class GrayEncoder       // Klassenname "GrayEncoder"
{
  protected:                    // private wird zu protected, nur intern zugängliche Elemente ...
    volatile byte const *PORT;  // verwendeter Port
    byte const PinA;            // Pin Port.Bit erste Phase
    byte const PinB;            // Pin Port.Bit zweite Phase
    int relMin;
    int relMax;
    byte shift;                 // Zählerkorrektur wegen Steps pro Rastung
    volatile long rel_counter;  // relativer Zähler
    volatile long abs_counter;  // absoluter Zähler, nicht veränderbar
    int enc_delta;
    int last;
    byte Phase_A;               // erste Phase
    byte Phase_B;               // zweite Phase
    long abs_old;

    int getPhases() {
      int n = 0;                      // new

      Phase_A = (*PORT >> PinA & 1);  // einzelnes Bit herausfischen
      Phase_B = (*PORT >> PinB & 1);

      if ( Phase_A ) n = 3;
      if ( Phase_B ) n ^= 1;          // convert gray to binary
      return n;
    }
    
    void update_RelativCounter () {
      long new_abs = abs_counter >> shift;          // halbiert, geviertelt ... Steps pro Rastung
      
      if ( new_abs != abs_old) {
        if (new_abs > abs_old) {
          rel_counter++;
        }
        else {
          rel_counter--;
        }
        abs_old = new_abs;
      }

      if (rel_counter < relMin) {
        rel_counter = relMax;
      }
      else if (rel_counter > relMax) {
        rel_counter = relMin;
      }
    }
    
  public:              // von außen zugängliche Elemente ...
        
    GrayEncoder (volatile byte *p_Port, byte _A, byte _B, int _max, byte _raster):
      // Initialisierungsliste
      PORT(p_Port),
      PinA(_A),
      PinB(_B),
      relMin(0),
      relMax(_max),
      shift(_raster/2),
      rel_counter(0),   // Zähler
      abs_counter(0),   // Zähler
      abs_old(0)
    { }
    
    void init()
    {
      last = getPhases();   // power on state
      enc_delta = 0;
    }

    void encode()
    {
      int n = getPhases();
      int diff = last - n;
      
      if ( diff & 1 )  {                        // bit 0 = value (1)
        last = n;                               // store new as next last
        enc_delta = (diff & 2) - 1;             // bit 1 = direction (+/-), Zähler
        abs_counter += (long) enc_delta;
      }
      update_RelativCounter();
    }
    
    long getRelCounter()  {return rel_counter; }  // relativen Zählwert abfragen, Rastung ist schon angepasst        
};


// ---------------------------------------------------------------------------------------

/*                        Port
                          |   Portbit Phase A                        
                          |   |  Portbit Phase B                        
                          |   |  |  Zählumfang
                          |   |  |  |  Steps pro Rastung                                        
                          |   |  |  |  |    */
GrayEncoder ALPS_EC11 (&PING, 1, 0, 8, 2);  // Port.G Bit.1 / Bit.0 / (Pin 40/41) / Zählumfang / Rastung

int ALPS_EC11_RelCounter;

const byte pin_Button = 2;    // Menüauswahl Bestätigung
bool state_Button = true;


void setup() {
  Serial.begin(9600);
  
  pinMode(40, INPUT_PULLUP);
  pinMode(41, INPUT_PULLUP);
  ALPS_EC11.init();

  pinMode(pin_Button, INPUT_PULLUP);
  
}

void loop() {

  update_Encoder();

  ausgabe();
  
  update_Taster();
  
  menue (ALPS_EC11_RelCounter, state_Button);
}


// ****** Funktionen ******

void update_Encoder ()
{
  ALPS_EC11.encode();
  ALPS_EC11_RelCounter = ALPS_EC11.getRelCounter();
}

void ausgabe()
{
  static int enc_old = 0;

  if (ALPS_EC11_RelCounter != enc_old) {
    enc_old = ALPS_EC11_RelCounter;
    Serial.println(ALPS_EC11_RelCounter);
  }
}


void update_Taster()
{
  static unsigned long last_ms = 0;
  const unsigned int DEBOUNCE = 40;             // Taster Entprellzeit
  
  if (millis() - last_ms < DEBOUNCE)  return;
  
  last_ms = millis();
  state_Button = digitalRead(pin_Button);
}


void menue (int number, bool state_Button)
{
  if (state_Button)  return;        // keine Änderung, Funktion verlassen
    
  switch (number) {
    case 0: Serial.println(F("Grundstellung"));
            break;
    case 1: Serial.println(F("Seite 1"));
            break;
    case 2: Serial.println(F("Seite 2"));
            break;
    case 3: Serial.println(F("Seite 3"));
            break;
    case 4: Serial.println(F("Seite 4"));
            break; 
    case 5: Serial.println(F("Seite 5"));
            break;
    case 6: Serial.println(F("Seite 6"));
            break;  
    default: Serial.println(F("ungueltige Nummer")); 
             break;            
  }
}