Hallo zusammen,
damit mein LCD-Display im Menü nicht flackert, will ich dieses nur aktuallisieren wenn sich der in diesem menü befindliche Potiwert ändert. Dafür habe ich in diesem Menüteil, der im Switch case ausgeführt wird, über eine Variable auf true gesetzt.
Im loop steht eine if-Anweisung. Wenn der Menüteil true ist, soll die Funktion updatePoti ausfeführt werden. Der Schwellenwert der Änderung beträgt +/- 2 und der aktuelle Potiwert soll immer zwei sekunden gespeichert werden eh dieser aktuallisiert wird, damit, da der Arduino so schnell ist, auch die Differenz erreicht wird und nicht mit dem drehen des Potis so schnell angepasst wird, dass die Differenz immer Null bleibt. Also sollte die ganze Zeit das switch-case Menü angezeigt werden und im Hintergrund immer auf einen aktuellen Wert des Protis gewartet werden. Leider hab ich da wohl irgendwo einen Denkfehler.
Ich poste hier nur die wichtigtsten Stellen des Codes, der sich für diesen Teil über drei Seiten erstreckt. Falls ihr den ganzen braucht, hänge ich noch zip-Sketch an.
Danke.
arduforcam.zip (2,9 KB)
//---Submenu1_1--//
void submenu1_1() {
menuState1_1 = true;
switch (menu) {
case 1:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Timer einstellen");
lcd.setCursor(0, 1);
lcd.print(PotiWert(1));
lcd.print("ms");
if (!digitalRead(selectButton)) {
submenu1_2();
}
}
//---loop---//
void loop() {
Bedienung();
if (menuState1_1 == true)updatePoti(); // die Variable menuState1_1 ist static boolean
//---updatePoti---//
void updatePoti() {
int const potiPin = 0;
int actPotiWert = analogRead(potiPin);
int oldPotiWert;
int PotiDif_1;
int PotiDif_2;
int Poti_update = 2000;
timestamp = millis();
if (millis() - timestamp >= Poti_update)
{
oldPotiWert = actPotiWert;
}
PotiDif_1 = actPotiWert - oldPotiWert;
//PotiDif_2 = oldPotiWert - actPotiWert;
Serial.println(PotiDif_1);
if (PotiDif_1 >= 2)submenu1_1(); else loop();
//if (PotiDif_2 >= -5)submenu1_1();else loop();
}
Hall
Ich würde Mal sagen die obige Zeile verschiebe hinter den Teil wo die Anzeige erfolgt . Ansonsten ist die Differenz ja immer null
Heinz
Hallo Heinz,
meinst du so?
So wird mir auch nichts angezeigt. Abgesehen von der Anzeige, funktioniert das auch mit der Aktuallisierung nicht.
void updatePoti() {
int const potiPin = 0;
int actPotiWert = analogRead(potiPin);
int oldPotiWert;
int PotiDif_1;
int PotiDif_2;
int Poti_update = 2000;
Serial.println(PotiDif_1);
timestamp = millis();
if (millis() - timestamp >= Poti_update)
{
oldPotiWert = actPotiWert;
}
PotiDif_1 = actPotiWert - oldPotiWert;
if (PotiDif_1 >= 2)submenu1_1(); else loop();
}
Gruß
Markus
Hallo,
ich weiß jetzt nicht wie Dein Menue aufgebaut ist, aber Du willst nur alle 2 sekunden aktualisieren und dann nur die Anzeige aktualisieren wenn sie sich geändert hat.
timestamp hast Du global geklariert ?
nicht getestet
void updatePoti() {
int const potiPin = 0;
int actPotiWert = analogRead(potiPin);
uint32_t static timestamp;
int static oldPotiWert;
int PotiDif_1;
int PotiDif_2;
int Poti_update = 2000;
// Serial.println(PotiDif_1);
if (millis() - timestamp >= Poti_update) {
timestamp = millis();
PotiDif_1 = actPotiWert - oldPotiWert;
Serial.println(PotiDif_1);
oldPotiWert = actPotiWert;
}
if (PotiDif_1 >= 2) submenu1_1(); //else loop(); nachträglich geändert
}
Hi,
ja, timestamp ist global unsigned long. "PotiDif_1 = actPotiWert - oldPotiWert;" gehört doch nicht in die Klammer, oder? Die Differenz soll ja so schnell wie möglich erkannt werden und nicht alles zwei Sekunden.
So funktionierts nicht.
Das darfst du nicht tun:
if (PotiDif_1 >= 2)submenu1_1(); else loop();
Niemals loop() direkt aufrufen. Die Funktion ist wie der Name sagt eine Schleife die immer durchläuft. Wenn du das per Hand aufrufst hast du irgendwann einen Stacküberlauf.
Funktionen kehren am Ende automatisch zum Aufrufs-Ort zurück
Generell ist lcd.clear() keine gute Idee. Das flackert immer, da LCDs relativ langsam sind. Auch wenn man seltener schreibt. Besser ist man schreibt direkt über den alten Text und ersetzt nur die Differenz durch Leerzeichen. Oder in anderen Worten man formatiert Text und Zahlen auf eine konstante Breite.
Ich hatte gestern viel rumprobiert und es sah so für mich aus als würde das Programm nach der switch-cas-Anweisung im submenu1_1 stecken bleiben.
Nachdem ich updateMenu() nach den geschweiften Kalmmer der switch-case-Anweisung im submenu1_1 geschrieben habe, kam ich erst wieder ins Menü zurück. Komisch. Kannst du das erklären?
Wie soll ich das submenu1_1 darstellen und immer wieder im Hintergrund den Potiwert überprüfen?
Hallo,
ohhh je , das hatte ich so gar nicht bemerkt. habs rausgeschmissen
T0
was willst Du denn ? wenn du die Anzeige nur alle 2 s aktualisieren willst und das nur wenn der Wert sich auch geändert hat dann reicht es doch die Differenz auch nur alle zwei s zu berechnen.
Was sich hier auch anbietet ist den statischen Text von den Aktualisierungen zu trennen. Als nicht immer alles neu schreiben. Sondern bei einem Zustands-Übergang den Menü-Text schreiben und dann bei Eingaben nur die Zahlen ändern.
Das geht? Dachte den Bildschirm partiell zu aktuallisieren geht nicht 
Das Problem ist, dass das gerade überhaupt nicht funktioniert. Irgendwie wird, warum auch immer, die Differenz gar nicht berechnet.
Das ist ein ganz einfaches LCD. Du setzt den Cursor an eine Stelle und von da an wird geschrieben. Alles andere bleibt stehen.
Wie gesagt, ständiges lcd.clear() wird nie gut aussehen. Darauf kann man praktisch komplett verzichten. Selbst wenn du das nur alle paar Sekunden machst sieht man das deutlich
Wie soll ich denn innerhalb des void switches, der nur einmal durchläuft, eine Schleife zu Aktuallisierung einbauen? Hast du eine Idee?
Trenne Zustand und Zustands-Übergänge sauber. Wenn das nur einmal gemacht wird dann ist das schonmal gut um festen Text zu Zeichnen. Jetzt brauchst du nur noch etwas das ständig in loop() aufgerufen wird um Dinge wie Aktualisierungen und Taster-Abfragen zu erledigen.
Es gibt keine "voids". Void ist ein Datentyp
Dass es keine void-switches gibt ist mir klar. Habs so genannt, da der swtich-case im void submenu1_1 ist.
Ich habe deine Erläuterung zu Zustandsautomaten für Fortgeschrittene gesehen.
Magst du mir das bitte an einem einfachen Beispiel noch einmal darstellen?
Danke.
Void ist einfach der Rückgabewert der Funktion. In diesem Fall nichts. Funktionen können auch Werte zurück geben.
Du kannst auch switch/case für den Zustands-Automaten verwenden. Allerdings brauchst du etwas extra Code beim Übergang um einmal etwas auszuführen. Das wird bei den einfachen Beispiel nur nicht gemacht weil man es nicht immer braucht. Das heißt nicht dass es nicht geht. Man kann auch an der Stelle wo man den Zustand ändert auch noch eine andere Funktion aufrufen die das Menü einmal neu schreibt.
z.B. auf die Schnelle:
enum class State : byte { OFF, STATE_1, STATE_2};
State currentState = State::OFF;
void setup ()
{
Serial.begin(115200);
}
void loop ()
{
input();
switch(currentState)
{
case State::STATE_1:
state_1();
break;
case State::STATE_2:
state_2();
break;
default:
break;
}
}
void input()
{
if (Serial.available())
{
char c = Serial.read();
switch(c)
{
case '0':
currentState = State::OFF;
state_off_transition();
break;
case '1':
currentState = State::STATE_1;
state_1_transition();
break;
case '2':
currentState = State::STATE_2;
state_2_transition();
break;
}
}
}
void state_off_transition()
{
Serial.println("-- Off transition --");
}
void state_1_transition()
{
Serial.println("-- State 1 transition -- ");
}
void state_1()
{
print(750, "State 1");
}
void state_2_transition()
{
Serial.println("-- State 2 transition --");
}
void state_2()
{
print(750, "State 2");
}
void print(unsigned int interval, const char* txt)
{
static unsigned long previousMillis;
if (millis() - previousMillis > interval)
{
previousMillis = millis();
Serial.println(txt);
}
}
0 für Aus. 1 und 2 für zwei Zustände. Gibt immer etwas aus und zeigt einmalig den Übergang an
Praktisch ist das bei dir natürlich komplizierter. Man muss die Eingabe abhängig vom aktuellen Zustand anders behandeln.