Forum: Mikrocontroller und Digitale Elektronik Zahlenschloss - Fehler


von Paul (Gast)


Lesenswert?

Hallo,

ich arbeite gerade an einem Zahlenschloss und habe leider bereits einen 
Fehler im Code den ich einfach nicht verstehe..

In dem Code sollen einfach die gedrückten Taster abgefragt werden.
1
int PasswortArray[5] = {5,4,3,2,1};
2
 int PasswortArray2[5];
3
4
5
  int zahlhalter1=0;
6
  int zahlhalter2=0;
7
  int zahlhalter3=0;
8
  int zahlhalter4=0;
9
  int zahlhalter5=0;
10
  int zahlhalter6=0;
11
12
  int zaehler2=0;
13
  int zaehler=0;
14
  int test= 0;
15
  int pineins = 7;
16
  int pinzwei = 6; 
17
  int pindrei = 5;
18
  int pinvier = 4;
19
  int pinfuenf = 3;
20
  int pinsechs = 2;
21
  
22
  int prelltime=300;
23
  int program=0;
24
 
25
  int ledgruen =12;
26
  int ledrot=11;
27
28
  boolean result;
29
  
30
  
31
void setup() {
32
 
33
  pinMode(pineins, INPUT_PULLUP);
34
  pinMode(pinzwei, INPUT_PULLUP);
35
  pinMode(pindrei, INPUT_PULLUP);
36
  pinMode(pinvier, INPUT_PULLUP);
37
  pinMode(pinfuenf, INPUT_PULLUP);
38
  pinMode(pinsechs, INPUT_PULLUP);
39
  pinMode(ledrot, OUTPUT);
40
  pinMode(ledgruen, OUTPUT);
41
  Serial.begin(9600);
42
 
43
}
44
45
void loop() {
46
  
47
 
48
  //Delay um Taster zu entprellen
49
  
50
  
51
   do
52
        {  
53
        delay(100);    // warte darauf das Taster gedrückt wird
54
        }
55
        while((digitalRead(pineins) == LOW) && (digitalRead(pinzwei) == LOW) && (digitalRead(pindrei) == LOW) && (digitalRead(pinvier) == LOW));
56
 
57
   for(int i = 1; i < 6; i++){   
58
     
59
  if(digitalRead(pineins) == LOW) {
60
       //Entprellen
61
     zahlhalter1 =i;
62
    Serial.println("EINS");
63
    Serial.println(zahlhalter1);
64
        Serial.println(i);
65
66
    delay(prelltime);
67
68
69
      
70
  }   
71
      else if(digitalRead(pinzwei) == LOW) {
72
      zahlhalter2 =i;
73
      Serial.println("ZWEI");
74
      Serial.println(zahlhalter2);
75
      Serial.println(i);
76
            delay(prelltime);
77
78
79
  }
80
  
81
  else if(digitalRead(pindrei) == LOW) {
82
      zahlhalter3 =i;
83
84
      Serial.println("DREI");
85
      Serial.println(zahlhalter3);
86
              Serial.println(i);
87
      delay(prelltime);
88
89
90
  }
91
  
92
  else if(digitalRead(pinvier) ==LOW) {
93
      zahlhalter4 =i;
94
      Serial.println("VIER");
95
      Serial.println(zahlhalter4);
96
              Serial.println(i);
97
                    delay(prelltime);
98
99
100
101
  }
102
 
103
104
  }
105
106
 }


Ich bitte falsch deklarierte bzw. unnötige Variablen zu ignoieren ist ja 
alles noch in der Testphase :)

Das Problem im Code ist nun das als gedrückter Taster immer eins 
anzeigt, außer ich halte den Taster, dann zählt er brav bis vier hoch.

Woran liegts?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Paul schrieb:
> Woran liegts?
Am "else if"...

Wie sieht deine Hardware aus? Wie sind die Taster angeschlossen? Welches 
Signal gibt ein betätigter Taster ab?

Das mit dem Entprellen ist Murks. Und delay() ist MurksQuadrat.

Siehe den Beitrag "Arduino UNO | IF Schleife |"

: Bearbeitet durch Moderator
von Paul (Gast)


Lesenswert?

Warum am else if?


Also die Taster sind an die Pins 7-4 mit einem Pullup Widerstand 
angeschlossen. Taster LOW -->Aktion.


Wieso? Eingabe ist nicht zeitkritisch also warum soll ich die 
Debounce-Libary verwenden?


Lese den Link gerade.

