Passwort Keypad

Hallo zusammen,

ich versuche mit dem Beispielsketch (siehe unten) eine Zugangskontrolle via Keypad für meine Garage (automatisches Tor) und für den Seiteneingang zu basteln.

Was will ich genau?

Sobald das richtige Passwort über das Keypad eingegeben wurde, soll die Möglichkeit bestehen mit der Taste A das Garagentor automatisch aufzufahren. Wenn erneut A gedrückt wird soll das Tor wieder zu fahren. Wenn die Taste B gedrückt wird soll der Seiteneingang freigegeben werden. Durch erneutes Drücken der Taste B soll der Seiteneingang verschlossen werden. Wenn ich dann die Taste * oder # soll das ganze System wieder Passwort geschützt sein.

Im großen und ganzen keine große Nummer. So mein erster Gedanke. Nun probiere ich schon seid Tagen herum, komme aber zu keinem Ergebnis.

Meiner Meinung nach kommt das Problem daher, das der Sketch mit unterschiedlichen Void Loops geschrieben ist die alle gleichzeitig laufen.

Ich habe versucht in den Bereich:

else {
digitalWrite(redPin, LOW);
digitalWrite(greenPin, HIGH);
digitalWrite(yellowPin, HIGH);
delay(1000);
digitalWrite(yellowPin, LOW);

Also Passwort wurde akzeptiert und ein weiterer Befehl kann programmiert werden eine Tasten Auswahl als weitere If Bedingung einzufügen:

void taster()
{
buttonState = digitalRead(button);
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(yellowPin, HIGH);
delay(3000);
} else {
// turn LED off:
digitalWrite(yellowPin, LOW);
}
}

Leider ohne Ergebnis. Ich habe das Gefühl, das wenn das Programm bei der letzten If Bedingung angekommen ist, diese erledigt hat, direkt wieder an den Programm Anfang springt ohne diese weitere If Bedingung (Aktion Taste C) auszuführen.

Ich hoffe ihr könnt mir helfen!

Hoffnungsvoll!
Florian

#include <Keypad.h>


 
char* secretCode = "1234";
int position = 0;
 
const byte ROWS = 4; // Four rows
const byte COLS = 4; //  columns
// Define the Keymap
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
 
byte rowPins[ROWS] = { 9,8,7,6 };// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte colPins[COLS] = { 5,4,3,2, };// Connect keypad COL0, COL1 and COL2 to these Arduino pins.


// Create the Keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
 
int redPin = 10;
int greenPin = 11;
const int yellowPin  = 12;
const int button = 13;

//boolean blink = false;
//boolean ledPin_state;
int buttonState = 0;  

 
void setup()
{
  Serial.begin(9600);
 
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  setLocked(true);

  pinMode(button, INPUT);

  
}
 
void loop()
{
  char key = keypad.getKey();
  if (key == 'A' || key == 'B') {
    position = 0;
    setLocked(true);
    
  }
 
  if (key == secretCode[position]) {
    position++;
  }
 
  if (position == 4) {
    setLocked(false);
  }
  delay(50);

      
   /*  if (key == 'C') {
            // turn LED on:
            digitalWrite(yellowPin, HIGH);
            delay(2000);
          } else {
            // turn LED off:
            digitalWrite(yellowPin, LOW);
           }


*/


/*

    buttonState = digitalRead(button);
            if (buttonState == HIGH) {
            // turn LED on:
            digitalWrite(yellowPin, HIGH);
          } else {
            // turn LED off:
            digitalWrite(yellowPin, LOW);
           }


*/

 } 

void setLocked(int locked)
{
  
  
  if (locked) {
    digitalWrite(redPin, HIGH);
    digitalWrite(greenPin, LOW);
    delay(1000);
    digitalWrite(yellowPin, HIGH);
    delay(20000);
    digitalWrite(yellowPin, LOW);
    
  }
  else {
    digitalWrite(redPin, LOW);
    digitalWrite(greenPin, HIGH);
    digitalWrite(yellowPin, HIGH);
    delay(1000);
    digitalWrite(yellowPin, LOW);
    
  


  }


  /*
 void taster()
              {
                 buttonState = digitalRead(button);
            if (buttonState == HIGH) {
            // turn LED on:
            digitalWrite(yellowPin, HIGH);
            delay(3000);
          } else {
            // turn LED off:
            digitalWrite(yellowPin, LOW);
           }
              }
    
       */
}

