Softwareseitige Mehrfachbelegung der Playtaste

Hallo zusammen, ich bin wieder dabei einen Tonuino zu basteln. Es wird wieder einer nach dem klassischen Layout mit diversen Zusätzen wie z.B. der Pololulu Switch zum Ein- und Ausschalten. Hierbei benutze ich den Play Button zum Einschalten. Die Software ist eine angepasste Version von @Thomas-Lehnert. Hier versuche ich eine Funktion zum Ausschalten des Tonuinos per längerem Tastendruck auf den Play Knopf zu realisieren. Folgenden Code habe ich für den Play-Knopf:

    // ******************* Pause Taste ****************************************************

    if (pauseButton.wasReleased())                              // wenn Pausetaste gedrückt wurde
    {
      if (activeModifier != NULL)                               // wenn Modifikation aktiv
        if (activeModifier->handlePause() == true)              // wenn akt.Modifikation pause Taste sperrt
          return;                                               // Abbrechen
      if (ignorePauseButton == false)                           // Wenn Taste gelesen
        if (isPlaying())                                        // wenn Wiedergabe
        {
          mp3.pause();                                          // Pause der Wiedergabe
          setstandbyTimer();
        }
        else if (knownCard)                                     // wenn keine Wiedergabe läuft und karte bekannt
        {
          mp3.start();                                          // Wiedergabe starten
          disablestandbyTimer();
        }
      ignorePauseButton = false;                                // Pausetaste auswerten
    }
    else if (pauseButton.pressedFor(LONG_PRESS)
             && ignorePauseButton == false)                     // Langer Druck Pausetaste für Ansage des aktuellen Tracks
    {
      if (activeModifier != NULL)                               // wenn Modifikationskarte aktiv
        if (activeModifier->handlePause() == true)              // wenn Pausetaste gesperrt - Abbruch
          return;
      if (isPlaying())                                          // wenn Wiedergabe läuft
      {
        uint8_t advertTrack = queue[currentQueueIndex];         // Auslesen der Tracknummer für Ansage Tracknr

        // Spezialmodus Von-Bis für Album und Party gibt die Dateinummer relativ zur Startposition wieder
        if (myFolder->mode == 8 || myFolder->mode == 9)         // Spezialmodus Album oder Spezialmodus Party
        {
          advertTrack = advertTrack - myFolder->special + 1;    // Ansage auf relative Track Nr
        }

        //************ Rücksetzen - Hörbuch auf Anfang ****************************
        // Im Hörbuchmodus wird durch langen Druck Pause Taste der Fortschritt auf Anfang gesetzt
#ifdef HB_Reset
        if (myFolder->mode == 5)                                // Hörbuchmodus
        {
          currentQueueIndex = 1;                                // aktueller Track auf 1 setzen
          advertTrack = currentQueueIndex;                      // Ansage auf aktueller Track
          mp3.playAdvertisement(advertTrack);                   // Tracknummer ansagen

#ifndef AiO
          EEPROM.update(myFolder->folder, currentQueueIndex);   // Track 1 im EEProm speichern
#endif
#ifdef AiO
          EEPROM_update(myFolder->folder, currentQueueIndex);   // Track 1 im EEProm speichern
#endif
#ifdef DEBUG
          Serial.println(F("Hörbuch Modus -> Anfang"));
#endif
          mp3.playFolderTrack(myFolder->folder, currentQueueIndex);  // aktuellen Track spielen
        }
#endif
        //************** Ende, Rücksetzen - Hörbuch auf Anfang ***********************
        else                                                    // alle anderen Abspielmodi
        {
          mp3.playAdvertisement(advertTrack);                   // Tracknummer ansagen
        }
      }
      else                                                      // wenn keine Wiedergabe läuft
      {
        playShortCut(0);                                        // Shortcut Pausetaste spielen
      }
      ignorePauseButton = true;                                 // PauseTaste übergehen
    }
