Hilfe bei Erstellung einer Menüstruktur mit langem Tastendruck

Hallo liebe Community,
Nach jahrelanger Pause bin ich kürzlich wieder in die Welt des Arduino eingetaucht und hoffe hier kann mir jemand bei einem kleinem Problem weiterhelfen :slight_smile:

Ich bin dabei eine Menüstruktur zu erstellen welche durch eine 4x1 Membrantastatur angesteuert wird.
Das Menü sollte wie folgt arbeiten:
Menüebene 1:
-taste 1-3 aktiviert unterschiedliche Timer
-Taste 4 stoppt alle timer vorzeitig
-Taste 4 lange gedrückt wechselt zur Menüebene 2
Menüebene 2 (anzeigen der eingestellten Zeiten der Timer):
-Taste 1+2 scrollt cursor rauf und runter
-Taste 4 wechselt zur Menüebene 3
-Taste 4 lange gedrückt springt wieder zur Ebene 1 zurück
Menüebene 3 (einstellen der angezeigten Zeiten und zwar jene wo der Cursor war):
-Taste 1-2 Zeit verstellen
-Taste 4 speichern und zurück zu Ebene 3
-Taste 4 lange gedrückt zurück zur Ebene 1

Die Tasten einzulesen verwende ich die Bounce2-bibliothek. Um den langen Tastendruck zu erkennen, nutze ich die funktion „debouncedState“ welche mir zurückgeben sollte ob die Taste aktuell gedrückt ist oder nicht. Damit werte ich einen Timer aus.
Den kurzen Tastendruck werte ich über das Loslassen der Taste aus.

Nun zum Problem:
Die Menüstruktur funktioniert soweit schon mal. Das eigentliche Problem liegt an den einem Fall wo ich von Ebene 3 zurück zur 2. springen will. Wenn ich in der Ebene 3 die Taste 4 kurz betätige wechselt es zur Ebene 2 und nach einer Sekunde (erkennung langer Tastendruck) springt es ganz raus in die 1. Ebene.
Habe mir die variable aus der Funktion „debouncedState“ auf dem Lcd ausgeben lassen und bemerkt dass diese beim wechsel der Ebene auf Low „hängen“ bleibt. Aber genau des kann ich mir net erklären, die Taste wurde ja losgelassen?! Und es passiert nur in diesem Fall. Zwischen Ebene 1 und 2 funktioniert der selbe code ohne probleme.

Anbei füge ich den Ausschnitt des „menüs“ ein. Diese Routine wird vom Main-loop aufgerufen.
Aktuell besteht das Programm nur aus diesem Teil um das Problem zu finden und beheben.

Ps: mir ist bewusst dass das Menü vielleicht „komisch“ sein könnte, anderst/besser gemacht werden usw. Aber wie gesagt, bin erst wieder ‚neu‘ in dieser Welt und hab einfach mal aus eigener Logik was aufbauen wollen. Bitte steinigt mich dafür net :sweat_smile:
Auch die ganzen anderen Zeilen imenü können vernachlässigt werden. Eigentlich hab ich nur die Menüstruktur in ein neues Projekt gepackt um fehler zu beheben und daher paar sachen eingefügt oder ausgeklammert zum Testen.
Es geht rein um die Funktionen der Taste 4 und das Rumspringen :slight_smile:

//Verarbeitung der Tastendücke

Bounce  myButton1  = Bounce();
Bounce  myButton2  = Bounce();
Bounce  myButton3  = Bounce();
Bounce  myButton4  = Bounce();


