Forum: Mikrocontroller und Digitale Elektronik Taster mehrmals gedrückt? mit Zähler?


von Lukas M. (luke_)


Lesenswert?

Hallo leute fuer euch Profis wahrscheinlich ein ganz simples Problem.
Ich möchte einen Taster abfragen ob er mehrmals gedrückt ist. 
Genauergesagt ober 5 mal gedrückt wurde.

Ich hätte jetzt gedacht an eine Schleife die 20 ms Sekunden warten und 
so eine Zählvariable raufzähl, jedoch funktioniert nicht wirklich?
Ist diese Idee von dem Grundkonzept brauchbar?, den aus dem Wiki Artikel 
werde ich als Laie nicht wirklich schlau daraus.



Ich hoffe ich geh auch nicht allzu sehr auf die Nerven falls doch 
Entschuldige ich mich gleich vorwegs.

mfG Lukas

von gast (Gast)


Lesenswert?

Aufpassen. Taster neigen zum prellen. Dies
könnte auch schon als Tastendruck gewertet werden.
Sonst geht es mit einer Zählvariable.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Mehrmaliges Drücken ist dadurch gekennzeichnet, dass es Gedrückt- und 
Losgelassen-Phasen bestimmter Mindestdauern und im Wechsel gibt. Beides 
kann man schon in einer Schleife abfragen.

Die Zeit 20ms für ein sicheres Erkennen eines Zustands 
("gedrückt/losgelassen wird nur registriert, wenn 20ms noch 
gedrückt/losgelassen ist") kann man nehmen. Das läuft dann auf das 
Warteschleifen-Verfahren bei der Softwareentprellung von Tastern raus 
(Entprellung)

von Lukas M. (luke_)


Lesenswert?

ich hab jz den Code :
1
/************************************************************************/
2
/*                                                                      */
3
/*                      Debouncing 8 Keys                               */
4
/*                      Sampling 4 Times                                */
5
/*                      With Repeat Function                            */
6
/*                                                                      */
7
/*              Author: Peter Dannegger                                 */
8
/*                      danni@specs.de                                  */
9
/*                                                                      */
10
/************************************************************************/
11
 
12
#include <stdint.h>
13
#include <avr/io.h>
14
#include <avr/interrupt.h>
15
 
16
#ifndef F_CPU
17
#define F_CPU           1000000                   // processor clock frequency
18
#warning kein F_CPU definiert
19
#endif
20
 
21
#define KEY_DDR         DDRD
22
#define KEY_PORT        PORTD
23
#define KEY_PIN         PIND
24
#define KEY0            7
25
#define KEY1            7
26
#define KEY2            7
27
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
28
 
29
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
30
#define REPEAT_START    50                        // after 500ms
31
#define REPEAT_NEXT     20                        // every 200ms
32
 
33
#define LED_DDR         DDRD
34
#define LED_PORT        PORTD
35
#define LED0            5
36
#define LED1            5
37
#define LED2            5
38
 
39
volatile uint8_t key_state;                                // debounced and inverted key state:
40
                                                  // bit = 1: key pressed
41
volatile uint8_t key_press;                                // key press detect
42
 
43
volatile uint8_t key_rpt;                                  // key long press and repeat
44
 
45
 
46
ISR( TIMER0_OVF_vect )                            // every 10ms
47
{
48
  static uint8_t ct0, ct1, rpt;
49
  uint8_t i;
50
 
51
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
52
 
53
  i = key_state ^ ~KEY_PIN;                       // key changed ?
54
  ct0 = ~( ct0 & i );                             // reset or count ct0
55
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
56
  i &= ct0 & ct1;                                 // count until roll over ?
57
  key_state ^= i;                                 // then toggle debounced state
58
  key_press |= key_state & i;                     // 0->1: key press detect
59
 
60
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
61
     rpt = REPEAT_START;                          // start delay
62
  if( --rpt == 0 ){
63
    rpt = REPEAT_NEXT;                            // repeat delay
64
    key_rpt |= key_state & REPEAT_MASK;
65
  }
66
}
67
 
68
///////////////////////////////////////////////////////////////////
69
//
70
// check if a key has been pressed. Each pressed key is reported
71
// only once
72
//
73
uint8_t get_key_press( uint8_t key_mask )
74
{
75
  cli();                                          // read and clear atomic !
76
  key_mask &= key_press;                          // read key(s)
77
  key_press ^= key_mask;                          // clear key(s)
78
  sei();
79
  return key_mask;
80
}
81
 
82
///////////////////////////////////////////////////////////////////
83
//
84
// check if a key has been pressed long enough such that the
85
// key repeat functionality kicks in. After a small setup delay
86
// the key is reported beeing pressed in subsequent calls
87
// to this function. This simulates the user repeatedly
88
// pressing and releasing the key.
89
//
90
uint8_t get_key_rpt( uint8_t key_mask )
91
{
92
  cli();                                          // read and clear atomic !
93
  key_mask &= key_rpt;                            // read key(s)
94
  key_rpt ^= key_mask;                            // clear key(s)
95
  sei();
96
  return key_mask;
97
}
98
 
99
///////////////////////////////////////////////////////////////////
100
//
101
uint8_t get_key_short( uint8_t key_mask )
102
{
103
  cli();                                          // read key state and key press atomic !
104
  return get_key_press( ~key_state & key_mask );
105
}
106
 
107
///////////////////////////////////////////////////////////////////
108
//
109
uint8_t get_key_long( uint8_t key_mask )
110
{
111
  return get_key_press( get_key_rpt( key_mask ));
112
}
113
 
114
int main( void )
115
{
116
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
117
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
118
 
119
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
120
  TIMSK = 1<<TOIE0;        // enable timer interrupt
121
 
122
  LED_PORT = 0xFF;
123
  LED_DDR = 0xFF;                     
124
 
125
  while(1){
126
    if( get_key_short( 1<<KEY1 ))
127
      LED_PORT ^= 1<<LED1;
128
 
129
    if( get_key_long( 1<<KEY1 ))
130
      LED_PORT ^= 1<<LED2;
131
 
132
                                                  // single press and repeat
133
 
134
    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
135
      uint8_t i = LED_PORT;
136
 
137
      i = (i & 0x07) | ((i << 1) & 0xF0);
138
      if( i < 0xF0 )
139
        i |= 0x08;
140
      LED_PORT = i;      
141
    }
142
  }
143
}