von Karl H. (kbuchegg)


Lesenswert?

Paul schrieb:

> Wieso? Eingabe ist nicht zeitkritisch also warum soll ich die
> Debounce-Libary verwenden?

Weil dein Zeugs ja wohl recht offensichtlich nicht vernünftig 
funktioniert. Sonst müsstest du ja nicht fragen.
Eine ordentlich und vernünftige Entprellung bzw. Erkennung eines 
Tastendrucks ist Voraussetzung für alles weitere. Egal wie die 
Flankenerkennung bzw. Entprellung dann tatsächlich realisiert ist. Aber 
funktionieren muss sie.

Und sowas
1
  do
2
        {  
3
        delay(100);    // warte darauf das Taster gedrückt wird
4
        }
5
        while((digitalRead(pineins) == LOW) && (digitalRead(pinzwei) == LOW) && (digitalRead(pindrei) == LOW) && (digitalRead(pinvier) == LOW));
ist noch viel größerer Murks. Selbst wenn der Kommentar zum Code stimmen 
würde.

Es wird nicht gewartet!
Deine loop() sieht als Pseudocode so aus
1
void loop()
2
{
3
  if Taste 1 gedrückt
4
    dann hänge eine 1 an die angegebene Kombination an
5
6
  else if Taste 2 gedrückt
7
    dann hänge eine 2 an die angegebene Kombination an
8
9
  else if Taste 3 gedrückt
10
    dann hänge eine 3 an die angegebene Kombination an
11
12
13
  if angegebene Kombination ist gleich der vorgegebenen Kombination
14
    dann öffne das Schloss
15
}

da wird nirgends gewartet. Alles was passiert ist: wenn ein Tastendruck 
festgestellt wird, dann wird dieser Tastendruck 'ausgewertet', indem die 
Zahl für die er steht an die bisherige Eingabe angehängt wird. Ist keine 
Taste gedrückt, dann passiert auch nichts weiter, bis loop() das nächste 
mal aufgerufen wird.

Weder muss es hier eine for-Schleife geben, die auf 6 Tasten wartet, 
noch muss man auf das Loslassen einer Taste warten. Denn letzteres macht 
die Erkennung eines Tastendrucks.
Und daher muss das Erkennen eines Tastendrucks (das Pedant zur 
Fragestellung_ ist jetzt gerade eine Taste gedrückt) absolut zuverlässig 
funktionieren. Und zwar auch für mehrere Tasten. Vorher hat es keinen 
Sinn darauf aufbauend irgendetwas weiterführendes zu programmieren.

: Bearbeitet durch User
von Paul (Gast)


Lesenswert?

Was hat das delay mit dem restlichen Code zu tun? Nur weil er 300 ms 
wartet bis der Taster nicht mehr prellt...



Karl Heinz schrieb:
> Und sowas  do
>         {
>         delay(100);    // warte darauf das Taster gedrückt wird
>         }
>         while((digitalRead(pineins) == LOW) && (digitalRead(pinzwei) ==
> LOW) && (digitalRead(pindrei) == LOW) && (digitalRead(pinvier) == LOW));
> ist noch viel größerer Murks. Selbst wenn der Kommentar stimmen würde.
>
> Es wird nicht gewartet!

Warum soll nicht gewartet werden? Solange kein Taster gedrückt wird 
kommt er ja nicht weiter sondern wiederholt die Schleife solange bis ein 
Taster gedrückt wird..?



Okey, dann lasse ich die for-Schleife weg, aber wie überprüfe ich dann 
ob der Code welcher Eingegeben wurde auch der ist welcher im Array 
steht?

Der Code sollte später ebenfalls über die Taster neu programmiert werden 
können.

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Paul schrieb:
> Warum soll nicht gewartet werden?
Weil damit Rechenzeit verplempert wird, die man irgendwann bitter nötig 
braucht. Oder frage dich mal andersrum: warum sollte gewartet werden? 
Lässt dich diese Aufgabe nicht ohne delay() lösen? Und bestenfalls "ganz 
unten", direkt an der Hardware kann es sein, dass man mal eine oder zwei 
us verplempern muss. Aber ein Delay im ms Bereich ist NIE nötig.


> Solange kein Taster gedrückt wird
Du bekommst es ja 300ms lang gar nicht mit, wenn da ein Taster gedrückt 
wird (nicht mal ein Wagnerscher Hammer prellt so lange). Du machst 
deinen uC absichtlich langsam und träge.


