Grundlagen eines Menüs

Hallo Leute!

Ich hab erst diese Tage mit dem Thema Arduino angefangen, daher verzeiht mir bitte meine Verständnisprobleme. Da ich niemanden kenne der sich dabei auskennt, daher wende ich mich an euch.

Mein Projekt soll 3 Sauerstoffsensoren auslesen und die Daten anzeigen bzw. weiterverarbeiten.
Da ich diese auch kalibrieren muss, wollte ich ein Menü erstellen, in dem dann kalibriert werden kann.

Ich besitze ein Adafruit Feather M0 Proto Board und ein Featherwing 2,4" TFT-Display.
Dort hab ich einen Homescreen erstellt der mir die 3 Sensorwerte anzeigen soll und den Mittelwert daraus.
Abgesehen davon dass ich keine schöne Schrift habe die mit Background arbeitet funktioniert das alles soweit.

Nun zum Thema Menü.
Ich hab schon einige Freds von euch durch, allerdings sind da immer andere Sachen mit drinnen die ich nicht verstehe und daher verliere ich immer den Faden.

Mein Plan wäre eine Bedienung über zwei Taster.
Wenn ich im Homescreen bin und beide Tasten gleichzeitig drücke, dann komm ich ins Menü.
Dort kann ich dann mit den beiden Tastern auf und ab blättern und beide gleichzeitig gedrückt ist select.

Ist sowas einigermaßen einfach realisierbar?

Weiters kommt dann das Problem der Kalibrierung.
Dachte an eine 2-Punkt-Kalibrierung über einen map-Befehl.
Aber wie bekommt man diese Werte in den Flash?
Sollen ja erhalten bleiben auch nach dem Ausschalten.
Angeblich hat das Board EEPROM-Emulation. Aber wie?

Könnte mir mal jemand ein paar Tipps geben und die Grundlagen eines Menüs erklären?

Danke!

MfG
Schebi

Hallo?!

Keiner einen Tipp für mich?
:frowning:

Schau Dir mal das Menü von Jomelo an.

Gruß Tommy

Danke erstmal für deine Antwort.
Meinst du das hier:
Projekt: LCDMenuLib und LCDMenuLib2 (LCDML)

Ja

Das habe ich schon gefunden, aber da ist alles mit Lib's verschachtelt und da versteh ich dann kaum was.
Wie gesagt, ich bin noch am Anfang bei Arduino und versuche die Grundfunktionen zu verstehen.

Wenn ich Beispielsweise in meinem Loop eine Abfrage der Tasten mache, und beide gedrückt sind, dann kann ich auf ein Unterprogramm verweisen, das mein Menü ist. Gibt es irgendwelche Befehle für ein Menü?
Konnte in der Arduino-Referenz, die ich ganz brauchbar finde, nix dazu sehen.
Im Menü muss ich wohl eine Variable bestimmen, die meine Position bestimmt. Durch drücken der Tasten wird diese dann größer oder kleiner. So bewege ich mich auf und ab.

Oder so ähnlich!?

Was ich damit sagen will.
Ich hätte gerne gelernt wie man ein Menü erstellt, und nicht wie man fertige Libraries verwendet.
Die sind wiederum so umfangreich, dass man als Anfänger nicht durchblickt.
Da kommen Befehle vor die ich nicht kenne, aber auch nicht sagen kann ob es Library-bezogene Sachen sind, oder Standardbefehle die ich nur nicht kenne.

Wenn mir das jemand vermitteln könnte, dann wäre ich dankbar.

Für mich bitte so, als wenn man einem Kind erklärt wie es den Stift halten muss um auf einem Blatt papier zu malen. Aber auch erklären dass man nicht über den Rand malen darf, da sonst das Bild kaputt ist wenn man das Blatt anhebt.

Bin ich doof.....

Und jetzt darf gelacht werden.

Ich halte das Projekt: LCDMenuLib und LCDMenuLib2 (LCDML) für Anfänger ungeeignet.
Es ist bestimmt sehr ausgereift und kann eine Menge. Und der Support ist vorbildlich.

Ich halte sowas für einen Anfänger leichter zu verstehen.

Schebi:
Hallo?!

Keiner einen Tipp für mich?
:frowning:

Was verstehst du unter Grundlagen eines Menüs ?