Deine Abfrage für Taste C ist auskommentiert. Wie soll die ausgeführt werden wenn Du die Taste drückst?
Ebenso die Buttonabfrage.

Stimmt!

Ich hatte die Parts nur aus kommentiert um das bereits geschriebenes nicht zu verlieren.

Hier der richtige Code mit eingefügter Funktion für die Taste C.

#include <Keypad.h>


 
char* secretCode = "1234";
int position = 0;
 
const byte ROWS = 4; // Four rows
const byte COLS = 4; //  columns
// Define the Keymap
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
 
byte rowPins[ROWS] = { 9,8,7,6 };// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins.
byte colPins[COLS] = { 5,4,3,2, };// Connect keypad COL0, COL1 and COL2 to these Arduino pins.


// Create the Keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
 
int redPin = 10;
int greenPin = 11;
const int yellowPin  = 12;
const int button = 13;

//boolean blink = false;
//boolean ledPin_state;
int buttonState = 0;  

 
void setup()
{
  Serial.begin(9600);
 
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  setLocked(true);

  pinMode(button, INPUT);

  
}
 
void loop()
{
  char key = keypad.getKey();
  if (key == 'A' || key == 'B') {
    position = 0;
    setLocked(true);
    
  }
 
  if (key == secretCode[position]) {
    position++;
  }
 
  if (position == 4) {
    setLocked(false);
  }
  delay(50);

      
  
 } 

void setLocked(int locked)
{
  char key = keypad.getKey();
  
  if (locked) {
    digitalWrite(redPin, HIGH);
    digitalWrite(greenPin, LOW);
    delay(1000);
    digitalWrite(yellowPin, HIGH);
    delay(20000);
    digitalWrite(yellowPin, LOW);
    
  }
  else {
    digitalWrite(redPin, LOW);
    digitalWrite(greenPin, HIGH);
   // digitalWrite(yellowPin, HIGH);
   // delay(1000);
   // digitalWrite(yellowPin, LOW);

    if (key == 'C') {
            // turn LED on:
            digitalWrite(yellowPin, HIGH);
            delay(2000);
          } else {
            // turn LED off:
            digitalWrite(yellowPin, LOW);
           }
    
  


  }

Ohne den Code jetzt genauer nachvollzogen zu haben, folgende Anmerkungen

Delays sind Mist.
Es fehlt eine Eingabesperre bei zu vielen Eingabeversuchen
Ich sehe auch keinen Timeout für nicht vollständige Eingabeversuche

FloMorris:
Sobald das richtige Passwort über das Keypad eingegeben wurde, soll die Möglichkeit bestehen mit der Taste A das Garagentor automatisch aufzufahren. Wenn erneut A gedrückt wird soll das Tor wieder zu fahren. Wenn die Taste B gedrückt wird soll der Seiteneingang freigegeben werden. Durch erneutes Drücken der Taste B soll der Seiteneingang verschlossen werden. Wenn ich dann die Taste * oder # soll das ganze System wieder Passwort geschützt sein.

Ich kann keinen Zusammenhang zwischen dem Sketch und dieser Beschreibung erkennen. Die Taste C kommt in deiner Beschreibung nicht vor, und die Tasten * und # kommen im Sketch nicht vor. Die Taten A und B machen offensichtlich etwas anderes als beschrieben.
Gewöhne dir bitte an, im Sketch zu kommentieren, was die einzelen Programmblocke überhaupt bewirken sollen, damit wir nachvollziehen können, was Wunsch und was Wirklichkeit ist. Auch für dich selbst ist das sehr sinnvoll, wenn Du mal später deinen Sketch noch verstehen willst.

Deine Aufgabe lässt sich - wie so oft - am besten mit einem ‘endlichen Automaten’ realisieren. Das wurde im Forum schon mehrmals vorgestellt z.B. hier .

Hallo zusammen,

schon einmal vielen Dank für die Unterstützung und die nett gemeinte Kritik.

Ich habe den Code angepasst, alles unnötige gelöscht und versucht verständlich zu Kommentieren.

Wie am Anfang beschrieben möchte ich die Möglichkeit haben nach Passwort Eingabe mit den weiteren Tasten auf meinem Keypad Aktionen auszuführen.

Folgender Ablauf schwebt mir vor:

  • Ich gebe das Passwort 1234 ein
  • Entriegeln Keypad: Weitere Funktionen möglich
  • Rote LED geht aus
  • Grüne LED geht an
  • Drücken Taste C → Garagentor fährt auf
  • Erneutes drücken Taste C —> Garagentor fährt zu
  • Drücken Taste D —> Seitentüre entriegelt
  • Drücken Taste D —> Seitentüre verriegelt
  • Drücken Taste A oder B —>Keypad verriegelt. Funktionen erst wieder möglich nach Passwort eingabe
  • Grüne LED geht aus
  • Rote LED geht an

Aktuelles Problem. Nach Passworteingabe kann ich keine weitere Aktion mehr durchführen (z.B. Taste C drücken). Keypad verriegeln über A / B klappt.

Ich hoffe so ist alles verständlich beschrieben und ihr könnt mir die zündende Idee geben.

Den Tipp mit dem endlichen Automaten habe ich mir angeschaut. So wie ich es verstehe bringt mir das in meinem fall nur was um die Delays zu ersetzten. Das ist für mich aber Schritt drei.

#include <Keypad.h>                         //Keypad Bib
 
char* secretCode = "1234";                 //Passwort
int position = 0;
 
const byte ROWS = 4;                       // Four rows
const byte COLS = 4;                       //  columns
                                           // Define the Keymap
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
 
byte rowPins[ROWS] = { 9,8,7,6 };                         // Verbindung mit dem Arduino
byte colPins[COLS] = { 5,4,3,2, };                        

                                                                                  
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );   // Create the Keypad
 
