Button Funktion

Hallo zusammen, wie bereits angedeutet, habe ich mich dem Thema Button angenommen. Ich habe mich bei meiner Box gegen einen Encoder entschieden und somit 5 Taster verbaut. Um die Box manuell in Sleepmodus zu schalten, wollte ich Multitaster 4+5 verwenden. Hier gab es dann leider ein paar Probleme und so habe ich mich durch das Programm gewurschtelt.

Ich habe folgende Anpassungen in Setting.h gemacht:

  1. Habe ich die Varibalen erweitert, so dass man unterscheiden kann, welche Funktion bei einem kurzem Tastendruck+loslassen, bei einem langem Tastendruck+loslassen und bei einem langen Tastendruck+ohne loslassen passieren soll. Das ganze für jeden einzelnen und für jede zweier Multitaster eingabe.
    2

#define BUTTON_0_SHORT CMD_NEXTTRACK
#define BUTTON_1_SHORT CMD_PREVTRACK
#define BUTTON_2_SHORT CMD_PLAYPAUSE
#define BUTTON_3_SHORT CMD_NOTHING
#define BUTTON_4_SHORT CMD_VOLUMEDOWN
#define BUTTON_5_SHORT CMD_VOLUMEUP

#define BUTTON_MULTI_01_SHORT   CMD_NOTHING   //CMD_TOGGLE_WIFI_STATUS (disabled now to prevent children from unwanted WiFi-disable)
#define BUTTON_MULTI_02_SHORT   CMD_NOTHING
#define BUTTON_MULTI_03_SHORT   CMD_NOTHING
#define BUTTON_MULTI_04_SHORT   CMD_NOTHING
#define BUTTON_MULTI_05_SHORT   CMD_NOTHING
#define BUTTON_MULTI_12_SHORT   CMD_NOTHING
#define BUTTON_MULTI_13_SHORT   CMD_NOTHING
#define BUTTON_MULTI_14_SHORT   CMD_NOTHING
#define BUTTON_MULTI_15_SHORT   CMD_NOTHING
#define BUTTON_MULTI_23_SHORT   CMD_NOTHING
#define BUTTON_MULTI_24_SHORT   CMD_NOTHING
#define BUTTON_MULTI_25_SHORT   CMD_NOTHING
#define BUTTON_MULTI_34_SHORT   CMD_NOTHING
#define BUTTON_MULTI_35_SHORT   CMD_NOTHING
#define BUTTON_MULTI_45_SHORT   CMD_NOTHING



#define BUTTON_0_LONG     CMD_NOTHING
#define BUTTON_1_LONG     CMD_NOTHING
#define BUTTON_2_LONG     CMD_NOTHING
#define BUTTON_3_LONG     CMD_NOTHING
#define BUTTON_4_LONG     CMD_VOLUMEDOWN
#define BUTTON_5_LONG     CMD_VOLUMEUP


#define BUTTON_0_LONG_Release     CMD_NOTHING
#define BUTTON_1_LONG_Release     CMD_NOTHING
#define BUTTON_2_LONG_Release     CMD_NOTHING
#define BUTTON_3_LONG_Release     CMD_NOTHING
#define BUTTON_4_LONG_Release     CMD_NOTHING
#define BUTTON_5_LONG_Release     CMD_NOTHING


#define BUTTON_MULTI_01_LONG   CMD_MEASUREBATTERY   //CMD_TOGGLE_WIFI_STATUS (disabled now to prevent children from unwanted WiFi-disable)
#define BUTTON_MULTI_02_LONG   CMD_NOTHING
#define BUTTON_MULTI_03_LONG   CMD_NOTHING
#define BUTTON_MULTI_04_LONG   CMD_NOTHING
#define BUTTON_MULTI_05_LONG   CMD_NOTHING
#define BUTTON_MULTI_12_LONG   CMD_NOTHING
#define BUTTON_MULTI_13_LONG   CMD_NOTHING
#define BUTTON_MULTI_14_LONG   CMD_NOTHING
#define BUTTON_MULTI_15_LONG   CMD_NOTHING
#define BUTTON_MULTI_23_LONG   CMD_NOTHING
#define BUTTON_MULTI_24_LONG   CMD_NOTHING
#define BUTTON_MULTI_25_LONG   CMD_NOTHING
#define BUTTON_MULTI_34_LONG   CMD_NOTHING
#define BUTTON_MULTI_35_LONG   CMD_NOTHING
#define BUTTON_MULTI_45_LONG   CMD_NOTHING


