www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Tastendruck mit ext. Interrupt erfassen


Autor: Alexander Ofner (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute, ich hab folgendes Problem:

Ich bin grad dabei mir einen Mp3-Player zu bauen und möchten diesen mit 
insgesamt 6 Tastern steuern (VOL-Lauter, VOL-Leiser, Play/Stopp, 
Vorwärts, Rückwärts, Menü).
Da der verwendete Kontroller (Atmega128) im Betrieb damit beschäftigt 
ist, Mp3-Daten von einer Micro-SD-Karte zu lesen, diese an den 
Mp3-Decoder (VS1001K) zu schicken und ein Farb-LCD anzusteuern, kann es 
je vorkommen, dass ein Tastendruck nicht erfasst wird, wenn die Tasten 
einfach an einem beliebigen Pin angeschlossen werden, da der Kontroller 
mit was anderem beschäftigt ist.
Jetzt hab ich das Problem, dass ich die Taster zwar auf einen ext. 
Interrupt-Pin legen kann und in der Interrupt-Routine abfrage, welcher 
Taster gedrückt ist. Wenn aber alle Taster an den selben Pin 
angeschlossen werden (ext. Interrupt-Pin), würde das bei einer 
gedrückten Taste dazu führen, dass alle Taster betätigt sind.
Jetzt hab ich mir gedacht, ich kann das so wie im oben gezeigten Bild 
lösen, indem ich die Interrupt-Leitung per 10kOhm Widerstand auf GND 
ziehe und wenn eine Taste gedrückt wird geht die Leitung auf HIGH und 
damit nicht alle Tasten betätigt werden, ist das ganze mit Dioden 
gesichert.

Als weitere Lösung ist mir gerade eingefallen, dass der Atmega128 8 ext. 
Interrupt-Pins hat. Also könnte ich alle Taster ja direkt auf einen 
ext-Int-Pin legen (also ein Taster pro Pin). 2 Pins davon kann ich aber 
schon nicht verwenden, da sich hier der I²C-Bus befindet. Und angenommen 
ich brauch noch irgendeinen anderen externen Interrupt ist diese Lösung 
auch schon hinfällig.

Aber prinzipiell möchte ich eigentlich nur wissen, ob meine Lösung mit 
den Dioden funktionieren kann, oder ob jemand eine bessere Lösung parat 
hat.

Ich freu mich schon auf eure Lösungsvorschläge. LG Alex

Autor: willi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ein tastendruck dauert mindestens ungefähr 300ms, bei 8 MHz sind das 2,4 
millionen anweisungen die dein controller durchführt, da sollte 
eigentlich was machbar sein

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Da der verwendete Kontroller (Atmega128) im Betrieb damit beschäftigt
>ist, Mp3-Daten [...], kann es
>je vorkommen, dass ein Tastendruck nicht erfasst wird, wenn die Tasten
>einfach an einem beliebigen Pin angeschlossen werden, da der Kontroller
>mit was anderem beschäftigt ist.

Dieses Problem kann man elegant über einen 10 ms-Timerinterrupt lösen. 
Bei Tasten an externen Interrupts hast Du das Problem des Prellens.  Es 
soll ja Schildbürger geben, die Tasten über externe Interrupts 
betreiben, um dann einen Timer zum Zweck der Entprellung zu bemühen. 
Das kann man sonderbar finden, denn man hat das Problem auch gelöst, 
wenn man die Tasten ohne jedweden externen Interrupt einfach nur 
zyklisch alle 10 ms (Beispielwert) abfragt.

>oder ob jemand eine bessere Lösung parat hat.

Alle Tasten alle 10 ms timergesteuert abfragen - fertig.

Wenn Dir sechs Pins für die sechs Tasten zu viel sind, kann man mehrere 
Tasten plus Widerstände auch nett an einen ADC-Pin hängen.

Autor: Andreas Watterott (andreasw) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entprellung -> Interrupt-Verfahren (nach Peter Dannegger)

Autor: Alexander Ofner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja also Timergesteuert alle Tasten abfragen hört sich sehr gut an. Das 
mit dem Prellen hab ich leider gar nicht bedacht, das wär nämlich extrem 
lästig.

LG Alex

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

kann AVRFan nur zustimmen. Mit der Tastenabfrage hatte ich damals nie 
Probleme, AT90S8515, 8MHz, , 32k ext. Ram, 2,5" HD, MAS3507, 2x16 
Display.
Auch Software-Scrollen des MP3-Tag, I2C-Volume-/Klangreglung des MAS3507 
während der Wiedergabe machte bis 192kBit keine Probleme.

Gruß aus Berlin
Michael

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Das mit dem Prellen hab ich leider gar nicht bedacht, das wär nämlich extrem
>lästig.

Kannst ja mal nen Test machen:

- Irgendeinen AVR nehmen
- UART einschalten
- in einer Endlosschleife den Inhalt von Register r16 mit 1200 Baud zum 
PC senden (sonst nix)
- Taste an Ext-Interrupt-Pin klemmen, Pullup aktivieren
- Externen Interrupt auf fallende Flanke konfigurieren
- Im Ext-Interrupt-Handler das Register r16 inkrementieren (sonst nix)

Alles zusammen <20 Zeilen Assembler.

Dann kannst Du auf die Taste drücken und Dir am PC (z. B. mit 
Hyperterminal) live angucken, um wieviel der Zähler bei einem 
Tastendruck raufgeht.  Wenn die Taste beim Niederdrücken prellt, ist es 
mehr als 1, und wenn sie beim Loslassen prellt, geht der Zähler auch 
dann hoch.

Autor: Harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi,
vielleicht nicht die eleganteste, aber doch sehr wirksame methode, um 
nicht unnötigerweise ständig irs ausführen zu müssen.
alle taster mit je einem widerstand an ext. isr, mit verschiedenen 
widerständen alle auf einen adc führen, der einen wieteren gegen gnd 
hat.
jeder tastendruck löst einen isr aus, flag setzen, wenn flag gesetzt, 
wert via adc abfragen.
grüssens, harry

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Harry wrote:
> hi,
> vielleicht nicht die eleganteste, aber doch sehr wirksame methode, um
> nicht unnötigerweise ständig irs ausführen zu müssen.
> alle taster mit je einem widerstand an ext. isr, mit verschiedenen
> widerständen alle auf einen adc führen, der einen wieteren gegen gnd
> hat.
> jeder tastendruck löst einen isr aus, flag setzen, wenn flag gesetzt,
> wert via adc abfragen.
> grüssens, harry

Das geht ohne ext. Interrupt viel besser.

Tastenmatrix mit Widerstandsnetzwerk an ADC, ADC im Hintergrund laufen 
lassen (Free-Run), per Timer-Int (der sowiso da ist) alle 10 bis 20 ms 
ADC auslesen und per LuT den Tastenwert generieren. Tastenwert mit 
Vorwert vergleichen und bei Gleichheit Prellzähler runterzählen, beim 
Erreichen von 0 Taste für gültig erklären und Prellzähler nicht weiter 
runterzählen. Bei ungleichen Tastenwerten Prellzähler auf Startwert 
setzen.

Läuft mit Pollin-Tastenmatrix (2x7, aber nur 12 Tasten) wunderbar.

...

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>jeder tastendruck löst einen isr aus,

Nicht einen, sondern mehrere (*), nämlich für jeden Tastenpreller einen. 
Weil die externen Interrupts so schnell sind.  Wie willst Du dem 
Prellproblem begegnen?

(*) Wenn Du's nicht glaubst, schreib mal ein Testprogramm nach obiger 
Anleitung.

Autor: Alexander Ofner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gut, also das mit dem externen Interrupt zum Erfassen des Tastendrucks 
lass ich jetzt mal. Danke für eure hilfreichen Tipps :-)

