//
// Programm zum Emulieren von Tasterbetätigungen über einen Wechselschalter
//                    Schalterstellungen
//             1               0               1
//      Effekt schnell     Effekt aus    Effekt langsam
//       2 x Taster 1     1 X Taster 2    1 x Taster 1
//

#include <Streaming.h>
Print &cout {Serial};

class Timer {
public:
  void start() { timeStamp = millis(); }
  bool operator()(const uint32_t duration) const { return (millis() - timeStamp >= duration) ? true : false; }

private:
  uint32_t timeStamp {0};
};

enum EffectSelection : uint8_t { effectA, effectB, effectsOff };

template <size_t N> EffectSelection checkPinState(const uint8_t (&pins)[N]) {
  for (size_t i = 0; i < N; ++i) {
    if (digitalRead(pins[i]) == LOW) { return static_cast<EffectSelection>(i); }
  }
  return EffectSelection::effectsOff;
}

template <size_t N> void switchPins(const uint8_t (&pins)[N], uint16_t mask) {
  uint16_t bitmask = 1 << (N - 1);
  for (size_t i = 0; i < N; ++i) { (mask << i & bitmask) ? digitalWrite(pins[i], HIGH) : digitalWrite(pins[i], LOW); }
}

//
// Konstanten und Variablendefinitionen
//
constexpr uint8_t deviceCheckPins[2] {4, 5};   // Pins am Umschalter
constexpr uint8_t devicePins[2] {6, 7};        // Pins für die Effektschaltung

// Bitmasken zum Schalten der Effektpins
constexpr uint8_t SW_MASK_ALL_OFF {0x00};
constexpr uint8_t SW_MASK_DEV_D {0x02};
constexpr uint8_t SW_MASK_DEV_E {0x01};

constexpr uint32_t PIN_ENABLE_DURATION_MS {200};   // Dauer des emulierten Tasterdrucks in Millisekunden
constexpr uint32_t PIN_WAIT_DURATION_MS {300};     // Dauer zwischen zwei Tasterdrücken in Millisekunden

Timer checkTimer;
Timer impulseTimer;

//
// Hauptprogramm
//
void setup() {
  Serial.begin(115200);
  for (auto pin : deviceCheckPins) { pinMode(pin, INPUT_PULLUP); }
  switchPins(devicePins, SW_MASK_ALL_OFF);
  for (auto pin : devicePins) { pinMode(pin, OUTPUT); }
}

void deviceSelect() {
  static EffectSelection prevCheck {EffectSelection::effectsOff};
  static bool isPinHigh {false};

  EffectSelection check = checkPinState(deviceCheckPins);
  // Es hat eine Schaltebetätigung stattgefunden und das Abfragedelay ist abgelaufen
  if (check != prevCheck && checkTimer(PIN_WAIT_DURATION_MS) == true) {
    prevCheck = check;
    checkTimer.start();
    impulseTimer.start();
    isPinHigh = true;
    switch (check) {
      case EffectSelection::effectA:
        cout << F("Schalte Taster D - Effekt schnell\n");
        switchPins(devicePins, SW_MASK_DEV_D);
        break;
      case EffectSelection::effectB:
        cout << F("Schalte Taster D - Effekt langsam\n");
        switchPins(devicePins, SW_MASK_DEV_D);
        break;
      default:
        cout << F("Mittelstellung -> Schalte Taster E - Effekt aus\n");
        switchPins(devicePins, SW_MASK_DEV_E);
        break;
    }
  }

  if (isPinHigh == true && impulseTimer(PIN_ENABLE_DURATION_MS)) {
    switchPins(devicePins, SW_MASK_ALL_OFF);
    isPinHigh = false;
  }
}

void loop() { deviceSelect(); }
Schalter anklicken