jedoch leuchtet bei Betätigung des Taster keine Led auf, die Definition 
meiner Ports müsste richtig sein

PD7--> Taster(High Active)
PD5--> Led

Ich frage mich schon ne Zeit woran das liegen könnte?

mfG

von Karl H. (kbuchegg)


Lesenswert?

Lukas Migi schrieb:

> PD7--> Taster(High Active)
> PD5--> Led

Du hast Taster und LED an ein und demselben Port

1
 TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
2
  TIMSK = 1<<TOIE0;        // enable timer interrupt
3
 
4
  LED_PORT = 0xFF;
5
  LED_DDR = 0xFF;

Gratuliere. Du hast soeben den komplette Port D auf Ausgang gestellt

von Lukas M. (luke_)


Lesenswert?

Peinlich Peinlich :D
ich hab jz den Taster auf PortB gelegt:
1
/************************************************************************/
2
/*                                                                      */
3
/*                      Debouncing 8 Keys                               */
4
/*                      Sampling 4 Times                                */
5
/*                      With Repeat Function                            */
6
/*                                                                      */
7
/*              Author: Peter Dannegger                                 */
8
/*                      danni@specs.de                                  */
9
/*                                                                      */
10
/************************************************************************/
11
 
12
#include <stdint.h>
13
#include <avr/io.h>
14
#include <avr/interrupt.h>
15
 
16
#ifndef F_CPU
17
#define F_CPU           1000000                   // processor clock frequency
18
#warning kein F_CPU definiert
19
#endif
20
 
21
#define KEY_DDR         DDRB
22
#define KEY_PORT        PORTB
23
#define KEY_PIN         PINB
24
#define KEY0            1
25
#define KEY1            1
26
#define KEY2            1
27
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
28
 
29
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
30
#define REPEAT_START    50                        // after 500ms
31
#define REPEAT_NEXT     20                        // every 200ms
32
 
