Forum: Mikrocontroller und Digitale Elektronik Tastenkombination in einer bestimmten Zeit auswerten


von Rene Z. (renezimmermann)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe ein Problem bei dem ich über eine elegante Lösung nachdenke.

Ich habe einen ATTiny an dem 2 Taster nach Masse angeschlossen sind.
Ausserdem sich noch 3 LED verbunden. Habe das im Anhang mal schnell
visualisiert.

Nun soll wenn innerhalb von 3 sekunden eine Tastenkombination gedrückt
wird eine LED nach folgendem Schema leuchten.

Taste1 Taste1 Taste1 Led1
Taste1 Taste1 Taste2 Led2
Taste1 Taste2 Taste1 Led3

Wie ich eine Taste abfrage und entprelle oder die Led ein- und 
ausschalte weiss ich und soll hier nicht berücksichtigt werden. Es geht 
sich nur um eine elegante Lösung des Problems das unterschiedliche 
Tasten innerhalb einer bestimmten Zeit gedrückt und ausgewertet werden 
müssen.

Warscheinlich sehe ich gerade den Wald vor lauter Bäumen nicht. ;-)

Gruß Rene

von Karl H. (kbuchegg)


Lesenswert?

Rückfragen:

Ab wann sollen die 3 Sekunden zu laufen anfangen.
Mit dem ersten Tastendruck, oder ist das so zu verstehen, dass ich nach 
jedem Tastendruck weitere 3 Sekunden Zeit bekomme um die nächste Taste 
zu drücken. (und wenn ich die Zeit verstreichen lasse, dann ist die 
komplette bisherige Eingabe hinfällig)?

Was ist wenn ich innerhalb der 3 Sekunden 4 mal auf die Taste drücke?

2 1 1 2

die ersten 3 tastendrücke sind keine zulässige Kombination, aber wenn 
man den ersten Druck ignoriert, dann wäre 1 1 2 zulässig.

Warum ich frage:
Weil es viel einfacher ist, wenn ich sage:
Nach jedem Tastendruck beginnt ein Timer zu laufen, der nach 3 Sekunden 
die bisherige Eingabe löscht.
Jeder Tastendruck wird einfach in ein Array 'eingeschoben' und nach 
jedem Tastendruck wird nachgesehen ob eine zulässige Lösung vorliegt.

Bsp   0 ist keine Taste
      1 ist       Taste 1
      2 ist       Taste 2
      3 ist       Taste 3

Ausgangssituation

  +---+---+---+
  | 0 | 0 | 0 |    Grundzustand
  +---+---+---+

Taste 2 gedrückt

  +---+---+---+
  | 0 | 0 | 2 |
  +---+---+---+

keine zulässige Lösung

Taste 1 gedrückt

  +---+---+---+
  | 0 | 2 | 1 |
  +---+---+---+

keine zulässige Lösung

Taste 1 gedrückt

  +---+---+---+
  | 2 | 1 | 1 |
  +---+---+---+

keine zulässige Lösung

Taste 3 gedrückt

  +---+---+---+
  | 1 | 1 | 3 |
  +---+---+---+

zulässige Lösung, Led 3 an und wieder Grundzustand

  +---+---+---+
  | 0 | 0 | 0 |    Grundzustand
  +---+---+---+

Taste 3 gedrückt

  +---+---+---+
  | 0 | 0 | 3 |
  +---+---+---+

Taste 2 gedrückt

  +---+---+---+
  | 0 | 3 | 2 |
  +---+---+---+

(3 Sekunden verstreichen lassen -> Timer kickt ein und setzt alles auf 
Grundzustand

  +---+---+---+
  | 0 | 0 | 0 |
  +---+---+---+


(der Timer wird mit jedem Tastendruck wieder neu gestartet)

von Rene Z. (renezimmermann)


Lesenswert?

Na das ging ja mal schnell.

Also, gültig sollen immer nur Eingaben innerhalb von 3 Sekunden sein. 
Werden mehr Tasten betätigt so ist die erste gültige Reihenfolge 
abzuarbeiten. Werden innerhalb von 3 Sekunden keine 3 gültigen Eingabe 
erkannt so ist nichts zu unternehmen.

P.S. Es gibt keine Taste 3. ;-)))))

Gruß Rene

von Karl H. (kbuchegg)


Lesenswert?

ok.
Dann würde ich das so modifizieren, dass der Timer gestartet wird, wenn 
das "System" aus dem Grundzustand heraus kommt. Alles andere bleibt 
gleich

von Rene Z. (renezimmermann)


Lesenswert?

Ok,

meiner Meinung nach habe ich es so gemacht. ;-)

