Forum: Mikrocontroller und Digitale Elektronik Tastenabfrage mit Interrupts


von Lokus P. (derschatten)


Lesenswert?

Hallo Leute,

ich möchte mir eine Schaltung basteln die Abfragt ob eine Taste kurz 
oder länger gedrückt wurde.
Bei kurzem druck soll eine Variable erhöt werden
Bei Langem Druck der Wert ins EEPROM gespeichert werden.

Bisher hab ich mir folgendes zusammengestrickt:
1
//----------------------------------------
2
// Titel  : Arcade Tastenprogrammierung
3
//----------------------------------------
4
#include <avr/io.h>
5
#include <avr/interrupt.h>
6
#include <stdint.h>
7
#include <avr/eeprom.h>
8
#include <avr/pgmspace.h>
9
10
typedef unsigned char BYTE;
11
typedef unsigned int WORD;
12
13
BYTE bPortB;
14
BYTE nKeyPress;
15
16
const unsigned char Tabelle[] PROGMEM = {249, 164, 176, 153, 146, 130, 248, 128, 144};
17
18
#define CNTDEBOUNCE 10
19
#define CNTREPEAT 200
20
21
#define KEY_PIN  PINB
22
#define KEY_PINNO PB6
23
24
uint8_t eeFooByte;
25
volatile uint8_t gKeyCounter;
26
27
28
ISR(TIMER1_COMPA_vect)
29
{
30
   uint8_t tmp_kc;
31
 
32
   tmp_kc = gKeyCounter;
33
 
34
   if (!(KEY_PIN & (1<<KEY_PINNO)))
35
   {
36
      if (tmp_kc < CNTREPEAT)
37
    {
38
         tmp_kc++;
39
      }
40
   }
41
   else
42
   {
43
      tmp_kc = 0;
44
   }
45
   gKeyCounter = tmp_kc;
46
}
47
48
void init(void)
49
{
50
  PORTB |= _BV(6);  // Pull-Up Port B6 aktivieren
51
    DDRB = 0xFF;    // Port B als Eingang
52
  DDRD = 0xFF;    // Port D als Ausgang
53
  TIMSK |= (1<<TOIE1); //Timer1 Interrupt aktiviert
54
  TCCR1B = 1;     //Prescaler 1
55
  TCNT1 = 65535-3600; //Preloader 3600
56
}
57
58
int main (void)
59
{
60
  init();
61
  sei();
62
63
    bPortB = 1;
64
  nKeyPress = eeprom_read_byte(&eeFooByte);
65
66
    while(1)
67
  {
68
69
70
        if ( gKeyCounter > CNTDEBOUNCE )
71
        {
72
          if (gKeyCounter == CNTREPEAT)  // Code fuer "Taste lange gedrueckt"
73
          {
74
            eeprom_write_byte(&eeFooByte, nKeyPress);
75
          }
76
               else               // Code fuer "Taste kurz gedrueckt"
77
          {
78
            PORTD = pgm_read_byte(&Tabelle[nKeyPress]);
79
            if (nKeyPress < 8)
80
            {
81
              nKeyPress++;
82
83
            }
84
            else
85
            {
86
              nKeyPress = 0;
87
88
            }
89
          }
90
        }
91
92
  }
93
  return 0;
94
}

Jedoch ist da noch irgendwo ein hund begraben.
Mit den Interrupts tu ich mir etwas schwer. Ich bin sicher das da der 
Fehler drinn steckt.

von Hannes L. (hannes)


Lesenswert?


von Lokus P. (derschatten)


Lesenswert?

Ja, die Entprellung hatte ich sogar vor kurzem noch drinn.
Sah dann so aus:
1
while(1)
2
  {
3
    if (bit_is_clear (PINB, 6))
4
    {
5
          if (bPortB)
6
      {
7
        if ( gKeyCounter > CNTDEBOUNCE )
8
        {
9
          if (gKeyCounter == CNTREPEAT)  // Code fuer "Taste lange gedrueckt"
10
          {
11
            eeprom_write_byte(&eeFooByte, nKeyPress);
12
          }
13
               else               // Code fuer "Taste kurz gedrueckt"
14
          {
15
            PORTD = pgm_read_byte(&Tabelle[nKeyPress]);
16
            if (nKeyPress < 8)
17
            {
18
              nKeyPress++;
19
              bPortB = 0;
20
            }
21
            else
22
            {
23
              nKeyPress = 0;
24
              bPortB = 0;
25
            }
26
          }
27
        }
28
          }
29
      }
30
      else
31
    {
32
          bPortB = 1;
33
      }
34
  }