#ifdef PUSH_ON_OFF
  else if (pauseButton.pressedFor(LONGER_PRESS) &&
           ignorePauseButton == true) {
    ignorePauseButton = false;                                // Pausetaste auswerten
    ShutDown();
  }
#endif
    
    // *********** Ende Pausetaste *************************************************

Das was ich hinzugefügt habe kommt nach #ifdef PUSH_ON_OFF. Eigentlich funktioniert es soweit fast immer. Manchmal kommt der Tonuino allerdings in einen Zustand wo keine Knöpfe mehr funktionieren, so dass nur ein Reset Abhilfe schafft. Hat einer vielleicht eine Idee wie ich das besser umsetzen kann? Es sollten folgende Sachen funktionieren:

  1. Kurzer Druck: Wiedergabe Pausieren (wie gehabt)
  2. Langer Druck (etwa 1 Sekunde): Ansage der aktuellen Tracknummer
  3. Längerer Druck (etwa 3 Sekunden): Der Tonuino soll ausgeschaltet werden, dabei soll die Trackansage nicht ausgeführt werden

Viele Grüße

Man muss sich hier was einfallen lassen, wie der Tonuino den Longpress und den longerpress unterscheiden soll. Man muss also ausschließen, dass ein longerpress vorher schon als Longpress interpretiert wird und die entsprechende Aktion verhindern. Eventuell könnte man hier die millis() Funktion verwenden und den Zeitpunkt des Loslassen der Taste auswerten. Allerdings verzögert das natürlich die Ausführung der Aktion bei Longpress, weil man erst abwarten müsste, ob die Taste länger gedrückt bleibt, als bei Longpress vorgesehen. Zuzüglich einer Toleranzzeit, weil man die exakte longpresszeit nie exakt treffen wird.
Meiner Meinung nach, ist da eine Tastenkombination immer besser und zuverlässiger zu realisieren.

Ich würde auf das ansagen der Tracknummer verzichten. Wie oft und wofür braucht man das…?!

Hmm… da habe ich mir ja was ausgesucht :thinking:

Wie könnte man die Auswertung, ob ein Long oder Longer Press realisieren, solange der Knopf gedrückt ist? Und die Ausführung der Aktion erst bei loslassen des Knopfes ausgeführt wird. Also wird zum Beispiel der Knopf Long gedrückt gehalten, dann die entsprechende Aktion ausführen. Wird allerdings der Knopf Longer gehalten, sollte die Long Aktion ignoriert werden und dann bei Loslassen des Knopfes die Longer Aktion ausgeführt werden. Ich weiß nicht genau wie man sowas programmiertechnisch umsetzen kann.

Zurzeit wird bei Longerpress die Trackansage ausgeführt und anschließend wird der Tonuino ausgemacht. Wäre ja ok, wenn es nicht manchmal zu Komplikationen (Absturz des Tonuino) führt.

Bin etwas überfragt mit der Programmierung, würde es sehr gerne so umsetzen wollen…

Vielleicht hat einer eine Idee. Danke euch!

Also ich hab für unseren tonuino mit @Thomas-Lehnert Always Queue auch eine Taste zum ein und ausschalten definiert allerdings die vor Taste da ich den Rotary encoder verwende und ich das mit dem Teil nicht hinbekomme.

Das Ausschalten läuft auch über longer_press

Allerdings wird dadurch manchmal erst long_press und dann erst longer_press ausgeführt

man muss im Long_Press Zweig abfragen ob der Taster auch released wurde bzw. noch auf pressed steht, wenn nicht auf ein Longer_Press abfragen.

Ich bin aktuell etwas überfordert mit der Umsetzung des Vorschlags. Das klingt aber logisch, was du da meinst. Hast du evtl einen Tipp wie ich die Abfragen einbauen kann?

ich mach das mal exemplarisch:

#define SHORT_PRESS 150
#define LONG_PRESS 1000
#define LONGER_PRESS 4000