#define BUTTON_MULTI_01_LONG_Release   CMD_NOTHING   //CMD_TOGGLE_WIFI_STATUS (disabled now to prevent children from unwanted WiFi-disable)
#define BUTTON_MULTI_02_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_03_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_04_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_05_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_12_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_13_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_14_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_15_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_23_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_24_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_25_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_34_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_35_LONG_Release   CMD_NOTHING
#define BUTTON_MULTI_45_LONG_Release   CMD_SLEEPMODE
  1. Habe ich die Zeitvariablen etwas umbenannt und erweitert.
    buttonDebounceInterval : ist wie gebt die Zeit um die Taster zu entprellen
    buttonDelayLastButtonState : ist die Zeit, in der man bei einem Multitaster+loslassen die Taster gleichzeitig loslassen muss
    intervalToLongPress: ist die Zeit, ab wann es ein langer Tasterdruck ist.
    intervalToLongPressRepeat: ist es ein langer Tasterdruck, wird die Funktion in dieser Zeit wiederholt ausgeführt. Dies ist praktisch, um z.B. die Lautstärke zu erhöhen.

	constexpr uint8_t buttonDebounceInterval = 20;                // Interval in ms to software-debounce buttons
	constexpr uint16_t buttonDelayLastButtonState = 1000;                // Interval in ms to software-debounce buttons
	
	constexpr uint16_t intervalToLongPress = 2000;                 // Interval in ms to distinguish between short and long press of buttons
	constexpr uint16_t intervalToLongPressRepeat = 100;                 // Interval in ms to distinguish between short and long press of buttons

Button.cpp
Hier habe ich natürlich recht viel angepasst. Im wesentlichen habe ich den Code von vorher übernommen und angepasst. Die Zeit wird sich beim Tastendruck gemerkt usw.

#include <Arduino.h>
#include "settings.h"

#include "Button.h"

#include "Cmd.h"
#include "Log.h"
#include "Port.h"
#include "System.h"

bool gButtonInitComplete = false;

// Only enable those buttons that are not disabled (99 or >115)
// 0 -> 39: GPIOs
// 100 -> 115: Port-expander
#if (NEXT_BUTTON >= 0 && NEXT_BUTTON <= MAX_GPIO)
	#define BUTTON_0_ENABLE
#elif (NEXT_BUTTON >= 100 && NEXT_BUTTON <= 115)
	#define EXPANDER_0_ENABLE
#endif
#if (PREVIOUS_BUTTON >= 0 && PREVIOUS_BUTTON <= MAX_GPIO)
	#define BUTTON_1_ENABLE
#elif (PREVIOUS_BUTTON >= 100 && PREVIOUS_BUTTON <= 115)
	#define EXPANDER_1_ENABLE
#endif
#if (PAUSEPLAY_BUTTON >= 0 && PAUSEPLAY_BUTTON <= MAX_GPIO)
	#define BUTTON_2_ENABLE
#elif (PAUSEPLAY_BUTTON >= 100 && PAUSEPLAY_BUTTON <= 115)
	#define EXPANDER_2_ENABLE
#endif
#if (ROTARYENCODER_BUTTON >= 0 && ROTARYENCODER_BUTTON <= MAX_GPIO)
	#define BUTTON_3_ENABLE
#elif (ROTARYENCODER_BUTTON >= 100 && ROTARYENCODER_BUTTON <= 115)
	#define EXPANDER_3_ENABLE
#endif
#if (BUTTON_4 >= 0 && BUTTON_4 <= MAX_GPIO)
	#define BUTTON_4_ENABLE
#elif (BUTTON_4 >= 100 && BUTTON_4 <= 115)
	#define EXPANDER_4_ENABLE
#endif
#if (BUTTON_5 >= 0 && BUTTON_5 <= MAX_GPIO)
	#define BUTTON_5_ENABLE
#elif (BUTTON_5 >= 100 && BUTTON_5 <= 115)
	#define EXPANDER_5_ENABLE