Hatte ich aber wieder rausgenommen, weil ich dachte das die hier nicht 
von nöten wäre.
Das alleine dürfte aber nicht das Problem sein glaub ich.
Ich möchte gerne eine Tastenabfrage haben die prüft ob diese kürzer als 
2 Sekunden gedrückt wurde und dann dementsprechend den Code für Kurz und 
für langen Tastendruck ausführt.

von Peter D. (peda)


Lesenswert?

Manfred W. schrieb:
> Ja, die Entprellung hatte ich sogar vor kurzem noch drinn.
> Sah dann so aus:
> ...

Hat ja überhaupt keine Ähnlichkeit mit der Eiwomisa:

http://www.mikrocontroller.net/articles/Entprellung#Komfortroutine_.28C_f.C3.BCr_AVR.29


> Hatte ich aber wieder rausgenommen, weil ich dachte das die hier nicht
> von nöten wäre.

Das denken leider auch viele professionelle Entwickler.
Entprellen ist der Grundstein für sauberes Programmieren und macht 
vieles einfacher.


Peter

von DerSchatten (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Hat ja überhaupt keine Ähnlichkeit mit der Eiwomisa:

Ich weiß. Das ist ja auch ein komplett anderes Beispiel.
Das ich übrigens auch schon ausprobiert hatte.
Leider funktioniert das bei mir irgendwie nicht.

Es leuchten nach dem Einschalten nur alle LEDs, mehr tut sich nicht.

von Karl H. (kbuchegg)


Lesenswert?

DerSchatten schrieb:
> Peter Dannegger schrieb:
>> Hat ja überhaupt keine Ähnlichkeit mit der Eiwomisa:
>
> Ich weiß. Das ist ja auch ein komplett anderes Beispiel.
> Das ich übrigens auch schon ausprobiert hatte.
> Leider funktioniert das bei mir irgendwie nicht.

Dann solltest du dem nachgehen.
Die Funktionen funktionieren 1A

von DerSchatten (Gast)


Lesenswert?

Ok, hast recht.
Funktioniert.
Ausschlaggebend ist Taste Key1 auf B.1

Bei mir soll ja als Ausgabe eine 7-Segment Anzeige verbaut werden 
anstelle der LED's

Wieso wird denn die while-Schleife permanent wiederholt? Auch wenn keine 
taste gedrückt ist.

Das macht es für mein Vorhaben etwas unbrauchbar, weil ich dort meine 
Variable nicht einbaun kann:
1
  while(1){
2
    if( get_key_short( 1<<KEY1 ))
3
      LED_PORT ^= 1<<LED1;
4
    PORTD = pgm_read_byte(&Tabelle[nKeyPress]);
5
    if (nKeyPress < 8)
6
    {
7
      nKeyPress++;
8
    }
9
      else
10
      {
11
      nKeyPress = 0;
12
      }
13
 
14
    if( get_key_long( 1<<KEY1 ))
15
      LED_PORT ^= 1<<LED2;
16
    eeprom_write_byte(&eeFooByte, nKeyPress);
17
   }

von Peter D. (peda)


Lesenswert?

Da fehlen wohl nur ein paar {}:
1
  while(1){
2
    if( get_key_short( 1<<KEY1 )){
3
      LED_PORT ^= 1<<LED1;
4
      PORTD = pgm_read_byte(&Tabelle[nKeyPress]);
5
      if (nKeyPress < 8){
6
        nKeyPress++;
7
      }else{
8
        nKeyPress = 0;
9
      }
10
    }
11
    if( get_key_long( 1<<KEY1 )){
12
      LED_PORT ^= 1<<LED2;
13
      eeprom_write_byte(&eeFooByte, nKeyPress);
14
    }
15
  }


Peter

von Flo (Gast)


Lesenswert?

Bin mal neugierig und ich frag mich, wozu ihr im Programm das EEPROM 
beschreibt?

von Di P. (drpepper) Benutzerseite


Lesenswert?

Man kann auch hardwareseitig entprellen (hier aber nicht gern gesehn ;)

duckundweg

von Stephan H. (stephan-)


Lesenswert?

@Flo,

irgendwie muss der ja mal kapuut zu kriegen sein.  :-))

von DerSchatten (Gast)


Lesenswert?

Stephan Henning schrieb:
> irgendwie muss der ja mal kapuut zu kriegen sein.  :-))

Keine Sorge, das ist mir bereits gelungen... :)

Aber immerhin, das ganze funktioniert nun wunderbar. Einfach nur Geil! 
:)

Wozu das ins EEPROM schreiben?
Ganz einfach, ich möchte die Einstellung nach einem Reset (bzw. EIN/AUS) 
wieder hergestellt haben.

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.