Wäre es möglich das da noch mal ein paar Augen draufschauen?
Würde mich echt freuen. Die Tastenentprellung ist hier bewusst
noch nicht berücksichtigt. Verbesserungsvorschläge sind herzlich
Willkommen.
1
#include <stdio.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
#define Taste_DDR            DDRB
6
#define Taste_PIN            PINB
7
#define Taste_PORT            PORTB
8
#define Taste1              PB4
9
#define Taste2              PB3
10
11
#define Led_DDR              DDRB
12
#define Led_PORT            PORTB
13
#define Led1              PB2
14
#define Led2              PB1
15
#define Led3              PB0
16
17
#define Led1_an              Led_PORT &= ~(1<<Led1)
18
#define Led1_aus            Led_PORT |= (1<<Led1)
19
#define Led2_an              Led_PORT &= ~(1<<Led2)
20
#define Led2_aus            Led_PORT |= (1<<Led2)
21
#define Led3_an              Led_PORT &= ~(1<<Led3)
22
#define Led3_aus            Led_PORT |= (1<<Led3)
23
24
#define Timer0_Reload          255 - 43        // 1,1 ms bei 11,0592 MHz
25
26
#define max_Buffer_len          3            // max. 3 Tasten speichern
27
28
uint8_t Buffer[max_Buffer_len];                  // Buffer für Tasten
29
30
//GPIOR sollte schneller sein als volatile auf Ram, ist das so ?????? Ich denke ja. Muß ich noch prüfen !!!!!!
31
32
#define Zeiger              GPIOR0          // Zeiger für Bufferposition
33
#define Zeit              GPIOR1          // Zeitzähler
34
#define Zeit_mul            GPIOR2          // Zeitmultiplikator für Interrupt
35
36
ISR(TIMER0_OVF_vect){                      // Timer0 Overflow alle 1,1 ms, 1,1 ms ist fest da
37
                                // noch für andere Sachen gebraucht, leider !!!! 
38
  TCNT0 = Timer0_Reload;                    // Reloadwert laden
39
  if (Zeit_mul > 90){                        // alle 91 ms x 1,1 ms = 100,1 ms 
40
    Zeit++;                            // Zeit in 1/10 sec weiterzählen
41
    Zeit_mul = 0;                        // Zeitmultiplikator zurücksetzten
42
  }
43
}
44
45
void Buffer_Init(void){
46
  Zeiger = 0;                          // Bufferzeiger auf Anfang
47
  Buffer[0] = 0;                        // Buffer löschen
48
  Buffer[1] = 0;                        // Buffer löschen
49
  Buffer[2] = 0;                        // Buffer löschen
50
}
51
52
inline void Init(void){
53
  // Tasten
54
  Taste_DDR &= ~(1<<Taste1)|(1<<Taste2);            // Taste1 & Taste2 Eingang
55
  Taste_PORT |= (1<<Taste1)|(1<<Taste2);            // Taste1 & Taste2 Pullup an
56
  // Led
57
  Led_DDR |= (1<<Led1)|(1<<Led2)|(1<<Led3);          // Led1 & Led2 & Led3 Ausgang
58
  Led_PORT |= (1<<Led1)|(1<<Led2)|(1<<Led3);          // Led1 & Led2 & Led3 aus
59
  // Timer 0
60
  TCCR0A = 0;                          // Timer Normal Mode
61
  TCCR0B = (1<<CS02);                      // clkI/O / 256 (From prescaler)
62
  TIMSK |= (1<<TOIE0);                    // Timer/Counter0 Overflow Interrupt an
63
  // Buffer
64
  Buffer_Init();                        // Bufferspeicher initialisieren
65
}
66
67
int main(void){
68
  Init();                            // alles Initialisieren
69
  sei();                            // Interrupt Global ein 
70
  while(1){                          // Endlosschleife
71
    
72
    if (Zeit > 30){                      // wenn ca. 30 1/10 sec = 3 sec um sind
73
      Buffer_Init();                      // Bufferspeicher initialisieren
74
    }
75
76
    if(Taste_PIN & (1<<Taste1)){              // ist Taste1 gedrückt?
77
      if (Zeiger == 0){                    // erste Taste gedrückt
78
        Zeit = 0;                        // Zeit zurücksetzen
79
      }
80
      if (Zeiger < max_Buffer_len - 1){            // wenn noch keine 3 Tasten gespeichert sind
81
        Buffer[Zeiger] = 1;                    // Tastendruck merken
82
        Zeiger++;                        // Zeiger weitersetzen
83
      }
84
      else{                          // es sind schon 3 Tasten gespeichert
85
        Buffer[0] = Buffer[1];                  // Bufferdaten Byteweise 1x links schieben, Byte 1
86
        Buffer[1] = Buffer[2];                  // Bufferdaten Byteweise 1x links schieben, Byte 2
87
        Buffer[2] = 1;                      // Tastendruck in Byte 2 merken
88
      }
89
    }
90
    else if(Taste_PIN & (1<<Taste2)){            // ist Taste2 gedrückt?
91
      if (Zeiger == 0){                    // erste Taste gedrückt
92
        Zeit = 0;                        // Zeit zurücksetzen
93
      }
94
      if (Zeiger < max_Buffer_len - 1){            // wenn noch keine 3 Tasten gespeichert sind
95
        Buffer[Zeiger] = 2;                    // Tastendruck merken
96
        Zeiger++;                        // Zeiger weitersetzen
97
      }
98
      else{                          // es sind schon 3 Tasten gespeichert
99
        Buffer[0] = Buffer[1];                  // Bufferdaten Byteweise 1x links schieben, Byte 1
100
        Buffer[1] = Buffer[2];                  // Bufferdaten Byteweise 1x links schieben, Byte 2
101
        Buffer[2] = 2;                      // Tastendruck in Byte 2 merken
102
      }
103
    }
104
105
    if (Buffer[0] == 1 && Buffer[1] == 1 && Buffer[2] == 1){// gedrückt Taste1 + Taste1 + Taste1
106
      Led1_an;
107
      Led2_aus;
108
      Led3_aus;
109
      Buffer_Init();                      // Bufferspeicher initialisieren
110
    }
111
    if (Buffer[0] == 1 && Buffer[1] == 1 && Buffer[2] == 2){// gedrückt Taste1 + Taste1 + Taste2
112
      Led1_aus;
113
      Led2_an;
114
      Led3_aus;
115
      Buffer_Init();                      // Bufferspeicher initialisieren  
116
    }
117
    if (Buffer[0] == 1 && Buffer[1] == 2 && Buffer[2] == 1){// gedrückt Taste1 + Taste2 + Taste1
118
      Led1_aus;
119
      Led2_aus;
120
      Led3_an;
121
      Buffer_Init();                      // Bufferspeicher initialisieren
122
    }
123
  }
124
}

