Ich sitze heir seit paar tagen dran und ich komme nicht weiter.
Aus der loop kann ich in das menü springen, aber ich komme aus den
einzelnen funktionen nicht mehr zurück zur loop oder vom submenu zur main.
Ich habe nichts im netz gefunden, deshalb hab ich mal nach meinem wissen
losgelegt, aber nun bin ich am ende.
Kann mir jemand paar tipps geben was ich hier falsch mache?
#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,10,9,8,7); //Create LCD object (RS,E,DB4,DB5,DB6,DB7)
#include <rotary.h> //github.com/brianlow/Rotary
Rotary r=Rotary(3,2);
const int RotSW=4; //Pushbutton
int butState=0;
int cnt=0;
int subMenu;
int rotTurn=0;
void setup()
{pinMode(RotSW,INPUT_PULLUP); lcd.begin(20,4); lcd.clear();
PCICR|=(1<<PCIE2); PCMSK2|=(1<<PCINT18)|(1<<PCINT19); sei();
}
void loop()
{lcd.clear(); lcd.setCursor(0,0); lcd.print("Your in the Loop");
butState=getButton(); //Read state of pushbutton
while(butState==3){Main();} //Button long press -> Menü aufrufen
delay(100);
}
void Main()
{lcd.setCursor(0,0); lcd.print("Set Exit ");
if(cnt==1){rotTurn++; cnt=0; if(rotTurn>1)rotTurn=0;} //Encoder turn right
if(cnt==2){rotTurn--; cnt=0; if(rotTurn<0)rotTurn=1;} //Encoder turn left
butState=getButton(); //Read state of pushbutton
switch(rotTurn)
{case 0: //In SubMenu() springen
lcd.setCursor(0,1); lcd.print("--- ");
if(butState==1&&subMenu!=1){subMenu=1; SubMenu();}
break;
case 1: //Menü() verlassen und in die Loop() zurückspringen
lcd.setCursor(0,1); lcd.print(" ---- ");
if(butState==1){butState=0; loop();} //Springt nicht zurück in die Loop()
break;
default: break;
}
butState=3;
}
void SubMenu()
{lcd.setCursor(0,0); lcd.print("Set "); lcd.setCursor(0,1); lcd.print(" ");
if(cnt==1){rotTurn++; cnt=0;} //Encoder turn right
if(cnt==2){rotTurn--; cnt=0;} //Encoder turn left
if(rotTurn<0){rotTurn=255;}
if(rotTurn>255){rotTurn=0;}
lcd.setCursor(0,1); lcd.print("RotTurn (0-255): "); lcd.print(rotTurn);
butState=getButton(); //Read state of pushbutton
if(butState==1){butState=0; Main();} //Sprint nicht zurück in die Main()
while(subMenu==1) {delay(100); SubMenu();} //Verläßt das SubMenu() nach paar sekunden!
}
ISR(PCINT2_vect) //Interrupt service routine for encoder
{unsigned char result=r.process();
if(result==DIR_CW) {cnt=1;}
else if(result==DIR_CCW){cnt=2;}
}
byte getButton() //Read Pushbutton with debounce
{butState=0; unsigned long dnTime, upTime;
if(!digitalRead(RotSW))
{delay(20);
if(!digitalRead(RotSW)) {dnTime=millis(); while(!digitalRead(RotSW));}
upTime=(millis()-dnTime);
if(upTime>=1000) return butState=3; //Long press
else if(upTime>=400) return butState=2; //Medium press
else return butState=1; //Short click
}
return butState=0;
}
Du darfst die Funktion nicht main() nennen, das ist ein reservierter Namen.
Des weiteren weigere ich mich Deinen Sketch zu lesen. Formatiere ihn leserlich und schreibe nicht mehrere Funktionen in eine Zeile.
OnlySketching:
Kann mir jemand paar tipps geben was ich hier falsch mache?
int cnt=0;
cnt muss volatile deklariert werden.
Da es ein int (2 Bytes) ist, müsste man auch eigentlich alle Zugriffe aus dem Hauptprogramm atomar gestalten,
in deinem Fall wäre es einfacher cnt zu einem (unsigned) char zu machen.
Das sei() in setup ist ohne vorhergehendes cli() sinnfrei, Interrupts sind standardmäßig eingeschaltet.
Pinchange Interrupts auf den externen Interruptpins halte ich für Verschwendung und komplizierter.
Wenn man eine Library benutzt die etwas anderes nicht unterstützt, von mir aus.
Deine while-delay Technik finde ich zum Speien.
Mehrere Statements in einer Zeile benutze ich normalerweise nicht.
Funktionen sind kein goto! Am Anfang der Funktion wird die Rücksprung-Adresse auf dem Stack gespeichert. Und am Ende kehrt sie wieder dahin wo sie aufgerufen wurde. Das bedeutet auch dass du normal nicht eine Funktion sich selbst aufrufen lassen kannst. Dadurch wird der Speicher ganz schnell voll.
Und auch nicht in loop() main() aufrufen und dann in loop() wieder main(). Das ist das gleiche. Die Funktion weiß von selbst wo es weitergeht
In der loop soll später (falls das mit dem menü klappt) eine led gedimmt werden, mit dem wert aus der 0-255 aus der void Sub_Menu().
Wenn der Nano strom bekommt, soll kein Menü zu sehen sein, das soll nur für die einstellungen sein.
Deshalb muß man 1,5 sek den button gedrückt halten, erst dann gehts zum menü.
Das geht ja auch soweit....und ich kann den wert 0-255 ändern, alles andere, wie menü verlassen geht nicht.
Whandall:
Habe ich nicht gesagt, lies es nochmal durch, ich habe diese Frage beantwortet:
und zwar mit nein (aus meiner Sicht, es gibt natürlich keine Vorschriften, wie man ein Programm schreibt).
Ahh ok du meintest, das es so nicht macht....ja das glaub ich dir, ich hab sowas noch nie gemacht, deshalb sieht das so aus...vielleicht werde ich in 3 monate über manen code lachen...aber zZ is es das beste was mir einfällt.
Deshalb möchte ich ja auch das farum nutzen, um das besser oder richtig zu machen.
Du wirst in drei Monaten nicht über Deinen alten Code lachen - Du wirst Dich ernsthaft fragen, 'was der Künstler Da eigentlich machen wollte'.
Das aber nicht nur, weil Du besser wirst - sondern auch, weil Du kaum Kommentare geschrieben hast.
Damit meine ich aber nicht
unsigned int zahl; Zahl, ohne Vorzeichen
... weil Das erklärt sich von selber - aber was 'zahl' hier macht, wäre eine Nennung wert.
Bei Deinem Sketch fehlt mir momentan der Elan, Den 'durchzukauen' - in Kurzform, was funktioniert nicht so, wie Du willst?
Bzw. Was erwartest Du und was bekommst Du statt Dessen?
Das Problem ist viel elementarer als "Mein Programm macht nicht was ich will"
Um das klar zu machen: hier geht es nicht um schlechten Stil, sondern dass der Controller so nicht arbeiten kann. Selbst wenn das im Moment geht (wahrscheinlich weil die Funktionsaufrufe nach langsamen Benutzereingaben erfolgen), wird er das auf Dauer sicherlich nicht tun
Ok was schlagt ihr mir jetzt vor? oder wars das mit dem menü?
Dann vergessen wir den code den ich gepostet habe komplett und fangen bei 0 an.
Ich schreib mal was ich von dem Menü erwarte:
Nach dem der nano saft bekommt, soll eine LED an einem PWM pin mit halber helligkeit leuchten zB 128.
Wenn man den Button des Encoder länger gedrückt hällt, soll in das Menü aufgerufen werden.
dort können zB 3 untermenüs sein (für 3 LEDs an 3 PWM pins) die man mit dem encoder durchscrollen kann.
mit jedem weiteren kurz-klick soll eins der 3 untermenüs aufgerufen werden, in dem man jetzt einen wert 0-255 einstellen kann.
loop
- menu (long press)
- submenu1 (klick) -> 0-255 (werte mit encoder ändern)
oder zurück zum menu
- submenu2 (klick) -> 0-255 (werte mit encoder ändern)
oder zurück zum menu
- submenu3 (klick) -> 0-255 (werte mit encoder ändern)
oder zurück zum menu
- exit (klick) -> menü beenden, zurück zu loop
Schau dir Zustandsautomaten an. Da hast du eine Variable die dir angibt in welchem Menu du dich befindest. Diese kann man je nach aktuellem Menü und Eingabe ändern.
In Funktionen bleibt man so nie fest hängen. Je nach Zustand wird eine andere Funktion ausgeführt. Und wenn nichts zu tun ist beendet diese sich sofort wieder.
Dadurch kommt loop() immer wieder gleich dran. Es ist nämlich auch ein Fehler zu denken du springst von Menü zu Menü und am Ende vielleicht einmal nach loop(). Die Bezeichnung loop() darfst du ruhig wörtlich nehmen. Das ist eine Schleife die ständig arbeitet.
Der Vorgang ist eher so:
void loop()
{
if zustand == MENU_1 //praktisch wird hier oft switch/case verwendet
menu_1();
else if zustand == MENU_2
menu_2();
//hier kann man "gleichzeitig" noch andere Dinge tun!
}
void menu_1()
{
if eingabe == ...
zustand = MENU_2;
...
}
Menüs kann man dann nur zum Zeitpunkt des Zustandswechels einmal neu zeichnen
@HotSystems
Warum nimmst du nicht einfach das hier:
forum.arduino.cc/index.php?topic=73816.0
Ist zwar auch mit Programmierung verbunden, aber du musst das "Rad" nicht neu erfinden.
Habe ich gerade getestet, verbraucht bereits 11KB mit dem beginner-menü.
Ich möchte erst mal nur 3 RGB werte ändern, dafür knall ich doch keine
11kb Code auf den armen arduino...und dann brauche ich eine ganze Armada an
buttons mit zwischenwiderstände. Sind Encoder verpöhnt, damit kann man
eigentlich alles steuern.
@Serenifly
Die Bezeichnung loop() darfst du ruhig wörtlich nehmen. Das ist eine Schleife die ständig arbeitet.
Ja das ist etwas gewöhnungsbedürftig. Ich verwächsel das immer mit index.php
und dann kann man über die links die webseiten anspringen....und dort verweilen
bis man wieder lust auf die startseite hat.
Ok dann lass ich das mit der menüprogrammierung. Die MenüLibrary ist mir zu stark nach
dem sprichwort "mit Kanonen auf Spatzen schießen".
Danke an alle, eventuell finde ich einen code den ich umbauen kann.
OnlySketching:
Habe ich gerade getestet, verbraucht bereits 11KB mit dem beginner-menü.
Ich möchte erst mal nur 3 RGB werte ändern, dafür knall ich doch keine
11kb Code auf den armen arduino...und dann brauche ich eine ganze Armada an
buttons mit zwischenwiderstände. Sind Encoder verpöhnt, damit kann man
eigentlich alles steuern.
Dann hast du es nicht richtig gelesen. Das Menü geht auch mit Encoder.
Und wieviel Tasten du dranbaust, bleibt dir überlassen.
Ich sehe bei den 11 kb kein Problem, ausser dein Speicher wird knapp.