Du brauchst übrigens einfach eine "Flankenerkennung": ist eine Taste 
gedrückt worden, dann gibt es genau einen Durchlauf der Auswertung.

Ich werde das Morgen am Rechner mal kurz runterschreiben, hier am Handy 
ist mir das zu mühsam... ;-)

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

So, wie versprochen:
1
  // Pins definieren, dazu braucht man keine Variablen, 
2
  // denn Pins sind nicht variabel und hüpfen nicht wild hin und her...
3
  #define  pineins  7
4
  #define  pinzwei  6 
5
  #define  pindrei  5
6
  #define  pinvier  4
7
  #define  pinfuenf  3
8
  #define  pinsechs  2
9
  #define  ledgruen 12
10
  #define  ledrot 11
11
  
12
  int Code[5] = {5,4,3,2,1};
13
  int Schritt = 0;
14
  int Taste = 0;
15
  int Led = 0; // 1 = grün, 2= rot
16
  byte T1 = 0;
17
  byte T2 = 0;
18
  byte T3 = 0;
19
  byte T4 = 0;
20
  byte T5 = 0;
21
  byte T6 = 0;
22
  long tiAkt,tiEntprellen,tiLED,tiTimeoutEingabe;
23
 
24
void setup() {
25
 
26
  pinMode(pineins, INPUT_PULLUP);
27
  pinMode(pinzwei, INPUT_PULLUP);
28
  pinMode(pindrei, INPUT_PULLUP);
29
  pinMode(pinvier, INPUT_PULLUP);
30
  pinMode(pinfuenf, INPUT_PULLUP);
31
  pinMode(pinsechs, INPUT_PULLUP);
32
  pinMode(ledrot, OUTPUT);
33
  pinMode(ledgruen, OUTPUT);
34
}
35
36
void loop() {
37
   // Aktuelle Zeit abholen  
38
   tiAkt = millis();
39
   // Tasten einlesen
40
   if (digitalRead(pineins) == LOW)  T1 = 1; 
41
   else                              T1 = 0;
42
   :
43
   if (digitalRead(pinsechs) == LOW) T6 = 1; 
44
   else                              T6 = 0;
45
   
46
   // Tasten entprellen
47
   if (T1+T2+T3+T4+T5+T6 == 0) {    // keine Taste gedrückt 
48
     tiEntprellen = tiAkt+20;      // --> Entprelltimeout laufend hochzählen
49
     if (Schritt==0)
50
       tiTimeoutEingabe = tiAkt+10000000; // nach 10 sec Eingabe abbrechen
51
   }
52
53
   if (tiAkt > tiTimeoutEingabe ) { // Maximalzeit für Eingabe abgelaufen 
54
     Schritt=0;
55
     Led = 2; // rot
56
     tiLED = tiAkt+500;
57
   }
58
59
   if (tiAkt > tiEntprellen) {     // Entprellzeit abgelaufen --> Taste gültig
60
     tiEntprellen = tiAkt+1000;    // Repeatfunktion (kostenlos ;-)
61
     if (T1+T2+T3+T4+T5+T6 > 1) {  // zu viele Tasten gedrückt ?
62
       Schritt = 0;                // ja --> Abbruch Codeeingabe!! 
63
       Led = 2;                    // rote LED für 500ms einschalten
64
       tiLED = tiAkt+500;
65
     } else {                      // nein --> auswerten
66
       // Umrechnen Taste in Zahl
67
       Taste = 0;
68
       if (T1) Taste = 1;
69
       if (T2) Taste = 2;
70
       if (T3) Taste = 3;
71
       if (T4) Taste = 4;
72
       if (T5) Taste = 5;
73
       if (T6) Taste = 6;
74
       
75
       // Code vergleichen
76
       if (Taste == Code[Schritt]) { // passt?
77
         Schritt++;                  // ja --> Schritt hochzählen
78
       } else {                      // falsche Zahl
79
         Schritt = 0;                // --> Abbruch Codeeingabe!! 
80
         Led = 2;                    // rote LED für 500ms einschalten
81
         tiLED = tiAkt+500;
82
       }
83
    }  
84
  } // tiAkt>tiEntprellen
85
86
  if (Schritt == 5) {               // geschafft: Code komplett richtig eingegeben
87
    Schritt = 0;
88
    Led = 1;                        // grüne LED für 500ms einschalten
89
    tiLED = tiAkt+500;
90
  }
91
 
92
  if (tiAkt>tiLED) {                 // Zeit für LEDs abgelaufen?
93
        digitalWrite(ledrot,LOW);    // ja: LEDs aus
94
        digitalWrite(ledgruen,LOW); 
95
  } else {                  
96
        if (Led==1) digitalWrite(ledgruen,HIGH); // nein: richtige LED ein
97
        if (Led==2) digitalWrite(ledrot,HIGH);
98
  }
99
}