33
#define LED_DDR         DDRD
34
#define LED_PORT        PORTD
35
#define LED0            5
36
#define LED1            5
37
#define LED2            5
38
 
39
volatile uint8_t key_state;                                // debounced and inverted key state:
40
                                                  // bit = 1: key pressed
41
volatile uint8_t key_press;                                // key press detect
42
 
43
volatile uint8_t key_rpt;                                  // key long press and repeat
44
 
45
 
46
ISR( TIMER0_OVF_vect )                            // every 10ms
47
{
48
  static uint8_t ct0, ct1, rpt;
49
  uint8_t i;
50
 
51
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
52
 
53
  i = key_state ^ ~KEY_PIN;                       // key changed ?
54
  ct0 = ~( ct0 & i );                             // reset or count ct0
55
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
56
  i &= ct0 & ct1;                                 // count until roll over ?
57
  key_state ^= i;                                 // then toggle debounced state
58
  key_press |= key_state & i;                     // 0->1: key press detect
59
 
60
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
61
     rpt = REPEAT_START;                          // start delay
62
  if( --rpt == 0 ){
63
    rpt = REPEAT_NEXT;                            // repeat delay
64
    key_rpt |= key_state & REPEAT_MASK;
65
  }
66
}
67
 
68
///////////////////////////////////////////////////////////////////
69
//
70
// check if a key has been pressed. Each pressed key is reported
71
// only once
72
//
73
uint8_t get_key_press( uint8_t key_mask )
74
{
75
  cli();                                          // read and clear atomic !
76
  key_mask &= key_press;                          // read key(s)
77
  key_press ^= key_mask;                          // clear key(s)
78
  sei();
79
  return key_mask;
80
}
81
 
82
///////////////////////////////////////////////////////////////////
83
//
84
// check if a key has been pressed long enough such that the
85
// key repeat functionality kicks in. After a small setup delay
86
// the key is reported beeing pressed in subsequent calls
87
// to this function. This simulates the user repeatedly
88
// pressing and releasing the key.
89
//
90
uint8_t get_key_rpt( uint8_t key_mask )
91
{
92
  cli();                                          // read and clear atomic !
93
  key_mask &= key_rpt;                            // read key(s)
94
  key_rpt ^= key_mask;                            // clear key(s)
95
  sei();
96
  return key_mask;
97
}
98
 
99
///////////////////////////////////////////////////////////////////
100
//
101
uint8_t get_key_short( uint8_t key_mask )
102
{
103
  cli();                                          // read key state and key press atomic !
104
  return get_key_press( ~key_state & key_mask );
105
}
106
 
107
///////////////////////////////////////////////////////////////////
108
//
109
uint8_t get_key_long( uint8_t key_mask )
110
{
111
  return get_key_press( get_key_rpt( key_mask ));
112
}
113
 
114
int main( void )
115
{
116
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
117
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
118
 
119
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
120
  TIMSK = 1<<TOIE0;        // enable timer interrupt
121
 
122
  LED_PORT = 0xFF;
123
  LED_DDR = 0xFF;                     
124
 
125
  while(1){
126
127
128
    if( get_key_short( 1<<KEY1 ))
129
      LED_PORT ^= 1<<LED1;
130
 
131
    if( get_key_long( 1<<KEY1 ))
132
      LED_PORT ^= 1<<LED1;
133
 
134
                                                  // single press and repeat
135
 
136
    if( get_key_press( 1<<KEY2 ) || get_key_rpt( 1<<KEY2 )){
137
      uint8_t i = LED_PORT;
138
 
139
      i = (i & 0x07) | ((i << 1) & 0xF0);
140
      if( i < 0xF0 )
141
        i |= 0x08;
142
      LED_PORT = i;      
143
    }
144
  }
145
}

jedoch ist die Situation gleich geblieben ...

mfG

von Karl H. (kbuchegg)


Lesenswert?

Überdenk das doch bitte noch mal
1
      uint8_t i = LED_PORT;
2
 
3
      i = (i & 0x07) | ((i << 1) & 0xF0);
4
      if( i < 0xF0 )
5
        i |= 0x08;
6
      LED_PORT = i;