void Taster_einlesen() {
  myButton1.update();
  myButton2.update();
  myButton3.update();
  myButton4.update();
  debouncedState = myButton4.read();

  if (menu_ebene == 0){
    if (myButton1.fallingEdge()) {
     // Ventil_1_Ansteuern = 1;
      lcd.setCursor(0, 0);
      lcd.print("*");
      startMillisV1 = millis();
    }
    if (myButton2.fallingEdge()) {
     // Ventil_2_Ansteuern = 1;
      lcd.setCursor(0, 1);
      lcd.print("*");
      startMillisV2 = millis();
    }
    if (myButton3.fallingEdge()) {
     //Ventil_3_Ansteuern = 1;
      lcd.setCursor(0, 2);
      lcd.print("*");
      startMillisV3 = millis();
    }
    if (myButton4.fallingEdge()) {
      //STOPP = 1;
      
    }
    if (debouncedState == LOW && myButton4.currentDuration() > 1000 && taste_blockieren == 0){
       menu_ebene = 1;
       taste_blockieren = 1;  //dient dazu nicht gleich wieder in die Funktion zu springen bevor taste losgelassen
       settings_position = 0;
       lcd.setCursor(0, 0);
       lcd.print(">Zeit1  ");
       lcd.setCursor(0, 1);
       lcd.print(" Zeit2  ");
       lcd.setCursor(0, 2);
       lcd.print(" Zeit3  ");
       
      }
    if (myButton4.risingEdge()) {
      taste_blockieren = 0;
    }
  }
  
  if (menu_ebene == 1){
    if (myButton1.fallingEdge()) {
     if(settings_position < 2){
       settings_position ++;
     }
      lcd.setCursor(0,settings_position);
      lcd.print(">");
      lcd.setCursor(0,(settings_position-1));
      lcd.print(" ");

    }
    if (myButton2.fallingEdge()) {
      if(settings_position > 0){
       settings_position --;
       
     }
      lcd.setCursor(0,settings_position);
      lcd.print(">");
      lcd.setCursor(0,(settings_position+1));
      lcd.print(" ");
    }
    if (myButton3.fallingEdge()) {
     
    }
    if (myButton4.fallingEdge()) {
      STOPP = 1;
      
      
    } 
    if (debouncedState == LOW && myButton4.currentDuration() > 1000 && taste_blockieren == 0){
      menu_ebene = 0;
      taste_blockieren = 1;
      lcd.setCursor(0, 0);
      lcd.print(" Ventil1");
      lcd.setCursor(0, 1);
      lcd.print(" Ventil2");
      lcd.setCursor(0, 2);
      lcd.print(" Ventil3");
    }
    if (myButton4.risingEdge()) {
      taste_blockieren = 0;
      menu_ebene = 2;
      lcd.setCursor(13, settings_position);
      lcd.print("-");
      delay (500);
    }
  }

  if (menu_ebene == 2){
    if (myButton1.fallingEdge()) {
      
    }
    if (myButton2.fallingEdge()) {
      
    }
    if (myButton3.fallingEdge()) {
     
    }
    if (myButton4.fallingEdge()) {
      
    }
    if (debouncedState == LOW && myButton4.currentDuration() > 1000 && taste_blockieren == 0){
      menu_ebene = 0;
      taste_blockieren = 1;
      lcd.setCursor(0, 0);
      lcd.print(" Ventil1");
      lcd.setCursor(0, 1);
      lcd.print(" Ventil2");
      lcd.setCursor(0, 2);
      lcd.print(" Ventil3");
    }
    if (myButton4.risingEdge()) {
      taste_blockieren = 0; 
      menu_ebene = 1;
      lcd.setCursor(13, settings_position);
      lcd.print("-");
      delay (500);
    } 
  }

  

Ich hoffe ich konnte mich einigermaßen verständlich ausdrücken und mir kann jemand erklären wieso die erkennung des langen Tastendruck startet obwohl ich den Taster losgelassen habe (und des nur in dem einen Fall). Hab des jetzt alles schon 3 mal neu geschrieben und anderst aufgebaut aber komm einfach nicht dahinter. Vielleicht hab ich mich auch einfach irgendwo verrant und übersehe eine Kleinigkeit. Aber die Buttons werden ja bei jedem Durchlauf neu geupdatet und der Teil vom Code ist in jeder Eben der Selbe :thinking:

Ich bedanke mich schon mal im Voraus. Falls es Unklarheiten oder Verbesserungsvorschläge gibt, bitte Bescheid sagen :blush:

Grüße
Simon

Ich hab den Code noch nicht gesehen, aber Du brauchst eine zusätzliche Variable als Merker.
Die Logik dahinter sähe dann so aus:

  1. Frage auf langenTastendruck ab
  2. Nur wenn Merker nicht gesetzt,
  • Setze den Merker
  • springe in den angeforderten menupunkt
  1. frage auf gedrückte Taste ab
  2. Nur wenn nicht gedrückt
  • lösche den Merker
    -> Danach fange an von vorn.

Im Allgemeinen mach ich das mit einer Schrittkette....

Hallo my_xy_projekt,

Danke für deinen Vorschlag aber ich glaube du hast mich da fasch verstanden :slight_smile:

Die Erkennung des langen und kurzem Tastendrucks funktioniert schon.
Nur wen ich von Ebene 3 auf 2 spring bleibt im hintergrund die Abfrage vom langen Tastendruck aktiv und wird dann ausgelößt. Obwohl die Bedingungen für die Abfrage nicht erfüllt sind und der besagte Programmabschnitt gar nicht mehr aufgerufen werden dürfte (es handelt sich exakt um die If-schleife in Ebene 3, das hab ich rausgetestet).

Grüße

Nein.

Genau.
Habe ich geschrieben.
Du brauchst eine Variable, die gesetzt wird wenn Du den langen Tastendruck ausgelöst hast um damit eine neue Auswertung zu sperren.
Erst wenn die Taste wieder losgelassen ist, wird die Variable gelöscht.
Und erst dann kannst Du einen neuen langen Tastendruck auswerten.
Bevor ich jetzt lange code review mache.
Sag mir mal die Codezeile, wo Du das menu rückwärts mit dem langen Tastendruck verlässt.
Und die, wo der lange Tastendruck (temporär) nicht ausgewertet werden soll.

Also es geht um die letzten paar Zeilen in der 2. Menuebene (unten nochmal angehängt). Wenn ich die Taste 4 lange drück ändert es die Variable „menü-ebene“ erfolgreich zu 0 und springt auch richtig raus. Wenn ich sie aber kurz drücke, ändert sie sich richtigerweiße zu 1 (zweite menüebene) aber im nachhinein wird dann noch die if-schleife für den langen Tastendruck ausgeführt. Aber erstens wurde der Taster ja losgelassen; daher dürfte die Schleife gar net durchlaufen (aber der Parameter ‚debouncedState’ bleibt da eben auf 0 hängen). Und zweitens, und des ist was mich noch mehr wundert, befinde ich mich ja außerhalb dieser Menüebene und die Schleife dürfte fürs Programm gar nicht mehr „sichtbar“ sein…

@mossim könnte auch einfach die MoToButtons Klasse meiner MobaTools verwenden. Die erledigt das alles alleine.
Da braucht's auch nur eine Instanz für alle 4 Tasten. Hier ist ein Beispiel mit 4 Tastern.

Was hindert Dich daran, die zweite Abfrage mit einer zusätzlichen Bedingung zu versehen?
Variante 1:
als else zweig geht nur entweder oder
Variante 2:
Du fragst auf != menue_ebene == 0 ab.

   if (debouncedState == LOW && myButton4.currentDuration() > 1000 && taste_blockieren == 0)
    {
      menu_ebene = 0;
      taste_blockieren = 1;
      lcd.setCursor(0, 0);
      lcd.print(" Ventil1");
      lcd.setCursor(0, 1);
      lcd.print(" Ventil2");
      lcd.setCursor(0, 2);
      lcd.print(" Ventil3");
    }
    // else if (myButton4.risingEdge()) // Variante 1
    // if (myButton4.risingEdge() && menue_ebene !=0) // Variante 2
    {
      taste_blockieren = 0;
      menu_ebene = 1;
      lcd.setCursor(13, settings_position);
      lcd.print("-");
      delay (500);
    }

Und irgendwie ist Dein Code unvollständig.... Das ist sehr schade, da mann damit keinen Überblick bekommt und sich nicht in die Funktion einarbeiten kann.

Vielen Dank für die Anregungen.

@MicroBahner : Das werd ich mir mal anschauen, danke.

@my_xy_projekt : natürlich hindert mich nichts daran :slightly_smiling_face: ich werde es mal ausprobieren und schauen ob es was ändert :+1: Verstehe nur nicht wieso genau der gleiche Code-Teil in zwei Menüebenen funktioniert und in einer eben nicht (daher meine Annahme dass es ohne diese Zusatzbedingungen funktionieren müsste).
Zur Unvollständigkeit: wie bereits geschrieben besteht dieses Programm aktuell nur aus diesem Menü (ist eine .h). Das was fehlt ist nur die main.ino bei der im mainloop nur dauerhaft in die Taster_einlesen() gesprungen wird und die 2-3 Variablen vom Menu deklariert sind.
Das liegt daran dass ich aktuell am Stand lieg und nur die einzelnen Dateien aufm Handy hab :grin:
Am Wochenede bin ich wieder Zuhause und werde eure Vorschläge probieren. Eventuell kann ich dann noch die main.ino dazugeben wenn des erwünscht ist.

Grüße,
Simon

Moin,
mach mal... Erhol Dich und komm gut gekräftigt zurück. Dann schaun wa, was sich machen lässt... :sunny: :muscle: :thread:

1 Like

Hallo Leute,
ich bin inzwischen wieder zu Hause und konnte mich wieder ans Projekt setzten. Als ich den Code heute nochmal hochgeladen habe hat er sich plötzlich anderst verhalten als das letzte mal :face_with_spiral_eyes: Entweder war letztes mal was schiefgegangen oder ich habe "unterbewusst" nochmal was ausgeklammert :sweat_smile:
Jedenfalls springt das Menü jetzt nicht mehr von alleine weiter. Diesmal konnte ich Zwischen Ebene 1 und 2 normal wechseln (mit langem Tastendruck), aber der Sprung in die 2. Ebene (kurzer Druck in Ebene 1) funktionierte nicht. Bzw funktionierte schon, aber zu schnell sodass es sofort wieder in die Ebene 1 zrücksprang. Dies konnte ich dann lösen indem ich die If-Abfragen der Ebenen als else if abgeändert habe (danke für die Anregung) :grin:

Jetzt müsste ich nur noch das Problem lösen, dass es nach einem Wechsel der Ebenen die Auswertung der losgelassenen Taste logischerweise gleich in der neuen Ebene mit auslöst.
Ich wüsste jetzt nur die Lösung nach dem Langen Tastendruck einen Merker zu setzten und die Abfrage fürs Loslassen zweimal ausführe; einmal Merker=wahr und einmal falsch. Sollte soweit kein Problem sein aber gäbe es hierfür vielleicht eine souveränere Lösung? Also etwas kompakteres, um Code zu "sparen"? =)

