Hilfe bei der Menüstruktur

Hallo zusammen, Erst mal zu meinem Projekt: Ich möchte einen automatischen Cocktailmischer bauen und ihn via Arduino uno steuern. Mechanisch habe ich jetzt schon einiges getan, sodass ich dachte, dass ich mich mal an die Programmierung wagen muss. Ich möchte 2 Taster benutzen: einen für die Getränkeauswahl und den anderen um den Vorgang in Gang zu setzen. Welcher Cocktail ausgewählt ist, soll auf einem LCD Display angegeben werden. Ist ein Cocktail ausgewählt fährt ein Schrittmotor (Adafruit Motorshield) die Flaschen an und befüllt das Glas mittels Hubmechanik. Ich habe schon einen Sketch im Internet gefunden, welchen ich gerne für meine Zwecke umändern möchte. Hier ist aber mein Problem, das ich nicht so recht weiß wie :/ Ich würde in dem Code gerne die LEDs und den Temp. Sensor rausnehmen und dafür meine verschiedenen Positionen eingeben. Als alternativen Code hätte ich noch den da:

http://www.coagula.org/content/pages/tutorial-manage-menu-and-lcd-display-arduino

aber da bekomme ich eine Fehlermeldung, welche ich einfache nicht wegbekomme... deswegen vorzugsweise den ersten Sketch. Fehler:

error: 'menuUsed' was not declared in this scope

error: 'menuChanged' was not declared in this scope

exit status 1 'menuUsed' was not declared in this scope

Erster Sketch: https://codebender.cc/sketch:184576#Rotary%20encoder%20menu%20part%202.ino (der Sketch ist leider zu lange um ihn hier zu posten, daher der Link)

Ich hoffe mir kann jemand einen Schubs in die Richtige Richtung geben, damit das Projekt nicht an der Programmierung scheitert ;)

Gruß

André

Hallo André,

ich schaue mir mal den Code an und gebe dir feedback, wenn ich damit zurecht komme. Habe selbst gerade ein kleines Menü mit Arduino, Rotary und LCD geschrieben; ist aber sehr speziell und (noch) nicht sehr übersichtlich geschrieben, tut aber das, was es soll.

Mal sehen, vielleicht ist der Codebender-Ansatz auch für mich etwas übersichtlicher und besser zu modifizieren, wenn man nachträglich neue Ideen zur Verschlimmbesserung hat.

Melde mich in Kürze wieder; momentan noch mit anderen Projekten beschäftigt.

Hi André,

habe mal beide sketche geladen und getestet. Beim "coagula.org"-sketch kommt auch bei mir besagte Fehlermeldung. Kann sein, dass entweder die aktuellen IDE's etwas kritischer sind (der sketch ist schon etwas älter) oder, dass ich eine andere backendmenu lib geladen habe. Den Hinweis, ab Zeile xyz einen kleinen Code in die lib einzukopieren, habe ich beachtet, nutzt aber nichts und ich habe weder Zeit noch Lust, mich damit auseinanderzusetzen.

Den anderen Sketch habe ich auch nicht ganz ans Laufen gebracht. Die Temperaturabfrage ist raus, aber der Rotary-Encoder wird nicht sauber abgefragt. Ist auch eine ganz simple rotary-Routine drin, die wahrscheinlich mit meinem Drehencoder (ist ein ganz billiger für unter 5€) nicht zusammenspielt.

Auch die Buttonabfrage lief erst, nachdem ich die debounce time von 200ms auf 50ms runtergesetzt hatte. Bevor ich mich weiter mit deinem Thema beschäftige:

Du schreibst, du willst eigentlich mit nur 2 Buttons alles regeln. Das ist aber, wenn du ein Menü durchlaufen willst, etwas mühsam, wenn ich mir vorstelle, dass du mal so ca. 10-12 verschieden Cocktails mixen willst. Dann drückst du dich zum Äffchen, um von 1 nach 12 zu kommen. Der 2. Button ist dann die ganze Zeit arbeitslos und wird nur benötigt, um die Auswahl zu bestätigen, wenn ich dich richtig verstanden habe?

Einfacher wäre es, anstelle der 2 Buttons tatsächlich den Ansatz mit einem Rotary-Encoder zu machen. Hier kann ich mir vorstellen, dass du mit dem Drehknopf durch das Menü scrollst und mit dem "eingebauten" Button dann die angezeigte Auswahl bestätigst und den Mix-Vorgang in Gang setzt.

