Forum: Mikrocontroller und Digitale Elektronik Gemeinsame Tastenabfrage mit Atmels XMega Serie?


von Daniel (Gast)


Lesenswert?

Hallo,

ich möchte gerne eine gemeinsame Tastenabfrage in der folgenden Schleife 
einbauen....

if (!(PORTD.IN & 0b00000001) && (...) && (...))
{
Tu was....
}

...bis jetzt wird nur der Tastenzustand am PIN0 abgefragt mit PORTD.IN & 
0b00000001


Was muss ich ändern wenn ich irgendeine Taste am Port abfragen möchte?

Es sind 8 Tasten an einem Port angeschlossen und sowie eine aber auch 
nur eine gedrückt wird soll ein Befehl ausgeführt werden.

Sämtliche Versuche mit dem Befehl PORT.IN scheiterten bisher.

Gruß Daniel

von Werner (Gast)


Lesenswert?

Daniel schrieb:
> if (!(PORTD.IN & 0b00000001) && (...) && (...))
...
> Was muss ich ändern wenn ich irgendeine Taste am Port abfragen möchte?

Wenn do "oder" meinst, mußt du auch "||" schreiben.

Erste Frage wäre, wie deine Tasten angeschlossen sind, d.g. ob sie beim 
Drücken L oder H liefern. Dann kannst du mit "&" eine Maske auf die 
erforderlichen Tasten legen und prüfst ober das Ergebnis bzw. das 
Inverse == 0 ist.

von Daniel (Gast)


Lesenswert?

Werner schrieb:
> enn do "oder" meinst, mußt du auch "||" schreiben.
>
> Erste Frage wäre, wie deine Tasten angeschlossen sind, d.g. ob sie beim
> Drücken L oder H liefern. Dann kannst du mit "&" eine Maske auf die
> erforderlichen Tasten legen und prüfst ober das Ergebnis bzw. das
> Inverse == 0 ist.

Also der Port D wurde als Eingang festgelegt

Mit der Maskenfunktion

PORTCFG.MPCMASK |=(1<<PIN0_bp) | (1<<PIN1_bp) | (1<<PIN2_bp) | 
(1<<PIN3_bp)
                | (1<<PIN4_bp) | (1<<PIN5_bp) | (1<<PIN6_bp) | 
(1<<PIN7_bp);

wurden die PINS am Port D maskiert

anschließend wurden mit der Gruppenfunktion

PORTD.PIN0CTRL = PORT_OPC_PULLUP_gc;

die Pullups aktiviert.

Mit anderen Worten wenn eine Taste gedrückt wird, liegt am Porteingang

eine 0 an. Daher die verneinte Abfrage !(PORTD.IN & 0b00000001)

if (!(PORTD.IN & 0b00000001) && (Bedingung1==TRUE) && 
(Bedingung2==TRUE))
{
Tu was....
}

Die Verknüpfung && hat bisher noch nichts mit den anderen Tasten zu tun 
und
soll nur prüfen ob die Bedingung1 und Bedingung2 aus dem übrigen Code 
auch TRUE ist.

Wie genau muss jetzt die Codezeile aussehen wenn ich alle 8 Tasten auf 
Low-Zustand abfragen will?

Folgendes funktioniert leider nicht :

if (!(PORTD.IN & ((0b00000001)||(0b00000010))) && (Bedingung1==TRUE) && 
(Bedingung2==TRUE))
{
Tu was....
}

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Wie wäre es mit switch..case?
1
void button_interpreter(void) {
2
switch(PORTD.IN) {
3
  case 0xFE : // Taste an Bit0 gedrückt
4
              // Tu was
5
              break;
6
  case 0xFD : // Taste auf Bit1
7
              break;
8
// usw.
9
  case default : // alle nicht behandelten Tastendruckkombinationen
10
  }
11
}

von M. H. (mh555)


Lesenswert?

Verstehe ich Dich richtig? Am Port liegt 0b11111111 an, wenn keine Taste 
gedrückt wird und etwas anderes, wenn eine gedrückt wird?