Hier jetzt nochmal der gesamte Code, runtergebrochen auf das nötigste :slightly_smiling_face:

#include <LiquidCrystal_I2C.h>
#include <Bounce2.h>
#include <Wire.h>

LiquidCrystal_I2C lcd(0x27, 20, 4);

const int Taster1 = 14;
const int Taster2 = 15;
const int Taster3 = 10;
const int Taster4 = 16;

int WertTaste = 0;
int menu_ebene = 0;
int menu_position = 0;
int settings_position = 0;
int setting_on = 0;
int taste_blockieren = 0;

unsigned long currentMillis;
int debouncedState = 0;
Bounce  myButton1  = Bounce();
Bounce  myButton2  = Bounce();
Bounce  myButton3  = Bounce();
Bounce  myButton4  = Bounce();

void setup() {
  pinMode(Taster1, INPUT_PULLUP);
  myButton1.attach(Taster1);
  myButton1.interval(10); // 10s zum Entprellen
  pinMode(Taster2, INPUT_PULLUP);
  myButton2.attach(Taster2);
  myButton2.interval(10); // 10ms zum Entprellen
  pinMode(Taster3, INPUT_PULLUP);
  myButton3.attach(Taster3);
  myButton3.interval(10); // 10ms zum Entprellen
  pinMode(Taster4, INPUT_PULLUP);
  myButton4.attach(Taster4);
  myButton4.interval(10); // 10ms zum Entprellen
  

  lcd.init();
  lcd.backlight();

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(" Menuebene");
  lcd.setCursor(0, 1);
  lcd.print(" Settingsposition");
  lcd.setCursor(0, 2);
  lcd.print(" debouncedstate");

}