Da jedes Menü anders aufgebaut ist und andere Funktionen beinhaltet, ist da schwer etwas drüber zu schreiben.

@ Hausknecht:

Danke für den Link, das werd ich mal genauer begutachten.

@ HotSystems:

Mir gehts um die Menüfunktion direkt.
Wie macht man ein Menü mit zwei Punkten zwischen denen ich hin und her springen kann und auswählen.
Die Punte sollten farblich hervorgehoben sein wenn man darüber steht.

Wie oben schon erwähnt mit zwei Tastern bedienbar.

So nebenbei, wie integriert ihr eure Codeschnipsel mitten im Post?

Gibt es irgendwelche Befehle für ein Menü

Als Teil eines Arduino - Betriebssystems?
Nein. Schon weil ein Arduino gar kein Display hat.

Dort kann ich dann mit den beiden Tastern auf und ab blättern und beide gleichzeitig gedrückt ist select.
Ist sowas einigermaßen einfach realisierbar?

Einfacher wären mehr Tasten, aber realisierbar ist es wohl


.

Text markieren, dann </> oben links
Oder von Hand [ code] und [/ code] davor und dahinter.

Hausknecht:
Ich halte sowas für einen Anfänger leichter zu verstehen.

Hallo,

zum Link, mit verlaub, dass ist totaler Schrott wenn ich das sagen darf.

TO:
bevor du dich überhaupt ans Menü programmieren begeben kannst, solltest du Grundlagen lernen. Wie fragst du prellfrei deine Taster ab. Wie zählt man auf Tastendruck hin eine Variable hoch und runter. Wie erkennt man den Tastendruck zweier Tasten. Wenn das klappt kannste dir Gedanken machen über deine Menüsteuerung. Für all das benötigst du noch kein Display. Serielle reicht aus.

Doc_Arduino:
zum Link, mit verlaub, dass ist totaler Schrott wenn ich das sagen darf.

Ich hab diesen Schrott in abgewandelter Form im Einsatz und bin damit zufrieden.

Ich muss als Anfänger verstehen was passieren soll und nachprüfen können, ob es dies auch tut.
So lerne ich. Wenn ich etwas nicht verstehe, dann kann es noch so genial sein, es bringt mir nichts.
Es ist ganz leicht etwas schlecht zu machen, aber es ist nicht so leicht etwas anfängergerechtes rüber zu bringen.

Wenn sich große Jungs unterhalten, dann sollte ich mich zukünftig besser raus halten.

Sei mein Held und zeige mir Anfänger wie ein Menue aussehen kann, das auch ein Anfänger versteht und kein Schrott ist.

Hallo,

ich bin wahrlich kein Profi, nur beschäftige ich mich schon länger mit Encoder auslesen. Die Grundlagen dafür gibts hier.
https://www.mikrocontroller.net/articles/Drehgeber

Beim Encoder auslesen kommt es darauf an, dass er auch bei mistigen Dingern noch sauber zählt. Das heißt ein Kontaktprellen kann man nicht unterdrücken, es darf nur den Encoderzähler nicht durcheinander bringen. Er darf mal kurz hin und her "pendeln" aber dabei keine wilden Sprünge machen oder dergleichen. Er korrigiert sich selbst.

Genau das sehe ich in dem Code von Wampo nicht. Darauf bezog sich meine Aussage. Wenn der Zähler funktioniert, dann ist ein kleines Menü auch nicht weit. switch-case wäre dein Freund. Und nein ich werde dir kein Menü bauen. Wenn du jedes Detail verstehen möchtest, dann musst du es selbst programmieren. Das ist auch nicht böse gemeint und ich möchte dich auch nicht ärgern, ich sage nur wie es ist.

Ich gebe dir recht, das Auslesen des Encoder hatte bei mir mit dem verlinkten Beispiel nicht geklappt. Ich habe sie dann durch eine Interrupt gesteuerte Abfrage ersetzt.

Dem TO ging es aber (so hatte ich das verstanden) um ein Menu und erst in zweiter Linie um die Steuerung . Die wollte er ja mit zwei Taster machen.

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;            
  }
}

Schebi:
So nebenbei, wie integriert ihr eure Codeschnipsel mitten im Post?

Das findest du hier.