#endif

t_button gButtons[7]; // next + prev + pplay + rotEnc + button4 + button5 + dummy-button
bool gShutdownCurrentState;
bool AllButtonsReleased;
bool AllButtonsReleasedLast;
unsigned long gShutdownPressedTimestamp;

#ifdef PORT_EXPANDER_ENABLE
extern bool Port_AllowReadFromPortExpander;
#endif

static volatile SemaphoreHandle_t Button_TimerSemaphore;

hw_timer_t *Button_Timer = NULL;
static void IRAM_ATTR onTimer();
static void Button_DoButtonActions(void);

void Button_Init() {
#if (WAKEUP_BUTTON >= 0 && WAKEUP_BUTTON <= MAX_GPIO)
	if (ESP_ERR_INVALID_ARG == esp_sleep_enable_ext0_wakeup((gpio_num_t) WAKEUP_BUTTON, 0)) {
		Log_Printf(LOGLEVEL_ERROR, wrongWakeUpGpio, WAKEUP_BUTTON);
	}
#endif



// Activate internal pullups for all enabled buttons connected to GPIOs
#ifdef BUTTON_0_ENABLE
	if (BUTTON_0_ACTIVE_STATE) {
		pinMode(NEXT_BUTTON, INPUT);
	} else {
		pinMode(NEXT_BUTTON, INPUT_PULLUP);
	}
#endif
#ifdef BUTTON_1_ENABLE
	if (BUTTON_1_ACTIVE_STATE) {
		pinMode(PREVIOUS_BUTTON, INPUT);
	} else {
		pinMode(PREVIOUS_BUTTON, INPUT_PULLUP);
	}
#endif
#ifdef BUTTON_2_ENABLE
	if (BUTTON_2_ACTIVE_STATE) {
		pinMode(PAUSEPLAY_BUTTON, INPUT);
	} else {
		pinMode(PAUSEPLAY_BUTTON, INPUT_PULLUP);
	}
#endif
#ifdef BUTTON_3_ENABLE
	if (BUTTON_3_ACTIVE_STATE) {
		pinMode(ROTARYENCODER_BUTTON, INPUT);
	} else {
		pinMode(ROTARYENCODER_BUTTON, INPUT_PULLUP);
	}
#endif
#ifdef BUTTON_4_ENABLE
	if (BUTTON_4_ACTIVE_STATE) {
		pinMode(BUTTON_4, INPUT);
	} else {
		pinMode(BUTTON_4, INPUT_PULLUP);
	}
#endif
#ifdef BUTTON_5_ENABLE
	if (BUTTON_5_ACTIVE_STATE) {
		pinMode(BUTTON_5, INPUT);
	} else {
		pinMode(BUTTON_5, INPUT_PULLUP);
	}
#endif

	// Create 1000Hz-HW-Timer (currently only used for buttons)
	Button_TimerSemaphore = xSemaphoreCreateBinary();
	Button_Timer = timerBegin(0, 240, true); // Prescaler: CPU-clock in MHz
	timerAttachInterrupt(Button_Timer, &onTimer, true);
	timerAlarmWrite(Button_Timer, 10000, true); // 100 Hz
	timerAlarmEnable(Button_Timer);
}

