Hallo,
ich möchte 10 Tasten an einem ATMega328 auslesen lassen. Da die Kiste
schon eh relativ viel zutun hat, bin ich auf Interrupts angewiesen. Nur
wie mache ich das?
Eine Idee ist, alle Taster zusätzlich an den Interrupt zu hängen und mit
einer Diode bzw. MMBF170 die Spannung nur in eine Richtung durchlasse.
Die andere Idee, wäre die Verwendung von Logik-Gattern. 7432 z.B. mit 4x
OR. Was meint ihr, was ist da der beste Weg?
Hallo,
nimm einen 16-bit I/O expander für I2C (PCF8575) oder etwas ähnliches.
16 Eingänge für deine Tasten, I2C oder SPI zur Kommunikation und eine
/INT Leitung um deinen Prozessor scharf zu machen.
Heute ist Freitag, da kann man es sich auch einfach machen :-)
Grüße aus Berlin
> was ist da der beste Weg?
Taster einfach per Software sinnvoll abfragen.
wenn man 10taster im Timer aller 10ms Abfragt, ist das überhaupt keine
Last für dem Atmel.
Was meinst du viel zu tun ? Fuer die geschwindigheit brauchst du doch
nicht die interrupt oder ? Was musz der Kontroller denn alles machen ?
Bestudiere dir die moeglichkeit mit software mehrere processen
semi-parallel laufen zu lassen, zB mittels state-machines und loops.
Bestudiere dir mal diese principe-programms um ein LED blinken zu lassen
auf 1 Hz
Programm 1)
WHILE (1) {
LED_ON
WAIT_500MSEC
LED_OFF
WAIT_500MSEC
}
Programm 2)
WHILE (1) {
IF (MSTIMER() MOD 1000) < 500
LED_ON
ELSE
LED_OFF
}
Bei programm 1 hat man schon 100% der Prozessorzeit benutzt, wenn man
ein zweiter LED auf 1.3 Hz blinken lassen woll hat man ein problem und
musz man alles neu programmieren
Bei programm 2 kann mann innerhalb der WHILE-loop sehr viel dabei
machen. Dieses Programm kann natuerlich noch optimalisiert werden.
MSTIMER() ist eine auslesung wieviel ms der uP schon lauft sowie die
millis() funktion beim Arduino.
Patrick
Torben G. schrieb:> Eine Idee ist, alle Taster zusätzlich an den Interrupt zu hängen und mit> einer Diode bzw. MMBF170 die Spannung nur in eine Richtung durchlasse.>> Die andere Idee, wäre die Verwendung von Logik-Gattern. 7432 z.B. mit 4x> OR. Was meint ihr, was ist da der beste Weg?
Ich meine OR Gatter mit Dioden ist der bessere Weg. Entprellt werden muß
aber auch noch ...
Peter II schrieb:> wenn man 10taster im Timer aller 10ms Abfragt, ist das überhaupt keine> Last für dem Atmel.
Eben...
Nur zu schrieb:> Entprellt werden muß aber auch noch ...
Macht man auch in Software!
Wenn dein Controller wirklich keine Zeit hat um alle 10ms mal ein oder
zwei Ports einzulesen dann hat dein Programm einen grundsätzlichen
Designfehler und sollte weggeschmissen werden. Das anze dann irgendwie
mit Hardware und Logikgattern retten zu wollen ist der Gipfel der
Idiotie (Konsequenz heißt, auch Holzwege zu Ende zu gehen).
Ich vermute mal dein Controller hängt die meißte Zeit in irgendwelchen
Busy-Waites und du weisst nicht wie du die Tasterabfrage da dazwischen
reinpfriemeln kannst.
Rene Schube schrieb:> Hallo,>> nimm einen 16-bit I/O expander für I2C (PCF8575) oder etwas ähnliches.> 16 Eingänge für deine Tasten, I2C oder SPI zur Kommunikation und eine> /INT Leitung um deinen Prozessor scharf zu machen.>> Heute ist Freitag, da kann man es sich auch einfach machen :-)> Grüße aus Berlin
Hmm.. ein interessanter Chip. Ich werde mir mal ein paar davon bestellen
Patrick C. schrieb:> Was meinst du viel zu tun ? Fuer die geschwindigheit brauchst du doch> nicht die interrupt oder ?
Mit viel zutun meine ich...
Wir sind uns ja darüber einig, dass die Software nach dem "Setup" in
Loops läuft. Ist ein Loop abgearbeitet, fängt die Kiste wieder von vorne
an. Ein solcher Loop dauert bei dem Programm schon relativ lange, etwa
300ms. Und dabei kann ich nicht wirklich kontrollieren, welche
abzweigungen genommen werden.
Das richtige Stichwort an der Stelle wären wohl Timer, nur habe ich alle
Timer bereits belegt. Und da ich nicht an jeder zweiten Quellcodezeile
die Tastenabfrage einbauen möchte, die natürlich auch wieder (teure)
Rechenzeit kostet, müssen Interrupts herhalten. Und genau dafür sind die
ja auch da.
Haro schrieb:> Das anze dann irgendwie> mit Hardware und Logikgattern retten zu wollen ist der Gipfel der> Idiotie (Konsequenz heißt, auch Holzwege zu Ende zu gehen).
Wieso? Interrupts sind doch genau dafür gedacht. Wieso sollte ich die da
nicht für benutzen? Sicher, man hätte gleich einen anderen Controller
nehmen können, der Interrupts auf allen Pins zulässt, aber wieso?
Du solltest einfach einen Timer nutzen, um zyklisch alle wichtigen Tasks
aufzurufen. Im Timer selbst wird nur das Nötigste gemacht. Wenn man den
Timer-Zyklus vernünftig wählt, kann man Tasks die selten benötigt werden
auch entsprechend seltener aufrufen. Und mehrere davon sogar zeitlich
versetzt zueinander.
Die zeitintensiven Routinen müssen dann so geschrieben sein, dass sie
jederzeit durch den Timer-IR unterbrochen werden können, der den
zeitlichen Ablauf des Gesamtsystems steuert.
Bei unserem Schrittmotorcontroller [1] hatten wir anfangs auch so ein
Konstrukt mit externen Logikverknüpfungen für die Endschalter. Das haben
wir aber schnell wieder rausgeworfen.
Der Controller steuert 4 Schrittmotorachsen, kommuniziert über einen
FTDI mit dem PC, berechnet Rampen und gibt aktuelle Positionen auf dem
grafischen LCD aus. Nebenbei werden noch eine Tastatur sowie End- und
Referenzschalter abgefragt. Durch Anwendung des o.g. Schemas ist das
alles auch für einen alten Mega128 kein Problem.
Mit freundlichen Grüßen
Thorsten Ostermann
[1] http://www.mechapro.de/schrittmotorensteuerung.html
Torben G. schrieb:> Ein solcher Loop dauert bei dem Programm schon relativ lange, etwa> 300ms. Und dabei kann ich nicht wirklich kontrollieren, welche> abzweigungen genommen werden.
Dann nützt Dir aber ein Interrupt genau 0,nix.
Das RETI kehrt nämlich genau dort hin zurück, wo der Interrupt das Main
unterbrochen hat. D.h. die 300ms werden nach dem Interrupt schön brav
zuende abgearbeitet.
Torben G. schrieb:> nur habe ich alle> Timer bereits belegt.
Erzähl mal noch einen vom Pferd.
Irgendeinen Timerinterrupt mit irgendeinem Zeitintervall wirst Du doch
haben. Und da fügt man einfach das Entprellen mit ein.
Man kann z.B. auch einen ständig laufenden ADC-Interrupt als Timer
benutzen. Also alle Interrupts, die periodisch auftreten, sind quasi
auch Timer.
Torben G. schrieb:> Sicher, man hätte gleich einen anderen Controller> nehmen können, der Interrupts auf allen Pins zulässt,
Reichen Dir die 23 Interrupt-Pins PCINT0..14, 16..23 denn nicht?
Aber wie gesagt, das bringt eh nichts.
Peter Dannegger schrieb:> Dann nützt Dir aber ein Interrupt genau 0,nix.> Das RETI kehrt nämlich genau dort hin zurück, wo der Interrupt das Main> unterbrochen hat. D.h. die 300ms werden nach dem Interrupt schön brav> zuende abgearbeitet.
Und wieso soll das nichts bringen?
Das laufende Programm wird angehalten, die Tasten werden eingelesen, der
User bekommt ein Feedback in Form einer leuchtenden LED und ist
zufrieden. Dann wird das unterbrochene Programm weiter rechnen, mit den
alten werten. Und beim nächsten Durchlauf dann mit neuen Tasten-Werten.
Ich sehe da keine Probleme.
Torben G. schrieb:> Hallo,>> ich möchte 10 Tasten an einem ATMega328 auslesen lassen. Da die Kiste> schon eh relativ viel zutun hat, bin ich auf Interrupts angewiesen. Nur> wie mache ich das?
Spannungsteiler nehme, schau mal z.B. hier:
http://forum.arduino.cc/index.php?topic=30476.msg226242#msg226242. Du
brauchst dann einen ADC-Eingang.
Die Abfrage an sich machst du zyklisch, da haben meine Vorredner recht.
Alle 10ms (oder auch alle 100ms) sollte kein Problem sein.
Max
Mir persönlich ist es egal, ob Du Tastenabfragen mit Interrupts
realisierst.
Designfehler gibts genug in der Technik, ein weiterer stört mich nicht
wirklich.
Schade ist nur, daß Du die Gelegenheit etwas zu lernen herschenkst.
Du stellst eine Frage, aber die Antworten verwirfst Du.
Vielleicht liegts daran, daß Du die bestehende Software nicht ändern
willst oder kannst. Dann sind natürlich alle Antworten, die genau dies
verlangen für Dich nicht akzeptabel.
Aber sag das dann auch.
>Ein solcher Loop dauert bei dem Programm schon relativ lange,>etwa 300ms.
Du hast also eine Software wo der Hauptschleifendurchlauf 300 ms braucht
?
???
Wahrscheinlich sind da ganz viele (unsinnige) feste Wartezeiten drin,
oder andere grobe Designprobleme.
Du solltest diese SW komplett überarbeiten.
Gruss
Torben G. schrieb:> Ein solcher Loop dauert bei dem Programm schon relativ lange, etwa> 300ms.
Bei einer so langen Laufzeit muss ja Busy-Waiting involviert sein - ich
glaube nicht, dass in den µC genügend Code und Daten passen, um so lange
sinnvoll rumzurechnen.
Also eine/mehrere Statemachines statt Busy-Waiting und schon hast Du
genügend Zeit um Deine Taster vernünftig abzufragen.
Wenn Du partout nicht vom Interrupt abweichen willst, mach ein wired-OR
mit Dioden.
Torben G. schrieb:> Peter Dannegger schrieb:>> Dann nützt Dir aber ein Interrupt genau 0,nix.>> Das RETI kehrt nämlich genau dort hin zurück, wo der Interrupt das Main>> unterbrochen hat. D.h. die 300ms werden nach dem Interrupt schön brav>> zuende abgearbeitet.>> Und wieso soll das nichts bringen?> Das laufende Programm wird angehalten, die Tasten werden eingelesen, der> User bekommt ein Feedback in Form einer leuchtenden LED und ist> zufrieden. Dann wird das unterbrochene Programm weiter rechnen, mit den> alten werten. Und beim nächsten Durchlauf dann mit neuen Tasten-Werten.>> Ich sehe da keine Probleme.
Das einzige Problem ist die Entprellung.
Denn alles andere kann eine Timer-gesteuerter Polling Mechanismus
genauso gut machen. Nur das bei ihm das Entprellen in Software trivial
ist während man bei einer Interrupt Lösung dann wieder externe
Entprellhardware braucht. Kann man natürlich machen - aber wozu, wenn
die Alternative gänzlich ohne auskommt und lediglich ein paar Hunderstel
Prozent an Rechenzeit kostet.
Irgendeinen Timer hat man doch immer. Es ist ja nicht verboten, dass man
in einer Timer ISR mehrere Themenkreise abarbeitet. Die meisten
Programme haben sowieso so etwas wie einen internen Basistaktgenerator
in Form eines Timers. Da kommen eben die paar Anweisungen fürs Pollen
und Entprellen noch mit dazu und gut ists.
Karl Heinz schrieb:> Das einzige Problem ist die Entprellung.> Denn alles andere kann eine Timer-gesteuerter Polling Mechanismus> genauso gut machen. Nur das bei ihm das Entprellen in Software trivial> ist während man bei einer Interrupt Lösung dann wieder externe> Entprellhardware braucht.
Und was würde gegen so eine Entprellung in Software sprechen?
Das der nächste Tastendruck verschluckt wird, wenn er nicht innerhalb
von 200ms nach dem letzten Tastendruck kommt? Was insbesondere beim
allerersten getätigten Tastendruck schwer werden wird.
Jetzt wirds wieder mal lustig.
Der nächste der iterativ eine Tastenentprellung online entwickelt und
sich in 15 Programmversionen hintastet. :-)
Also - nächster Versuch
als erstes wirst du jetzt wahrscheinlich mal das kleiner zu einem größer
umdrehen, woraufhin ich mit 2 mehr oder weniger gleichzeitig gedrückten
Tasten kontere, die man als Benutzer durchaus in einem Abstand von
weniger als 0.2 Sekunden drücken kann, die dein Code dann aber manchmal
nicht richtig erkennt, weil du den nächsten (Flanken?)Interrupt erst 0.2
Sekunden später erst wieder zulässt. Ganz abgesehen davon, dass du mit
einer gedrückt gehaltenen Taste die Auswertung der anderen Tasten
blockieren kannst, weil dann durch das Dioden-Or keine Flanke mehr
durchkommt.
Karl Heinz schrieb:> Jetzt wirds wieder mal lustig.> Der nächste der iterativ eine Tastenentprellung online entwickelt und> sich in 15 Programmversionen hintastet. :-)> Also - nächster Versuch> unsigned long time;> void myInterrupt(){>> if(millis()-time < 200){> time = millis();
Das ist doch Arduino, oder?
Dann wird es besonders lustig.
@Torben G. (Gast) Lassen sich die Tastenabfragen nicht mit Bordmitteln
bewältigen?
mfg.
spontan schrieb:> Jetzt wird noch blöder.>> Keine Zeit in der Main, da wahhhhhnsinnnnig viel zu tun, und dann im> Interrupt Zeiten verbraten?
na, ja.
Er 'verbratet' sie ja nicht. millis() fragt nur die Systemzeit ab. Die
Idee, der er nachgeht ist, dass er nach dem Austreten des ersten
Interrupts alle weiteren Interrupts für eine gewisse Zeit lang (200ms)
sperrt, bzw. ignoriert. D.h. er stellt fest: wann war der letzte
Interrupt und sind seitdem schon mindestens 200ms vergangen - wenn er
den Vergleich richtig rum hätte.
Ich geh mal davon aus, dass diese myInterrupt die ISR ist, die zu einem
flankengetriggerten externen Interrupt gehört.
Thomas Eckmann schrieb:> @Torben G. (Gast) Lassen sich die Tastenabfragen nicht mit Bordmitteln> bewältigen?
Ohne jetzt die Arduino-Doku durchforstet zu haben.
Da es für Ardunio jede Menge Klassen für alles mögliche gibt, geh ich
eigentlich davon aus, dass es auch eine Klasse gibt, die sich um
Tastenauswertung kümmert :-)
Karl Heinz schrieb:> Thomas Eckmann schrieb:>>> @Torben G. (Gast) Lassen sich die Tastenabfragen nicht mit Bordmitteln>> bewältigen?>> Ohne jetzt die Arduino-Doku durchforstet zu haben.> Da es für Ardunio jede Menge Klassen für alles mögliche gibt, geh ich> eigentlich davon aus, dass es auch eine Klasse gibt, die sich um> Tastenauswertung kümmert :-)
Das meine ich auch. War auch mehr als Anregung, denn als Frage gedacht.
Denn wenn man die eingetretenen Pfade verlässt, um es mit irgendwelchen
halbgaren Lösungen zu versuchen, handelt man sich nur Probleme ein, die
man dann viertelgar lösen muss. Was dann auch noch beliebig
steigerungsfähig ist.
mfg.
Karl Heinz schrieb:> als erstes wirst du jetzt wahrscheinlich mal das kleiner zu einem größer> umdrehen,
richtig
> woraufhin ich mit 2 mehr oder weniger gleichzeitig gedrückten> Tasten kontere, die man als Benutzer durchaus in einem Abstand von> weniger als 0.2 Sekunden drücken kann, die dein Code dann aber manchmal> nicht richtig erkennt, weil du den nächsten (Flanken?)Interrupt erst 0.2> Sekunden später erst wieder zulässt. Ganz abgesehen davon, dass du mit> einer gedrückt gehaltenen Taste die Auswertung der anderen Tasten> blockieren kannst, weil dann durch das Dioden-Or keine Flanke mehr> durchkommt.
Das ist kein Problem, sondern ein Feature. 200ms Wartezeit zwischen dem
drücken von Tasten und man kann nur eine Taste zur gleichen Zeit
drücken.
Karl Heinz schrieb:> Ohne jetzt die Arduino-Doku durchforstet zu haben.> Da es für Ardunio jede Menge Klassen für alles mögliche gibt, geh ich> eigentlich davon aus, dass es auch eine Klasse gibt, die sich um> Tastenauswertung kümmert :-)
Das Codeschnittsel oben war auch nur eine Art Schnellschuss, um zu
zeigen, dass eine Entprellung des Interrupts kein Problem ist. Okay, es
war evtl. zu Quick&Dirty.
Torben G. schrieb:> Das ist kein Problem, sondern ein Feature. 200ms Wartezeit zwischen dem> drücken von Tasten und man kann nur eine Taste zur gleichen Zeit> drücken.
Na, wenn du das als Feature bezeichnest.
Bei Microsoft sind sicher noch Stellen frei.
Thomas Eckmann schrieb:>> Das meine ich auch. War auch mehr als Anregung, denn als Frage gedacht.
:-)
Ich ahne ja auch schon wies weiter geht.
10 Stück digitalRead, von denen jeder einzelne 5 bis 6 mal mehr Takte
braucht als die ganze PeDa Entprellung und Störpulsunterdrückung
insgesamt für 8 Tasten (sofern die an einem Port angeschlossen sind).
Und die kann dann auch noch Autorepeat als zusätzliches Zuckerl.
Torben G. schrieb:> Das Codeschnittsel oben war auch nur eine Art Schnellschuss, um zu> zeigen, dass eine Entprellung des Interrupts kein Problem ist.
Und er zeigt sehr schön, daß es doch ein Problem ist.
Entprellen als Schnellschuß geht regelmäßig in die Hose, Du bist da
nicht der erste.
Man muß da schon deutlich mehr Gehirnschmalz reinstecken. Man kann aber
auch eine bewährte Lösung übernehmen.
Christoph Kessler (db1uq) schrieb:> Hab jetzt nicht alles gelesen
Hättest Du mal besser getan.
Die Interrupteingänge sind garnicht das Problem, der ATmega328 hat 23
davon.
Als ich mal nur noch einen einzigen A/D-Eingang übrig und wenig Platz
hatte, hab ich mit einem Widerstandsnetzwerk und eimen kleinen Stütz-C
gearbeitet (die Tasten in analoge Spannungen umgewandelt und dann
gemessen) Entprellung war recht zuverlässig: Bei 2 Messungen
nacheinander ungefähr gleicher Spannungswert unterhalb von Vmax -> Taste
erkannt. Lief ganz gut. Nur so als weitere Idee.