Autor: Harry Up (harryup)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi,
@avrfan: Nicht einen, sondern mehrere (*)...
glaub ich gern', weiss ich auch, es soll aber möglichkeiten des 
programmierens geben, mit hilfe derer eine mehrfache auslösung 
unterbunden wird. in solchem fall steht es ja jedem coder frei, nach 
seinem eigenen gusto zu agieren. ich ging schon davon aus, dass die 
trivialen dinge des codens geläufig sind, wenn du nicht weisst wie's 
geht, kannst ja gerne mal 'ne anfrage im forum stellen.
ansonsten steh' ich nicht auf leuts, die einem gerne und mit unendlicher 
geduld erklären, dass zum radwechsel das lösen jeder einzelnen mutter 
vonnöten ist, es gibt sachen, die verstehen sich einfach von selbst.
grüsse, harry

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>glaub ich gern', weiss ich auch, es soll aber möglichkeiten des
>programmierens geben, mit hilfe derer eine mehrfache auslösung
>unterbunden wird. in solchem fall steht es ja jedem coder frei, nach
>seinem eigenen gusto zu agieren.

Welches ist denn Deine Methode?  Ich frag einfach deshalb, weil sie ja 
vielleicht sehr gut ist.

>ich ging schon davon aus, dass die
>trivialen dinge des codens geläufig sind,