Könnte noch der eine oder andere Fehler drin sein, aber die grundlegende 
Idee dürfte klar werden...

: Bearbeitet durch Moderator
von johann (Gast)


Lesenswert?

Den Code würde ich erst nach Eingabe aller Zeichen vergleichen.
sonst sieht man sofort, wenn man einen Fehler gemacht hat...
Normalerweise hätte man die Sicherheit von 1 000 000 Möglichkeiten...
Signalisiert man den Fehler sofort, hat man nur noch max. 60 
Varianten...
Ansonsten sieht der Code für mich (als Anfänger) gut aus.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

johann schrieb:
> Den Code würde ich erst nach Eingabe aller Zeichen vergleichen.
> sonst sieht man sofort, wenn man einen Fehler gemacht hat...
Richtig. Kleine Anpassung nötig... ;-)
1
  int Code[5] = {5,4,3,2,1};
2
  int Codeeingabe[5];
3
  int Schritt = 0;
4
  int Treffer = 0;
5
  int Taste = 0;
6
   
7
8
  ...
9
10
      // Umrechnen Taste in Zahl
11
       Taste = 0;
12
       if (T1) Taste = 1;
13
       if (T2) Taste = 2;
14
       if (T3) Taste = 3;
15
       if (T4) Taste = 4;
16
       if (T5) Taste = 5;
17
       if (T6) Taste = 6;
18
       
19
       // Code abspeichern
20
       Codeeingabe[Schritt] = Taste);
21
       Schritt++;
22
23
    }  
24
  } // tiAkt>tiEntprellen
25
  
26
  if (Schritt == 5) {             // geschafft: Code prüfen
27
    for (Treffer=0, Schritt=0; Schritt<5; Schritt++) // einfach mal ansehen, wann was wie in der for-Schleife gemacht wird. Es lohnt sich... ;-)
28
       if (Code[i] = Codeeingabe[i]) Treffer++;
29
30
    if (Treffer==5) {             // alle Zahlen richtig
31
      Led = 1;                    // grüne LED für 500ms einschalten
32
      tiLED = tiAkt+500;
33
    } else {                      // falsche Zahl
34
      Schritt = 0;                 
35
      Led = 2;                    // rote LED für 500ms einschalten
36
      tiLED = tiAkt+500;
37
    }
38
  }
39
 
40
  if (tiAkt>tiLED) {                 // Zeit für LEDs abgelaufen?
41
   ...
42
}

Ich würde das Prüfen aber in der Realität mit einem memcmp() statt der 
for-Schleife machen...

: Bearbeitet durch Moderator
von Peter D. (peda)


Lesenswert?

johann schrieb:
> Den Code würde ich erst nach Eingabe aller Zeichen vergleichen.

Man kann auch sofort vergleichen und merkt sich einfach nur das 
Falschbit bis zur letzten Taste.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger schrieb:
> Man kann auch sofort vergleichen und merkt sich einfach nur das
> Falschbit bis zur letzten Taste.
Tausende von Möglichkeiten...  ;-)

Da nehme ich wieder mal den ersten Code:
1
  int Code[5] = {5,4,3,2,1};
2
  int Schritt = 0;
3
  int Falscheingabe = 0;
4
  int Taste = 0;
5
  int Led = 0; // 1 = grün, 2= rot
6
7
  ...
8
9
   // Tasten entprellen
10
   if (T1+T2+T3+T4+T5+T6 == 0) {    // keine Taste gedrückt 
11
     tiEntprellen = tiAkt+20;       // --> Entprelltimeout laufend hochzählen
12
     if (Schritt==0) {              // noch nicht angefangen?
13
       Falscheingabe = 0;
14
       tiTimeoutEingabe = tiAkt+10000000; // nach 10 sec Eingabe abbrechen
15
     }
16
   }
17
18
   if (tiAkt > tiTimeoutEingabe ) { // Maximalzeit für Eingabe abgelaufen 
19
     Schritt = 0;
20
     Led = 2; // rot
21
     tiLED = tiAkt+500;
22
   }
