Forum: Mikrocontroller und Digitale Elektronik Tastenmatrix erkennt 2 Tasten bei einer gedrückten Taste


von Taster (Gast)


Lesenswert?

Hallo miteinander,

ich bin gerade dabei eine 4x4 Tastenmatrix mit Hilfe eines Mega328 
auszuwerten.

Meine Schaltung sieht folgendermaßen aus:
1
      PD5   PD4   PD3   PD2
2
       |     |     |     |
3
       |     |     |     |
4
PB1----a-----b-----c-----d
5
       |     |     |     |
6
PB0----e-----f-----g-----h
7
       |     |     |     |
8
PD7----i-----j-----k-----l
9
       |     |     |     |
10
PD6----m-----n-----o-----p

Dabei werden PD5 - PD2 als Eingang mit aktivem Pullup und PB1, PB0, PD7 
und PD6 mit hochomig initialisiert.
Dann multiplexe ich die Reihen in einem Timerinterrupt alle 10 ms und 
lese dabei PD5 - PD2 aus.
Nun hab ich folgendes Problem, dass wenn ich die Taste a drücke, erkennt 
er einen Tastendruck auf a und e. Drücke ich Taste e, dann erkennt er 
einen Tastendruck auf e und i. Drücke ich jedoch eine beliebige andere 
Taste (außer a und e), so erkennt er korrekt nur eine Taste.

Mein Code:
Init:
1
   // Ausgangspins fuer Tastenmatrix setzen
2
   // Reihen auf Eingang ohne Pullup
3
   DDRB &= ~(1 << 1);
4
   DDRB &= ~(1 << 0);
5
   DDRD &= ~(1 << 7);
6
   DDRD &= ~(1 << 6);
7
   // Spalten auf Eingang mit Pullup
8
   DDRD &= ~(1 << 5);
9
   DDRD &= ~(1 << 4);
10
   DDRD &= ~(1 << 3);
11
   DDRD &= ~(1 << 2);
12
   PORTD |= (1 << 5);
13
   PORTD |= (1 << 4);
14
   PORTD |= (1 << 3);
15
   PORTD |= (1 << 2);
ISR:
1
ISR(TIMER1_COMPA_vect)
2
{
3
   DDRD &= ~((1 << 7) | (1 << 6));
4
   PORTD &= ~((1 << 7) | (1 << 6));
5
   DDRB &= ~((1 << 1) | (1 << 0));
6
   PORTB &= ~((1 << 1) | (1 << 0));
7
   switch (btn_row)
8
   {
9
      case 0:
10
            DDRB |= (1 << 1);
11
            PORTB &= ~(1 << 1);
12
         break;
13
      case 1:
14
            DDRB |= (1 << 0);
15
            PORTB &= ~(1 << 0);            
16
         break;
17
      case 2:
18
            DDRD |= (1 << 7);
19
            PORTD &= ~(1 << 7);
20
         break;
21
      case 3:
22
            DDRD |= (1 << 6);
23
            PORTD &= ~(1 << 6);      
24
         break;
25
   }
26
   btns[btn_row][0] = (!(PIND & (1 << 5))) ? 1 : 0;
27
   btns[btn_row][1] = (!(PIND & (1 << 4))) ? 1 : 0;
28
   btns[btn_row][2] = (!(PIND & (1 << 3))) ? 1 : 0;
29
   btns[btn_row][3] = (!(PIND & (1 << 2))) ? 1 : 0;
30
   btn_row++;
31
   if (btn_row >= 4) {btn_row = 0;};
32
}

Vielleicht kann mir jemand auf die Sprünge helfen. Danke im vorraus.

von c-hater (Gast)


Lesenswert?

Taster schrieb:

> Vielleicht kann mir jemand auf die Sprünge helfen. Danke im vorraus.

Hmm...

Ich würde von einem "Timing"-Problem ausgehen (eigentlich eher: 
Crosstalk).

Also, wenn ich mit meiner Annahme Recht habe, sollte es genügen, immer 
nach der "Aktivierung" einer jeden Spaltenleitung erst einen kleinen 
Moment zu warten, bevor du die Zeilenstati einliest. Der kleine Moment 
sollte so etwa in der Größenordnung einiger (sehr weniger) µs liegen. 
Vielleicht zum Testen erstmal 2 oder 3.

Wenn das nicht zum Erfolg führt, solltest du überprüfen, ob für alle 
Zeileneingänge wirklich die Pullups aktiviert sind (ich hatte keine 
Lust, deinen Code durchzusehen).

von Taster (Gast)


Lesenswert?

c-hater schrieb:
> Also, wenn ich mit meiner Annahme Recht habe, sollte es genügen, immer
> nach der "Aktivierung" einer jeden Spaltenleitung erst einen kleinen
> Moment zu warten, bevor du die Zeilenstati einliest. Der kleine Moment
> sollte so etwa in der Größenordnung einiger (sehr weniger) µs liegen.
> Vielleicht zum Testen erstmal 2 oder 3.

Habe nun ein Delay von 2 µs hinzugefügt und tadaa. Nun werden auch a und 
e richtig erkannt.
Danke schön

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Taster schrieb:
> Vielleicht kann mir jemand auf die Sprünge helfen. Danke im vorraus.

 Ist das Ganze nicht verkehrt herum ?
 PB.0 / PB.1 / PD.6 / PD.7 als Ausgang mit Pullup.
 PD.2 -> PD.5 als Eingang mit Pullup.
 In der ISR ein Ausgang nach dem anderen auf Low schalten, paar Takte
 warten, PinD einlesen, AND mit 0x3C, auswerten.

von c-hater (Gast)


Lesenswert?

Taster schrieb:

> Habe nun ein Delay von 2 µs hinzugefügt und tadaa. Nun werden auch a und
> e richtig erkannt.

Gut. Nun solltest du noch versuchen, das Delay so weit wie möglich zu 
verkleinern. Die 2..3µs waren recht großzügig angegeben, wahrscheinlich 
genügt auch ein wesentlich kürzeres Delay im Bereich einiger 10 bis 
einiger 100 ns bereits, um den crosstalk ausreichend abebben zu lassen.

von Sascha W. (sascha-w)


Lesenswert?

@Taster,

du könntest auch erst den Zustand einlesen und im Anschluss die Pins 
umschalten, so liegt der Zustand bis zum nächsten Aufruf der ISR stabil 
an.

Sascha

von Taster (Gast)


Lesenswert?

8 NOPs sind ausreichend. Macht bei 16 MHz eine Dauer von 500 ns

von c-hater (Gast)


Lesenswert?

Sascha Weber schrieb:

> du könntest auch erst den Zustand einlesen und im Anschluss die Pins
> umschalten, so liegt der Zustand bis zum nächsten Aufruf der ISR stabil
> an.

Genau das ist tatsächlich die bestmögliche Lösung des Problems, denn sie 
kommt ohne jedes Delay in einer ISR aus

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.