Wenn ich das dann richtig wiedergegeben habe, was du vorhast, kann ich wahrscheinlich eine Subroutine von einem meiner Projekte etwas umbauen, damit du dann einen Ansatz hast. Und - ein Menü mit einem Rotary-Encoder ist schon was Feines, wenn es denn funktioniert.

Gib mir bitte ein feedback damit ich weiß, ob ich dir mit meinem Ansatz weiterhelfen kann.

Hallo, ich würde 3 Taster nehmen. Vor- Zurück und Auswahl. Dann mit SwitchCase. Gruß und Spaß Andreas

Als Alternative gibt es noch dieses Menü. LCD-Menü Das funktioniert und ist sehr ausbaufähig.

Das geht wahlweise mit Tasten oder auch Drehencoder.

@HotSystems:

Als Alternative gibt es noch dieses Menü. LCD-Menü Das funktioniert und ist sehr ausbaufähig.

Das geht wahlweise mit Tasten oder auch Drehencoder.

Daran hatte ich auch schon gedacht, als ich mein Menü mit Rotary geschrieben habe; vor ein paar Monaten war ich aber absoluter Laie und kam mit der Library überhaupt nicht zurecht, da noch die jetzt vorhandene Beschreibung - und mir die Zeit und auch das Verständnis zum Einlesen in "Fremd-Code" fehlte, vor allem, wenn das Ding so mächtig ist.

Deshalb habe ich nach einfacheren, wenn auch nicht so universell einsetzbaren Ansätzen gesucht und habe mich durch tonnenweise Rotary-Encoder Sketche gewühlt, bis ich etwas mehr verstanden habe und mein Projekt damit realisieren konnte.

@andrearduino:

Hier mein versprochener Ansatz für dein Projekt.
Beachte, dass ich einen ganz einfachen Rotary-Drehencoder mit Switch verwende und ohne jegliche zusätzliche Hardware (Entprellkondensatoren etc.) auskomme. Das funktioniert dank der super library von Ben Buxton.

Die von mir verwendete library hatte ich vor einiger Zeit mal im Netz gefunden; die Seite von Ben Buxton enthält eine Version, die den Button nicht unterstützt; ich habe aber seinerzeit eine ergänzte Version gefunden, die sowohl den Rotary Encoder als auch den Button in einer library unterstützt. Du kannst x-beliebige Pins verwenden, es müssen keine Interrupt-Pins sein. Der Algorithmus der Buxton library ist m.E. so ziemlich das beste, was man für billige Drehencoder finden kann, aber mache dir selbst ein Bild.

Du musst wahrscheinlich die Einbindung deines LCD Screens anpassen, da ich wegen chronischem Pin-Mangel bei meinen Projekten die LCDs mittels I2C anspreche. Da gehen dann nur 2 Pins drauf.

Hier der Test-Code, der bei mir einwandfrei läuft und im Anhang die Rotary library.
Viel Spaß beim Testen.

Raimund

/* Cocktail Production - Menu Test Sketch
 *  Created by VulkanDesign.com 
 *  Free to use -> but: pls pay attention to the copyrights of the included libraries
 *  Granted by Dipl.-Ing. Raimund P. Trierscheid
 */


/* Rotary encoder handler for arduino.

   Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3.
   Contact: bb@cactii.net

   Quick implementation of rotary encoder routine.

   More info: http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html

*/
// Include the library code
#include <Wire.h>                   // needed for I2C communication
#include <LiquidCrystal_I2C.h>      // LCD with I2C adapter
#include <rotary.h>                 // rotary handler

/*  maybe for later enhancements
  #include <EEPROMex.h>
  #include <EEPROMVar.h>
  #include <OneButton.h>
*/





// Initialize the Rotary object
// Rotary(Encoder Pin 1, Encoder Pin 2, Button Pin) Attach center to ground
Rotary r = Rotary(3, 4, 2);        // there is no must for using interrupt pins !!
// Half-step mode
#define HALF_STEP

// Define I2C_LCD
LiquidCrystal_I2C  lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);


// Define your cocktail information