23
24
   if (tiAkt > tiEntprellen) {     // Entprellzeit abgelaufen --> Taste gültig
25
     tiEntprellen = tiAkt+1000;    // Repeatfunktion (kostenlos ;-)
26
     if (T1+T2+T3+T4+T5+T6 > 1) {  // zu viele Tasten gedrückt ?
27
       Schritt = 0;                // ja --> Abbruch Codeeingabe!! 
28
       Led = 2;                    // rote LED für 500ms einschalten
29
       tiLED = tiAkt+500;
30
     } else {                      // nein --> auswerten
31
       // Umrechnen Taste in Zahl
32
       Taste = 0;
33
       if (T1) Taste = 1;
34
       if (T2) Taste = 2;
35
       if (T3) Taste = 3;
36
       if (T4) Taste = 4;
37
       if (T5) Taste = 5;
38
       if (T6) Taste = 6;
39
       
40
       // Code vergleichen
41
       if (Taste != Code[Schritt]) // Falscheingabe?
42
         Falscheingabe++;          // ja: merken!
43
44
       Schritt++;                  // Nächste Zahl: Schritt hochzählen
45
    }  
46
  } // tiAkt>tiEntprellen
47
48
  if (Schritt == 5) {               // geschafft: 5 Zahlen eingegeben
49
    Schritt = 0;
50
    if (Falscheingabe==0)           // Falscheingabe?
51
      Led = 1;                      // nein: grüne LED einschalten
52
    else 
53
      Led = 2;                      // ja: rote LED einschalten
54
    tiLED = tiAkt+500;              // für 500ms 
55
  }
56
 
57
  if (tiAkt>tiLED) {                 // Zeit für LEDs abgelaufen?
58
  ...
59
}

: Bearbeitet durch Moderator
von Peter D. (peda)


Lesenswert?

Paul schrieb:
> Wieso? Eingabe ist nicht zeitkritisch also warum soll ich die
> Debounce-Libary verwenden?

Eine separate Tastenfunktion mit Entprellung und Flankenerkenung macht 
aber das Programmieren erheblich einfacher.
Man braucht dann nur noch den eigentlichen Ablauf zu programmieren.

von Karl H. (kbuchegg)


Lesenswert?

Ich würde ehrlich gesagt gar keine Möglichkeit zum Abbruch der 
Codeeingabe vorsehen.

Der Benutzer tippt einfach dahin. Die letzten 5 eingegebenen Ziffern 
gelten (werden mit jeder Benutzereingabe um 1 Stelle weitergeshiftet, 
die am 5-weitesten zurück liegende Eingabe fällt raus).
Stimmen zu irgendeinem Zeitpunkt alle 5 Ziffern, wird die LED grün, 
ansonsten rot.

D.h. wenn sich ein Benutzer mal vertippt, dann fängt er einfach erneut 
mit der Eingabe der 6 Ziffern an, egal wieviele Stellen er schon 
eingegeben hat. Ist das Schloss geöffnet, dann braucht er einfach nur 
irgendeine Ziffer tippen (vernünftiger Code vorausgesetzt) und das 
Schloss ist wieder geschlossen.
Ein 'Einbrecher' erhält dadurch keinerlei Information. Weder über 
gültige Ziffern noch über die Codelänge.
1
void loop()
2
{
3
  .... Tastenerkennung ....
4
5
  if( Tastedruck registriert ) {
6
    for( i = 0; i < 4; i++ )
7
      Codeeingabe[i] = Codeeingabe[i+1];
8
    Codeeingabe[4] = nächster Tastendruck;
9
10
    Treffer = TRUE;
11
    for( i = 0; i < 5; i++ ) {
12
      if( Codeeingabe[i] == Code[i] )
13
        Treffer = FALSE;
14
    }
15
16
    digitalWrite(ledrot, Treffer ? HIGH : LOW);
17
    digitalWrite(ledgruen, Treffer ? LOW : HIGH );
18
  }
19
}

Ich hätte auch die Tastenerkennung/Enprellung einfacher gemacht. Da hier 
wohl niemand nur ganz kurz antippen wird, hätte ich einfach eine 
Flankenerkennung alle 50ms gemacht. 50ms dürfte ausreichen, um 
eventuelles Prellen zu eliminieren und wenn nicht, dann geht man eben 
mit der Zeit noch etwas hoch.