void loop() {
  Taster_einlesen();
  
  lcd.setCursor(19, 0);
  lcd.print(menu_ebene);
  lcd.setCursor(19, 1);
  lcd.print(settings_position);
  lcd.setCursor(19, 2);
  lcd.print(debouncedState);

}


void Taster_einlesen() {
  myButton1.update();
  myButton2.update();
  myButton3.update();
  myButton4.update();
  debouncedState = myButton4.read();

  if (menu_ebene == 0){
    if (myButton1.fallingEdge()) {
      lcd.setCursor(0, 0);
      lcd.print("*");
    }
    if (myButton2.fallingEdge()) {
      lcd.setCursor(0, 1);
      lcd.print("*");
    }
    if (myButton3.fallingEdge()) {
      lcd.setCursor(0, 2);
      lcd.print("*");
    }
    if (myButton4.fallingEdge()) {
      
    }
    if (debouncedState == LOW && myButton4.currentDuration() > 1000 && taste_blockieren == 0){
       menu_ebene = 1;
       taste_blockieren = 1;
       settings_position = 0;
       lcd.setCursor(0, 0);
       lcd.print(">");
       lcd.setCursor(0, 1);
       lcd.print(" ");
       lcd.setCursor(0, 2);
       lcd.print(" ");
       
      }
    if (myButton4.risingEdge()) {
      taste_blockieren = 0;
      lcd.setCursor(0, 0);
      lcd.print(" ");
      lcd.setCursor(0, 1);
      lcd.print(" ");
      lcd.setCursor(0, 2);
      lcd.print(" ");
    }
  }
  
  else if (menu_ebene == 1){
    if (myButton1.fallingEdge()) {
     if(settings_position < 2){
       settings_position ++;
     }
      lcd.setCursor(0,settings_position);
      lcd.print(">");
      lcd.setCursor(0,(settings_position-1));
      lcd.print(" ");
    }
    if (myButton2.fallingEdge()) {
      if(settings_position > 0){
       settings_position --;
     }
      lcd.setCursor(0,settings_position);
      lcd.print(">");
      lcd.setCursor(0,(settings_position+1));
      lcd.print(" ");
    }
    if (myButton3.fallingEdge()) {
     
    }
    if (myButton4.fallingEdge()) {
      
    } 
    if (debouncedState == LOW && myButton4.currentDuration() > 1000 && taste_blockieren == 0){
      menu_ebene = 0;
      taste_blockieren = 1;
      lcd.setCursor(0, 0);
      lcd.print(" ");
      lcd.setCursor(0, 1);
      lcd.print(" ");
      lcd.setCursor(0, 2);
      lcd.print(" ");
    }
    if (myButton4.risingEdge()) {
      taste_blockieren = 0;
      menu_ebene = 2;
      lcd.setCursor(18, settings_position);
      lcd.print("-");
    }
  }

  else if (menu_ebene == 2){
    if (myButton1.fallingEdge()) {
      
    }
    if (myButton2.fallingEdge()) {
      
    }
    if (myButton3.fallingEdge()) {
     
    }
    if (myButton4.fallingEdge()) {
      
    }
    if (debouncedState == LOW && myButton4.currentDuration() > 1000 && taste_blockieren == 0){
      menu_ebene = 0;
      taste_blockieren = 1;
      lcd.setCursor(0, 0);
      lcd.print(" ");
      lcd.setCursor(0, 1);
      lcd.print(" ");
      lcd.setCursor(0, 2);
      lcd.print(" ");
    }
    if (myButton4.risingEdge()) {
      taste_blockieren = 0;
      menu_ebene = 1;
      lcd.setCursor(18, settings_position);
      lcd.print(" ");
    }
  }
}