int maxNumber = 12;
char* myCocktails[] = {
  "Manhattan",
  "Gin Tonic",
  "Old Fashion",
  "Singapore Sling",
  "Pina Colada",
  "Mai Tai",
  "Bloody Mary",
  "Mojito",
  "Cuba Libre",
  "Tequila Sunrise",
  "Caipirinha",
  "Wodka Lemon",
};

int x = 0;


void setup() {


  //initialize serial and wait for port to open :
  Serial.begin(9600);   // only for debugging, comment out later
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Initialized");
  Serial.println();

  lcd.begin(16, 2);
  lcd.clear (); // go home
  lcd.print ("Cocktail Master");
  lcd.setCursor(0, 1);
  lcd.print("Please Select");
  delay(2000);
  //lcd.backlight();                      // only needed for 0x3F I2C Adapter

  // ------- Quick 3 blinks of backlight  -------------
  blinkLCD();

  char lcdline1[13];
  sprintf (lcdline1, "Cocktail #:  %02i", x + 1);    // index starts at 0
  lcd.setCursor(0, 0);
  lcd.print (lcdline1);
  lcd.setCursor(0, 1);
  lcd.print("                ");              // erase previous content
  lcd.setCursor(0, 1);
  lcd.print(myCocktails[x]);
}

void loop() {


  volatile unsigned char result = r.process();
  if (result) {
    result == DIR_CCW ? x = x - 1 : x = x + 1;

    if (x < 0) {             // no values < 0; later: use unsigned int
      blinkLCD();
      x = maxNumber - 1;    // roll over
    }

    if (x > maxNumber - 1) {           // no more strings
      // ------- Quick 3 blinks of backlight  -------------
      blinkLCD();
      x = 0;                 // roll over
    }

    char lcdline1[13];
    sprintf (lcdline1, "Cocktail #:  %02i", x + 1);
    lcd.setCursor(0, 0);
    lcd.print (lcdline1);
    lcd.setCursor(0, 1);
    lcd.print("                ");              // erase previous content
    lcd.setCursor(0, 1);
    lcd.print(myCocktails[x]);


  }

  if (r.buttonPressedReleased(25)) {

    switch (x) {
      case 0:
        lcdScreen1();
        Cocktail_1();                      // Start der Produktion
        break;
      case 1:
        lcdScreen1();
        Cocktail_2();                      // Start der Produktion
        break;
      case 2:
        lcdScreen1();
        Cocktail_3();                      // Start der Produktion
        break;
      case 3:
        lcdScreen1();
        Cocktail_4();                      // Start der Produktion
        break;
      case 4:
        lcdScreen1();
        Cocktail_5();                      // Start der Produktion
        break;
      case 5:
        lcdScreen1();
        Cocktail_6();                      // Start der Produktion
        break;
      case 6:
        lcdScreen1();
        Cocktail_7();                      // Start der Produktion
        break;
      case 7:
        lcdScreen1();
        Cocktail_8();                      // Start der Produktion
        break;
      case 8:
        lcdScreen1();
        Cocktail_9();                      // Start der Produktion
        break;
      case 9:
        lcdScreen1();
        Cocktail_10();                      // Start der Produktion
        break;
      case 10:
        lcdScreen1();
        Cocktail_11();                      // Start der Produktion
        break;
      case 11:
        lcdScreen1();
        Cocktail_12();                      // Start der Produktion
        break;
    }
    blinkLCD();
    lcd.clear (); // go home
    lcd.print ("Cocktail Master");
    lcd.setCursor(0, 1);
    lcd.print("Drink is ready!");           //
    delay(3000);
    //lcd.backlight();                      // only needed for 0x3F I2C Adapter

    // ------- Quick 3 blinks of backlight  -------------
    blinkLCD();
    x = 0;                                  // reset to start position
    lcd.clear();
    char lcdline1[13];
    sprintf (lcdline1, "Cocktail #:  %02i", x + 1);
    lcd.print (lcdline1);
    lcd.setCursor(0, 1);
    lcd.print(myCocktails[x]);
  }

}


// ####################   Functions ###################

void blinkLCD() {
  for (int i = 0; i < 3; i++)
  {
    lcd.noBacklight();
    delay(50);
    lcd.backlight();
    delay(50);
  }
}