void loop () {

 if (pauseButton.pressedFor(LONGER_PRESS) ) {
     //shutdown
   }
 if (pauseButton.pressedFor(LONG_PRESS) ) {
    if (!pauseButton.isPressed()) {
         //spiele TrackNr. 
     }
   }
 if (pauseButton.pressedFor(SHORT_PRESS) ) {
    if (!pauseButton.isPressed()) {
        //pause
      }
   }
}

Probier das mal so.
Pause auf .wasReleased könnte in dem Konstrukt stören, desalb hab ich es durch ein SHORT_PRESS ersetzt.

Hallo @marco-117, ich habe deinen Vorschlag mal versucht in den Code zu implementieren. Hier die aktuelle Version:

    // ******************* Pause Taste ****************************************************

    if (pauseButton.pressedFor(SHORT_PRESS))                              // wenn Pausetaste gedrückt wurde
		{
		if (!pauseButton.isPressed())
			{
			  if (activeModifier != NULL)                               // wenn Modifikation aktiv
				if (activeModifier->handlePause() == true)              // wenn akt.Modifikation pause Taste sperrt
				  return;                                               // Abbrechen
			  if (ignorePauseButton == false)                           // Wenn Taste gelesen
				if (isPlaying())                                        // wenn Wiedergabe
				{
				  mp3.pause();                                          // Pause der Wiedergabe
				  setstandbyTimer();
				}
				else if (knownCard)                                     // wenn keine Wiedergabe läuft und karte bekannt
				{
				  mp3.start();                                          // Wiedergabe starten
				  disablestandbyTimer();
				}
			  ignorePauseButton = false;                                // Pausetaste auswerten
			}
		}	
	
	if (pauseButton.pressedFor(LONG_PRESS))                     // Langer Druck Pausetaste für Ansage des aktuellen Tracks
		{
		if (!pauseButton.isPressed())
			{
			  if (activeModifier != NULL)                               // wenn Modifikationskarte aktiv
				if (activeModifier->handlePause() == true)              // wenn Pausetaste gesperrt - Abbruch
				  return;
			  if (isPlaying())                                          // wenn Wiedergabe läuft
			  {
				uint8_t advertTrack = queue[currentQueueIndex];         // Auslesen der Tracknummer für Ansage Tracknr

				// Spezialmodus Von-Bis für Album und Party gibt die Dateinummer relativ zur Startposition wieder
				if (myFolder->mode == 8 || myFolder->mode == 9)         // Spezialmodus Album oder Spezialmodus Party
				{
				  advertTrack = advertTrack - myFolder->special + 1;    // Ansage auf relative Track Nr
				}

				//************ Rücksetzen - Hörbuch auf Anfang ****************************
				// Im Hörbuchmodus wird durch langen Druck Pause Taste der Fortschritt auf Anfang gesetzt
				#ifdef HB_Reset
				if (myFolder->mode == 5)                                // Hörbuchmodus
				{
				  currentQueueIndex = 1;                                // aktueller Track auf 1 setzen
				  advertTrack = currentQueueIndex;                      // Ansage auf aktueller Track
				  mp3.playAdvertisement(advertTrack);                   // Tracknummer ansagen

				#ifndef AiO
				  EEPROM.update(myFolder->folder, currentQueueIndex);   // Track 1 im EEProm speichern
				#endif
				#ifdef AiO
				  EEPROM_update(myFolder->folder, currentQueueIndex);   // Track 1 im EEProm speichern
				#endif
				#ifdef DEBUG
				  Serial.println(F("Hörbuch Modus -> Anfang"));
				#endif
				  mp3.playFolderTrack(myFolder->folder, currentQueueIndex);  // aktuellen Track spielen
				}
				#endif
				//************** Ende, Rücksetzen - Hörbuch auf Anfang ***********************
				else                                                    // alle anderen Abspielmodi
				{
				  mp3.playAdvertisement(advertTrack);                   // Tracknummer ansagen
				}
			  }
			  else                                                      // wenn keine Wiedergabe läuft
			  {
				  playShortCut(0);                                        // Shortcut Pausetaste spielen
			  }
			  ignorePauseButton = true;                                 // PauseTaste übergehen
			}
		}

	#ifdef PUSH_ON_OFF
	if (pauseButton.pressedFor(LONGER_PRESS))
	{
		ShutDown();
	}
	#endif
   
    // *********** Ende Pausetaste *************************************************