Nimm einfach mal an, so wie du das gemacht hast, dass LED_PORT am Anfang 
0xFF ist. Und dann gehe einfach alles durch und sieh nach, was da am 
Ende dabei rauskommt und wie das deine LED am Pin 5 beeinflusst.

Ich bin mir nicht ganz sicher, was da bei den Abfragen tatsächlich 
passiert. Aber warum teilst du den Tasten-Routinen mit, dass du 3 Tasten 
hättest, wenn dann alle Tasten am gleichen Pin sitzen. De Facto hast du 
damit ja nur 1 Taste. -> Hör auf die Routinen anzulügen und konfiguriere 
das richtig.
1
#define KEY_DDR         DDRB
2
#define KEY_PORT        PORTB
3
#define KEY_PIN         PINB
4
#define KEY0            1
5
#define ALL_KEYS        (1<<KEY0)
6
 
7
#define REPEAT_MASK   // kein Repeat auf irgendeiner Taste

von Lukas M. (luke_)


Lesenswert?

Hilft auch nichts.
Pull Up hab ich auch keinen Drauf da die Internen aktiv sind.
Häng ich in die While (1)schleife ne Led Rein leuchtet die ohne Mucken.
Irgendwie weis ich nicht woran das liegt?

mfG

von Karl H. (kbuchegg)


Lesenswert?

Du hast vergessen die Interrupts freizugeben

Taster an Port B, Pin 1
LED an Port B, Pins 4, 5, 6
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
 
5
#ifndef F_CPU
6
#define F_CPU           1000000                   // processor clock frequency
7
#warning kein F_CPU definiert
8
#endif
9
 
10
#define KEY_DDR         DDRB
11
#define KEY_PORT        PORTB
12
#define KEY_PIN         PINB
13
#define KEY0            1
14
#define ALL_KEYS        (1<<KEY0)
15
 
16
#define REPEAT_MASK     0                         // repeat: key1, key2
17
#define REPEAT_START    50                        // after 500ms
18
#define REPEAT_NEXT     20                        // every 200ms
19
 
20
#define LED_DDR         DDRB
21
#define LED_PORT        PORTB
22
#define LED0            4
23
#define LED1            5
24
#define LED2            6
25
 
26
volatile uint8_t key_state;                                // debounced and inverted key state:
27
                                                  // bit = 1: key pressed
28
volatile uint8_t key_press;                                // key press detect
29
 
30
volatile uint8_t key_rpt;                                  // key long press and repeat
31
 
32
 
33
ISR( TIMER0_OVF_vect )                            // every 10ms
34
{
35
  static uint8_t ct0, ct1, rpt;
36
  uint8_t i;
37
 
38
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
39
 
40
  i = key_state ^ ~KEY_PIN;                       // key changed ?
41
  ct0 = ~( ct0 & i );                             // reset or count ct0
42
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
43
  i &= ct0 & ct1;                                 // count until roll over ?
44
  key_state ^= i;                                 // then toggle debounced state
45
  key_press |= key_state & i;                     // 0->1: key press detect
46
 
47
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
48
     rpt = REPEAT_START;                          // start delay
49
  if( --rpt == 0 ){
50
    rpt = REPEAT_NEXT;                            // repeat delay
51
    key_rpt |= key_state & REPEAT_MASK;
52
  }
53
}
54
 
55
///////////////////////////////////////////////////////////////////
56
//
57
// check if a key has been pressed. Each pressed key is reported
58
// only once
59
//
60
uint8_t get_key_press( uint8_t key_mask )
61
{
62
  cli();                                          // read and clear atomic !
63
  key_mask &= key_press;                          // read key(s)
64
  key_press ^= key_mask;                          // clear key(s)
65
  sei();
66
  return key_mask;
67
}
68
 
69
///////////////////////////////////////////////////////////////////
70
//
71
// check if a key has been pressed long enough such that the
72
// key repeat functionality kicks in. After a small setup delay
73
// the key is reported beeing pressed in subsequent calls
74
// to this function. This simulates the user repeatedly
75
// pressing and releasing the key.
76
//
77
uint8_t get_key_rpt( uint8_t key_mask )
78
{
79
  cli();                                          // read and clear atomic !
80
  key_mask &= key_rpt;                            // read key(s)
81
  key_rpt ^= key_mask;                            // clear key(s)
82
  sei();
83
  return key_mask;
84
}
85
 