int redPin = 10;                      //Rote LED (Passwort eingeben) an Pin 11
int greenPin = 11;                    //Grüne LED (Passwort eingegeben, entriegelt!) an Pin 12
const int yellowPin  = 12;            //Gelbe LED (Test LED)
//const int button = 13;              // Test Button
//int buttonState = 0;                // Test Button

 
void setup()
{
  Serial.begin(9600);
 
  pinMode(redPin, OUTPUT);          // LEDs als Ausgang definieren
  pinMode(greenPin, OUTPUT);
  pinMode(yellowPin, OUTPUT);
  setLocked(true);

 // pinMode(button, INPUT);

  
}
 
void loop()
{
  char key = keypad.getKey();
  if (key == 'A' || key == 'B') {       // Wenn das Schloss entsperrt ist, kann mit der Taste A oder B das Schloss wieder gesperrt werden
    position = 0;
    setLocked(true);                    // Schloss sperren wenn A oder B gedrückt wurde
    
  }
 
  if (key == secretCode[position]) {
    position++;
  }
 
  if (position == 4) {            //Länge Passwort (4 Stellen)
    setLocked(false);
  }
  delay(50);

  

 } 

void setLocked(int locked)
{
  char key = keypad.getKey();
  
  if (locked) {                       // Wenn das Schloss gesperrt ist, soll:
    digitalWrite(redPin, HIGH);       // die rote LED leuchten
    digitalWrite(greenPin, LOW);      // die grüne LED nicht leuten
    delay(1000);
    digitalWrite(yellowPin, HIGH);    //Für 20 Sekunden der Taster am Garagentor auf HIGH geschaltet werden (Tor fährt zu)
    delay(20000);
    digitalWrite(yellowPin, LOW);
    
  }
  else {                                    // Wenn das Schloss entsperrt ist, soll:
    digitalWrite(redPin, LOW);              // die rote LED nicht leuchten
    digitalWrite(greenPin, HIGH);           // die grüne LED leuchten
   // digitalWrite(yellowPin, HIGH);        // Für 1 Sekunde der TAster am Garagentor auf HIGH geschaltet werden (Tor fährt auf)
   // delay(1000);
   // digitalWrite(yellowPin, LOW);

    if (key == 'C') {                         // Wenn das Schloss entsperrt ist, soll über die Taste C das Garagentor gesteuert werden können 
            // turn LED on:                   // LEider funktioniert aus unerklärlichen Gründen diese If Bedingung nicht. Sobald das Schloss entsperrt ist besteht nicht die Möglichkeit
            digitalWrite(yellowPin, HIGH);    // die Taste C zu drücken. Ich habe keine Ahnung was ich dafür ändern muss.
            delay(2000);
          } else {
            // turn LED off:
            digitalWrite(yellowPin, LOW);
           }
    
  


  }
}