Wenn das stimmt, dann gibt diese Umformulierung ja schon die Antwort. 
Einfach auf PORTD.IN != 0b11111111 testen, um zu sehen ob irgendeine 
Taste gedrückt ist.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Ups, habe im case default das break vergessen...

von M. H. (mh555)


Lesenswert?

> und sowie eine aber auch nur eine gedrückt wird

Ach, Du willst die Aktion nicht machen, wenn zwei Tasten gleichzeitig 
gedrückt werden?

Na dann musst Du die Maskierungen wie in (PORTD.IN & 0b00000001) 
weglassen, weil eine Maskierung gerade macht, dass die anderen Bits egal 
sind. Teste also einfach auf alle 8 Zustände, die Du haben willst
  (PORT.IN == 0b11111110) || (PORT.IN == 0b11111101) || ...

von M. H. (mh555)


Lesenswert?

Matthias Sch. schrieb:
> Ups, habe im case default das break vergessen...

Wieso? Es schadet zwar nicht, das dort zu haben, aber notwendig ist es 
nicht.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

M. H. schrieb:
>> Ups, habe im case default das break vergessen...
>
> Wieso? Es schadet zwar nicht, das dort zu haben, aber notwendig ist es
> nicht.

Ich habs halt gerne strukturiert :-). Aber klar, ist überflüssig. 
Compiler würde es eh wegrationalisieren.

von Daniel (Gast)


Lesenswert?

M. H. schrieb:
> Ach, Du willst die Aktion nicht machen, wenn zwei Tasten gleichzeitig
> gedrückt werden?
>
> Na dann musst Du die Maskierungen wie in (PORTD.IN & 0b00000001)
> weglassen, weil eine Maskierung gerade macht, dass die anderen Bits egal
> sind. Teste also einfach auf alle 8 Zustände, die Du haben willst
>   (PORT.IN == 0b11111110) || (PORT.IN == 0b11111101) || ...

Also die Aktion soll gemacht werden wenn irgendeine Taste von den 8 
Tasten gedrückt wird. Vorzugsweise soll nichts passieren wenn mehrere 
Tasten gleichzeitig gedrückt werden.


Muss ich jedesmal PORTd.IN schreiben oder kann ich das noch verkürzen?

Dann liegt mein Fehler also bei der and & Operation richtig?

Sprich aus dem & muss ein == werden...

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Daniel schrieb:
> Muss ich jedesmal PORTd.IN schreiben oder kann ich das noch verkürzen?

Schreib ich eigentlich chinesisch? In meinem Codefragment wird genau 
einmal PORTD.IN abgefragt.
Wenns dir nur darum geht, irgendeine einzelne taste abzufragen:
1
void button_interpreter(void) {
2
switch(PORTD.IN) {
3
  case 0xFE : // Taste an Bit0 gedrückt
4
  case 0xFD : // Taste auf Bit1
5
  case 0xFB :
6
  case 0xF7 :
7
  case 0xEF :
8
  case 0xDF :
9
  case 0xBF :
10
  case 0x7F : // hier tu ich was
11
              break;
12
// usw.
13
  case default : // alle nicht behandelten Tastendruckkombinationen
14
  }
15
}

von Daniel (Gast)


Lesenswert?

Matthias Sch. schrieb:
> Schreib ich eigentlich chinesisch? In meinem Codefragment wird genau
> einmal PORTD.IN abgefragt.

Chinesisch nicht aber du schreibst eine CASE..

und meine Frage war ob man in der if() nur einmal PORTD.IN schreiben 
kann und dahinter eine || oder Abfrage machen kann...

von Peter D. (peda)


Lesenswert?

Daniel schrieb:
> Vorzugsweise soll nichts passieren wenn mehrere
> Tasten gleichzeitig gedrückt werden.

Darum brauchst Du Dir keine Sorgen zu machen. Kein Mensch kann 2 Tasten 
innerhalb weniger ns zusammen drücken.
Es wird immer eine Taste zuerst gedrückt werden.


Peter

von M. H. (mh555)


Lesenswert?

Daniel schrieb:
> meine Frage war ob man in der if() nur einmal PORTD.IN schreiben
> kann und dahinter eine || oder Abfrage machen kann...