// If timer-semaphore is set, read buttons (unless controls are locked)
void Button_Cyclic() {

	unsigned long currentTimestamp;
	currentTimestamp = millis();



	#ifdef PORT_EXPANDER_ENABLE
			Port_Cyclic();
	#endif

		if (System_AreControlsLocked()) {
			return;
		}


		gButtons[0].ActualStateIsPressed = false;
		gButtons[1].ActualStateIsPressed = false;
		gButtons[2].ActualStateIsPressed = false;
		gButtons[3].ActualStateIsPressed = false;
		gButtons[4].ActualStateIsPressed = false;
		gButtons[5].ActualStateIsPressed = false;




		// Buttons can be mixed between GPIO and port-expander.
		// But at the same time only one of them can be for example NEXT_BUTTON
		#if defined(BUTTON_0_ENABLE) || defined(EXPANDER_0_ENABLE)

				if(Port_Read(NEXT_BUTTON) ^ BUTTON_0_ACTIVE_STATE){
					gButtons[0].ActualStateIsPressed = false;
				}else{
					gButtons[0].ActualStateIsPressed = true;
				}
		#endif
		#if defined(BUTTON_1_ENABLE) || defined(EXPANDER_1_ENABLE)
				if(Port_Read(PREVIOUS_BUTTON) ^ BUTTON_1_ACTIVE_STATE){
					gButtons[1].ActualStateIsPressed = false;
				}else{
					gButtons[1].ActualStateIsPressed = true;
				}

		#endif
		#if defined(BUTTON_2_ENABLE) || defined(EXPANDER_2_ENABLE)

				if(Port_Read(PAUSEPLAY_BUTTON) ^ BUTTON_2_ACTIVE_STATE){
					gButtons[2].ActualStateIsPressed = false;
				}else{
					gButtons[2].ActualStateIsPressed = true;
				}

		#endif
		#if defined(BUTTON_3_ENABLE) || defined(EXPANDER_3_ENABLE)
				if(Port_Read(ROTARYENCODER_BUTTON) ^ BUTTON_3_ACTIVE_STATE){
					gButtons[3].currentState = false;
				}else{
					gButtons[3].currentState = true;
				}

		#endif
		#if defined(BUTTON_4_ENABLE) || defined(EXPANDER_4_ENABLE)
				if(Port_Read(BUTTON_4) ^ BUTTON_4_ACTIVE_STATE){
					gButtons[4].ActualStateIsPressed = false;
				}else{
					gButtons[4].ActualStateIsPressed = true;
				}
		#endif
		#if defined(BUTTON_5_ENABLE) || defined(EXPANDER_5_ENABLE)
				if(Port_Read(BUTTON_5) ^ BUTTON_5_ACTIVE_STATE){
					gButtons[5].ActualStateIsPressed = false;
				}else{
					gButtons[5].ActualStateIsPressed = true;
				}
		#endif


	



		AllButtonsReleased = true;

		
		for (uint8_t i = 0; i < sizeof(gButtons) / sizeof(gButtons[0]); i++) {

			if (gButtons[i].ActualStateIsPressed) {
				
				AllButtonsReleased = false;
			}
		}





		// Iterate over all buttons in struct-array
		for (uint8_t i = 0; i < sizeof(gButtons) / sizeof(gButtons[0]); i++) {


			gButtons[i].CommandPressedLong = false;
			gButtons[i].CommandReleaseShort = false;
			gButtons[i].CommandReleaseLong = false;



			if (gButtons[i].ActualStateIsPressed != gButtons[i].ActualStateIsPressedLast ) {
				
				
				if (gButtons[i].ActualStateIsPressed) {	// is pressed

					gButtons[i].PressedTimestamp = currentTimestamp;
					gButtons[i].DelayRepeatTimestamp = currentTimestamp;
					Log_Printf(LOGLEVEL_DEBUG, "tEST1. %d ", gButtons[i].PressedTimestamp);
					Log_Printf(LOGLEVEL_DEBUG, "Pressed.%d",i);
		
				} else {	//is released

					gButtons[i].ReleasedTimestamp = currentTimestamp;
					gButtons[i].DelayRepeatTimestamp = currentTimestamp;
					Log_Printf(LOGLEVEL_DEBUG, "tEST2. %d ", gButtons[i].ReleasedTimestamp);
					Log_Printf(LOGLEVEL_DEBUG, "Released. %d",i);
				}

				

			}
			gButtons[i].ActualStateIsPressedLast = gButtons[i].ActualStateIsPressed;





			if (gButtons[i].ActualStateIsPressed)	//remeber was pressed delayed
			{
				gButtons[i].DelayedActualStateIsPressed = true;
			}else if (currentTimestamp > (gButtons[i].ReleasedTimestamp + buttonDelayLastButtonState + buttonDebounceInterval)){
				gButtons[i].DelayedActualStateIsPressed = false;

			}
			

			


			if (gButtons[i].ActualStateIsPressed)	//is pressed
			{
				//long Press detected
				if ((currentTimestamp > (gButtons[i].PressedTimestamp + buttonDebounceInterval + intervalToLongPress))
				&& (currentTimestamp > (gButtons[i].DelayRepeatTimestamp + buttonDebounceInterval + intervalToLongPressRepeat))) {
					gButtons[i].CommandPressedLong = true;
					gButtons[i].DelayRepeatTimestamp = currentTimestamp;
					Log_Printf(LOGLEVEL_DEBUG, "CommandPressedLong. %d",i);
				}
				//Log_Printf(LOGLEVEL_DEBUG, "currentState. %d",i);
					//Log_Printf(LOGLEVEL_DEBUG, "tEST3. %d ", (gButtons[i].PressedTimestamp + buttonDebounceInterval + intervalToLongPress));
					//Log_Printf(LOGLEVEL_DEBUG, "tEST4. %d ", gButtons[i].ReleasedTimestamp);

			}else if(AllButtonsReleasedLast != AllButtonsReleased && AllButtonsReleased){
				//long Press detected
				if (gButtons[i].ReleasedTimestamp > (gButtons[i].PressedTimestamp + buttonDebounceInterval + intervalToLongPress)) {
					
					if(gButtons[i].DelayedActualStateIsPressed){
						gButtons[i].CommandReleaseLong = true;
						Log_Printf(LOGLEVEL_DEBUG, "CommandReleaseLong. %d",i);	

					}
					
				}else
				{
					if(gButtons[i].DelayedActualStateIsPressed){
						gButtons[i].CommandReleaseShort = true;
						Log_Printf(LOGLEVEL_DEBUG, "CommandReleaseShort. %d",i);	

					}
					

				}
			}




		}


		

		for (uint8_t i = 0; i < sizeof(gButtons) / sizeof(gButtons[0]); i++) {

			if(gButtons[i].CommandReleaseLong || gButtons[i].CommandReleaseShort || gButtons[i].CommandPressedLong){
				
				Log_Println("call1", LOGLEVEL_NOTICE);
				Button_DoButtonActions();
				break;
			}
			
		}



		AllButtonsReleasedLast = AllButtonsReleased;
		gButtonInitComplete = true;
	
	
}