Gruß Rene

von Karl H. (kbuchegg)


Lesenswert?

Rene Zimmermann schrieb:

> Würde mich echt freuen. Die Tastenentprellung ist hier bewusst
> noch nicht berücksichtigt.

Dann mach das mal zusammen mit einer vernünftigen Auswertung eines 
Tasten-DRUCKS

was glaubst/schätzt du, wie oft wird wohl dein µC diese 'Basisschleife'
1
   while(1){                          // Endlosschleife
2
3
...
4
5
     if(Taste_PIN & (1<<Taste1)){              // ist Taste1 gedrückt?
6
...
7
     }
8
     else if(Taste_PIN & (1<<Taste2)){            // ist Taste2 gedrückt?
9
...
10
     }
11
...
12
   }

ausführen, während du eine Taste deinem Gefühl nach ganz kurz drückst. 
10000 mal, vielleicht sogar 15000 mal. Irgend sowas in der Gegend wird 
es wohl sein.

von Rene Z. (renezimmermann)


Lesenswert?

Hi,

danke für die Antwort. Das ich das auf einem MC nicht laufen lassen kann 
war mir klar. Mir ging es nur um die Umsetzung des eigentlichen 
Problems. Aber kein Thema habe die Entprellung eingebaut und mich bei 
Peter Dannegger bedient. Anbei der geänderte Quellcode:
1
// Tasten Entprellroutine von Peter Dannegger: danni@specs.de
2
3
#include <stdio.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
7
#define Taste_DDR            DDRB
8
#define Taste_PIN            PINB
9
#define Taste_PORT            PORTB
10
#define Taste1              PB4
11
#define Taste2              PB3
12
13
#define Led_DDR              DDRB
14
#define Led_PORT            PORTB
15
#define Led1              PB2
16
#define Led2              PB1
17
#define Led3              PB0
18
19
#define KEY_DDR              Taste_DDR
20
#define KEY_PORT            Taste_PORT
21
#define KEY_PIN              Taste_PIN
22
#define KEY0              Taste1
23
#define KEY1              Taste2
24
#define ALL_KEYS            (1<<KEY0 | 1<<KEY1)
25
26
#define Led1_an              Led_PORT &= ~(1<<Led1)
27
#define Led1_aus            Led_PORT |= (1<<Led1)
28
#define Led2_an              Led_PORT &= ~(1<<Led2)
29
#define Led2_aus            Led_PORT |= (1<<Led2)
30
#define Led3_an              Led_PORT &= ~(1<<Led3)
31
#define Led3_aus            Led_PORT |= (1<<Led3)
32
33
#define Timer0_Reload          255 - 43        // 1,1 ms bei 11,0592 MHz
34
35
#define max_Buffer_len          3            // max. 3 Tasten speichern
36
37
uint8_t Buffer[max_Buffer_len];                  // Buffer für Tasten
38
39
//GPIOR sollte schneller sein als volatile auf Ram, ist das so ?????? Ich denke ja. Muß ich noch prüfen !!!!!!
40
41
#define Zeiger              GPIOR0          // Zeiger für Bufferposition
42
#define Zeit              GPIOR1          // Zeitzähler
43
#define Zeit_mul            GPIOR2          // Zeitmultiplikator für Interrupt
44
45
volatile uint8_t Zeit_Entprellen;
46
volatile uint8_t key_state;                    // debounced and inverted key state:
47
volatile uint8_t key_press;                    // key press detect
48
49
50
uint8_t get_key_press( uint8_t key_mask ){
51
  cli();                                                // read and clear atomic !
52
  key_mask &= key_press;                                // read key(s)
53
  key_press ^= key_mask;                                 // clear key(s)
54
  sei();
55
  return key_mask;
56
}
57
58
59
60
ISR(TIMER0_OVF_vect){                      // Timer0 Overflow alle 1,1 ms, 1,1 ms ist fest da
61
                                // noch für andere Sachen gebraucht, leider !!!!
62
  static uint8_t ct0, ct1;
63
    uint8_t i;
64
65
  TCNT0 = Timer0_Reload;                    // Reloadwert laden
66
67
  if (Zeit_Entprellen > 10){                  // alle 10 ms x 1,1 ms = 11 ms  
68
    i = key_state ^ ~KEY_PIN;                             // key changed ?
69
      ct0 = ~( ct0 & i );                                   // reset or count ct0
70
      ct1 = ct0 ^ (ct1 & i);                                // reset or count ct1
71
      i &= ct0 & ct1;                                       // count until roll over ?
72
      key_state ^= i;                                       // then toggle debounced state
73
      key_press |= key_state & i;                           // 0->1: key press detect
74
    Zeit_Entprellen = 0;                    // Entprellmultiplikator zurücksetzen
75
  }
76
  if (Zeit_mul > 90){                      // alle 91 ms x 1,1 ms = 100,1 ms 
77
    Zeit++;                            // Zeit in 1/10 sec weiterzählen
78
    Zeit_mul = 0;                        // Zeitmultiplikator zurücksetzten
79
  }
80
}
81
82
void Buffer_Init(void){
83
  Zeiger = 0;                          // Bufferzeiger auf Anfang
84
  Buffer[0] = 0;                        // Buffer löschen
85
  Buffer[1] = 0;                        // Buffer löschen
86
  Buffer[2] = 0;                        // Buffer löschen
87
}
88
89
inline void Init(void){
90
  // Tasten
91
  Taste_DDR &= ~(1<<Taste1)|(1<<Taste2);            // Taste1 & Taste2 Eingang
92
  Taste_PORT |= (1<<Taste1)|(1<<Taste2);            // Taste1 & Taste2 Pullup an
93
  // Led
94
  Led_DDR |= (1<<Led1)|(1<<Led2)|(1<<Led3);          // Led1 & Led2 & Led3 Ausgang
95
  Led_PORT |= (1<<Led1)|(1<<Led2)|(1<<Led3);          // Led1 & Led2 & Led3 aus
96
  // Timer 0
97
  TCCR0A = 0;                          // Timer Normal Mode
98
  TCCR0B = (1<<CS02);                      // clkI/O / 256 (From prescaler)
99
  TIMSK |= (1<<TOIE0);                    // Timer/Counter0 Overflow Interrupt an
100
  // Buffer
101
  Buffer_Init();                        // Bufferspeicher initialisieren
102
}
103
104
int main(void){
105
  Init();                            // alles Initialisieren
106
  sei();                            // Interrupt Global ein 
107
  while(1){                          // Endlosschleife
108
    
109
    if (Zeit > 30){                      // wenn ca. 30 1/10 sec = 3 sec um sind
110
      Buffer_Init();                      // Bufferspeicher initialisieren
111
    }
112
113
    if(get_key_press(1<<Taste1)){              // ist Taste1 gedrückt?
114
      if (Zeiger == 0){                    // erste Taste gedrückt
115
        Zeit = 0;                        // Zeit zurücksetzen
116
      }
117
      if (Zeiger < max_Buffer_len - 1){            // wenn noch keine 3 Tasten gespeichert sind
118
        Buffer[Zeiger] = 1;                    // Tastendruck merken
119
        Zeiger++;                        // Zeiger weitersetzen
120
      }
121
      else{                          // es sind schon 3 Tasten gespeichert
122
        Buffer[0] = Buffer[1];                  // Bufferdaten Byteweise 1x links schieben, Byte 1
123
        Buffer[1] = Buffer[2];                  // Bufferdaten Byteweise 1x links schieben, Byte 2
124
        Buffer[2] = 1;                      // Tastendruck in Byte 2 merken
125
      }
126
    }
127
    else if(get_key_press(1<<Taste2)){            // ist Taste2 gedrückt?
128
      if (Zeiger == 0){                    // erste Taste gedrückt
129
        Zeit = 0;                        // Zeit zurücksetzen
130
      }
131
      if (Zeiger < max_Buffer_len - 1){            // wenn noch keine 3 Tasten gespeichert sind
132
        Buffer[Zeiger] = 2;                    // Tastendruck merken
133
        Zeiger++;                        // Zeiger weitersetzen
134
      }
135
      else{                          // es sind schon 3 Tasten gespeichert
136
        Buffer[0] = Buffer[1];                  // Bufferdaten Byteweise 1x links schieben, Byte 1
137
        Buffer[1] = Buffer[2];                  // Bufferdaten Byteweise 1x links schieben, Byte 2
138
        Buffer[2] = 2;                      // Tastendruck in Byte 2 merken
139
      }
140
    }
141
142
    if (Buffer[0] == 1 && Buffer[1] == 1 && Buffer[2] == 1){// gedrückt Taste1 + Taste1 + Taste1
143
      Led1_an;
144
      Led2_aus;
145
      Led3_aus;
146
      Buffer_Init();                      // Bufferspeicher initialisieren
147
    }
148
    if (Buffer[0] == 1 && Buffer[1] == 1 && Buffer[2] == 2){// gedrückt Taste1 + Taste1 + Taste2
149
      Led1_aus;
150
      Led2_an;
151
      Led3_aus;
152
      Buffer_Init();                      // Bufferspeicher initialisieren  
153
    }
154
    if (Buffer[0] == 1 && Buffer[1] == 2 && Buffer[2] == 1){// gedrückt Taste1 + Taste2 + Taste1
155
      Led1_aus;
156
      Led2_aus;
157
      Led3_an;
158
      Buffer_Init();                      // Bufferspeicher initialisieren
159
    }
160
  }
161
}