Dein Sketch mit MobaTools:

#include <LiquidCrystal_I2C.h>
#define MAX8BUTTONS     // Nur zur Speicheroptimierung, wenn nicht mehr als 8 Tasten genutzt werden.
#include <MobaTools.h>
//#include <Wire.h>     // braucht man nicht, macht die LiquidCrystal_I2C selbst

//LiquidCrystal_I2C lcd(0x3f, 20, 4);
LiquidCrystal_I2C lcd(0x27, 20, 4);

const uint8_t TasterPins[] = {14,15,10,16};
MoToButtons myButtons( TasterPins, 4, 20, 800 ); // 20ms Entprellzeit, 800ms = langer Tastendruck
enum :byte { TASTE1=0,TASTE2,TASTE3,TASTE4};
int WertTaste = 0;
int menu_ebene = 0;
int menu_position = 0;
int settings_position = 0;
int setting_on = 0;

// brauchst Du für die Tasterauswertungen nicht mehr :
unsigned long currentMillis;
int debouncedState = 0;

void setup() {
  

  lcd.init();
  lcd.backlight();

  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print(" Menuebene");
  lcd.setCursor(0, 1);
  lcd.print(" Settingsposition");
  lcd.setCursor(0, 2);
  lcd.print(" debouncedstate");

}

