Variable bei längerem Tastendruck schnell hochzählen

moin,

ich habe zur Zeit ein Projekt mit einem LCD. Möchte für ein Menü eine Variable per Tastendruck hochzählen. Wenn ich den Taster kurz drücke soll sie einmal hochgezählt werden, drücke ich den Taster länger als 2-3 Sekunden soll die Variable schnell hochgezählt werden. Leider klappt das nicht wirklich

habe das mit einer While-Schleife probiert was an sich blöd ist weil er dann ja erst aktualisiert wenn ich den Taster loslasse und somit gar nicht sehe welchen Wert die gerade hat Variable hat.

#include <Arduino.h>
#include <U8g2lib.h>

U8G2_ST7565_64128N_F_4W_SW_SPI u8g2(U8G2_R2, /* clock=*/ 12, /* data=*/ 10, /* cs=*/ 8, /* dc=*/ 11, /* reset=*/ 9);

bool Taster_status = 0;
byte Sollwert;

#define Taster 5
#define Led_blau 2
#define Led_gruen 3

void setup() {
  Serial.begin(115200); 

  u8g2.begin(); 

  u8g2.setContrast(163);
  u8g2.setFontMode(0);
  u8g2.setFont(u8g2_font_ncenB08_tr);

  pinMode(Taster, INPUT);
  pinMode(Led_gruen, OUTPUT);
  pinMode(Led_blau, OUTPUT);

  // Backlight
  digitalWrite(Led_blau, HIGH);
  digitalWrite(Led_gruen, HIGH);

}

void loop()
{
  Taster_Abfrage();

  char SollwertString[6];
  sprintf(SollwertString, "%02i", Sollwert);

  u8g2.setCursor(20, 45);
  u8g2.print(SollwertString);
  u8g2.sendBuffer();

}

void Taster_Abfrage() {

  bool Taster_gedrueckt = digitalRead(Taster);

  if ((Taster_gedrueckt == 0) && (Taster_status == 0))
  {
    Serial.println("Taster gedrueckt");

    static unsigned long letzteMillis = 0;
    unsigned long aktuelleMillis = millis();

    while (digitalRead(Taster) == LOW)
    {
      if (aktuelleMillis - letzteMillis >= 2000)
      {
        Sollwert++; // Bei langem drücken schnell hochzählen
        delay(30);
        letzteMillis = aktuelleMillis;
      }
    }

    Taster_status = 1;
    delay(5);
  }

  if ((Taster_gedrueckt == 1) && (Taster_status == 1))
  {
    Serial.println("Taster wurde losgelassen");
    u8g2.clearBuffer();

    Taster_status = 0;
    delay(5);
  }
}

Jemand ne Idee wie man das umsetzt ? Danke schon mal

Mfg

habe das mit einer While-Schleife probiert was an sich blöd ist weil er dann ja erst aktualisiert wenn ich den Taster loslasse und somit gar nicht sehe welchen Wert die gerade hat Variable hat

Gut beobachtet.
Statt Zusätzlich zur Flankenerkennung musst du dir nur die Zeit seit dem letzten Hochzählen merken und - wenn der Taster immer noch gedrückt ist - wieder eins mehr usw. Um diese Zeit abzuwarten ist eine while Schleife innerhalb von loop natürlich -wie immer- Mist weil unnötig kompliziert..

michael_x:
Zusätzlich zur Flankenerkennung musst du dir nur die Zeit seit dem letzten Hochzählen merken und - wenn der Taster immer noch gedrückt ist - wieder eins mehr usw. Um diese Zeit abzuwarten

Hi,

so ungefähr hatte ich mir das auch gedacht

Ich wollte das sobald ich den Taster drücke das ein Timer startet. Ist der abgelaufen und Taster immer noch LOW soll er schnell hochzählen. Durch die Flankenerkennung läuft die If abfrage, ob der Taster gedrückt ist nur einmal bis ich ihn loslasse, weswegen millis() nichts bringt. Oder besser gesagt ich bekomms nicht hin.

da häng ich gerade.

Mfg

Hallo,

Du könntst Dir ma die oneButton Lib ansehen , da kannst Du einem Taster 3 Ereignisse zuweisen , drücken, doppel drücken, lang drücken.

Heinz

da häng ich gerade.

Kann dir zeigen, wie das bei mir aussehen würde.

Zumindest sind dort alle benötigten Softwarekomponenten klar von einander getrennt und benannt.

Wie du sie dann programmierst, wie das dann bei dir aussieht, ist egal.
Aber all das muss sein.