Bei deinen Anforderungen sehe ich keine Verwendung einer Zeitverzögerung, somit brauchst du kein delay.

Folgende Fragen solltest du dir noch stellen:

Was soll passieren, wenn du verriegeln vergisst?

Wie wird das Garagentor angesteuert?

Wie wird die Seitentüre angesteuert?

Was passiert bei unvollständiger Passworteingabe?

FloMorris:
Den Tipp mit dem endlichen Automaten habe ich mir angeschaut. So wie ich es verstehe bringt mir das in meinem fall nur was um die Delays zu ersetzten.

Da verstehst Du das falsch. Ein endlicher Automt hat mit delay() und millis() erstmal gar nicht zu tun. Er dient primär dazu Abläufe zu steuern. Die wesentlichen Punkte sind Zustände und Ereignisse, die zu einem Zustandswechsel führen.
Z.B. ist das verriegelte Keypad ein Zustand, der erst durch Eingabe des Passwortes verlassen wird. In diesem Zustand wird nur die Eingabe des Passwortes bearbeitet, sonst nichts. Ein falsches Passwort führt dann z.B. zu einem Zustand, in dem nur eine Zeit abläuft ( Wartezeit bis erneute Pasworteingabe möglich ). Das richtige Passwort führt in den Zustand, wo die Türen betätigt werden können u.s.w.

Zu den Fragen:

Was soll passieren, wenn du verriegeln vergisst?

  • Das Garagentor muss in der Stellung offen bleiben. Das Tor darf nicht automatisch wieder zu fahren
  • Das Seitentor darf automatisch wieder verriegeln.

Wie wird das Garagentor angesteuert?

  • Ich habe die Möglichkeit den Schalter zum manuellen öffnen zu überbrücken.

Tor aufmachen: - ein kurzer Impuls
Tor zumachen: - solange den Taster gedrückt halten bis das Tor zu ist

Wie wird die Seitentüre angesteuert?

  • Voraussichtlich über einen Elektrohubmagnet. Im aktuellen Sketch Teste ich nur mit den LED’s.

Was passiert bei unvollständiger Passworteingabe?

  • Nicht passiert. Es wird erst freigeschalten sobald der richtige PIN eingegeben wurde.

Vielen Dank für den Hinweis mit dem endlichen Automat. Da muss ich mich erst rein arbeiten bis ich den endlichen Automaten in mein Passwort Projekt einbinden kann. Also weiter fleißig tüfteln :slight_smile:

FloMorris:
Da muss ich mich erst rein arbeiten bis ich den endlichen Automaten in mein Passwort Projekt einbinden kann.

Du sollst ihn ja nicht einbinden, sondern dein Projekt damit lösen :wink:

FloMorris:
Also weiter fleißig tüfteln :slight_smile:

Das ist der richtige Weg :sunglasses:

Mal so als Pseudocode, um das Prinzip zu verdeutlichen:

loop
    switch ( Zustand )
      case Passwort:
        Taste einlesen
        Auf zeichen an position prüfen
        if ( falsches Zeichen )
            Blockadezeit setzen
            Zustand = Blockade
        else
            if ( passwort komplett )
                Leds umschalten
                Zustand = Tuerfunktionen
            else
                auf nächste Position schalten
        break
      case Blockade:
        if ( Blockadezeit abgelaufen )
            Passwortposition rücksetzen
            Zustand = Passwort
        break
      case Tuerfunktionen:
        Taste einlesen
        if ( A oder B )
            Leds umschalten
            Passwortposition rücksetzen
            Zustand = Passwort
        if ( D )
            Seitentüre ansteuern
        ....
         usw....

    Ende switch
Ende loop

