www.mikrocontroller.net

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


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Daniel (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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

Autor: Werner (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Daniel (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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....
}

Autor: Matthias Sch. (Firma: Matzetronics) (mschoeldgen)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Wie wäre es mit switch..case?
void button_interpreter(void) {
switch(PORTD.IN) {
  case 0xFE : // Taste an Bit0 gedrückt
              // Tu was
              break;
  case 0xFD : // Taste auf Bit1
              break;
// usw.
  case default : // alle nicht behandelten Tastendruckkombinationen
  }
}

Autor: M. H. (mh555)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Matthias Sch. (Firma: Matzetronics) (mschoeldgen)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ups, habe im case default das break vergessen...

Autor: M. H. (mh555)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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) || ...

Autor: M. H. (mh555)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Matthias Sch. (Firma: Matzetronics) (mschoeldgen)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Daniel (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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...

Autor: Matthias Sch. (Firma: Matzetronics) (mschoeldgen)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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:
void button_interpreter(void) {
switch(PORTD.IN) {
  case 0xFE : // Taste an Bit0 gedrückt
  case 0xFD : // Taste auf Bit1
  case 0xFB :
  case 0xF7 :
  case 0xEF :
  case 0xDF :
  case 0xBF :
  case 0x7F : // hier tu ich was
              break;
// usw.
  case default : // alle nicht behandelten Tastendruckkombinationen
  }
}

Autor: Daniel (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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...

Autor: Peter Dannegger (peda)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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

Autor: M. H. (mh555)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Matthias Sch. (Firma: Matzetronics) (mschoeldgen)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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:
uint8_t get_key_common( uint8_t key_mask )
{
  return get_key_press((key_press & key_mask) == key_mask ? key_mask : 0);
}

Beitrag "Universelle Tastenabfrage mit 2 Tastenerkennung"


Peter

Autor: M. H. (mh555)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht 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?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net