Nein, das geht nicht. Für den Fall, dass das Auslesen besonders lange 
dauert oder es problematisch wäre wenn sich der Port während der 
Abarbeitung des if-Statements ändert (beides sehe ich hier nicht), kann 
man die Portabfrage natürlich auch in eine Variable schreiben und die 
dann testen. Aber auch dann muss man diese mehrmals ins if() schreiben. 
Dieses Zwischenspeichern gänge natürlich auch mit einem Funktionsaufruf 
if(nur_eine_Taste_gedrückt(PORTD.IN)). Ich bin zwar kein Freund von 
case-Anweisungen, aber in diesem speziellen Fall finde ich sie die 
bessere Lösung, weil besser lesbar.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

M. H. schrieb:
> Ich bin zwar kein Freund von
> case-Anweisungen

Sag mal warum, würde mich interessieren. Hab hier gerade einen kleinen 
Frequenzumrichter (700Watt) mit Mega88, LCD und drei Tasten gebaut, und 
die Tastenabfrage mit switch und case ist prima, da ich eben auch zwei 
gleichzeitig gedrückte Tasten auswerten und für Sonderfunktionen 
benutzen kann.
Bei den verschachtelten if's und else's verliert man m.E. viel schneller 
den Überblick und verbaut sich die Erweiterbarkeit.
Ich könnte mir nämlich vorstellen, das der TO irgenwann doch mal 
zwischen den Buttons unterscheiden will und dann die if's wieder 
auseinanderdröseln muss.

Bei meinem Konstrukt hingegen schreibste im case dann deine gewünschte 
Funktion und fertig.

von Peter D. (peda)


Lesenswert?

Matthias Sch. schrieb:
> die Tastenabfrage mit switch und case ist prima

Ist sie nicht.
Man muß erst alle anderen Tasten ausmaskieren.
Und es kommen ja noch weitere Probleme hinzu, wie Entprellung und 
Flankenerkennung.

Man schreibt sich daher am besten eine Funktion dafür:
1
uint8_t get_key_common( uint8_t key_mask )
2
{
3
  return get_key_press((key_press & key_mask) == key_mask ? key_mask : 0);
4
}

Beitrag "Universelle Tastenabfrage mit 2 Tastenerkennung"


Peter

von M. H. (mh555)


Lesenswert?

Matthias Sch. schrieb:
> Sag mal warum, würde mich interessieren.

Wie gesagt: In diesem Fall finde ich Case sehr elegant und würde es auch 
so nutzen. Aber so grundsätzlich nutze ich Case nicht gern. Eher aus dem 
Bauch heraus als mit harten Fakten belegbar. Liegt wohl eher daran, dass 
ich nicht nur in C programmiere, sondern auch in anderen Sprachen (in 
denen es ein Case nicht gibt). Außerdem ist Case nicht (nachträglich) um 
zusätzliche Bedingungen (auf andere Variablen) erweiterbar und nicht so 
mächtig wie ifs. (Du schreibst oben etwas von verschachtelten if-else. 
Solche Dinge sind inhaltlich doch überhaupt nicht mit Cases abzubilden?) 
Zu guter letzt: Die Case-Anwendung ist syntaktisch ein Fremdkörper in C. 
Überall gibt es Code-Blöcke, die mit geschweiften Klammern 
zusammengehalten werden. Nur an einer Stelle muss man die gleiche Sache 
anders notieren: bei Cases.

Peter Dannegger schrieb:
> Matthias Sch. schrieb:
>> die Tastenabfrage mit switch und case ist prima
>
> Ist sie nicht.
> Man muß erst alle anderen Tasten ausmaskieren.

Sorry, aber auch Leute, die exzellente Algorithmen für die 
Tastenerkennung geschrieben haben, sollten einen Thread lesen und die 
Anforderungen verstehen bevor sie antworten.

Mit der Frage nach Flankenerkennung und Entprellung hast Du allerdings 
recht. Was sagt Daniel (OP) dazu? Hast Du Dir darüber schon Gedanken 
gemacht? Dein jetziger Ansatz wird den entsprechenden Code hunderte oder 
tausende Male durchlaufen solange eine Taste auch nur kurz gedrückt 
wird. Wäre das okay?

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.