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
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
>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.
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
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
>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.
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
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. ...
>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.
Gut, also das mit dem externen Interrupt zum Erfassen des Tastendrucks lass ich jetzt mal. Danke für eure hilfreichen Tipps :-)
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
>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
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.
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
>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.
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
>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
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 ...
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
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.