So ungefähr
1
...
2
uint8_t oldState[10];
3
uint8_t stateNow[10];
4
uint8_t keyPressed;
5
uint8_t isValid;
6
unsigned long lastCheckedTime ;
7
8
uint8_t pinNr[10] = { pinEins, pinZwei, pinDrei, .... };
9
10
#define CODE_LEN 5
11
uint8_t Code[CODE_LEN] = {5,4,3,2,1};
12
uint8_t Codeeingabe[CODE_LEN];
13
14
....
15
16
void loop()
17
{
18
  keyPressed = -1;
19
20
  // alle 50ms den Zustand der Tasten checken und auswerten
21
  if( millis() - lastCheckedTime > 50 ) {
22
    lastCheckedTime = millis();
23
24
    // 10 Tasten abfragen
25
    // gab es an irgendeinem Pin eine Veränderung?
26
    // Bei exakt gleichzeitiger Betätigung ist die Priorität
27
    // in aufsteigender Reihung 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
28
29
    for( i = 0; i < 10; i++ ) {
30
      stateNow[i] = digitalRead( pinNr[i] );
31
      if( stateNow[i] != oldState[i] && stateNow[i] == LOW )
32
        keyPressed = i;
33
      oldState[i] = stateNow[i];
34
    }
35
  }
36
37
  // wurde irgendeine Taste in der Zwischenzeit niedergedrückt?
38
  if( keyPressed != -1 ) {
39
    // bisherigen Code um 1 Stelle weiter schieben und Tstendruck
40
    // hinten anhängen
41
    for( i = 0; i < CODE_LEN-1; i++ )
42
      Codeeingabe[i] = Codeeingabe[i+1];
43
    Codeeingabe[CODE_LEN-1] = keyPressed;
44
45
   // ergibt sich dadurch ein gültiger Code ....
46
   isValid = TRUE;
47
    for( i = 0; i < CODE_LEN; i++ ) {
48
      if( Codeeingabe[i] == Code[i] )
49
        isValid = FALSE;
50
    }
51
52
    // ... die LEDs entsprechend der Gültigkeit schalten
53
    digitalWrite(ledrot, isValid ? HIGH : LOW);
54
    digitalWrite(ledgruen, isValid ? LOW : HIGH );
55
  }
56
}

: Bearbeitet durch User
von JH (Gast)


Lesenswert?

Karl Heinz schrieb:
> Ich würde ehrlich gesagt gar keine Möglichkeit zum Abbruch der
> Codeeingabe vorsehen.
>
> Der Benutzer tippt einfach dahin. Die letzten 5 eingegebenen Ziffern
> gelten (werden mit jeder Benutzereingabe um 1 Stelle weitergeshiftet,
> die am 5-weitesten zurück liegende Eingabe fällt raus).
> Stimmen zu irgendeinem Zeitpunkt alle 5 Ziffern, wird die LED grün,
> ansonsten rot.

Das würde ich nicht machen. Ist der Code bspw. 00001 und der Einbrecher 
probiert zuerst 10000, dann braucht er danach nur noch einmal die Eins 
drücken (will z.B. als nächstes 10001 probieren) und schon hat er den 
Code.

von Karl H. (kbuchegg)


Lesenswert?

JH schrieb:
> Karl Heinz schrieb:
>> Ich würde ehrlich gesagt gar keine Möglichkeit zum Abbruch der
>> Codeeingabe vorsehen.
>>
>> Der Benutzer tippt einfach dahin. Die letzten 5 eingegebenen Ziffern
>> gelten (werden mit jeder Benutzereingabe um 1 Stelle weitergeshiftet,
>> die am 5-weitesten zurück liegende Eingabe fällt raus).
>> Stimmen zu irgendeinem Zeitpunkt alle 5 Ziffern, wird die LED grün,
>> ansonsten rot.
>
> Das würde ich nicht machen. Ist der Code bspw. 00001

Ich vergass:
vernünftigen Code vorausgesetzt

> danach nur noch einmal die Eins drücken (will z.B. als nächstes
> 10001 probieren) und schon hat er den Code.

Ja, wenn.
Dazu muss er aber wissen, dass der Code 5 stellig ist. Da ihm aber das 
Gerät diese Information nicht verrät, ergibt sich da ein zusätzlicher 
Schutz, den es mit der Alternative nicht gibt.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> digitalWrite(ledrot, isValid ? HIGH : LOW);
Den Fragezeichenoperator wollte ich erst in der nächsten Stunde 
drannehmen... ;-)

> isValid
Das allein wäre mir zu wenig. Da bleibt der Türöffner ja bis zur 
nächsten Eingabe betätigt...