// Do corresponding actions for all buttons
void Button_DoButtonActions(void) {
	

		uint8_t Cmd_Short = 0;
		uint8_t Cmd_Long = 0;


Log_Println("call2", LOGLEVEL_NOTICE);
		
	


		gShutdownCurrentState = false;


			if(gButtons[0].ActualStateIsPressed)
			{

				if (gButtons[1].ActualStateIsPressed) {
					
					gShutdownCurrentState = BUTTON_MULTI_01_LONG_Release == CMD_SLEEPMODE;

				}else if (gButtons[2].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_02_LONG_Release == CMD_SLEEPMODE;

				}else if (gButtons[3].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_03_LONG_Release == CMD_SLEEPMODE;
					
				}else if (gButtons[4].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_04_LONG_Release == CMD_SLEEPMODE;

				}else if (gButtons[5].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_05_LONG_Release == CMD_SLEEPMODE;

				}else{
					gShutdownCurrentState = BUTTON_0_LONG_Release == CMD_SLEEPMODE;
				}

				if(gShutdownCurrentState){
					gShutdownPressedTimestamp = gButtons[0].PressedTimestamp;
				}
				



			}else if(gButtons[1].ActualStateIsPressed)
			{

				if (gButtons[2].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_12_LONG_Release == CMD_SLEEPMODE;

				}else if (gButtons[3].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_13_LONG_Release == CMD_SLEEPMODE;
					
				}else if (gButtons[4].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_14_LONG_Release == CMD_SLEEPMODE;

				}else if (gButtons[5].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_15_LONG_Release == CMD_SLEEPMODE;

				}else{
					gShutdownCurrentState = BUTTON_1_LONG_Release == CMD_SLEEPMODE;
				}

				if(gShutdownCurrentState){
					gShutdownPressedTimestamp = gButtons[1].PressedTimestamp;
				}

			}else if(gButtons[2].ActualStateIsPressed)
			{

				if (gButtons[3].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_23_LONG_Release == CMD_SLEEPMODE;
					
				}else if (gButtons[4].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_24_LONG_Release == CMD_SLEEPMODE;

				}else if (gButtons[5].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_25_LONG_Release == CMD_SLEEPMODE;

				}else{
					gShutdownCurrentState = BUTTON_2_LONG_Release == CMD_SLEEPMODE;
				}

				if(gShutdownCurrentState){
					gShutdownPressedTimestamp = gButtons[2].PressedTimestamp;
				}

			}else if(gButtons[3].ActualStateIsPressed)
			{

				if (gButtons[4].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_34_LONG_Release == CMD_SLEEPMODE;

				}else if (gButtons[5].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_35_LONG_Release == CMD_SLEEPMODE;

				}else{
					gShutdownCurrentState = BUTTON_3_LONG_Release == CMD_SLEEPMODE;

				}

				if(gShutdownCurrentState){
					gShutdownPressedTimestamp = gButtons[3].PressedTimestamp;
				}

			}else if(gButtons[4].ActualStateIsPressed)
			{

				if (gButtons[5].ActualStateIsPressed) {
					gShutdownCurrentState = BUTTON_MULTI_45_LONG_Release == CMD_SLEEPMODE;

				}else{
					gShutdownCurrentState = BUTTON_4_LONG_Release == CMD_SLEEPMODE;
				}

				if(gShutdownCurrentState){
					gShutdownPressedTimestamp = gButtons[4].PressedTimestamp;
				}

			}else if(gButtons[5].ActualStateIsPressed)
			{


				gShutdownCurrentState = BUTTON_4_LONG_Release == CMD_SLEEPMODE;
				

				if(gShutdownCurrentState){
					gShutdownPressedTimestamp = gButtons[5].PressedTimestamp;
				}

			}



			//////////////////////////////////////////////////////////////////////////
			//Long Push
			//////////////////////////////////////////////////////////////////////////

			if(gButtons[0].CommandPressedLong)
			{

				if (gButtons[1].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_01_LONG;

				}else if (gButtons[2].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_02_LONG;

				}else if (gButtons[3].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_03_LONG;
					
				}else if (gButtons[4].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_04_LONG;

				}else if (gButtons[5].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_05_LONG;

				}else{
					Cmd_Long = BUTTON_0_LONG;
				}

			}else if(gButtons[1].CommandPressedLong)
			{

				if (gButtons[2].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_12_LONG;

				}else if (gButtons[3].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_13_LONG;
					
				}else if (gButtons[4].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_14_LONG;

				}else if (gButtons[5].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_15_LONG;

				}else{
					Cmd_Long = BUTTON_1_LONG;
				}

			}else if(gButtons[2].CommandPressedLong)
			{
				if (gButtons[3].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_23_LONG;
					
				}else if (gButtons[4].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_24_LONG;

				}else if (gButtons[5].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_25_LONG;

				}else{
					Cmd_Long = BUTTON_2_LONG;
				}

			}else if(gButtons[3].CommandPressedLong)
			{
				if (gButtons[4].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_34_LONG;

				}else if (gButtons[5].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_35_LONG;

				}else{
					Cmd_Long = BUTTON_3_LONG;
				}

			}else if(gButtons[4].CommandPressedLong)
			{
				if (gButtons[5].ActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_45_LONG;

				}else{
					Cmd_Long = BUTTON_4_LONG;
				}

			}else if(gButtons[5].CommandPressedLong)
			{
			
				Cmd_Long = BUTTON_5_LONG;
			
			}


	






			//////////////////////////////////////////////////////////////////////////
			//Short Command
			//////////////////////////////////////////////////////////////////////////

			if(gButtons[0].CommandReleaseShort)
			{

				if (gButtons[1].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_01_SHORT;

				}else if (gButtons[2].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_02_SHORT;

				}else if (gButtons[3].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_03_SHORT;
					
				}else if (gButtons[4].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_04_SHORT;

				}else if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_05_SHORT;

				}else{
					Cmd_Short = BUTTON_0_SHORT;

				}

			}else if(gButtons[1].CommandReleaseShort)
			{

				if (gButtons[2].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_12_SHORT;

				}else if (gButtons[3].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_13_SHORT;
					
				}else if (gButtons[4].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_14_SHORT;

				}else if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_15_SHORT;
					
				}else{
					Cmd_Short = BUTTON_1_SHORT;

				}

			}else if(gButtons[2].CommandReleaseShort)
			{
				if (gButtons[3].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_23_SHORT;
					
				}else if (gButtons[4].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_24_SHORT;

				}else if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_25_SHORT;
					
				}else{
					Cmd_Short = BUTTON_2_SHORT;

				}

			}else if(gButtons[3].CommandReleaseShort)
			{
				if (gButtons[4].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_34_SHORT;

				}else if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_35_SHORT;

				}else{
					Cmd_Short = BUTTON_3_SHORT;
				}

			}else if(gButtons[4].CommandReleaseShort)
			{
				if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Short = BUTTON_MULTI_45_SHORT;

				}else{
					Cmd_Short = BUTTON_4_SHORT;
				}

			}else if(gButtons[5].CommandReleaseShort)
			{
				
				Cmd_Short = BUTTON_5_SHORT;
				
			}





			//////////////////////////////////////////////////////////////////////////
			//Long release Command
			//////////////////////////////////////////////////////////////////////////

			if(gButtons[0].CommandReleaseLong)
			{

				if (gButtons[1].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_01_LONG_Release;

				}else if (gButtons[2].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_02_LONG_Release;

				}else if (gButtons[3].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_03_LONG_Release;
					
				}else if (gButtons[4].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_04_LONG_Release;

				}else if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_05_LONG_Release;

				}else{
					Cmd_Long = BUTTON_0_LONG_Release;
				}

			}else if(gButtons[1].CommandReleaseLong)
			{

				if (gButtons[2].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_12_LONG_Release;

				}else if (gButtons[3].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_13_LONG_Release;
					
				}else if (gButtons[4].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_14_LONG_Release;

				}else if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_15_LONG_Release;

				}else{
					Cmd_Long = BUTTON_1_LONG_Release;
				}

			}else if(gButtons[2].CommandReleaseLong)
			{
				if (gButtons[3].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_23_LONG_Release;
					
				}else if (gButtons[4].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_24_LONG_Release;

				}else if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_25_LONG_Release;

				}else{
					Cmd_Long = BUTTON_2_LONG_Release;
				}

			}else if(gButtons[3].CommandReleaseLong)
			{
				if (gButtons[4].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_34_LONG_Release;

				}else if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_35_LONG_Release;

				}else{
					Cmd_Long = BUTTON_3_LONG_Release;
				}

			}else if(gButtons[4].CommandReleaseLong)
			{
				if (gButtons[5].DelayedActualStateIsPressed) {
					Cmd_Long = BUTTON_MULTI_45_LONG_Release;

				}else{
					Cmd_Long = BUTTON_4_LONG_Release;
				}

			}else if(gButtons[5].CommandReleaseLong)
			{
			
				Cmd_Long = BUTTON_5_LONG_Release;
			
			}









			if(Cmd_Long>0)
			{
				Cmd_Action(Cmd_Long);
			}


			if(Cmd_Short>0)
			{
				Cmd_Action(Cmd_Short);
			}



			
		
	
}

