Guten Abend Forengemeinde, ich mach zur Zeit meinen Techniker. Im Mikrocontrollerunterricht stellte uns nun unser Lehrer folgendes Problem: Ihr habt nen Taster der eine LED schalten (toggeln) soll. Dieser Taster ist am Externen Interrupt 0 angeschlossen. Wie kann man softwareseitig verhindern, dass der Taster nachprellt und somit die LED mehrfach schaltet? Die Lösung lautet wohl cli(); als ersten Befehl in die ISR zu schreiben. Erst danach den togglebefehl für die LED. (Wir verwenden das STK 500 mit ATmega16) Ich kann es nicht so recht glauben und hoffe hier auf kompetente Antwort auf folgende Fragen: 1. Geht das wirklich so? Ich meine es werden doch während ISR Ausführung eh alle Interrupts standardmäßig gesperrt. 2. Wenn nein, wie gehts? (Ausser mit solch großem Aufwand wie die Entprellfunktion die hier in den Tutorials zu finden ist) 3. Ist es da nicht sinnvoller am Ende der ISR das GIFR Register zu bereinigen? 4. Wenn ich die ISR verlasse, wird dann mein Interrupt Flag automatisch wieder gesetzt? Würde mich freuen wenn mir bei diesen Fragen jemand Aufklärung leisten könnte. Grüße Alex
Durch Int0 wird in die ISR gesprungen. LED toggeln. Delay für die Länge Prellzeit warten. Da das INT0 Flag durch die Prellerei wieder gesetzt ist, vor Rücksprung also Verlassen der ISR noch das INT0 Flag "von Hand" löschen. Zurücklehenen und genießen.
Alexander Pl schrieb: > Die Lösung lautet wohl cli(); als ersten Befehl in die ISR zu schreiben. Wie Du selber schon bemerkt hast, werden beim Einsprung in eine ISR weitere Interrupts gesperrt. Daher ist ein cli() überflüssig. Entprellen heißt, nach einem Signal vom Taster eine gewisse Zeit zu warten und dann zu prüfen, ob er gedrückt oder geöffnet ist. Per Software wird man je nach Qualität des Tasters ca. 50 ms warten müssen. Einfach auf Verdacht die LED sofort an- oder auszuschalten geht nicht, da die ISR zu INT0 auch durch einen Störimpuls angesprungen werden kann. Alexander Pl schrieb: > 2. Wenn nein, wie gehts? (Ausser mit solch großem Aufwand wie die > Entprellfunktion die hier in den Tutorials zu finden ist) Um einen gewissen 'Aufwand' kommst Du nicht umhin. Dein Lehrer will eine Software-Lösung sehen, sodaß ich Dir eine Hardware-Lösung zeigen kann, ohne Deine Arbeit zu machen. Einen Taster per Interrupt auszuwerten, ist in der Regel dann sinnvoll, wenn gleichzeitig der µC aufgeweckt werden soll oder keine Zeit ist, um das Prellen des Tasters im zig-Millisekundenbereich abzuwarten. http://www.mino-elektronik.de/power_at90s/powerat90s.htm Hier kannst Du auch die realen Signale eines Tasters sehen.
Alexander Pl schrieb: > 1. Geht das wirklich so? Ich meine es werden doch während ISR Ausführung > eh alle Interrupts standardmäßig gesperrt. Nein, so geht es nicht. Ja, die Interrupts werden gesperrt. > 2. Wenn nein, wie gehts? (Ausser mit solch großem Aufwand wie die > Entprellfunktion die hier in den Tutorials zu finden ist) Genau mit einer Entprellung, wie im Tutorial beschreiben. > 3. Ist es da nicht sinnvoller am Ende der ISR das GIFR Register zu > bereinigen? Kann sein. Aber nur, wenn du ein Delay in der ISR hast. Das ist aber absoluter Unsinn. > 4. Wenn ich die ISR verlasse, wird dann mein Interrupt Flag automatisch > wieder gesetzt? Welches Flag? Ein Interrupt-Flag wird gesetzt, wenn das entsprechende Ereignis eintritt. Und zwar immer. Wird die ISR dazu aufgerufen, wird dieses Flag gelöscht. Tritt das Ereignis während der Ausführung der ISR wieder ein, wird es wieder gesetzt. Dann wird nach dem Verlassen der ISR diese nochmal aufgerufen. Alexander Pl schrieb: > Ihr habt nen Taster der eine LED schalten (toggeln) soll. Dieser Taster > ist am Externen Interrupt 0 angeschlossen. Wie kann man softwareseitig > verhindern, dass der Taster nachprellt und somit die LED mehrfach > schaltet? Das verhindert man, indem man den Interrupt gar nicht benutzt, sondern den Pin per Timer alle 1-10ms pollt. Entweder erzählt euch euer Lehrer Unsinn, weil er es nicht besser weiss oder es ist Ziel dieser Aufgabenstellung, dass ihr erkennt, dass es so nicht geht. Bzw., dass man sich mit dieser einfachen "Lösung" jede Menge Probleme aufhalst. Setze ein Delay von etwa 10ms in deine ISR, schalte deine LED und lösche vor dem Verlassen das INT0-Flag im GIFR. Dann wird es funktionieren. Aber, wie schon geschrieben, ist das ziemlicher Unsinn. Zu dieser Erkenntnis werdet ihr dann wohl im weiteren Verlauf des Kurses kommen. Und dann führt an einer vernünftigen Entprellung kein Weg mehr vorbei. mfg.
:
Bearbeitet durch User
Thomas Eckmann schrieb: > Setze ein Delay von etwa 10ms in deine ISR, schalte deine LED und lösche > vor dem Verlassen das INT0-Flag im GIFR. Dann wird es funktionieren. Nee, nee, das ist zu schlicht! Ein gedrückter Taster kann immer noch prellen, was dann wiederholt die LED schalten würde. Ich denke, das ist nicht beabsichtigt. Thomas Eckmann schrieb: > Und dann führt an einer vernünftigen Entprellung kein Weg mehr vorbei. Ein wenig Hardware ist dabei sehr vernünftig ;-)
Falls der uC nur dafür da ist, genau diese Aufgabe zu erledigen, könnte man eine Entprellroutine die ohne Interrupts auskommt in die ISR packen. Das ist jedoch die unsaubere Methode und wir spätestens bei Programmen die mehr als nur das machen zu interessantem verhalten führen. Sauber wäre, die ISR nur zum Wecken des uCs zu verwenden, dann im Hauptprogramm eine PIN abfrage und die normale Entprellroutine laufen lassen. INT0 muss jedoch noch innerhalb der ISR abgeschaltet werden, sonst wird dauernd wieder rein gesprungen. So bald die Entprellroutine gelaufen ist und ein Tastendruck erkannt wurde, muss PIN jedoch regelmäßig gecheckt werden und bei der nächsten 1 die erkannt wird INT0 wieder aktiviert werden. Den Grund für extra HW Aufwand sehe ich nicht.
DerDaniel schrieb: > ... und wir spätestens bei Programmen > die mehr als nur das machen zu interessantem verhalten führen. Wieso das denn, drohst Du mit diffusen Höllenqualen? Wenn man in der ISR andere Interrupts wieder zuläßt und für 50 ms den INT0-Eingang auf stabilen Zustand abfragt, ist das doch kein Problem. An anderer Stelle ein Flag für den Tastendruck zu setzen und es in einer Warteschleife abzufragen, blockiert den Prozessor ebenfalls und dauert genauso lange. Ich denke, wenn der TO das so hinbekommt, wird sein Lehrer sehr zufrieden sein.
Super! Danke Leute, aufgrund eurer Hilfe hab ich denk ich ne ganz passable Lösung gefunden. Echt geiles Forum ;) Gruß Alex
Alexander Pl schrieb: > Danke Leute, aufgrund eurer Hilfe hab ich denk ich ne ganz passable > Lösung gefunden. > Echt geiles Forum ;) Stelle die Lösung doch hier vor. Das könnte auch andere Leute als Deinen Lehrer interessieren.
Hi Abgesehen von einer Interruptverarbeitung für einen einfachen Taster verstehe ich nicht, wieso das Entprellen eines Tasters den µC blockieren soll. Also, Signal kommt und wird in ein Flag geschrieben. Dann einfach einen Zähler setzen, der im Timer heruntergezählt wird. (Geht auch mit Programmzyklus für den Anfang). Erreicht der Wert des Zählers die 0, ist der Eingang gültig und kann im Programm verwendet werden. Da braucht kein Interrupt gesperrt oder der Interrupt mit einer Schleife belegt werden. Also einfach mal den Pseudocode nachvollziehen IO-Interrupt: Signal kommt, Zeit und Bit setzen Zyklus: Zeit = 0 dann kein Ereignis und weiter Zeit -1 -> Zeit = 0, dann Status Bit übernehmen oder Timer-Interrupt: Zeit = 0 dann kein Ereignis und weiter Zeit -1 -> Zeit = 0, dann Status Bit übernehmen Ist also gar nicht so kompliziert.... Gruß oldmax
Martin Vogel schrieb: > Also einfach mal den Pseudocode nachvollziehen > > IO-Interrupt: > Signal kommt, Zeit und Bit setzen > > Zyklus: > Zeit = 0 dann kein Ereignis und weiter > Zeit -1 -> Zeit = 0, dann Status Bit übernehmen > > oder Timer-Interrupt: > Zeit = 0 dann kein Ereignis und weiter > Zeit -1 -> Zeit = 0, dann Status Bit übernehmen > > Ist also gar nicht so kompliziert.... Und das ganze so lange in einer Schleife bis man es verstanden hat. Dein "Pseudocode" ist mir unverständlicher als weggelassene Kommentare.
Alexander Pl schrieb: > Dieser Taster ist am Externen Interrupt 0 angeschlossen. Genau an dieser Stelle beginnt das Problem. Ein Taster, der von einem Bediener mit maximal 10Hz betätigt wird, gehört nicht an einen Interrupt. Und das hier schlägt dem Fass dann den Boden aus: Jupp schrieb: > Durch Int0 wird in die ISR gesprungen. LED toggeln. > Delay für die Länge Prellzeit warten. Ein delay_ms() in einer ISR ist Selbstmord. Denn der uC kann solange nicht anderes tun. Auch nicht auf einen anderen Interrupt reagieren. Und das ist z.B. dann hässlich, wenn es ein Timerinterrupt ist, der während der Prellzeit (die ja durchaus einige ms lang sein kann) mehrmals kommen könnte. Alexander Pl schrieb: > Die Lösung lautet wohl cli(); als ersten Befehl in die ISR zu schreiben. Nein, die Lösung ist, diese schäbig langsamen Taster in der Hauptschleife einzulesen und zu verarbeiten. Was? Ihr habt keine Hauptschleife? Dann ist die Lösung, erst mal das Softwarekonzept so umzustellen, dass es eine solche Hauptschleife gibt, und in dieser die ganze Arbeit (oder mindestens 95% davon) erledigt wird. Eine ISR ist immer so kurz wie möglich zu halten. Ein delay_ms() in einer ISR ist ein Kündigungsgrund. m.n. schrieb: > Wenn man in der ISR andere Interrupts wieder zuläßt und für 50 ms den > INT0-Eingang auf stabilen Zustand abfragt, ist das doch kein Problem. Es ist Murks. > Ich denke, wenn der TO das so hinbekommt, wird sein Lehrer sehr > zufrieden sein. Ich denke, dann hat er sich den falschen Programmierstil begebracht. Hoffentlich sagt ihm der Lehrer das dann auch...
:
Bearbeitet durch Moderator
Hi @Jupp Wo ist das Problem? kanst du mit Pseudocodes nicht umgehen? Das tut mir leid für dich, aber du hast ja zum Glück nicht das Problem zu lösen. Falls unverständlich dann etwas anders.
1 | Programmschleife: |
2 | tuwas1 |
3 | tuwas2 |
4 | tuwas3 |
5 | wenn Zeit>0 dann |
6 | Zeit = Zeit- 1 |
7 | Wenn Zeit = 0 dann invertiere Ausgang |
8 | ende wenn |
9 | Tuwas4 |
10 | fang von vorn an |
11 | |
12 | IO-Interrupt |
13 | Zeit = 200 |
14 | ende Interrupt |
Und wenn für die Entprellroutine ein Timer eingesetzt wird, kommt einfach der Wenn-Abschnitt in den Timer-Interrupt. Die Entprellroutine belastet den Zyklus kaum und ob nun noch ein Bit mit einer weiteren Bearbeitung eingesetzt wird, spielt auch kaum eine Rolle. Gern darfst du das in irgendeine Sprache packen... Gruß oldmax
:
Bearbeitet durch User
Lothar Miller schrieb: > Nein, die Lösung ist, diese schäbig langsamen Taster in der > Hauptschleife einzulesen und zu verarbeiten. Da ist ja das Allerletzte. Wenn das Programm mit einer Nebenschleife zu tun hat, wird der Tastendruck ja garnicht erkannt. Die Tastererkennung muß im Hintergrund ablaufen. Entweder zyklisch per Timer oder aber auch per zugeordnetem Interrupt, wenn man verstanden hat, wie das geht ;-)
Als Erstes sollte mal dediziert angegeben werden, ob der INT0 flanken- oder levelgetriggert eingesetzt werden soll. Das erfordert jeweils eine unterschiedliche Weiterverarbeitung des Events.... @Martin Vogel Ganz so einfach ist das nicht. Wenn es nur ein einzelner Stör-Spike war und die Zeit ist abgelaufen, wird bei deinem Prinzip auch ein Toggle ausgelöst.... du musst überwachen, ob der Eingang innerhalb des Zeitfensters ununterbrochen die Stabil-Bedingung erfüllt hat. Wenn du nur einen Merker setzt, bei z.B. der Hi-Lo_Flanke, heisst das nicht zwingend, dass dieser Zustand auch nach Ablauf der Zeit noch am Eingang anliegt. Das geht nur durch Levelüberwachung bzw. (was auf das Selbe rausläuft) über das Auschliessen eines weiteren Flankenevents innerhalb des Zeitfensters.
Martin Vogel schrieb: > Dann einfach > einen Zähler setzen, der im Timer heruntergezählt wird. (Geht auch mit > Programmzyklus für den Anfang). Erreicht der Wert des Zählers die 0, ist > der Eingang gültig und kann im Programm verwendet werden. Na solange will man doch nicht warten. Sobald der Kontakt das erste mal schließt solls losgehen. MfG Klaus
m.n. schrieb: > Da ist ja das Allerletzte. Wenn das Programm mit einer Nebenschleife zu > tun hat, wird der Tastendruck ja garnicht erkannt. > Die Tastererkennung muß im Hintergrund ablaufen. Entweder zyklisch per > Timer oder aber auch per zugeordnetem Interrupt, wenn man verstanden > hat, wie das geht ;-) Wenn man verstanden hat, wie das geht, dann programmiert man seine Software so, dass die Hauptschleife immer in z.B. maximal 10ms durchlaufen wird. Damit wird eine gefühlte "Echtzeit" auf Benutzereingriffe erreicht. Und dann braucht man das ganze Herumgemurkse mit einer Tastenauswertung im Interrupt nicht mehr. Und die Tastenerfassung kann ja durchaus in einem Dreizeiler in einer Interruptroutine gemacht werden. So wie es z.B. PeDa im Timerinterrupt macht. Dieser Programmierstil "Programmieren in einer Schleife" läuft übrigens weltweit zigmilliardenfach auf jeder SPS. Es ist so simpel, dass es jeder Schlosser kapiert. Dieser Schlosser programmiert da dann Zustandsautomaten, dass manchem uC-Programmierer die Ohren schlackern. Und er hat keine Angst vor diesen Automaten, weil er sie einfach Schrittketten nennt und mit Merkern abhandelt...
:
Bearbeitet durch Moderator
Hi @simpel du magst ja Recht haben, trotzdem ist es einfach. Dann eben beide Flanken mit Interrupt erfassen. Kommende Flanke: Zeit setzen, gehende Flanke Zeit löschen. So, nun muss das Signal stehen bleiben, damit die Zeit abläuft und der Übergang nach 0 erkannt und ausgewertet wird. Ist es nur ein Störimpuls, dann wird durch die Abfrage "Zeit > 0" schon gar nichts mehr bearbeitet. @Klaus Nun, das ist zwar der einzige Grund, warum ein mech. Kontakt in einer ISR erfasst werden soll, aber die Prellzeit musst du schon abwarten, sonst ist der Zustand ziemlich zufällig. Es müssen aber nicht 200 Programmzyklen sein, vielleicht reichen auch 10 oder 20. Wenn es im Timer bearbeitet wird, denke ich, das in der Regel 5 ms ausreichen, also eine Zeit von 5 bei entsprechnedem Timer-Interrupt. Die Diskussion ob Taster mit einer ISR zu erfassen sind oder ob Pollen völlig ausreicht, ist hier m. E. nicht zu führen, da es eine Aufgabe ist, die dem angehenden Techniker gestellt wird. gruß oldmax
Lothar Miller schrieb: > Dieser Programmierstil "Programmieren in einer Schleife" läuft übrigens > weltweit zigmilliardenfach auf jeder SPS. Es ist so simpel, dass es > jeder Schlosser kapiert. Dieser Schlosser programmiert da dann > Zustandsautomaten, dass manchem uC-Programmierer die Ohren schlackern. > Und er hat keine Angst vor diesen Automaten, weil er sie einfach > Schrittketten nennt und mit Merkern abhandelt... Die Aufgabe war aber nicht, eine SPS zu programmieren, sondern bei einem ATmega16 einen Taster an INT0 auszuwerten. An diese Vorgabe sollte man sich bei der Lösung schon halten.
Bei Aufruf der ISR habe ich die Ausführung des externen Interrupts gesperrt bis Ende der ISR... ISR(INT0_vect) { GICR|=(0<<INT0); //restliche Anweisung GICR|=(1<<INT0); } Funktioniert soweit tadellos.
m.n. schrieb: > Die Aufgabe war aber nicht, eine SPS zu programmieren, sondern bei einem > ATmega16 einen Taster an INT0 auszuwerten. Durchaus nicht. Alexander Pl schrieb: >>> Im Mikrocontrollerunterricht stellte uns nun unser Lehrer folgendes >>> Problem: >>> Ihr habt nen Taster der eine LED schalten (toggeln) soll. Dieser Taster >>> ist am Externen Interrupt 0 angeschlossen. Wie kann man softwareseitig >>> verhindern, dass der Taster nachprellt und somit die LED mehrfach >>> schaltet? Man kann diesen Interrupt-Pin als normalen Eingangspin verwenden... Alexander Pl schrieb: > Bei Aufruf der ISR habe ich die Ausführung des externen Interrupts > gesperrt bis Ende der ISR... Das brauchst du nicht, das macht der Interruptcontroller schon ganz allein... > Funktioniert soweit tadellos. Schon wieder falsches Zeug gelernt.
:
Bearbeitet durch Moderator
Lothar Miller schrieb: > Schon wieder falsches Zeug gelernt. Eine Taste per Interrupt abzufragen, erscheint vielen Anfängern als logisch. Solange, bis man gelernt hat, dass das nichts taugt. Das ist ein µC-Kurs in der Technikerschule. Im nächsten Schritt wird wahrscheinlich die einzelne LED zum Lauflicht ausgebaut. Dann sieht jeder, dass die Interruptabfrage Mist ist. Finde ich didaktisch völlig OK. Zumindest unter der Annahme, dass der Dozent kein Idiot ist. mfg.
Ich meinte vorrangig das Sperren des Interrupts in der ISR. Wobei diese Anweisung sowieso nichts bringt, weil sie nichts ändert : > GICR|=(0<<INT0); Hier wären Grundlagen zum Thema Bitmanipulation mit C recht gut. Thomas Eckmann schrieb: > Finde ich didaktisch völlig OK. Zumindest unter der Annahme, dass der > Dozent kein Idiot ist. Du hast recht und ich hoffe dass deine Annahme zutrifft.
:
Bearbeitet durch Moderator
Thomas Eckmann schrieb: > Das ist ein µC-Kurs in der Technikerschule. Im nächsten Schritt wird > wahrscheinlich die einzelne LED zum Lauflicht ausgebaut. Dann sieht > jeder, dass die Interruptabfrage Mist ist. Oder es wird der Taster durch einen Hallsensor ersetzt, der von einem drehenden Rad ganz kurze Impulse abgibt. Dann sieht man sofort, wie sinnvoll die Interuptabfrage ist ;-)
m.n. schrieb: > Oder es wird der Taster durch einen Hallsensor ersetzt, der von einem > drehenden Rad ganz kurze Impulse abgibt. Dafür gibt es 1. Zähler im uC und 2. prellt dieser Geber nicht... > Dann sieht man sofort, wie sinnvoll die Interuptabfrage ist ;-) Nicht einfach Kraut mit Rüben vergleichen. Natürlich kann ein Interrupt sinnvoll sein (sonst gäbe es sowas nicht). Aber eben nicht für eine Taste, die eine LED schaltet.
:
Bearbeitet durch Moderator
Lothar Miller schrieb: > Nicht einfach Kraut mit Rüben vergleichen. Gut. Dann lassen wir das mit der SPS, steuern kein Lauflicht an, und für die Abtastung der Raddrehzahl nehm ich einen prellenden Taster mit Nockenbetätigung ;-)
Hi Wenn es nur um kurze Impulse geht ist der Interrupt völlig ok. Wenn ich aber von Klimmzügen lese: Interrupt gesperrt, Delay in ISR und ähnliches Zeug, zeigt es mir, das der Sinn eines Interrupts nicht verstanden wurde. Wenn eine ISR "verlängert" wird, indem dort ein Delay abläuft, macht er keinen Sinn. Ich weiß, den Experten ist das auch klar, aber einem Anfänger nicht. Und leider sind auch manche Dozenten aus diesem Stadium noch nicht raus... @Alexander Pl Falsch ist eine ISR, in der eine Warteschleife abläuft. Interrupt heißt doch, auf etwas sofort zu reagieren. Etwas, das jederzeit und extrem kurz auftritt. Ein Tastendruck ist für einen Controller eine Ewigkeit, wenn er auch ohne Zeitschleifen auskommt. Und das ist, was ich angedeutet habe. Laß ihn in seiner Schleife laufen und frage nur Bedingungen ab. So wie das mit der Zeit angedeutet, kann man auch Ereignisbits nehmen und abfragen. Sind sie gesetzt, werden Subnroutinen abgearbeitet und die Bits gelöscht. So ist erst eine erneute Bearbeitung fällig, wenn dises Bit wieder gesetzt wird. Das sind die "Tuwas" Anweisungen. Wenn du davon ausgehst, das eine Tuwas- Anweisung mal grob geschätzt 10 Taktzyklen benötigt, dann verplemperst du mit jedem Aufruf bei 1 MHz Systemtakt mindestens 10 µs, wenn der Controller nur die Bedingungen abfragt, aber keine Aufgabe vorfindet. Wird in Tuwas auch noch bei erfüllter Bedingung etwas erledigt, verlängert sich die Zeit entsprechend der Anzahl der Takte, die deine Befehlsverarbeitung benötigt. Da aber nicht alle Tuwas-Anweisungen bei jedem Zyklus etwas ausführen, verteilt sich die Zeit und selbst umfangreiche Programme liegen selten über ein paar ms mit der Zykluszeit. Ersetz mal "Tuwas" mit "Tuwas wenn Event = 1". Das sollte es deutlich machen, und wenn du die Aufgabe erledigt hast setzt du das Event auf 0. So, und nun wieder dein Taster. Wenn bei jedem Zyklus einmal die Peripherie eingelesen wird, meinst du, du kannst deinen Taster so schnell betätigen, das er ein Fenster von ca. 10 ms verfehlt? Bei 8 MHz hättest du dann nur noch eine Zykluszeit bei 2,5 ms. Also, einen normalen IO- Taster mit Interrupt zu erfassen dient lediglich der Übung. Es gibt aber natürlich auch Ausnahmen, doch das führt hier zu weit. Gruß oldmax
m.n. schrieb: > Gut. Dann lassen wir das mit der SPS, steuern kein Lauflicht an, und für > die Abtastung der Raddrehzahl nehm ich einen prellenden Taster mit > Nockenbetätigung ;-) Dann lasse ich die Erfassung des Pins in einem 1ms-Timer-Interrupt (wie die Tastenerfassung eben auch) laufen. Die Auswertung des erfassten Ereignisses erfolgt in der Hauptschleife...
Alexander Pl schrieb: > Super! > Danke Leute, aufgrund eurer Hilfe hab ich denk ich ne ganz passable > Lösung gefunden. > Echt geiles Forum ;) Der TO hat schon lange eine Lösung, ist aber so undankbar, sie hier nicht zu posten. :-( MfG Paul
Paul Baumann schrieb: > Der TO hat schon lange eine Lösung, ist aber so undankbar, sie hier > nicht > zu posten. > :-( Kann man so nicht sagen und seine Lösung wurde schon einige Beiträge lang kommentiert. Alexander Pl schrieb: > Bei Aufruf der ISR habe ich die Ausführung des externen Interrupts > gesperrt bis Ende der ISR... > > ISR(INT0_vect) > { > GICR|=(0<<INT0); > > //restliche Anweisung > > GICR|=(1<<INT0); > } > > Funktioniert soweit tadellos.
Aha. Ich dachte nicht daß das die endgültige Lösung wäre. Aber: Jeder, wie er will und wie er damit zufrieden ist. Ich mache mir immer einen Timerinterrupt zurecht, denn einen zyklischen Aufruf kann man immer gebrauchen (und sei es, sich einen Uhrentakt abzuleiten). Am besten sind 10ms. Jetzt geht's los: Ich frage in diesem Interupt ab, ob ein (Tasten)-Pin auf L-Pegel gegangen ist. Wenn ja, zähle ich eine Variable um 1 hoch, sonst lasse ich die Variable auf Null. Wenn die Variable den Wert 5 erreicht hat, sage ich: "Das war ein ernstgemeinter Tastendruck!" und setze einen Merker. Im Hauptprogramm lasse ich dann die Tätigkeit ausführen, die bei dieser gedrückten Taste getan werden soll, setze Variable und den Merker wieder zurück und bin wieder für den nächsten Druck bereit. Hinweis: Es mag bessere und/oder jede Menge anderer Methoden geben. Das ist die von mir Verwendete und die funktioniert tadellos. MfG Paul
Paul Baumann schrieb: > Ich mache mir immer einen Timerinterrupt zurecht, denn einen zyklischen > Aufruf kann man immer gebrauchen (und sei es, sich einen Uhrentakt > abzuleiten). Am besten sind 10ms. > > Jetzt geht's los: > Ich frage in diesem Interupt ab, ob ein (Tasten)-Pin auf L-Pegel > gegangen ist. Wenn ja, zähle ich eine Variable um 1 hoch, sonst lasse > ich die Variable auf Null. Wenn die Variable den Wert 5 erreicht hat, > sage ich: "Das war ein ernstgemeinter Tastendruck!" und setze einen > Merker. > Im Hauptprogramm lasse ich dann die Tätigkeit ausführen, die bei dieser > gedrückten Taste getan werden soll, setze Variable und den Merker wieder > zurück und bin wieder für den nächsten Druck bereit. Klingt besser als die tuwas if Schleifen in dem unformatierten Text von hier: Martin Vogel schrieb:
Paul Baumann schrieb: > Das > ist die von mir Verwendete und die funktioniert tadellos. Genau so macht es im Grunde auch Peter Danegger, nur eben mit 8 Bits gleichzeitig... Siehe dort bei 3.3: http://www.mikrocontroller.net/articles/Entprellung
>> Das >> ist die von mir Verwendete und die funktioniert tadellos. Lothar Miller schrieb: > Genau so macht es im Grunde auch Peter Danegger, nur eben mit 8 Bits > gleichzeitig... Ja, ich weiß. Diese (meine) Methode habe ich aber davon unabhängig in Bascom realisiert, weil die vorgefertigte Möglichkeit (Debounce) einen Timer nutzt, den ich dann nicht mehr "für mich" habe. MfG Paul
Paul Baumann schrieb: > weil die vorgefertigte Möglichkeit (Debounce) einen Timer > nutzt, den ich dann nicht mehr "für mich" habe. Warum darf denn ein Timer nicht mehrere Sachen machen? Man erinnere sich an die Schule, Stichwort größter gemeinsamer Teiler. Z.B. ich brauche 20ms und 25ms Takt. Dann reicht dafür ein 5ms Interrupt: GGT(20, 25) = 5
Peter Dannegger schrieb: > Warum darf denn ein Timer nicht mehrere Sachen machen? Ich habe nicht behauptet, daß ein Timer nicht mehrere Sachen machen kann. Wie kommst Du darauf? Ich nutze ja den (oder manchmal auch die) Timer, um mehrere Sachen zu tun. MfG Paul
Hi @Jupp Da du scheinbar mit Beschreibungen nicht viel anfangen kannst, hilft dir vielleicht ein PAP zur besserem Verständnis. Und da du auch der einzige bist, dem Pseudocode nix sagt, adressiere ich mal diesen Programmablaufplan. Nicht perfekt, aber du sollst ja noch ein bisschen zum Lästern haben. @Alexander Pl Natürlich soll die Skizze dir auch ein wenig helfen. Mit einem PAP hast du dir schnell mal ein Abbild vom Ablauf geschaffen und es muss nicht immer ein Programm sein, um solche Skizzen zu erstellen. Papier und Bleistift hift da manchmal auch schon. Gruß oldmax
Hi ich sollte vielleicht den PAP auch anhängen.. sorry Gruß oldmax
Ich habe gemerkt, daß es deutlich zuverlässiger ist, auch das Loslassen zu entprellen. Muskeln werden nicht statisch gesteuert, sondern mit Nervenimpulsen, d.h. die Drückkraft schwankt ständig leicht, auch ohne Parkinson. Auch kann sich bei älteren Tastern eine Oxydschicht auf den Kontakten bilden oder Verschmutzungen, die kurze Unterbrechungen bewirken. Beide Wechsel zu entprellen ist sogar einfacher, man macht ein EXOR zwischen Eingangszustand und entprelltem Zustand. Bei Ungleich wird mit der Zeitbasis gezählt, z.B. 4-mal und dann übernommen.
In welcher Sprache ist das Programm geschrieben? Assembler? Ich könnte dir ein Programm zur verfügung stellen, falls es C oder Assembler ist.
Lothar Miller schrieb: > Genau so macht es im Grunde auch Peter Danegger, nur eben mit 8 Bits > gleichzeitig... > Siehe dort bei 3.3: > http://www.mikrocontroller.net/articles/Entprellung Den Code gibt es im Tutorial auch noch einmal. Mir leuchtet nicht ein, was der da machen soll. Ich habe mir das aufgezeichnet und Schritt für Schritt auf Papier iteriert, aber key_press für die Auswertung im "main" wird mMn nie verändert. Jetzt habe ich mir den Teil aus der ISR herauskopiert und key_pin mit 0b01111111 (active low) initialisiert (also eine Taste gedrückt, siehe in -> mov in der zweite Zeile vom loop, weil es ja kein I/O-Register ist; die restlichen Register sind mit 0 initialisiert) und steppe das im Debugger (Atmel Studio 6.2, Atmega8, Simulator) durch. Das Register r20 (key_press) ist immer 0. Da ändert sich auch nach dem 100. Loop nichts:
1 | .def iwr0 = r16 |
2 | .def iwr1 = r17 |
3 | .def key_old = r18 |
4 | .def key_pin = r19 |
5 | .def key_press = r20 |
6 | .def key_state = r21 |
7 | |
8 | ldi key_pin, 0b01111111 |
9 | |
10 | loop: |
11 | mov iwr0, key_old |
12 | mov key_old, key_pin |
13 | eor iwr0, key_old |
14 | com key_old |
15 | mov iwr1, key_state |
16 | or key_state, iwr0 |
17 | and iwr0, key_old |
18 | eor key_state, iwr0 |
19 | and iwr1, iwr0 |
20 | or key_press, iwr1 |
21 | |
22 | rjmp loop |
Da stimmt doch irgendwas nicht. Ich dachte auch, irgendwo gelesen zu haben, dass das Assembler-Beispiel eine Übersetzung aus C-Code ist, finde das aber nicht mehr. Eventuell hat sich ja da ein Fehler eingeschlichen? Aber eigentlich interessiert mich, wie da GEZÄHLT wird. Im Artikel steht, dass die Taste 4 mal als gedrückt erkannt werden muss, um als valide zu gelten. Meine Vermutung war, dass die Register als Schieberegister benutzt werden und ein gültiges Bit immer eins weitergeschoben wird, bis es als valides Bit in key_press landet. Auf dieser Vermutung habe ich eine eigene Lösung gebaut, die zwar eins, zwei Zeilen länger und eins, zwei Register mehr braucht, aber auch funktioniert. Aber dennoch - wie wird da gezählt? Kann mir da bitte jemand auf die Sprünge helfen? Danke und einen schönen Abend!
Hannes schrieb: > Da ändert sich auch nach dem 100. Loop nichts: Kann auch nicht. key_press signalisiert nicht den Zustand des gedrückt haltens. Es signalisiert den Übergang von losgelassen nach gedrückt. Jedes Drücken ergibt also nur ein Ereignis. Man will ja z.B., daß eine LED bei jedem Drücken wechselt und nicht, daß sie ständig flackert, solange man die Taste gedrückt hält. Die Routine ist absichtlich so geschrieben, daß man nach einem Reset erstmal loslassen muß, ehe ein Drücken erkannt werden kann. Hannes schrieb: > Im Artikel > steht, dass die Taste 4 mal als gedrückt erkannt werden muss, um als > valide zu gelten. Das ist nur bei der C-Routine der Fall.
:
Bearbeitet durch User
Guten Morgen! Aha, das probiere ich aus. Danke!
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.