> Ich würde ehrlich gesagt gar keine Möglichkeit zum Abbruch der
> Codeeingabe vorsehen.
Ich würde im Gegenteil die Codeeingabe frühestmöglich abbrechen: nur ein 
zügig eingegebener Code ist ein gültiger Code. Wenn so eine zögerliche 
Eingabe erkannt und gespeichert, aber nicht angezeigt wird, dann 
probiert man sogar mit der richtigen Nummer herum, ohne dass die Tür 
aufgeht: nach holpriger Eingabe der richtigen Zahl leuchtet die rote 
LED... :-o

: Bearbeitet durch Moderator
von Karl H. (kbuchegg)


Lesenswert?

Lothar Miller schrieb:
> Karl Heinz schrieb:
>> digitalWrite(ledrot, isValid ? HIGH : LOW);
> Den Fragezeichenoperator wollte ich erst in der nächsten Stunde
> drannehmen... ;-)

:-)

>
>> isValid
> Das allein wäre mir zu wenig. Da bleibt der Türöffner ja bis zur
> nächsten Eingabe betätigt...

OK. Häng noch ein Software Monoflop hinten nach.
Ausserdem: Es ist das Projekt des TO. Was bleibt denn noch für ihn zu 
tun, wenn wir ihm alles erledigen :-)

Ich hab in letzter Zeit sowieso schon so meine persönlichen Probleme mit 
Projekten der Marke "Ich will ein Space Shuttle bauen ... aber ich kann 
noch nicht mal einen Papierflieger falten ... ich will es auch nicht 
lernen .... könnt ihr nicht mal .... guck mal Mama, was ICH gebaut habe"

>
>> Ich würde ehrlich gesagt gar keine Möglichkeit zum Abbruch der
>> Codeeingabe vorsehen.
> Ich würde im Gegenteil die Codeeingabe frühestmöglich abbrechen: nur ein
> zügig eingegebener Code ist ein gültiger Code. Wenn das nicht angezeigt
> wird, dann probiert man sogar mit der richtigen Nummer herum, ohne
> dass die Tür aufgeht...

Auch eine nette Alternative. Lässt sich (genauso wie bei dir) auch in 
meinem Schema problemlos nachrüsten. 5 Sekunden nach dem letzten 
Tastendruck, werden alle Stellen zwangsweise zb auf 0 gesetzt. Zeit des 
letzten Tastendrucks merken, Differenzbildung von millis() und wenn 
größer 5000 läuft die Rücksetzmaschinerie. Je mehr ich darüber 
nachdenke, desto besser gefällt mir diese Zeitbegrenzung.

: Bearbeitet durch User
von JH (Gast)


Lesenswert?

Karl Heinz schrieb:
> Ja, wenn.
> Dazu muss er aber wissen, dass der Code 5 stellig ist. Da ihm aber das
> Gerät diese Information nicht verrät, ergibt sich da ein zusätzlicher
> Schutz, den es mit der Alternative nicht gibt.

Karl Heinz schrieb:
> Ich vergass:
> vernünftigen Code vorausgesetzt

Wenn man das Schloss möglichst sicher machen möchte, dann sollte es 
keinen "vernünftigeren" Code geben :P

Karl Heinz schrieb:
> Ja, wenn.
> Dazu muss er aber wissen, dass der Code 5 stellig ist. Da ihm aber das
> Gerät diese Information nicht verrät, ergibt sich da ein zusätzlicher
> Schutz, den es mit der Alternative nicht gibt.

Wenn er nicht weiß, dass der wielang der Code ist, bleibt ihm ja nur 
alle Längen durchzuprobieren. Angenommen der Code sei dreistellig -> 
930. Er probiert also erstmall alle einstelligen Codes (0..9) ohne 
Erfolg. Jetzt startet er mit der Eingabe aller zweistelligen Codes 
(00..99) und öffnet das Schloss bereits bei der Eingabe von "30", da er 
vorher "29" probiert hat.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Auch eine nette ALternative.
Man könnte noch eins weiter gehen und die Zahlen komplett irrelevant 
machen. Dann gilt nur der Rhythmus der Tastaturbetätigungen. Ist 
natürlich nichts für Schlagzeuger, die schleppen gern... ;-)

von Karl H. (kbuchegg)


Lesenswert?

JH schrieb:

> Wenn er nicht weiß, dass der wielang der Code ist, bleibt ihm ja nur
> alle Längen durchzuprobieren. Angenommen der Code sei dreistellig ->
> 930. Er probiert also erstmall alle einstelligen Codes (0..9) ohne
> Erfolg. Jetzt startet er mit der Eingabe aller zweistelligen Codes
> (00..99) und öffnet das Schloss bereits bei der Eingabe von "30", da er
> vorher "29" probiert hat.

Sperr ihm die Eingabe nach der 5-ten Falscheingabe für 2 Minuten und der 
sitzt die ganze Nacht am Gerät um die 40 Eingaben zu machen. Ausserdem 
ist der Code nicht 3-stellig sondern 5 stellig (was aber ein Einbrecher 
nicht weiß).
Klar kann es passieren, dass er durch Zufall die richtige Kombination 
bekommt. Das kann im anderen Fall aber genau so passieren. Nur mit dem 
Unterschied, dass er mit dem Wissen des 5 stelligen Codes erst mal alle 
Geburtsdaten durchprobiert, den Hochzeitstag, etc. etc.

Aber ok.
Ich sag ja nicht, dass er muss. So würde ich das machen. Wenn ihm das 
nicht gefällt, kann er immer noch eine Rücksetztaste dazu bauen und die 
Anzahl der Tastendrücke mitzählen. Schliesslich sind wir Programmierer. 
Wir bestimmen, wie sich die Dinge verhalten sollen und so wie wir das 
definieren ist es per Definition richtig :-)

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> Sperr ihm die Eingabe nach der 5-ten Falscheingabe für 2 Minuten und der
> sitzt die ganze Nacht am Gerät um die 40 Eingaben zu machen.
Ich würde in diesem Fall während der (unsichtbaren) Sperrzeit nach 
irgendeinem Tastendruck beliebig mal die rote oder die grüne LED ein- 
und wieder ausschalten (natürlich ohne den Türöffner zu betätigen)... 
;-)

> so wie wir das definieren ist es per Definition richtig :-)
Und das ist gut so.
Der Trick dabei ist: der uC muss das machen, was wir wollen. Und das 
können wir ihm mit einfachen und strukturierten Anweisungen sagen.
Ein delay() trägt aber niemals etwas zur Struktur bei. Ein delay() 
verzögert bestenfalls irgendwelche Probleme, ist aber oft sogar die 
Ursache dafür...

: Bearbeitet durch Moderator
von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Wenn man einbaut, dass man immer zwei aufeinanderfolgende Ziffern 
paarweise gleichzeitig drücken muss, kann man den Code sogar noch 
ausdrucken und als Gedächtnisstütze direkt neben das Schloss kleben ;-)

: Bearbeitet durch Moderator
von kopfkratzer (Gast)


Lesenswert?

kopfkratz
Man könnte natürlich auch eine Tastenkombination als Auslöser nehmen, 
z.B. 0+9 gleichzeitig gedrückt testet ob der Code korrekt war ...
Oder man schafft sich ein paar nette Rottweiler an, die riechen's dann 
:-P

von Nosnibor (Gast)


Lesenswert?

Karl Heinz schrieb:
> Ich würde ehrlich gesagt gar keine Möglichkeit zum Abbruch der
> Codeeingabe vorsehen.
>
> Der Benutzer tippt einfach dahin. Die letzten 5 eingegebenen Ziffern
> gelten (werden mit jeder Benutzereingabe um 1 Stelle weitergeshiftet,
> die am 5-weitesten zurück liegende Eingabe fällt raus).
> Stimmen zu irgendeinem Zeitpunkt alle 5 Ziffern, wird die LED grün,
> ansonsten rot.

Der Nachteil dabei ist, daß der Angreifer mit jedem Tastendruck eine 
neue Kombination testen kann, was das Durchprobieren beschleunigt.

Die einfachste Abhilfe wäre eine zusätzliche Taste, mit der der Benutzer 
sagt, daß er jetzt fertig ist, und der Code geprüft werden soll.

Alternativ könnte man sich einen cleveren Sperrzeit-Algorithmus 
ausdenken, aber man muß dabei berücksichtigen, daß jede korrekte Eingabe 
eines fünfstelligen Codes erstmal mit vier falschen Eingaben anfängt.

von Paul (Gast)


Lesenswert?

Ich danke euch für die zahlreichen Antworten :)
Habe nun durch die Tipps meine eigenen Code geschrieben und es 
funktioniert.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Paul schrieb:
> Habe nun durch die Tipps meine eigenen Code geschrieben
Trau dich doch einfach, den Code hier zu posten. Andere könnten etwas 
davon lernen...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.