Gruß Rene

von Karl H. (kbuchegg)


Lesenswert?

Rene Zimmermann schrieb:

Das hier

>     if(get_key_press(1<<Taste1)){              // ist Taste1 gedrückt?
>       if (Zeiger == 0){                    // erste Taste gedrückt
>         Zeit = 0;                        // Zeit zurücksetzen
>       }
>       if (Zeiger < max_Buffer_len - 1){            // wenn noch keine 3
> Tasten gespeichert sind
>         Buffer[Zeiger] = 1;                    // Tastendruck merken
>         Zeiger++;                        // Zeiger weitersetzen
>       }
>       else{                          // es sind schon 3 Tasten
> gespeichert
>         Buffer[0] = Buffer[1];                  // Bufferdaten Byteweise
> 1x links schieben, Byte 1
>         Buffer[1] = Buffer[2];                  // Bufferdaten Byteweise
> 1x links schieben, Byte 2
>         Buffer[2] = 1;                      // Tastendruck in Byte 2
> merken
>       }
>     }
>     else if(get_key_press(1<<Taste2)){            // ist Taste2
> gedrückt?
>       if (Zeiger == 0){                    // erste Taste gedrückt
>         Zeit = 0;                        // Zeit zurücksetzen
>       }
>       if (Zeiger < max_Buffer_len - 1){            // wenn noch keine 3
> Tasten gespeichert sind
>         Buffer[Zeiger] = 2;                    // Tastendruck merken
>         Zeiger++;                        // Zeiger weitersetzen
>       }
>       else{                          // es sind schon 3 Tasten
> gespeichert
>         Buffer[0] = Buffer[1];                  // Bufferdaten Byteweise
> 1x links schieben, Byte 1
>         Buffer[1] = Buffer[2];                  // Bufferdaten Byteweise
> 1x links schieben, Byte 2
>         Buffer[2] = 2;                      // Tastendruck in Byte 2
> merken
>       }
>     }

