Hallo, ich habe das Forum nach Entprelltipps für Taster durchsucht und auch einiges gefunden. Jetzt vielleicht eine dumme Frage: Wenn ich einen Taster an INT0 (ATTiny12) benutze und der Interrupt bei steigender Flanke ausgelöst werden soll, muss ich dann den Taster noch entprellen? Meiner (noch formbaren) Meinung nach müsste doch der Interrupt bei der ersten steigenden Flanke ausgelöst werden, egal ob danach der Taster noch prellt, oder? Ich lasse mich aber auch belehren. Danke, Michael.
natürlich, durch das Prellen kann es sein, dass deine Interrrupt Routine mehrfach durchlaufen wird. Gruss Jürgen
ich würde auch die Entprellroutine von Peter D. nehmen. Farge: Was passiert denn, wenn ich als erstes in der ISR den Int. sperre und vor dem reti das Int.-Flag lösche; natürlich dann den Int. wieder freigebe? In der Zeit müsste sich das Prellen doch erledigt haben? Natürlich wird jetzt jdede noch so kleine Störung einen Tastendruck Int. auslösen. Quark
ich nehme für Tasten überhaupt keinen Interrupt. Alle 10ms mal vorbeischaun, ein Timer läuft doch sowieso in fast Programm.
Richtig... Das Problem ist nur, dass es immer wieder welche gibt, die sich wehren wie die Zicke am Strick, einen Timer zur globalen Programmsteuerung einzusetzen. ...
Tja, Danke erstmal für die angeregte Diskussion. Der Interrupt soll deswegen genommen werden, damit der Tastendruck den Tiny auch aus dem Sleepmode weckt. Oder hat da jemand eine bessere Methode? Da würde ich nämlich auf die Timerlösung umschwenken... Das "Projekt" sieht folgendermassen aus: Taster soll LED 5 oder 10 Sekunden einschalten. Wenn in dieser Zeit der Taster nicht gedrückt wird, soll die LED ausgehen und der Sleepmodus aktiviert werden.(Welcher mit dem nächsten Druck auf den Taster wieder verlassen werden soll. Gruß, Michael.
hi, da ich genau an diesen Punkt mich auch gerade befinde, schreibe ich auch mal ein paar zeilen dazu. Ich habe genau wie Michael vor per externem Interrupt, über einen Taster, den µC in den schlafmodus zu versetzen und ihn auch daraus wieder zu wecken. Dazu habe ich den Port auf "eingang" und internem "pull up" konfiguriert und den Taster auf der anderen seite an Masse geschlossen(Low-level interrupt). Bei meinem ATmega169, mit 4MHz getaktet, (*1) ist hierbei laut Datenblatt zu beachten, daß der zum wecken verwendete externe Interrupt INT0 nur durch "LOW Level detection" asynchron aufgerufen werden kann. D.h., daß gerade mal im "idle" Modus der benötigte Takt "I/O clk" für eine Flankengesteuerte Interrupterkennung vorhanden ist. Beim ATmega169 heißt das (*1), alle sleep modies erfordern eine Level gesteuerte Interrupterkennung. Leider hat dies auch zur Folge, daß der Interrupt fortwährend erkannt wird wie ein "Low Level" vorhanden ist, sprich: der Taster gedrückt ist. Dazu habe ich als Experiment mal nur eine globale Variable in der ISR inkrementieren lassen "int_counter++;" und sie dann ausgeben lassen. Ergebnis: durch ein normales Taster betätigen, wird die ISR rund 10000 mal aufgerufen. Hierbei spielt das Taster Prellen eher weniger die Rolle, dafür ist das entstehende Problem, der immer wieder aufrufen der ISR, aber umso gravierender. Zur Lösung fallen mir nur 2 Ansätze ein: a) das verhindern des wiederholten Aufrufes der ISR , oder b) das verhindern des wiederholten Codeausführen in der ISR . Ich habe mich für zweiteres entschieden. Dazu später evtl. mehr. mfg Sebastian (*1): wahrscheinlich bei den anderen AVRs auch ISR: Interrupt Service Routine, Interrupt handler
Und wenn man den Low-Level-Int "nur" zum Wecken nimmt?? Also der AVR macht seine Arbeit, gesteuert vom Timer-Int. Wenn er hinterher ist und nix mehr anliegt (Erkennung folgt weiter unten), löscht die "Gute-Nacht-Prozedur" das Int-Flag für Ext-Intin GIFR , aktiviert danach den Int in GIMSK und schickt den AVR schlafen. Bei Tastendruck wird der AVR geweckt und die zugehörige ISR aufgerufen. In dieser wird der ext-Int erstmal wieder deaktiviert (GIMSK). Das Flag in GIFR wird dann vor dem nächsten Aktivieren erst wieder gelöscht. Dann kann der Timer wieder arbeiten und in seinen nächsten "Runden" die Taste sicher erkennen und entprellen und das zugehörige Flag für das Hauptprogramm setzen. Weiterhin zählt der Timer ein weiteres Register runter, das bei Erreichen von 0 die "Gute-Nacht-Prozedur" aufruft. Dieses Register wird von allen aktiven Teilen des Programms gelöscht (oder auf einen definierten Wert gesetzt, falls 256 Warterunden zu "verschwenderisch" sein sollten), so dass es nur dann 0 werden kann, wenn 256 (oder so) Timerrunden stattgefunden haben, in denen das Hauptprogramm nix mehr zu tun hatte. Somit hat man eine sauber entprellte Taste und kann den AVR trotzdem schlafen schicken. Da der Schlafmodus ja zum Stromsparen genutzt wird, kommt nun die Frage, ob denn auch der Analogcomparator deaktiviert wurde... ...
Das hört sich ja interessant an. Aber wenn ich das aber richtig verstanden habe, dann kann ich - während meine LED-Prozedur läuft - keine weiteren Tastendrücke (sprich Interrupts) erkennen, sondern erst, wenn die Prozedur durchlaufen wurde und der AVR auf den Schlafmodus wartet ?!? und ja ... er wurde... er wurde... ;)
Während dein Programm (was immer es auch tut) läuft, löscht es immer wieder das Register, was zum "Einschlafen" Null werden muss. Daher kann der AVR nicht pennen gehen, solange "Arbeit anliegt". Und solange tuckert auch der Timer und kann mit einer in dem Timer-ISR laufenden Entprellroutine weitere Tastendrücke abfragen. Erst wenn dein Programm fertig ist wird der "Einschlafzähler" nicht mehr gelöscht und kann ablaufen. Wenn dann schonmal eine Timer-ISR periodisch aufgerufen wird, dann kann sie auch die gesamte LED-Steuerung übernehmen. Dinge wie Lauflicht, Ausgabe von Zuständen über blinkende LEDs usw. mach ich grundsätzlich in der Timer-ISR. Viele meiner Programme haben als Main nur RJMP main, da das gesamte Hauptprogramm in der Timer-ISR läuft. Dort kann man auch ein weiteres Zählregister mitlaufen lassen, welches darüber entscheidet, welche Programmteile in der jeweiligen "Runde" ausgeführt oder übersprungen werden. Damit erreicht man eine "Zeitscheibe", die die anliegenden Arbeiten halbwegs gleichmäßig verteilen kann. Z.B. Multiplexen eines mehrstelligen LED-Zifferndisplay, Tastaturabfrage, PWM-Erzeugung ADC-Auslesen... - Alles in der Timer-ISR, aber alles zu seiner Zeit. Sollten zeitaufwendige Berechnungen nötig sein, dann kann man diese im Hauptprogramm (zwischen den ISR-Aufrufen) ausführen, gesteuert über Flags, die von der Timer-ISR gesetzt werden und vom Hauptprogramm nach Erledigung des Jobs wieder gelöscht werden. ...
@CrazyHorse: "ich nehme für Tasten überhaupt keinen Interrupt. Alle 10ms mal vorbeischaun, ein Timer läuft doch sowieso in fast Programm." Es gibt auch Leute, bei denen alle Timer mit anderen Dingen beschäftigt sind. Die Idee, asynchrone spodradisch auftretende Vorgänge mit einem Interrupt zu behandeln, ist guter Programmierstil. Genau für so etwas sind Interrupts schließlich da! ;) Gruß, Michael
Danke, danke. So langsam dämmerts. Ich werde wohl mein Programmdesign komplett überarbeiten müssen, aber das scheint mir doch sinnvoll zu sein. Nochmal eine Frage zum externen INT0: (Ich kenne nur den Tiny12, denke aber, dass das bei den "größeren" genauso ist...) Ich hatte vor, den ext. INT über die steigende Flanke zu triggern. Sebastian (s.o.) hat einen Low-level. Macht das einen Unterschied? Gibts da Vor- oder Nachteile? Bei Sebastian müsste doch der INPUT dann (Wenn der Taster nicht gedrückt ist) an Vcc liegen, oder? Nimmt der AVR dann im Schlafmodus hier auch Strom auf? Danke und Gruß, Michael.
Flanke kann nicht wecken, da Flanke Takt voraussetzt. Takt ist aber abgeschaltet wenn der AVR schläft... Du musst also den Low-Level nehmen. Da der AVR Spannung hat, nimmt er keinen zusätzlichen Strom auf, wenn Pins auf H liegen. ...
@MSE Über "guten Programmierstil" kann man sicher streiten. Externe Ints sind für mich wertvolle Resourcen, die ich nicht an einen Taster verschwende (den hier beschriebenen Fall zum Aufwecken nehme ich davon mal aus). Ich baue ein Programm meist folgendermassen auf: Ein Timer (der Timer0) liefert den Grundtakt für das gesamte Programm, welche Zeit man dafür nimmt, hängt vom konkreten Fall ab. Daraus leite ich über Zähler in der main diverse Aktionen aus, im einfachsten Fall ist das ein linearer Ablauf in main. while (!timer_ready); //wird vom Timer0-Int gesetzt timer_ready=0; . . .Der Rest der Programms Vorteil der Sache: definierte, konstante Abarbeitungszyklen, auch nach Änderungen im Programm. Das ist mir wichtiger als min. mögliche Programmlaufzeit. Und in dem Zuge frage ich auch Schalter/Taster mit ab, die Prozessorbelastung dafür ist minimal. Wie du das siehst, ist mir herzlich egal, ich bin damit immer gut gefahren. Und es ist ja auch kein Dogma - wenn es wirklich mal so schnell wie möglich sein muss, kann man es ja auch weglassen. Aber eigentlich ist es immer so, dass der MC sowieso irgendwo warten muss.
@CrazyHorse: Bei mir wartet der MC oft nicht sondern arbeitet durch. Es kommt auf die Anwendung an, was gerade am günstigsten ist. Dein Ansatz hat sicher in vielen Fällen Vorteile. Gruß, Michael
Sag mir mal ein Beispiel, in welchem du 100% Auslastung hast. Ich kann mir keins vorstellen bzw. würde zu dem Schluss kommen, dass ich den falschen MC/zu geringe Taktfrequenz/zu hohe Programmlaufzeit habe.
Tja, ~90% komme ich auch manchmal, das ist aber schon fast der Grenzwert, den ich noch tolerieren würde, ich mag es nicht, im Grenzbereich zu arbeiten, kleine Erweiterungen können dann das ganze Design kippen. Und wenn die Abarbeitung der main max. 9ms dauert, was spricht dann dagegen, die mit 10ms zu synchronisieren? Baue ich noch Kleinkram ein, bleibt es bei den 10ms, zur Not könnte ich problemlos auf 15 oder 20ms wechseln. Oder aber aufteilen, wenn grössere Berechnungen anzustellen sind. In den ersten 10ms läuft eine Berechnung, beim nächsten Mal die andere. Es gibt auch Fälle, bei denen die Laufzeit von Programmteilen abhängig ist von den Eingangsparametern, das kann auch sehr unschöne Effekte hervorbringen Allgemeingültig kann man das alles nicht sagen, es gibt sicher Fälle, wo man davon abweichen muss, ist aber relativ selten. Wie gesagt, persönliche Vorlieben tun auch einiges zur Sache, mir persönlich ist ein geordnetes Zeitregime viel Wert. Und zur Anzahl der Timer: 10.000ende von Projekten mussten sich mit einem Timer (Standard-8051, der 2. ging meist für die serielle Schnittstelle drauf) zufrieden geben, und das ging und geht auch heute noch. Insofern bin ich mit dem AVR mit freiem Timer1 und (meist vorhanden Timer2) gut bestückt, wenn der Timer0 das Programm steuert. Und nebenbei kann er ja weiterhin übliche Timeraufgaben übernehmen, das entfällt ja deswegen nicht.
@HanneS : ok. Low-level-int nur um da nichts falsch zu machen: Ich gebe also (Beim TINY12) die Vcc auf Pin 6 (IN2) und 8 und schalte den internen Pullup dazu. Dann Taste ich die Vcc gegen Masse und der AVR erwacht. Alles richtig so? Nochmals Danke. Das ist alles sehr aufschlussreich für mich. Michael.
Quatsch! - hätte ich beinahe gesagt... Du legst Vcc auf Pin 8, dein interner Pullup zieht den Int-Eingang auf H, dein Taster beim Betätigen auf L. Würdest du da Vcc anlegen, würde dein Taster einen Kurzschluss verursachen. ... @Crazy: Es gibt Controller, deren Rechenzeit zu 100% ausgelastet ist. Und zwar mit Warteschleifen, da man sich vor der Verwendung eines Timers drückt (kennichnich, essichnich...) ;-) ...
Na, Danke! Das hätte bestimmt schön gekokelt... Wie sieht denn dann das ganze aus, wenn man statt eines Schließers einen Öffner nimmt? Dann sollte doch der interne Pullup abgeschaltet sein, damit er nicht direkt an Vcc liegt, sondern nur, wenn der Öffner in Ruhestellung ist, oder? Dann müsste man einen externen Widerstand zwischen Vcc und Öffner-Pin6 packen. Aber wie kommt dann die Masse ins Spiel? Ich hoffe, dann habe ichs gerafft... Gruß, Michael.
Wenn der Schalter/Tester einen Pegelwechsel verursachen soll, dann muss durch den geschlossenen Kontakt Strom fließen. Strom kostet meist Geld, also wäre es töricht, den Strom im unbetätigten Zustand zu verheizen.
@CrazyHorse: Da wir neulich darüber sprachen: Ich habe jetzt ein Problem, bei dem der Controller 24 h am Tag fleißig vor sich hin arbeiten soll und alle paar Tage wird vielleicht einmal eine Taste betätigt. In so einem Fall scheint es mir nicht unvernünftig, die Eingabe über einen Interrupt zu detektieren und nicht irgendwelche Polling-Abfragen durchzuführen, die zu 99,99% der Laufzeit stets mit negativem Ergebnis enden. Gruß, Michael PS: Ich will damit nichts gegen die von Dir aufgeführten Konzepte sagen, die lesen sich durchaus schlüssig und sind bestimmt bei Geräten, die häufig bedient werden, nicht verkehrt!
>der Controller 24 h am Tag fleißig >vor sich hin arbeiten soll und alle paar Tage wird vielleicht einmal >eine Taste betätigt. In so einem Fall scheint es mir nicht >unvernünftig, die Eingabe über einen Interrupt zu detektieren und nicht >irgendwelche Polling-Abfragen durchzuführen, die zu 99,99% der Laufzeit >stets mit negativem Ergebnis enden. Solange eine Abfrage praktisch überhaupt keine Rechenleistung benötigt, wie das bei Tastenpolling der Fall ist (*), ist es doch völlig wurscht, wie groß der Anteil an positiven und negativen Ergebnissen ist!? (*) Abschätzung: Tasten mögen alle 10 ms abgefragt werden; die Abfrageroutine hat 50 Instruktionen --> ca. 100 Taktzyklen --> bei 8 MHz Systemtakt ist die Routine innerhalb 12.5 µs abgearbeitet. 12.5 µs / 10 ms = 0.00125. Ergebnis: Das Tastenabfragen kostet stolze 0.125 % der gesamten Rechenleistung.
Richtig... Aber: Er möchte doch den Controller in den Tiefschlaf versetzen um Strom zu sparen (Batterie). Deshalb auch der Low-Level-Int zum Wecken. ...
ich zitiere mich mal selbst: "Externe Ints sind für mich wertvolle Resourcen, die ich nicht an einen Taster verschwende (den hier beschriebenen Fall zum Aufwecken nehme ich davon mal aus)." @MSE: -Du musst den Schalter entprellen (dann wartest du in der ISR und blockierst die restlichen Ints??) -ansonsten kann dir ein einziger Tastendruck ganz viele Interrupts auslösen (was dann wiederum einen Timer oder Warteschleifen verlangt, um die zu umgehen). -was machst du, wenn ein 2. oder 3. oder noch mehr Taster hinzukommen? Summa summarum: nichts gewonnen, Vorteile verspielt, schlechtes Geschäft gemacht. Und, wie schon gesagt, kann doch jeder machen, wie er will, solange es funktioniert. Ich will dich nicht bekehren, aber deine Lösung hat keine Vorteile.
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.