Es geht doch nicht ums Coden, sondern um die Verfahrensweise an sich (zu 
beschreiben in normaler Umgangssprache), wie Du das Prellproblem löst. 
Wie man die Methode dann auf einem bestimmten Controller in einer 
bestimmten Programmiersprache implementiert, ist ja eine andere 
Geschichte.

>wenn du nicht weisst wie's geht, kannst ja gerne mal 'ne anfrage im forum 
>stellen.

Weisst Du, wie's geht?  Dann erklär's hier doch in ein paar Worten; es 
würde mich und sicher auch andere wirklich interessieren.

Auch Gruß
AVRFan

Autor: Michael H* (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ohne alles gelesen zu haben:
du kannst auch zum mega88 wechseln. ist pin- und code-kompatibel und 
kann an jedem pin einen pin change interrupt auslösen lassen.

Autor: Harry Up (harryup)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi,
naja, meine quick & dity methode ist, den int innerhalb der routine zu 
disablen, flag setzen (taste wurde gedrückt), wert in einer adc-sub 
mehrfach auslesen (wegen prellen) und flag löschen.
innerhalb der adc-sub kann man dann entscheiden, ob nur ein tastendruck 
gewertet werden soll oder mehrere (wenn die taste gedrückt bleibt), z.b. 
um sollwerte zackig verändern zu können.
danach in der main isr wieder enablen, fertig.
grüssens, harry

Autor: AVRFan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>quick & dity

Trifft zu, denke ich, aber ich habe so meine Zweifel, ob man sich mit 
Quick&Dirty einen Gefallen tut.  Zu oft wirkt sich, was zuerst Quick 
war, in einer späteren Entwicklungsphase als ausgesprochen Slow aus, 
nämlich dann, wenn Erweiterungen oder das Aufspüren und Beseitigen von 
Fehlern anstehen.  Ist einfach ne Erfahrungstatsache.  Um es mal 
freimütig auszudrücken: Kompliziert proggen kann jeder; die Kunst 
besteht im Finden von "KISS"-Lösungen (wers nicht kennt: gemeint ist das 
KISS-Designprinzip "Keep it simple and stupid!").

>den int innerhalb der routine zu disablen,
>flag setzen (taste wurde gedrückt), wert in einer adc-sub
>mehrfach auslesen (wegen prellen) und flag löschen.

Mehrfach auslesen mit wahrscheinlich einer Delayschleife dazwischen. 
Solche "führe 10000 mal nop aus"-Schleifen finde ich immer fragwürdig, 
weil es Rechenzeit verschwendet.  Bei der timerbasierten Lösung gibts 
zwar andauernd Interrupts (z. B. 100 pro Sekunde, aber ich sehe keinen 
Grund, warum man sich daran stören sollte), dafür wird jedoch kein 
überflüssiger Code ausgeführt.

>um sollwerte zackig verändern zu können.

Zackig?  Das Prellen musst Du immer abwarten und das hat eine 
(unmerkliche) Zeitverzögerung zwischen Tastendruck und der dadurch 
ausgelösten Aktion zur Folge, die Du mit keiner Entprellmethode 
wegbekommst.

>danach in der main isr wieder enablen, fertig.

Ehrlich gesagt: Für meinen Geschmack unnötig umständlich.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Harry Up wrote:
> um sollwerte zackig verändern zu können.

Bloß versteht der MC unter "zackig" etwas völlig anderes als der Mensch.

Ein MC findet <10µs "zackig".
Ein Mensch dagegen findet alles <300.000µs "zackig" genug (ein 
Windows-User sogar alles <1.000.000µs).

Ein MC wird auch nicht müde, ihn stört überhaupt nicht, etwas alle 10ms 
auszuführen, was <0,1% CPU-Last kostet.
Im Gegenteil, Programme mit regelmäßiger Belastung arbeiten flüssiger 
und stabiler als Programme mit großen Lastsprüngen.


Peter

Autor: Paul Baumann (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Im Gegenteil, Programme mit regelmäßiger Belastung arbeiten flüssiger
>und stabiler als Programme mit großen Lastsprüngen.

Kann man da nicht die Stützkondensatoren vergrößern, um die Lastsprünge 
abzufangen?

schnell weg hier
Paul

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Paul Baumann wrote:
>>Im Gegenteil, Programme mit regelmäßiger Belastung arbeiten flüssiger
>>und stabiler als Programme mit großen Lastsprüngen.
>
> Kann man da nicht die Stützkondensatoren vergrößern, um die Lastsprünge
> abzufangen?

Gute Idee, so kenne ich Dich...

Aber glaub's einfach, regelmäßiges "Nachschaun im Vorbeigehen" ist bei 
Tasten (und auch beim ADC) bedeutend effektiver als dieser ruckweise 
Zirkus mit ext. Interrupt und anschließender "WAITms 20"-Warterei 
(vielleicht noch im Interrupt).

Wenn ich mich nicht verzählt habe kostet die Entprellung nach Peters 
Algorithmus in ASM im schlimmsten Fall je Runde:

- 13 Takte für die Grundroutine (4-fachentprellung mit Erkennung der
  neuen Tastendrücke

- 20 Takte für 4-fachentprellung mit getrennter Erkennung von
  Tastendrücken und Tastenloslassen

- 21 Takte für 4-fachentprellung mit Erkennung neuer Tastendrücke und
  Autorepeat bei längerem Tastendruck

Es lohnt sich also nicht mehr, Gründe zu erfinden, warum man diesen 
genialen Algorithmus nicht nutzen sollte.

>
> *schnell weg hier*

Warum? - Hier ist doch schön...

> Paul

...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Paul Baumann wrote:
> Kann man da nicht die Stützkondensatoren vergrößern, um die Lastsprünge
> abzufangen?

Es geht nicht um den Stromverbrauch, sondern um die Rechenzeit.

Es ist z.B. äußerst unschön, wenn die UART manchmal beim Tastendruck ein 
Zeichen verliert, nur weil man mit einem riesen langen Delay die CPU 
lahmlegt.
Oder das die CPU gerade was anders macht und der Tastendruck nicht 
erkannt wird.
Ich hab da leider auch so ein altes Gerät mit 32Bit, Multitasking, 
Bells&Whistles usw., aber Tasten muß man schön lange drücken, sonst 
packt es das Ding nicht.

Daher lieber ne gleichmäßige CPU-Belastung, als hohe Spitzen, wo ihr 
dann die Puste ausgeht.


Peter

Autor: Harry Up (harryup)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hi,
na, jetzt wird's dann fast schon philosophisch (oder heisst das jetzt 
folisofisch?).
klar, 'ne schön gleichmässig arbeitende cpu ist was feines, wenn's der 
code erlaubt, erfasse ich auch tatstendrücke in interupts, die ohnehin 
ausgelöst werden, z.b. weil meine anzeigeeinheit aus 7-segment anzeigen 
gemultiplext werden muss, und das dann doch 80x je sec. in solchem fall 
spricht nichts dagegen. anders bei einer batteriebetriebenen anwendung, 
habe ein fernanzeigemodul für ölzähler (2x mignon, machen's doch 
immerhin ein paar jahre) am start, die cpu ist zu 99,9% im power-down 
mode, weil das ding nur per irq mitzählt (auch hier muss entprellt 
werden). wenn der user allerdings den zählerstand wissen möchte, drückt 
er eine taste, dann geht das o.g. procedere los. während einer 
tastaturaktivität ist eh das human interface aktiv, da hat die cpu alle 
zeit der welt, weil das langsamste ohnehin der mensch ist. wenn also 
grundwerte verändert werden und auf's lcd gebracht werden sollen, 
aktualisiere ich alle 1/10 sec. das ist ein guter wert, um schnell 
verändern zu können, aber langsam genug, um den zielwert nicht zu 
'überfahren'.
aber unterm strich macht das doch eh jeder coder nach seinem eigenen 
gusto - und eben abhängig von der anwendung, im o.g. fall würde der irq 
die batterien unnötigerweise leersaugen.
wie auch immer, für jede anwendung gibt's ja gottlob die geeignete 
lösung.
und wenn ich hier mal quick & dirty schreibe, heisst das nicht, das 
unsere produkte schlampig gecodet sind, es soll mehr zum ausdruck 
bringen, dass ich hier nicht bis in's detail darlegen möchte, dass ich 
des codens mächtig binmein erster war ein netter sinclair zx81 mit 1k 
ram, damals der pure luxus. es kommt immer nicht gut, wenn 'kollegen' 
den finger heben und meinen, den rest der welt belehren zu müssen. viele 
von uns leben von ihrer arbeit - und das nicht, weil sie keinen plan 
haben, wie ein kleines problem effizient gelöst werden kann.
grüsse & nettes plaudern, harry

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Harry Up wrote:
> klar, 'ne schön gleichmässig arbeitende cpu ist was feines, wenn's der
> code erlaubt, erfasse ich auch tatstendrücke in interupts, die ohnehin
> ausgelöst werden, z.b. weil meine anzeigeeinheit aus 7-segment anzeigen
> gemultiplext werden muss, und das dann doch 80x je sec. in solchem fall
> spricht nichts dagegen. anders bei einer batteriebetriebenen anwendung,

Nö, ist kein Unterschied, man nimmt dann genau die gleiche Routine.

Bei allen modernen AVRs gibts ja den Pin-Change-Interrupt, d.h. die CPU 
wacht auf, wenn ne Taste gedrückt wird.
Dann macht die Entprellroutine im Timerinterrupt die Behandlung und 
ändert sich ne Weile nichts, gehts wieder ab in Sleep bis zum nächsten 
Pin-Change-Interrupt.

Es ist sehr komfortabel, wenn man sich keine Gedanken mehr machen muß 
und die Tastaturroutine einfach so in neue Projekte einfügen kann ohne 
auf irgendwelche Delays achten zu müssen.
Damit ist die Tastenabfrage sehr quick, aber überhaupt nicht dirty.

Und daß mindestens 8 Tasten parallel entprellt werden und gemerkt 
werden, falls das Main grad beschäftigt ist, ist auch sehr praktisch.


Peter

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
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
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 bestätigst du, die Nutzungsbedingungen anzuerkennen.