kannst du vereinfachen. ISt doch jedesmal derselbe Code, nur eine 
einzige Zahl (nämlich die Tastennummer) ist anders.

Also könnte man zb
1
     nextTaste = 0;
2
3
     if( get_key_press(1<<Taste1) )
4
       nextTaste = 1;
5
6
     if( get_key_press(1<<Taste2) )
7
       nextTaste = 2;
8
9
     if( nextTaste != 0 ) {       // eine Taste wurd egedrückt, füge sie ein
10
11
       if (Zeiger == 0){                    // erste Taste gedrückt
12
         Zeit = 0;                        // Zeit zurücksetzen
13
       }
14
        if (Zeiger < max_Buffer_len - 1){            // wenn noch keine 3 Tasten gespeichert sind
15
          Buffer[Zeiger] = nextTaste;                // Tastendruck merken
16
          Zeiger++;                        // Zeiger weitersetzen
17
        }
18
        else{                              // es sind schon 3 Tasten gespeichert
19
          Buffer[0] = Buffer[1];                  // Bufferdaten Byteweise 1x links schieben, Byte 1
20
          Buffer[1] = Buffer[2];                  // Bufferdaten Byteweise 1x links schieben, Byte 2
21
          Buffer[2] = nextTaste;                  // Tastendruck in Byte 2 merken
22
        }
23
      }