void loop() {
  myButtons.processButtons();
  Taster_einlesen();
  
  lcd.setCursor(19, 0);
  lcd.print(menu_ebene);
  lcd.setCursor(19, 1);
  lcd.print(settings_position);
  lcd.setCursor(19, 2);
  lcd.print(debouncedState);

}


void Taster_einlesen() {

  if (menu_ebene == 0){
    if (myButtons.pressed(TASTE1)) {
      lcd.setCursor(0, 0);
      lcd.print("*");
    }
    if (myButtons.pressed(TASTE2)) {
      lcd.setCursor(0, 1);
      lcd.print("*");
    }
    if (myButtons.pressed(TASTE3)) {
      lcd.setCursor(0, 2);
      lcd.print("*");
    }
    if (myButtons.pressed(TASTE4)) {
      
    }
    if (myButtons.longPress(TASTE4)){
       menu_ebene = 1;
       settings_position = 0;
       lcd.setCursor(0, 0);
       lcd.print(">");
       lcd.setCursor(0, 1);
       lcd.print(" ");
       lcd.setCursor(0, 2);
       lcd.print(" ");
       
      }
    if (myButtons.shortPress(TASTE4)) {
      lcd.setCursor(0, 0);
      lcd.print(" ");
      lcd.setCursor(0, 1);
      lcd.print(" ");
      lcd.setCursor(0, 2);
      lcd.print(" ");
    }
  }
  
  else if (menu_ebene == 1){
    if (myButtons.pressed(TASTE1)) {
     if(settings_position < 2){
       settings_position ++;
     }
      lcd.setCursor(0,settings_position);
      lcd.print(">");
      lcd.setCursor(0,(settings_position-1));
      lcd.print(" ");
    }
    if (myButtons.pressed(TASTE2)) {
      if(settings_position > 0){
       settings_position --;
     }
      lcd.setCursor(0,settings_position);
      lcd.print(">");
      lcd.setCursor(0,(settings_position+1));
      lcd.print(" ");
    }
    if (myButtons.pressed(TASTE3)) {
     
    }
    if (myButtons.pressed(TASTE4)) {
      
    } 
    if (myButtons.longPress(TASTE4)){
      menu_ebene = 0;
      lcd.setCursor(0, 0);
      lcd.print(" ");
      lcd.setCursor(0, 1);
      lcd.print(" ");
      lcd.setCursor(0, 2);
      lcd.print(" ");
    }
    if (myButtons.shortPress(TASTE4)) {
      menu_ebene = 2;
      lcd.setCursor(18, settings_position);
      lcd.print("-");
    }
  }

  if (menu_ebene == 2){
    if (myButtons.pressed(TASTE1)) {
      
    }
    if (myButtons.pressed(TASTE2)) {
      
    }
    if (myButtons.pressed(TASTE3)) {
     
    }
    if (myButtons.longPress(TASTE4)){
      menu_ebene = 0;
      lcd.setCursor(0, 0);
      lcd.print(" ");
      lcd.setCursor(0, 1);
      lcd.print(" ");
      lcd.setCursor(0, 2);
      lcd.print(" ");
    }
    if (myButtons.shortPress(TASTE4)) {
      menu_ebene = 1;
      lcd.setCursor(18, settings_position);
      lcd.print(" ");
    }
  }
}

Die gesamte Unterscheidung langer-kurzer Tastendruck passiert in der Lib, Du musst nur nach langem (longPress) oder kurzem (shortPress) Druck abfragen. Du musst auch nichts blockieren.