void IRAM_ATTR onTimer() {
	xSemaphoreGiveFromISR(Button_TimerSemaphore, NULL);
}

Button.h
Hier habe ich teils Variablen umbenannt und weitere hinzugefügt:
Ich habe es einfach mal Kommentiert, hoffe man versteht die Variablen.

gShutdownCurrentState: Wird für die Animation benötigt Roter Kreis wird gefüllt
AllButtonsReleased: Ist dazu gekommen, da ich immer Drücken+loslassen immer auf alle Taster prüfe.

#pragma once

typedef struct {


	bool CommandPressedLong	  : 1;	//Befehl für langes Drücken+halten ausführen
	bool CommandReleaseShort	  : 1; 	//Befehl für kurzes Drücken+loslassen ausführen
	bool CommandReleaseLong	  : 1; //Befehl für langes Drücken+loslassen ausführen

	bool ActualStateIsPressed :1;	//aktuell wird der Taster gedrückt
	bool DelayedActualStateIsPressed :1;	//aktuell wird der Taster gedrückt oder wurde bereits losgelassen aber liegt noch in der Delay Zeit


	bool ActualStateIsPressedLast: 1;		//wurde im letzten Zyklus gedrückt
	
	unsigned long PressedTimestamp;			//Zeitstempel als der Taster gedrückt wurde
	unsigned long ReleasedTimestamp;		//Zeitstempel als der Taster losgelassen wurde
	unsigned long DelayRepeatTimestamp;		//Zeitstempel um die Funktion zu wiederholen
	
} t_button;