86
///////////////////////////////////////////////////////////////////
87
//
88
uint8_t get_key_short( uint8_t key_mask )
89
{
90
  cli();                                          // read key state and key press atomic !
91
  return get_key_press( ~key_state & key_mask );
92
}
93
 
94
///////////////////////////////////////////////////////////////////
95
//
96
uint8_t get_key_long( uint8_t key_mask )
97
{
98
  return get_key_press( get_key_rpt( key_mask ));
99
}
100
 
101
int main( void )
102
{
103
  uint8_t cnt;
104
105
  KEY_DDR &= ~ALL_KEYS;                // konfigure key port for input
106
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
107
 
108
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
109
  TIMSK = 1<<TOIE0;        // enable timer interrupt
110
 
111
  LED_DDR |= ( 1 << LED0 ) | (1<<LED1) | (1<<LED2);
112
113
  cnt = 0;
114
115
  sei();
116
117
  while(1){
118
119
    if( get_key_press( 1<<KEY0 )) {
120
      cnt++;
121
      LED_PORT = (cnt << 4) | ALL_KEYS;
122
    }
123
  }
124
}

von Lukas M. (luke_)


Lesenswert?

welche Interrupts meinst du?

von Lukas M. (luke_)


Lesenswert?

tut mir Leid, dass ich immer mit so Anfängerfragen nerve, ich will 
jedoch nicht nur Programme abkupfern sondern die auch einigermaßen 
verstehen.

Danke trotzdem für die hilfreichen Antworten!



mfG,
Lukas

von Karl H. (kbuchegg)


Lesenswert?

Lukas Migi schrieb:
> welche Interrupts meinst du?

Die globale Interruptfreigabe mittels sei()

von Lukas M. (luke_)


Lesenswert?

Oh danke jetzt hab ichs!
Vielen DANK!
mfG
Lukas

von Lukas M. (luke_)


Lesenswert?

Ich habs jetzt nochmals getestet jedoch funktioniert das auch mit der 
Änderung der Interrupts nicht.

Soll ich trotzdem einen externen Pullup verwenden?


mfG

von Lukas M. (luke_)


Lesenswert?

Jetzt leuchte auf einmal 2 Leds dauerhaft und bei der 3ten passiert 
nichts?
Komisch irgendwie?
Achja verwenden tu ich einen Mega8




mfG

von Karl H. (kbuchegg)


Lesenswert?

Benutze das Programm, das ich weiter oben gepostet habe.
Taster und Led so verdrahten wie angegeben.

Das wurde auf einem Mega16 getestet und läuft definitiv.
Bei jedem Tastendruck wird ein Zähler hochgezählt und der aktuelle 
Zählerstand an den 3 Led ausgegeben -> mit jedem Tastendruck ändert sich 
das Muster und du kannst die Binärzahlen an den Led erkennen.

von Gast (Gast)


Lesenswert?

>Soll ich trotzdem einen externen Pullup verwenden?

Das ist schnurz, weil es höchstwahrscheinlich nicht am Pullup liegt, und 
auch nicht daran, dass der Controller defekt ist, und Dein Compiler hat 
auch keinen Bug. Es liegt schlicht an Deinem Programm.

Projektvorschlag: Eine LED + ein Taster. Sonst nix. Die LED geht beim 
Drücken (und Loslassen) der Taste an, und beim nächsten Drücken wieder 
aus, und immer so weiter. "Ist ja voll easy" mag man glauben, aber das 
Gegenteil trifft zu: Dies so zu realisieren, dass es einwandfrei und 
zuverlässig funktioniert ist eine erstaunlich anspruchsvolle 
Aufgabenstellung, denn dazu muss der Taster ordentlich entprellt 
werden.

Versuch, erstmal das hinzubekommen. Solange das nicht hundertpro klappt, 
kann auch alles weitere nicht richtig funzen. Step by Step heißt die 
Devise. Viel Erfolg.

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.