Interessantes Thema. Deshalb gebe ich auch nochmal meinen Senf dazu - natürlich mit MobaTools ![]()
Ich finde auch wichtig, dass es einen definierten Anfang gibt, und das es auch möglich ist, von einem zum nächsten Schritt mehrere Schalteränderungen zu fordern. Da können dann prinzipiell beim Schalten auch ungültige Zwischenstellungen erreicht werden, was innerhalb der Karenzzeit von +/- 0,5 Sek nicht zum Fehler führen darf.
Die seriellen Ausgaben zum Verfolgen muss man später natürlich entfernen. Das Anzeigen mit den Led's ist noch nicht enthalten, nur die Abfolge.
#include <MobaTools.h>
const byte schalterPins[] = { 8, 5, 2, 9 };
//const byte schalterPins[] = { A0,A1,A2,A3 };
const byte schalterZahl = sizeof(schalterPins);
const byte codierMask = 0b0111; // Nur die ersten 3 Schalter ( 0..2 ) sind für die Kodierung
MoToButtons schalter( schalterPins, schalterZahl, 20, 500 );
struct muster {
button_t position; // Sollpositionen der Schalter
uint16_t zeit; // Zeit die diese Position unverändert sein soll
};
const muster musterFolge[] = {
{ 0b0100, 2000 }, // erste Position nach 'Alles Aus'
{ 0b0110, 5000 },
{ 0b0010, 3000 },
{ 0b0011, 0 } // Zeit 0 ist Ende der Liste
};
const byte musterZahl = sizeof(musterFolge) / sizeof(musterFolge[0]);
byte musterIx; // Index in der Mustertabelle
int fehlerZeit = 20000; // Nach dieser Zeit wird ein Fehler gemeldet ( wird auf die Summe aller Zeiten
// in 'musterFolge' gesetzt )
const int karenzZeit = 1000; // Zeitfenster in dem die Schalter geändert werden dürfen.
MoToTimer maxTime; // maximale Zeit für die Eingabe
MoToTimer warteZeit;
button_t codeStatus; // aktueller Status der Codeschalter
enum : byte { IDLE, // Warten bis alle Schalter auf 0 sind
START, // alle Schalter auf 0, warten bis erste Betätigung
WAIT, // Zeit in der sich die Schalterstellung nicht ändern darf
CHECK, // prüfen der Stellungen ( Karenzzeit für das Ändern der Schalter)
OPEN, // Tür öffnen
FEHLER // Fehler erkannt, keine weitere Auswertung, nur warten bis Max Zeit abgelaufen
} keyStatus = IDLE;
void setup() {
// put your setup code here, to run once:
Serial.begin( 115200 );
while (!Serial); // nur für 32u4 (Leonardo/Micro ) nötig
}
void loop() {
// put your main code here, to run repeatedly:
schalter.processButtons(); // Schalter entprellen und einlesen
codeStatus = schalter.allStates() & codierMask; // aktueller Status der Kodierschalter
switch ( keyStatus ) {
//-----------------------------------------------------------------------
case IDLE: // beliebige Schalterposition, warten bis alles auf 0
if ( codeStatus == 0 ) {
keyStatus = START;
musterIx = 0;
}
break;
//-----------------------------------------------------------------------
case START: // warten auf erste Schalterbetätigung
if ( codeStatus != 0 ) {
// der erste Schalter wurde betätigt, Karenzzeit für das Einstellen des ersten Musters starten
// maximalZeit für die Codeeingabe berechnen
int maxZeit = karenzZeit;
for ( byte iX = 0; iX < musterZahl; iX++ ) maxZeit += musterFolge[iX].zeit;
warteZeit.setTime( karenzZeit ); // in dieser Zeit muss der korrekte Code eingestellt sein
keyStatus = CHECK;
maxTime.setTime( maxZeit );
musterIx = 0;
Serial.print( musterIx ); Serial.println(". Muster eingeben");
}
break;
//-----------------------------------------------------------------------
case WAIT: // während dieser Zeit darf sich nichts tun
if ( codeStatus != musterFolge[musterIx - 1].position ) {
// falsche Betätigung
Serial.println("Fehleingabe");
keyStatus = FEHLER;
}
if ( warteZeit.expired() ) {
// Wartezeit abgelaufen, warte auf nächste Schalterstellung
keyStatus = CHECK;
warteZeit.setTime( 1000 ); // muss innerhalb 1 sek eingestellt sein
Serial.print( musterIx ); Serial.println(". Muster eingeben");
}
break;
//-----------------------------------------------------------------------
case CHECK: // nach Ablauf der Karenzzeit auf korrektes Muster prüfen und weiterschalten
if ( warteZeit.expired() ) {
if ( codeStatus == musterFolge[musterIx].position ) {
// nächstes Muster wurde korrekt eingestellt
musterIx += 1;
if ( musterIx >= musterZahl ) {
// Letztes Muster korrekt, Tür öffnen
keyStatus = OPEN;
} else {
// auf nächstes Muster schalten
warteZeit.setTime( musterFolge[musterIx - 1].zeit - (karenzZeit / 2) ); // in dieser Zeit darf sich nichts ändern
keyStatus = WAIT;
Serial.print( codeStatus, HEX); Serial.println("-keine Änderung mehr vornehmen!");
}
} else {
// falsches Muster
Serial.print( codeStatus, HEX); Serial.println("-fehlerhaft!");
keyStatus = FEHLER;
}
}
break;
//-----------------------------------------------------------------------
case OPEN:
Serial.println("Tür öffnen");
keyStatus = IDLE;
break;
//-----------------------------------------------------------------------
case FEHLER:
// falsche Eingabe, warten bis maxZeit abgelaufen, denn Neustart
if ( maxTime.expired() ) {
Serial.println(" EIngabezeit abgelaufen");
keyStatus = IDLE;
}
break;
}
}