void lcdScreen1() {                                   // instead of the real mixing process, just for demo

  lcd.setCursor(0, 0);
  lcd.print("Now Mixing of   ");
  // scroll 13 positions (string length) to the left
  // to move it offscreen left:
  for (int positionCounter = 0; positionCounter < 10; positionCounter++) {
    // scroll one position left:
    lcd.scrollDisplayLeft();
    // wait a bit:
    delay(250);
  }

  // scroll 29 positions (string length + display length) to the right
  // to move it offscreen right:
  for (int positionCounter = 0; positionCounter < 20; positionCounter++) {
    // scroll one position right:
    lcd.scrollDisplayRight();
    // wait a bit:
    delay(250);
  }

}

void Cocktail_1() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_2() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_3() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_4() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_5() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_6() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_7() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_8() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_9() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_10() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_11() {
  // produce the requested cocktail -> stepper motor actions
}

void Cocktail_12() {
  // produce the requested cocktail -> stepper motor actions
}

Rotary_Button.zip (9.31 KB)

rpt007: Daran hatte ich auch schon gedacht, als ich mein Menü mit Rotary geschrieben habe; vor ein paar Monaten war ich aber absoluter Laie und kam mit der Library überhaupt nicht zurecht, da noch die jetzt vorhandene Beschreibung - und mir die Zeit und auch das Verständnis zum Einlesen in "Fremd-Code" fehlte, vor allem, wenn das Ding so mächtig ist.

Ja, da gebe ich dir Recht. Das Menü ist sehr komplex und natürlich nicht einfach zu händeln. OK, für einen totalen Anfänger evtl. nicht zu empfehlen.

Nur bevor man sich aus dem Netz mehrere Sketche zusammenkopiert, die dann auch nicht laufen, ist das eine bessere Alternative. Und die lässt sich recht einfach erweitern.

Also kein Problem wenn der TO sich anders entscheidet.

Ich habe mir damit einen Schaltcomputer (Schaltuhr mit unterschiedlichen Steuerfunktionen) aufgebaut und bin begeistert von der Handhabung. Muss allerdings dazu sagen, dass ich auch leichte Anfangsschwierigkeiten hatte.

Das Menü ist sehr komplex und natürlich nicht einfach zu händeln. OK, für einen totalen Anfänger evtl. nicht zu empfehlen.

Inzwischen fühle ich mich mit einem gefährlichen Halbwissen bewaffnet - auch wenn ich inzwischen ein sehr komplexes Projekt erfolgreich im Industrieumfeld umgesetzt habe - doch ich traue mir jetzt doc einiges mehr zu.

Die Herausforderung war, ein mit Rotary/Button gesteuertes Setup-Menü, was aus dem lfd. "Main-Loop-Betrieb" jederzeit aufgerufen werden sollte, mit dem Main-Loop-Code nahtlos zu verbinden. Das war nicht trivial und nervig, da die einzelnen Codes für sich einwandfrei liefen, sobald ich aber die Teile zusammenfügen wollte, stand der Laden. Seitdem mache ich einen großen Bogen um alles, was nach unnötige delays, serial.print und while() aussieht.

Im Bereich Schrittmotoren fühle ich mich jetzt, auch dank meiner selbst gebauten CNC-Steuerung, recht fit. Vor ein paar Wochen habe ich dann meine selbstgestrickte LCD-Rotary-Menu-Struktur endlich so hinbekommen, dass ich nun auch in der Lage bin, kurzfristig erforderliche Erweiterungen einzubauen. Dazu muss man seinen Code kennen, damit man sich nicht neue Fehler einbaut.

Die Jomelo-Library halte ich im Auge und werde da mal ein paar Tests machen, ob sie mir ggf. in zukünftigen Projekten weiterhelfen kann, wo ich mit meinem Latein am Ende wäre.

Der Thread ist zwar schon etwas älter, aber bei meiner Suche nach Hilfe betreffend RotaryEncoder Menus, bin ich hier gelandet.

Nach durcharbeit von einigen Beispielen, habe ich gelernt, dass ich erstmal meine Komponenten verstehen muss. Und Codebeispiele aus dem Jahr 2012 leider nicht mehr funkionieren.

Vielen Dank für den Beispiel-Sketch und die Rotary Bibliothek. Ich werde mich damit nun etwas näher befassen und versuchen, mein Wecker Projekt damit zu realisieren