und schon fällt die Hälfte von diesem Code weg. Und noch besser, bei 
Änderungen am Verhalten kann man nicht vergessen, das für beide Tasten 
gleich zu ändern.

Und da dein Programm sowieso schon optisch relativ lang ist, bietet es 
sich an, den Akt des Einfügens in eine Funktion auszulagern
1
void insertTaste( uint8_t nextTaste )
2
{
3
  if (Zeiger == 0){                    // erste Taste gedrückt
4
    Zeit = 0;                        // Zeit zurücksetzen
5
  }
6
7
  if (Zeiger < max_Buffer_len - 1) {           // wenn noch keine 3 Tasten gespeichert sind
8
    Buffer[Zeiger] = nextTaste;                // Tastendruck merken
9
    Zeiger++;                        // Zeiger weitersetzen
10
  }
11
  else {                              // es sind schon 3 Tasten gespeichert
12
    Buffer[0] = Buffer[1];                  // Bufferdaten Byteweise 1x links schieben, Byte 1
13
    Buffer[1] = Buffer[2];                  // Bufferdaten Byteweise 1x links schieben, Byte 2
14
    Buffer[2] = nextTaste;                  // Tastendruck in Byte 2 merken
15
  }
16
}
17
18
19
int main()
20
{
21
   ....
22
23
  while( 1 ) {
24
25
    if (Zeit > 30){                      // wenn ca. 30 1/10 sec = 3 sec um sind
26
      Buffer_Init();                      // Bufferspeicher initialisieren
27
    }
28
29
    if( get_key_press(1<<Taste1) )        // ist Taste1 gedrückt?
30
      insertTaste( 1 );
31
32
    else if( get_key_press(1<<Taste2) )   // ist Taste2 gedrückt?
33
      insertTaste( 2 );
34
35
    // die empfangene Sequenz auswerten, ob es eine Übereinstimmung gibt
36
37
    if (Buffer[0] == 1 && Buffer[1] == 1 && Buffer[2] == 1){// gedrückt Taste1 + Taste1 + Taste1
38
      Led1_an;
39
      Led2_aus;
40
    ....

und du bist am Weg, deinen Code selbstdokumentierend zu machen.
1
    if( get_key_press( 1<<Taste1 ) )        // ist Taste1 gedrückt?
2
      insertTaste( 1 );
Da erzählt der Code schon die ganze Geschichte. Da braucht es keinen 
zusätzlichen Kommentar. Im Code steht mehr oder weniger im Klartext: 
Wenn Taste 1 gedrückt, dann füge eine 1 zum Tastenbuffer hinzu. Jede 
Codeänderung, die es dir ermöglicht einen Kommentar loszuwerden, ist 
eine gute Änderung. Entgegen landläufiger Meinung ist ein Programm nicht 
dann besonders gut, wenn es viele Kommentare enthält, sondern dasjenige 
ist gut, welches keine Kommentare braucht, weil alles Wissenswerte schon 
im Programmtext selber steht. Kommentare beschränken sich dann auf die 
Dinge, die man eben nicht im Code sieht.

Was zb. erzählt mir hier
1
    Buffer[2] = nextTaste;                  // Tastendruck in Byte 2 merken
der Kommentar, was ich nicht auch schon im Code sehe. Das ist ein 
unnützer Kommentar, der im besten Fall einfach nur nichtssagend ist, im 
schlimmsten Fall aber falsch ist (weil er nach Codeänderungen nicht an 
die Änderung angepasst wurde)


Für die Auswertung kann man sich dann auch noch was überlegen, bzw. 
diese zb in eine eigene Funktion auslagern.
Dein Hauptschleife wird dann
1
  while( 1 ) {
2
3
    if (Zeit > 30){                      // wenn ca. 30 1/10 sec = 3 sec um sind
4
      Buffer_Init();                      // Bufferspeicher initialisieren
5
    }
6
7
    if( get_key_press(1<<Taste1) )        // ist Taste1 gedrückt?
8
      insertTaste( 1 );
9
10
    else if( get_key_press(1<<Taste2) )   // ist Taste2 gedrückt?
11
      insertTaste( 2 );
12
13
    checkForSequences();
14
  }

(und die Funktion checkForSequences überprüft, ob es eine Sequenz im 
Buffer gibt).
Schöne kurze Hauptschleife, die man mit einem Blick überschauen kann und 
bei der man sofort erkennt, was das Programm im wesentlichen macht. Wenn 
man an den Details interessiert ist, wie genau zb das Hinzufügen zum 
Buffer funktioniert, dann hat man die Funktion, in der nur dieses 1 
Detail konzentriert ist.

von Rene Z. (renezimmermann)


Lesenswert?

Woooo!

Und ich habe mir Gedanken gemacht ob das byteweise Linksschieben im 
Buffer noch besser zu lösen ist. Oh je, ich gehe mal meinen Verstand 
suchen. "grins"
Ich habe es jetzt mal schnell auf folgenden Code gebracht:

1
// Tasten Entprellroutine von Peter Dannegger: danni@specs.de
2
3
#include <stdio.h>
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
7
#define Taste_DDR            DDRB
8
#define Taste_PIN            PINB
9
#define Taste_PORT            PORTB
10
#define Taste1              PB4
11
#define Taste2              PB3
12
13
#define Led_DDR              DDRB
14
#define Led_PORT            PORTB
15
#define Led1              PB2
16
#define Led2              PB1
17
#define Led3              PB0
18
19
#define KEY_DDR              Taste_DDR
20
#define KEY_PORT            Taste_PORT
21
#define KEY_PIN              Taste_PIN
22
#define KEY0              Taste1
23
#define KEY1              Taste2
24
#define ALL_KEYS            (1<<KEY0 | 1<<KEY1)
25
26
#define Led1_an              Led_PORT &= ~(1<<Led1)
27
#define Led1_aus            Led_PORT |= (1<<Led1)
28
#define Led2_an              Led_PORT &= ~(1<<Led2)
29
#define Led2_aus            Led_PORT |= (1<<Led2)
30
#define Led3_an              Led_PORT &= ~(1<<Led3)
31
#define Led3_aus            Led_PORT |= (1<<Led3)
32
33
#define Timer0_Reload          255 - 43        // 1,1 ms bei 11,0592 MHz
34
35
#define max_Buffer_len          3            // max. 3 Tasten speichern
36
37
uint8_t Buffer[max_Buffer_len];                  // Buffer für Tasten
38
39
//GPIOR sollte schneller sein als volatile auf Ram, ist das so ?????? Ich denke ja. Muß ich noch prüfen !!!!!!
40
41
#define Zeiger              GPIOR0          // Zeiger für Bufferposition
42
#define Zeit              GPIOR1          // Zeitzähler
43
#define Zeit_mul            GPIOR2          // Zeitmultiplikator für Interrupt
44
45
volatile uint8_t Zeit_Entprellen;
46
volatile uint8_t key_state;                    // debounced and inverted key state:
47
volatile uint8_t key_press;                    // key press detect
48
49
50
uint8_t get_key_press(uint8_t key_mask){
51
  cli();                                                // read and clear atomic !
52
  key_mask &= key_press;                                // read key(s)
53
  key_press ^= key_mask;                                 // clear key(s)
54
  sei();
55
  return key_mask;
56
}
57
58
void insertTaste(uint8_t nextTaste){
59
  if (Zeiger == 0){                                  // erste Taste gedrückt
60
    Zeit = 0;                                        // Zeit zurücksetzen
61
  }
62
63
  if (Zeiger < max_Buffer_len - 1){                // wenn noch keine 3 Tasten gespeichert sind
64
    Buffer[Zeiger] = nextTaste;                    // Tastendruck merken
65
    Zeiger++;                            // Zeiger weitersetzen
66
  }
67
  else {                            // es sind schon 3 Tasten gespeichert
68
    Buffer[0] = Buffer[1];                      // Bufferdaten Byteweise 1x links schieben, Byte 1
69
    Buffer[1] = Buffer[2];                      // Bufferdaten Byteweise 1x links schieben, Byte 2
70
    Buffer[2] = nextTaste;                      // Tastendruck in Byte 2 merken
71
  }
72
}
73
74
ISR(TIMER0_OVF_vect){                      // Timer0 Overflow alle 1,1 ms, 1,1 ms ist fest da
75
                                // noch für andere Sachen gebraucht, leider !!!!
76
  static uint8_t ct0, ct1;
77
    uint8_t i;
78
79
  TCNT0 = Timer0_Reload;                    // Reloadwert laden
80
81
  if (Zeit_Entprellen > 9){                  // alle 10 ms x 1,1 ms = 11 ms  
82
    i = key_state ^ ~KEY_PIN;                             // key changed ?
83
      ct0 = ~( ct0 & i );                                   // reset or count ct0
84
      ct1 = ct0 ^ (ct1 & i);                                // reset or count ct1
85
      i &= ct0 & ct1;                                       // count until roll over ?
86
      key_state ^= i;                                       // then toggle debounced state
87
      key_press |= key_state & i;                           // 0->1: key press detect
88
    Zeit_Entprellen = 0;                    // Entprellmultiplikator zurücksetzen
89
  }
90
  if (Zeit_mul > 90){                      // alle 91 ms x 1,1 ms = 100,1 ms 
91
    Zeit++;                            // Zeit in 1/10 sec weiterzählen
92
    Zeit_mul = 0;                        // Zeitmultiplikator zurücksetzten
93
  }
94
}
95
96
void Buffer_Init(void){
97
  Zeiger = 0;                          // Bufferzeiger auf Anfang
98
  Buffer[0] = 0;                        // Buffer löschen
99
  Buffer[1] = 0;                        // Buffer löschen
100
  Buffer[2] = 0;                        // Buffer löschen
101
}
102
103
inline void Init(void){
104
  // Tasten
105
  Taste_DDR &= ~(1<<Taste1)|(1<<Taste2);            // Taste1 & Taste2 Eingang
106
  Taste_PORT |= (1<<Taste1)|(1<<Taste2);            // Taste1 & Taste2 Pullup an
107
  // Led
108
  Led_DDR |= (1<<Led1)|(1<<Led2)|(1<<Led3);          // Led1 & Led2 & Led3 Ausgang
109
  Led_PORT |= (1<<Led1)|(1<<Led2)|(1<<Led3);          // Led1 & Led2 & Led3 aus
110
  // Timer 0
111
  TCCR0A = 0;                          // Timer Normal Mode
112
  TCCR0B = (1<<CS02);                      // clkI/O / 256 (From prescaler)
113
  TIMSK |= (1<<TOIE0);                    // Timer/Counter0 Overflow Interrupt an
114
  // Buffer
115
  Buffer_Init();                        // Bufferspeicher initialisieren
116
}
117
118
void checkForSequences(void){
119
  if (Buffer[0] == 1 && Buffer[1] == 1 && Buffer[2] == 1){  // gedrückt Taste1 + Taste1 + Taste1
120
    Led1_an;
121
    Led2_aus;
122
    Led3_aus;
123
    Buffer_Init();                        // Bufferspeicher initialisieren
124
  }
125
  if (Buffer[0] == 1 && Buffer[1] == 1 && Buffer[2] == 2){  // gedrückt Taste1 + Taste1 + Taste2
126
    Led1_aus;
127
    Led2_an;
128
    Led3_aus;
129
    Buffer_Init();                        // Bufferspeicher initialisieren  
130
  }
131
  if (Buffer[0] == 1 && Buffer[1] == 2 && Buffer[2] == 1){  // gedrückt Taste1 + Taste2 + Taste1
132
    Led1_aus;
133
    Led2_aus;
134
    Led3_an;
135
    Buffer_Init();                        // Bufferspeicher initialisieren
136
  }
137
}
138
139
int main(void){
140
  Init();                            // alles Initialisieren
141
  sei();                            // Interrupt Global ein 
142
  while(1){                          // Endlosschleife
143
    
144
    if (Zeit > 30){                      // wenn ca. 30 1/10 sec = 3 sec um sind
145
      Buffer_Init();                      // Bufferspeicher initialisieren
146
    }
147
148
    if(get_key_press(1<<Taste1)){              // ist Taste1 gedrückt?
149
      insertTaste(1);                      // Taste1 zum Buffer hinzufügen
150
    }
151
    else if(get_key_press(1<<Taste2)){            // ist Taste2 gedrückt?
152
      insertTaste(2);                      // Taste2 zum Buffer hinzufügen
153
    }
154
    
155
    checkForSequences();                  // prüfe auf gültige Tastenkombination
156
157
  }
158
}

Muß das morgen mal auf das Steckbrett bringen und testen.

Gruß Rene

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.