Hallo FloMorris,
Dein problem ist folgendes: Nach Eingabe des richtigen Passwortes, springt dein Program aus der loop() in die setLocked(int locked). Da fragst Du sofort das keypad ab. erledigst ein par kliene Dinge und prüfst, ob 'C' gedrückt wurde. Wenn ja: Yellow Led ein, wenn nein: Yellow Led aus. Dann zurück in die loop() NUR: So schnell wie der Arduino nach drücken der letzten Passwortziffer wieder zurück in der loop ist, kannst Du die ziferntaste gar nicht loslassen und auf 'C' drücken. Sobald das Porgramm mit position == 4 wieder zurück ist, wird position nochmals um eins auf 5 erhöht (warum auch immer). Danach kannst Du auf 'C' drücken solamge und sooft Du willst, setLocked(false) wird nicht mehr aufgerufen (da ja position NICHT mehr == 4 ist!
Du köntest z.B eine bool benutzen um den Status locked/unlocked zu merken und setLocked statt direkt mit true/false dmit dieser variablen aufrufen. Dazu auch noch 'char key' global deklariren, die keypad abfrage in setLocked rausnehmen.
Ausserdem die abfrage:

if (position == 4) {

so ergänzen / schreiben:

if (position == 4 || locked == false) {
  locked = false;
  setLocked(locked);
}

Würde fürs erste mal grob funktieonieren.
Ich würde Dir jedoch empfehlen, das Passwort bei eingabe in ner variablen zu merken, danach mit ner Taste (z.B. 'D' zu bestätigen, und dann das Passwort auch auf richtige länge zu prüfen. (macht es schwieriger, das passwort rauszufinden).

LG Stefan

Auch solltest du die Falscheingaben mitzählen und dann eine immer grösser werdende Verzögerung einbauen

Allen vielen Dank!

Ich merke das es bei mir an den Basics etwas fehlt. Ich glaube ich habe mir mit dem Programm eine zu große Herausforderung gesetzt.

Ich habe versucht alle Tips einzubauen. Bisher leider ohne Erfolg.

Den ersten void loop () bekomme ich in den endlichen Automaten eingebaut.

Nach dem void loop() folgt void setLocked(int locked) ab da komme ich schon nicht weiter :frowning:

FloMorris:
Meiner Meinung nach kommt das Problem daher, das der Sketch mit unterschiedlichen Void Loops geschrieben ist die alle gleichzeitig laufen.

FloMorris:
Den ersten void loop () bekomme ich in den endlichen Automaten eingebaut.

Was meinst Du eigentlich da mit mehreren loops() ? Es gibt immer nur einem loop, und gleichzeitig läuft da auch nie etwas ab, sondern immer nur nacheinander.
Vielleicht fehlt es wirklich noch etwas an den Basics, und Du solltest erstmal ein paar Beispiele durcharbeiten und verstehen :wink: .

Aber wenn Du uns deine Versuche nicht zeigst, können wir auch nicht sagen was falsch ist...

FloMorris:
Zu den Fragen:
Was passiert bei unvollständiger Passworteingabe?

  • Nicht passiert. Es wird erst freigeschalten sobald der richtige PIN eingegeben wurde.

D.h. also, wenn jemand 2 Ziffern eingibt, und nix weiter, und du weisst nix davon, und gibst 4 richtige Ziffern ein, ist doch der erste Code falsch und es stehen wieder 2 Ziffern im Puffer.

Oder willst du, dass wenn in einer “Dauereingabe” von Ziffern (“Stream”) die richtigen 4 in der richtigen Reihenfolge dabei sind, das Ding aufgeht?

Schmeiss deinen Code weg und beginne von Vorne.

a) Definiere jeden möglichen Zustand und gib diesen Zuständen eine Nummer, diese hältst du in einer globalen variablen

b) lege fest, unter welcher Bedingung du von einem Zustand in den nächsten wechselst

c) implementiere dann die Tasteneigaben, die Zustandsvariable lässt du dir zunächst nur anzeigen

d) wenn die Logik so hinhaut, wie gewünscht, fügst du die entsprechenden Ausgaben anhand der Zustandsvariablen hinzu (z.B. mit switch/case) ...