#include <CombieTypeMangling.h>
#include <CombiePin.h>
#include <CombieTimer.h>
#include <CombieTools.h>
#include <INTERVAL.h>

using namespace Combie::Millis;
using namespace Combie::Tools;
using namespace Combie::Timer;
using namespace Combie::Pin; 

using CounterType = Counter<unsigned long>;

TasterGND<2>      taster; // Taster gegen GND geschaltet
EntprellTimer     entprellen {20_ms};
FlankenErkennung  flankenerkennung;
RisingEdgeTimer   ton {2_sec};  // langer Tastendruck nach x sec erkannt
CounterType       counter;


void setup() 
{
    Serial.begin(9600);
    taster.initPullup();
    counter.onCount([](CounterType &counter)
                    { 
                      Serial.print("Ereignis Nr: ");
                      Serial.println(counter);
                    });
}

void loop() 
{ 
  bool Y; // Tastendruck Verteiler/Merker Y-Stück
  counter = flankenerkennung = Y = entprellen = taster;

  // langen Tastendruck abhandeln 
  INTERVAL(100_ms) counter = ton = Y;
}

CombieLib.zip (76.1 KB)

könntest du kein if statement mit +1 bei der variable programmieren?
sodass das arduino alle paar millisekunden checkt ob der taster gedrückt wird & wenn ya dann +1 dazugibt

verstehst du wie ich meine?

bin neu aber so würde ich es versuchen, kann ich auch machen wenn du willst

imho brauchst du die while nur raus geben in den Körper der Funktion und unter die Bedingung stellen, dass der Taster gedrückt ist - und vorhin auch gedrückt war. Dann noch ein paar Variablen den Scope erhöhen bzw. die richtigen nehmen, dann könnte es ca so aussehen:

//#include <Arduino.h>
//#include <U8g2lib.h>

//U8G2_ST7565_64128N_F_4W_SW_SPI u8g2(U8G2_R2, /* clock=*/ 12, /* data=*/ 10, /* cs=*/ 8, /* dc=*/ 11, /* reset=*/ 9);

bool Taster_status = 0;
byte Sollwert;

#define Taster 5
#define Led_blau 2
#define Led_gruen 3

void setup() {
  Serial.begin(115200);

  /*
    u8g2.begin();
    u8g2.setContrast(163);
    u8g2.setFontMode(0);
    u8g2.setFont(u8g2_font_ncenB08_tr);
  */

  pinMode(Taster, INPUT);
  pinMode(Led_gruen, OUTPUT);
  pinMode(Led_blau, OUTPUT);

  // Backlight
  digitalWrite(Led_blau, HIGH);
  digitalWrite(Led_gruen, HIGH);
}

void loop()
{
  Taster_Abfrage();

  char SollwertString[6];
  sprintf(SollwertString, "%02i", Sollwert);

  /*
    u8g2.setCursor(20, 45);
    u8g2.print(SollwertString);
    u8g2.sendBuffer();
  */
}

void Taster_Abfrage() {

  bool Taster_gedrueckt = digitalRead(Taster);

  static unsigned long letzteMillis = 0;
  unsigned long aktuelleMillis = millis();
  
  if ((Taster_gedrueckt == 0) && (Taster_status == 0))
  {
    Serial.println("Taster erstmals gedrueckt");
    Taster_status = 1;
    letzteMillis = millis();
    delay(5);
  }

  if ((Taster_gedrueckt == 0) && (Taster_status == 1))
  {
    Serial.println("Taster ist noch immer gedrückt");
    if (aktuelleMillis - letzteMillis >= 2000)
    {
      Serial.println("... und zwar lange");
      Sollwert++; // Bei langem drücken schnell hochzählen
      delay(30);
    }
  }

  if ((Taster_gedrueckt == 1) && (Taster_status == 1))
  {
    Serial.println("Taster wurde losgelassen");
    //u8g2.clearBuffer();

    Taster_status = 0;
    delay(5);
  }
}

Wenn du schon eine Funktion namens Tasterabfrage() hast, könnte die doch auch etwas zurückliefern (z.B. false wenn kein Taster gedrückt ist, oder true um einen neuen Tastendruck anzuzeigen oder zu simulieren)

Das eigentliche Problem ist übrigens dein delay(30); // schnell hochzählen .

