Forum: Mikrocontroller und Digitale Elektronik 10 Taster an einem Interrupt


von Torben G. (Gast)


Lesenswert?

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?

von Rene S. (Firma: BfEHS) (rschube)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

> 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.

von Patrick C. (pcrom)


Lesenswert?

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

von Nur zu (Gast)


Lesenswert?

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 ...

von Ingo (Gast)


Lesenswert?

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!
1
ISR (Timer)
2
{
3
 static unsigned char Debounce = 0;
4
5
 if (Deboucne) Debounce--;
6
7
 if (Taster && !Debounce){
8
   ereignisflag = 1;
9
   Debounce = 200;
10
 }
11
}

Sehr wenig CPU Belastung

von Ingo (Gast)


Lesenswert?

Ich gehe von einem 1ms Timerinterrupt aus, d.h. 200ms Entprellzeit!

von Haro (Gast)


Lesenswert?

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.

von Torben G. (Gast)


Lesenswert?

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?

von Thorsten O. (Firma: mechapro GmbH) (ostermann) Benutzerseite


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

: Bearbeitet durch User
von Torben G. (Gast)


Lesenswert?

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.

von Max G. (l0wside) Benutzerseite


Lesenswert?

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

von spontan (Gast)


Lesenswert?

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.

von Erich (Gast)


Lesenswert?

>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

von Martin H. (marrtn)


Lesenswert?

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.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

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.

von Torben G. (Gast)


Lesenswert?

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?
1
unsigned long time;
2
3
void myInterrupt(){
4
5
 if(millis()-time < 200){
6
   time = millis();
7
   // Rest, alle Tasten abfragen
8
  }
9
}

von Ingo (Gast)


Lesenswert?

Ich habe doch schon eine Lösung vorgeschlagen!

von Karl H. (kbuchegg)


Lesenswert?

Torben G. schrieb:

>
1
> unsigned long time;
2
> 
3
> void myInterrupt(){
4
> 
5
>  if(millis()-time < 200){
6
>    time = millis();
7
>    // Rest, alle Tasten abfragen
8
>   }
9
> }
10
>


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.

: Bearbeitet durch User
von Thomas E. (thomase)


Lesenswert?

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.

von spontan (Gast)


Lesenswert?

Jetzt wird noch blöder.

Keine Zeit in der Main, da wahhhhhnsinnnnig viel zu tun, und dann im 
Interrupt Zeiten verbraten?

Gehts noch?

von Karl H. (kbuchegg)


Lesenswert?

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.

: Bearbeitet durch User
von Nur zu (Gast)


Lesenswert?

Wenn ich mir die entstandene Diskussion ansehe, scheint mir der HW 
Ansatz einschließlich HW Entprellung für Torben G. doch problemloser zu 
sein :)

von Karl H. (kbuchegg)


Lesenswert?

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 :-)

von Thomas E. (thomase)


Lesenswert?

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.

von Torben G. (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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.

von Christoph db1uq K. (christoph_kessler)


Lesenswert?

Hab jetzt nicht alles gelesen, mein erster Gedanke:
Man könnte einen Prioritätsencoder 74HC147 irgendwie ausnutzen.
http://www.nxp.com/products/logic/encoders/74HC147N.html

von Peter D. (peda)


Lesenswert?

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.

von Rainer U. (r-u)


Lesenswert?

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.

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.