//
// 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 SwitchEffects : uint8_t { on, ready, startWait, wait, waitEnd };
enum EffectSelection : uint8_t { effectA, effectB, effectsOff };
struct States {
SwitchEffects pState;
bool twoPulses;
bool blockCheck;
};
//
// 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 {100}; // Dauer zwischen zwei Tasterdrücken in Millisekunden
Timer timer; // Timer für Zeitmessungen erzeugen
//
// Funktionen
//
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], uint8_t mask) {
uint8_t bitmask = 1 << (N - 1);
for (size_t i = 0; i < N; ++i) { (mask << i & bitmask) ? digitalWrite(pins[i], HIGH) : digitalWrite(pins[i], LOW); }
}
template <size_t N> void fstm(const uint8_t (&pins)[N], States &st, Timer &tmr) {
//
// Notwendig für das Ausschalten des HIGH Signals an den entsprechenden Pins
// (Entspricht dem Loslassen eines Tasters) und zum Auslösen des zweiten Tastenrucks (je nach Schalterstellung)
//
switch (st.pState) {
case SwitchEffects::on: // Warten bis die Zeit für den emulierten Tastendruck abgelaufen ist
if (true == tmr(PIN_ENABLE_DURATION_MS)) { // Zeit abgelaufen, Pin wieder auf LOW bringen (= Taster loslassen)
switchPins(devicePins, SW_MASK_ALL_OFF);
// Wenn weiterer Tastendruck notwendig dann Status "startWait" für einen weiteren Durchlauf
st.pState = (true == st.twoPulses) ? SwitchEffects::startWait : SwitchEffects::ready;
}
break;
case SwitchEffects::startWait: // Warten bis zur nächsten Tastersimulation
tmr.start();
st.pState = SwitchEffects::wait;
break;
case SwitchEffects::wait: // Testen ob die Wartezeit für den zweiten Tasterdruck abgelaufen ist
if (true == tmr(PIN_WAIT_DURATION_MS)) { // Wenn ja dann nächsten Tastendruck emulieren
timer.start();
st.pState = SwitchEffects::waitEnd;
}
break;
case SwitchEffects::waitEnd:
if (true == timer(PIN_ENABLE_DURATION_MS)) { // Nächsten Tastendruck emulieren
tmr.start();
switchPins(devicePins, SW_MASK_DEV_D);
st.twoPulses = false;
st.pState = SwitchEffects::on;
}
break;
case SwitchEffects::ready: st.blockCheck = false; break;
default: break;
}
}
void deviceSelect() {
static EffectSelection prevCheck {EffectSelection::effectsOff};
static States states {SwitchEffects::ready, false, false};
if (false == states.blockCheck) { // Die Abfrage wird blockiert, wenn gerade eine Schaltung erfolgt
EffectSelection check = checkPinState(deviceCheckPins);
delay(50); // Taster entprellen
if (check != prevCheck) { // Es hat eine Schaltebetätigung stattgefunden.
timer.start();
prevCheck = check;
states.pState = SwitchEffects::on;
states.blockCheck = true; // Schalterabfrage solange blocken bis Tasteremulation beendet ist
switch (check) {
case EffectSelection::effectA:
cout << F("Schalte Taster D - Effekt langsam\n");
switchPins(devicePins, SW_MASK_DEV_D);
break;
case EffectSelection::effectB:
cout << F("Schalte Taster D - Effekt schnell\n");
switchPins(devicePins, SW_MASK_DEV_D);
states.twoPulses = true;
break;
default:
cout << F("Mittelstellung -> Schalte Taster E - Effekt aus\n");
switchPins(devicePins, SW_MASK_DEV_E);
break;
}
}
}
fstm(devicePins, states, timer);
}
//
// 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 loop() { deviceSelect(); }
Schalter anklicken