P.S: die Menues sind eine perfekte Situation um die switch ... case Anweisung einzusetzen. Ich habe deinen Sketch aber erstmal weitestgehend so gelassen wie er war, nur die notwendigen Änderungen für die MoToButtons.

Hi,

also erstmal vielen Dank für die Mühe meinen Sketch umzuschreiben :raised_hands:

Ich hab mir deine Bibliothek heute mal angeschaut aber nicht ganz durchgeblickt und daher dass mein Pfusch dann ja funktioniert hat, hatte ich keinen Kopf mehr mich weiter reinzulesen :sweat_smile: aber jetzt mit deinem Beispiel sieht es schon sehr verständlicher aus und gefällt mir auch gut. Werde ich wahrscheinlich so übernehmen (versuche nur immer so wenig fremde Biblios wie möglich aufzunehmen weil mann dann halt nicht weiß was im Hintergund alles so läuft) :slightly_smiling_face:

Zwei Verständnissfragen welche mir hier noch aufgekommen sind:

-Ich nehme mal an deine Bibliothek deklariert die Ausgänge im hintergrund durch die Pinummern "TasterPins[]" oder?

-was macht denn die Zeile: enum :byte { TASTE1=0,TASTE2,TASTE3,TASTE4};

Bzgl der Switch-Case-Auswahl: ja, das hatte ich ganz am Anfang auch so. Hab erst die Tasten ausgelesen und den Wert zurückgegeben und dann mittels Switch abgearbeitet. Aber als ich dann zum Langen Tastendruck gekommen bin hat des irgendwie nicht mehr klappen wollen und daher hab ich auf die If-Methode gewechselt.

Sonst hätte ich des mit Switch auch schöner gefunden.

Und nochwas.. ist zwar leider nicht mehr Teil dieses Toppics aber vielleicht könnt ihr mir ja kurz erklären was ich da übersehe:

Versuche gerade (Countdown)Timer zu programmieren und diese im Uhrformat auszugeben.

Habe da folgende Formel finden können um die Millisekunden umzurechnen:

int seconds = (millis() / 1000) % 60 ;
int minutes = ((millis() / (1000*60)) % 60);

Die Sekunden funktionieren ohne Probleme. Bei der Formel von den Minuten ist aber was komisch. Die funktioniert nur bis zu einem Faktor ( bei 1000x60) bis max 32. Also wenn ich "1000x32" rechne zält der Wert, logischerweise alle 32 Sekunden, hoch. Aber ab 33 oder mehr bleibt die Variable immer auf 0. :face_with_raised_eyebrow: Muss zugeben, dass ich den Modulo-operator noch net wirklich verstehe, aber ob ich da 30000 berechne oder 60000 kann doch keinen Unterschied machen :face_with_monocle:

Grüße

Ohne andere Anweisung rechnet er rechts in int und bei 16 Bit ist bei 32767 Schluß.
Also besser

1000UL*60

UL ==> Unsigned Long

Gruß Tommy

Hi,
super danke, so funktionierts! Habe die Variablen zwar als UL definiert aber wusste net dass des in der Berrechung auch nochmal so gemacht werden muss o.O

Grüße

Ja, gemau so ist das.

Die Taster werden intern einfach von 0 an durchnumeriert ( wie der Index in Array 'TasterPins[] ).
Durch dei enum-Zeile kanst Du stattdessen die Namen TASTE1 usw verwenden. Grundsätzlich hättest Du auch einfach 0...3 verwenden können. Aber so finde ich es verständlicher. Du kannst da ja auch noch 'sprechendere' Namen für die Taster benutzen.

Zu deinem Timerproblem. Das liegt an den Wertebereichen der verschiedenen Datentypen. Standardmässig verwendet der Compiler bei Berechnungen den Datentyp 'int'. Das ist auf den 8-Bit Controllern eine 16-Bit Variable. Die hat einen Wertebereich von -32768 bis +32767. Da kannst Du 1000*60 nicht mehr darstellen. wenn Du 1000UL*60 verwendest wird der Wertebereich erweitert ( unsigned long, der gleiche Typ wie millis() ). Dann sollte es funktionieren.
Edit: Tommy war schneller :laughing:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.