Irgendwie funktioniert es noch nicht so richtig. Das Ausschalten läuft. Die anderen beiden Abfragen (SHORT bzw. LONG Press) funktionieren irgendwie noch nicht, keine Reaktion. Was müsste im Code noch angepasst werden?

nimm mal die
if (!pauseButton.isPressed())
raus.

Wenn das aber wieder zu fehl Verhalten führt, musst du wahrscheinlich eine andere Bilbiothek für die Buttons verwenden, das wird dann aber aufwändig.

Hallo zusammen, ich habe etwas recherchiert und eine Möglichkeit gefunden mehr als zwei Funktionen über einen Taster sauber auszuführen. Das ganze arbeitet, wie @Thomas-Lehnert auch vorgeschlagen hat, mit der millis Funktion. Fragt mich allerdings nicht genau wie es funktioniert. Folgendes wird ausgeführt:

  1. Kurzer Tastendruck: Pause/Play
  2. Doppeldruck: Ansage des aktuellen Tracks
  3. Langer Druck (zwischen 3 und 8 Sekunden): Ausschalten des Tonuino (ohne Ansage des Tracks)
    Bei dem Langen Druck musste die maximale Zeit begrenzt werden (daher 8 Sekunden), da beim Verlassen des Adminmenüs der Tonuino sonst ausgemacht wurde.

Das ist der Code:

// Deklaration von Variablen:
#define LONGER_PRESS 3000						// längerer Druck >= 3 sekunden
// ---------------Zur Erkennung von Mehrfachfunktionen bei Druck auf Play-/Pausetaste-------------------
int lastButtonState = HIGH;   					        // the previous reading from the input pin
unsigned long lastDebounceTime = 0;  			      // the last time the output pin was toggled
unsigned long debounceDelay = 25;    			      // the debounce time; increase if the output flickers
bool buttonState = HIGH; 						            // saving state of the switch
byte tapCounter; 								                // for saving no. of times the switch is pressed
int timediff; 									                // for saving the time in between each press and release of the switch
bool flag1, flag2; 								              // just two variables
long double presstime, releasetime; 			      // for saving millis at press and millis at release