bool Tasterabfrage() {
  static unsigned long startzeit;
  static bool Taster_status; // Flankenerkennung: true = gedrückt
  static bool Taster_dauer;  // true : REPEAT abwarten, false: STARTVERZ abwarten
  const int STARTVERZ = 2000;
  const int REPEAT = 200;

  bool Taster_gedrueckt = ! digitalRead(Taster); // negieren wg. INPUT_PULLUP  

  if ((Taster_gedrueckt) && (! Taster_status)) {
    Serial.println("Taster gedrueckt");
    startzeit = millis();
    Taster_dauer = false;
    Taster_status = true;
    delay(5); // entprellen
    return true;
  }

  if ((Taster_gedrueckt) && (Taster_status)) {
    if(millis() - startzeit >= (Taster_dauer? REPEAT:STARTVERZ)  {
        startzeit= millis();
        Taster_dauer = true;
        return true;
    }
    else return false; // gedrückt, aber noch nicht hochzählen 
  }

  if ((!Taster_gedrueckt && Taster_status))
  {
    Serial.println("Taster wurde losgelassen");
    Taster_status = false;
    delay(5); // entprellen
    return false;
  }
}

Das in loop richtig auszuwerten überlasse ich dir.
Einer Funktion namens Tasterabfrage() sollte egal sein, welche Anzeige-Bibliothek verwendet wird und welche globale Variable evtl. zu verändern ist.
Dass diese Abfrage nur für einen bestimmten Taster funktioniert (und mit static Variablen auskommt), habe ich mal so gelassen. Aber Taster_gedrueckt sollte auch bedeuten, was der Name sagt.

Wenn man combie ist, verwendet man natürlich combie-libraries. Erstmal geht's zur Not auch ohne.

Wenn man combie ist, verwendet man natürlich combie-libraries.

Immerhin hat das Ich min. 5 Jahre intensiv beobachtet, welche Pattern am häufigsten zum Einsatz kommen, diese dann, nach und nach, benannt und in eine Libsammlung gegossen.

Erstmal geht's zur Not auch ohne.

Sicherlich dutzende alternative Wege, es gibt.

Dinge, welche ich nicht so mag:

  • geschachtelte if()
  • komplexe Bedingungen in if()
  • statische Variablen
  • offen mitgeschleppte Zustände

Das mit den komplexen if(komplexe Bedingung) else Schachtelungen durchdringe ich nicht, oder nur widerwillig.
Vermutlich bin ich zu doof dafür. :o

Bin ja sogar zu blöd, um im dunklen Angst zu haben.

Danke für die vielen Vorschläge werde ich zuhause gleich mal ausprobieren

michael_x:

if(millis() - startzeit >= (Taster_dauer? REPEAT:STARTVERZ)  {

Das hab ich ja noch nie gesehen mit dem Fragezeichen. Was fragt die denn ab?

@combie:

Hast du die Bibliotheken selber geschrieben oder dich nur danach benannt?

Das hab ich ja noch nie gesehen mit dem Fragezeichen. Was fragt die denn ab?

Das ist der ternäre Operator.
Das C++ Handbuch gibt Auskunft!

@combie:

Hast du die Bibliotheken selber geschrieben oder dich nur danach benannt?

Hatte schon "Vorbilder", und auch Kommunikation im Forum hier, aber ja, selber geschrieben.
Meinen Dank an der Stelle.

Mein Name kommt von "Computer Bienen".
Denn dank der Bienen habe ich begriffen, wie man Computer "richtig und wahrhaftig" programmiert.
Die haben es mir vorgelebt.
Auch: Danke!

combie:
Das C++ Handbuch gibt Auskunft!

Generation Google. Hab noch nie ein Buch in der Hand gehabt.

michael_x:
Das in loop richtig auszuwerten überlasse ich dir.

Dazu hätte ich mal ne frage.

habe das so gemacht:

 bool bla = Tasterabfrage();

  if (bla == true)
    Serial.println("Taster gedrueckt");

Aber warum bekomme ich hier nichts bzw. nur 0 raus ?

Serial.println("Tasterabfrage());

die Funktion Tasterabfrage() ist doch ein bool, müsste ich durch das return dann nicht 0 oder 1 raus bekommen ?

Mfg

Klingelprofi:

if(millis() - startzeit >= (Taster_dauer? REPEAT:STARTVERZ)  {

Das hab ich ja noch nie gesehen mit dem Fragezeichen. Was fragt die denn ab?

Das Konstrukt mit dem Fragezeichen ist eine Art „if-then-else“:

A?B:C

heißt „wenn A, dann B, sonst C“

Gruß

Gregor

Klingelprofi:
Aber warum bekomme ich hier nichts bzw. nur 0 raus ?

Serial.println("Tasterabfrage());

die Funktion Tasterabfrage() ist doch ein bool, müsste ich durch das return dann nicht 0 oder 1 raus bekommen ?

Ich bekomme da einen Syntax Error

Hab noch nie ein Buch in der Hand gehabt.

Tipp: Das könntest du ändern.

Hi

In Dem Beispiel, wenn 'Taster_dauer' ungleich Null ist, wird der Wert 'REPEAT' zum Vergleich benutzt, sonst der Wert 'STARTVERZ'.

Wobei ich diese Werte irgendwie 'anders' genannt hätte - damit man sieht, daß Es Sich um Zeiten handelt.
REPEAT deutet zumindest nicht direkt auf ein Warten - meine Meinung

MfG

gregorss:
Das Konstrukt mit dem Fragezeichen ist eine Art „if-then-else“:

Yep. Das hatte ich gefunden

is this condition true ? yes : no

combie:
Ich bekomme da einen Syntax Error

Tipp: Das könntest du ändern.

#define Taster D6

void setup()
{
  pinMode(Taster, INPUT);
  Serial.begin(115200);
}

void loop()
{
  bool bla = Tasterabfrage();

  if (bla == true)
    Serial.println("Taster gedrueckt");

  // Serial.println(Tasterabfrage()); // Bekomme nur 0 Raus

}


bool Tasterabfrage() {

  static unsigned long startzeit;
  static bool Taster_status; // Flankenerkennung: true = gedrückt
  static bool Taster_dauer;  // true : REPEAT abwarten, false: STARTVERZ abwarten
  const int STARTVERZ = 2000;
  const int REPEAT = 200;

  bool Taster_gedrueckt = digitalRead(Taster); 
  
  if ((Taster_gedrueckt) && (! Taster_status))
  {
    //   Serial.println("Taster gedrueckt");
    startzeit = millis();
    Taster_dauer = false;
    Taster_status = true;
    delay(5); // entprellen
    return true;
  }

  if ((Taster_gedrueckt) && (Taster_status))
  {
    if (millis() - startzeit >= (Taster_dauer ? REPEAT : STARTVERZ))
    {
      startzeit = millis();
      Taster_dauer = true;
      return true;
    }
    else return false; // gedrückt, aber noch nicht hochzählen
  }

  if ((!Taster_gedrueckt && Taster_status))
  {
    //Serial.println("Taster wurde losgelassen");
    Taster_status = false;
    delay(5); // entprellen
    return false;
  }
}

Ich meinte das ich Google besser finde. Wenn du was auf der ersten Seite nicht verstehst gehst du einfach auf die nächste und so weiter. Kannst du bei einem Buch nicht.Hat sich die Letzten Jahre gut bewehrt

Mfg

Klingelprofi:
Ich meinte das ich Google besser finde. Wenn du was auf der ersten Seite nicht verstehst gehst du einfach auf die nächste und so weiter. Kannst du bei einem Buch nicht.Hat sich die Letzten Jahre gut bewehrt

TIPP: Ein Buch hat Seiten, die meistens sogar numeriert sind. Funktioniert auch ohne Strom.

Gruß

Gregor

... oder ohne Innanetz ... hatte Gestern eine halbe Stunde Router und Modem dann doch noch überreden können, doch noch Mal miteinander zu schwätzen ... hegte schon einen Groll gegen 'Die da Oben' wegen der Reduzierung auf Null :slight_smile:

Da hast Du dann auch 'nur noch' die Datenblätter, Die man Sich so im Laufe der Jahre angehamstert hat :slight_smile:

MfG

gregorss:
TIPP: Ein Buch hat Seiten, die meistens sogar numeriert sind. Funktioniert auch ohne Strom.

Daran ist es wahrscheinlich gescheitert :smiley:

Versteh aber das Problem nicht. Warum sind alle so abgeneigt davon man mit dem Internet lernt?
Meine Noten haben mir die letzten Jahre gezeigt, dass es anscheinend doch ganz gut klappt

Mfg

Klingelprofi:
Versteh aber das Problem nicht. Warum sind alle so abgeneigt davon man mit dem Internet lernt?
Meine Noten haben mir die letzten Jahre gezeigt, dass es anscheinend doch ganz gut klappt

Meine Meinung dazu ist ein bisschen diffus. Und ich arbeite nun mal gerne mit Papier. Und ich erinnere mich an jemanden, der mit mir eine Wohnung besichtigen wollte. Vor der Haustür, die eine RIESENGROSSE „46“ zeigt, wurde ich von einem ankommenden Mitbesichtiger gefragt, ob das die Nr. 46 sei - sein Navi ist sich da nicht sicher ...

:slight_smile:

Gregor