extern bool AllButtonsReleased;				//Alle Taster wurden losgelassen
extern bool AllButtonsReleasedLast;			//Im letzten Zyklus wurden alle Taster losgelassen

extern bool gShutdownCurrentState;			//SleepModus wird vorraussichtlich aktiviert
extern unsigned long gShutdownPressedTimestamp;	//Sleepmodus wird vorraussichtlich aktiviert Zeitstempel


extern bool gButtonInitComplete;

void Button_Init(void);
void Button_Cyclic(void);


LED.CPP

Hier habe ich im wesentlichen die Animation für den SleepModus angepasst.

Hier habe ich die Varibale gShutdownCurrentState hinzugefügt

// check indications and set led-mode
		// this mode will then be animated if the priority and the current animation state fit
		if (!LED_INDICATOR_IS_SET(LedIndicatorType::BootComplete)) {
			nextAnimation = LedAnimationType::Boot;
		} else if (gShutdownCurrentState) {
			nextAnimation = LedAnimationType::Shutdown;
		} else if (LED_INDICATOR_IS_SET(LedIndicatorType::Error)) {
			LED_INDICATOR_CLEAR(LedIndicatorType::Error);

Und diese Funktion etwas umgebaut

AnimationReturnType Animation_Shutdown(const bool startNewAnimation, CRGBSet &leds) {
	// return values
	bool animationActive = true;
	int32_t animationDelay = 0;
	// static vars
	static bool singleLedStatus = false;
	static uint32_t animationIndex = 0;


	if (startNewAnimation) {
		animationIndex = 0;
	}

	if constexpr (NUM_INDICATOR_LEDS == 1) {
		leds = CRGB::Black;
		if (millis() - gShutdownPressedTimestamp <= intervalToLongPress) {
			leds[0] = CRGB::Red;
			animationDelay = 5;
		} else {
			if (singleLedStatus) {
				leds[0] = CRGB::Red;
			}
			singleLedStatus = !singleLedStatus;
			animationDelay = 50;
		}
		animationActive = false;
	} else {
	
		if (animationIndex == 0) {
			leds = CRGB::Black;
		}
		if (animationIndex < leds.size()) {
			leds[Led_Address(animationIndex)] = CRGB::Red;

		
			animationDelay = intervalToLongPress / leds.size();
			
			animationIndex++;

		}else { // Wait a little
			animationDelay = 20 * 100;
			animationActive = false;
		}
		
		
	}
	return AnimationReturnType(animationActive, animationDelay, true);
}

Ich denke ich habe noch weitere Anpassungen gemacht, aber dies sind die Wesentlichen.
Außerdem denke ich auch, dass ich bestimmt noch ein paar Denkfehler drin habe, habe mit dieser Programmierumgebung sozusagen 0 Erfahrung.
Da ich das ganze nicht wirklich debuggen konnte, habe ich das ganze immer mal wieder in der Console ausgegeben. Diese Codezeilen kann man natürlich ignorieren.

Soweit erstmal:-)
Bei Interesse, kann ich natürlich auch den ganzen Code bereitstellen.

Grüße
Felix

1 „Gefällt mir“

Hallo,
vll. war es zu viel Code, vll. ist es auch uninteressant. Aber ich versuche es nochmal kurz zusammenzufassen.
Ich denke die Anpassungen sind eher für die Leute interessant, die keinen Encoder verbaut haben.

Die wesentliche Vorteile:

  1. Man kann den Sleepmodus auch mit Multitaster und langem Drücken aktivieren. Sobald man diese wieder loslässt.
    Man kann den Vorgang auch wieder abbrechen, indem man erstmal nur einen loslässt.

  2. Man kann z.B. die Lautstärkenregelung mit kurzem Tastendruck erhöhen oder indem
    man die Taste lange gedrückt hält. Sobald einmalig die lange Tastendruckzeit erkannt wurde, reduziert sich die Wartezeit und die Lautstärke kann deutlich schneller und einfacher erhöht werden.
    z.B. einmal 2s drücken und halten → Lautstärke++ , danach weiter halten alle 100ms → Lautstärke++