// in der void loop () eintragen:
	// ************** Vorbereitung zur Auswertung der Multifunktionen der Play-/Pausetaste ****************
	int reading = digitalRead(ButtonPause);

	if (reading != lastButtonState) {
		// reset the debouncing timer
		lastDebounceTime = millis();
	}

	if ((millis() - lastDebounceTime) > debounceDelay) {
		// whatever the reading is at, it's been there for longer than the debounce
		// delay, so take it as the actual current state:

		// if the button state has changed:
		if (reading != buttonState) {
		  buttonState = reading;
		}
	}

	//when button is pressed
	if (buttonState == 0 && flag2 == 0)
	  {
		presstime = millis(); //time from millis fn will save to presstime variable
		flag1 = 0;
		flag2 = 1;
		tapCounter++; //tap counter will increase by 1
		//delay(10); //for avoiding debouncing of the button
	}
	//when button is released
	if (buttonState == 1 && flag1 == 0)
	{
		releasetime = millis(); //time from millis fn will be saved to releasetime var
		flag1 = 1;
		flag2 = 0;

		timediff = releasetime - presstime; //here we find the time gap between press and release and stored to timediff var
		//Serial.println(timediff);
		//delay(10);
	}
	// *********** Ende der Vorbereitung zur Auswertung der Multifunktionen der Play-/Pausetaste *************
    // ******************* Pause Taste ****************************************************
	if ((millis() - presstime) > 300 && buttonState == 1)			  //wait for some time and if button is in release position
	{
		if (tapCounter == 1)										  //if tap counter is 1
		{
		  if (timediff >= LONGER_PRESS && timediff < 8000)			  //if time diff is larger than LONGER_PRESS = 3s and lower than 8s then its a hold
		  {
			//----fn to call when the button is hold----
			#ifdef PUSH_ON_OFF
				ShutDown();											  // Tonuino Ausschalten
			#endif			
		  }

		  else if (timediff < 300)									  //if timediff is less than 300 then its a single tap
		  {
			//----fn to call when the button is single taped----
			if (activeModifier != NULL)                               // wenn Modifikation aktiv
			  if (activeModifier->handlePause() == true)              // wenn akt.Modifikation pause Taste sperrt
				return;                                               // Abbrechen
			if (isPlaying())                                          // wenn Wiedergabe
			{
				mp3.pause();                                          // Pause der Wiedergabe
				setstandbyTimer();
			}
			else if (knownCard)                                       // wenn keine Wiedergabe läuft und karte bekannt
			{
				mp3.start();                                          // Wiedergabe starten
				disablestandbyTimer();
			}
		  }
		}

		else if (tapCounter == 2 ) //if tapcounter is 2
		{
			//----fn to call when doubletap----
			if (activeModifier != NULL)                               // wenn Modifikationskarte aktiv
			  if (activeModifier->handlePause() == true)              // wenn Pausetaste gesperrt - Abbruch
				  return;
			if (isPlaying())                                          // wenn Wiedergabe läuft
			{
			  uint8_t advertTrack = queue[currentQueueIndex];         // Auslesen der Tracknummer für Ansage Tracknr

			  // Spezialmodus Von-Bis für Album und Party gibt die Dateinummer relativ zur Startposition wieder
			  if (myFolder->mode == 8 || myFolder->mode == 9)         // Spezialmodus Album oder Spezialmodus Party
			  {
				advertTrack = advertTrack - myFolder->special + 1;    // Ansage auf relative Track Nr
			  }

			  //************ Rücksetzen - Hörbuch auf Anfang ****************************
			  // Im Hörbuchmodus wird durch langen Druck Pause Taste der Fortschritt auf Anfang gesetzt
			  #ifdef HB_Reset
			  if (myFolder->mode == 5)                                // Hörbuchmodus
			  {
				currentQueueIndex = 1;                                // aktueller Track auf 1 setzen
				advertTrack = currentQueueIndex;                      // Ansage auf aktueller Track
				mp3.playAdvertisement(advertTrack);                   // Tracknummer ansagen

				#ifndef AiO
				EEPROM.update(myFolder->folder, currentQueueIndex);   // Track 1 im EEProm speichern
				#endif
				#ifdef AiO
				EEPROM_update(myFolder->folder, currentQueueIndex);   // Track 1 im EEProm speichern
				#endif
				#ifdef DEBUG
				Serial.println(F("Hörbuch Modus -> Anfang"));
				#endif
				mp3.playFolderTrack(myFolder->folder, currentQueueIndex);  // aktuellen Track spielen
			  }
			  #endif
			  //************** Ende, Rücksetzen - Hörbuch auf Anfang ***********************
			  else                                                    // alle anderen Abspielmodi
			  {
				mp3.playAdvertisement(advertTrack);                   // Tracknummer ansagen
			  }
			}
			else                                                      // wenn keine Wiedergabe läuft
			{
			  playShortCut(0);                                        // Shortcut Pausetaste spielen
			}
		}
		tapCounter = 0;
	}
	lastButtonState = reading;
    // *********** Ende Pausetaste *************************************************

Es funktioniert bisher recht gut. Man hätte sogar noch weitere Funktionen ausführen können. Zum Beispiel lässt sich ein Short Press und danach ein Hold als eine Tastenkombination oder ein Tripple-Druck realisieren.

Quelle zum Nachlesen: https://diyusthad.com/2019/04/arduino-projects-single-switch-multiple-functions.html

Ich werde das mal durch meinen Tester (mein Sohn) ausführlich ausprobieren lassen :slight_smile:
Schöne Grüße

2 „Gefällt mir“