Hallo, ich möchte einen Atmega8 über einen externen Interrupt (Int 0) mit einer steigenden Flanke ein- und ausschalten. Das Verständnissproblem, wenn ich in der ISR ausschalte, wie kann ich dann mit der selben ISR ihn wieder einschalten? Da würde ja das ein- und ausschalten gleichzeitig im ISR stehen!? Mein Ansatz: // Externer Interrupt 0 zum Ein- Ausschalten MCUCR |= (1<<ISC00) | (1<<ISC01); //steigende Flanke, INT0 GICR |= (1<<INT0); //INT0 Freigabe ISR(INT0_vect) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); } Danke für euere Hilfe.
Du brauchst einfach nur eine (volatile) globale Variable, in der Du den letzten Status speicherst. In der ISR schaust Du dann, ob gleich Null (dann z.B. einschalten), bei 1 dann ausschalten.
Martin schrieb: > Das Verständnissproblem, wenn ich in der ISR ausschalte, wie kann ich > dann mit der selben ISR ihn wieder einschalten? Da würde ja das ein- und > ausschalten gleichzeitig im ISR stehen!? Der Prozessor schaltet nicht in der ISR ein, der schaltet bei Auftreten der passenden Flanke am Eingang ein, und setzt dann die entsprechenden ISR-Flags, und macht dann ganz normal weiter. Wenn der innerhalb einer ISR in den sleep-modus gegangen ist, führt der zunächst die laufenden ISR zu Ende aus, und springt dann erneut in die ISR, um den neu aufgetretenen "Aufweck"-Interrupt zu bearbeiten. Aber wofür soll das alles gut sein? Oliver
@ Martin (Gast) >ich möchte einen Atmega8 über einen externen Interrupt (Int 0) mit einer >steigenden Flanke ein- und ausschalten. Das geht nicht, der ATmega8, kann nur mit einem Low Level Interrupt aufgeweckt werden, siehe Sleep Mode. ALternativ kann man den ATmega88 verwenden, der hat einen Pin Change Interrupt, mit dem geht das. >Das Verständnissproblem, wenn ich in der ISR ausschalte, wie kann ich >dann mit der selben ISR ihn wieder einschalten? Da würde ja das ein- und >ausschalten gleichzeitig im ISR stehen!? Die ISR bleibt leer, die Verarbeitung erfolgt im Hauptprogramm, siehe den Artikel oben. Mfg Falk
Euere Hilfe ist schneller als ich Zeit habe - Vielen Dank @ Falk Danke für den hilfreichen Link, im AVR-GCC-Tutorial fand ich keinen Link dazu. Ich habe nun folgenden Quelltext versucht: ISR(INT0_vect) { PORTB &= ~(1 << PIN2); //LED an _delay_ms(1000); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); GICR &= ~(1 << INT0); // externen Interrupt _delay_ms( 1000 ); GICR |= (1<<INT0); PORTB |= (1 << PIN2); //LED aus } // Externer Interrupt 0 zum Ein- Ausschalten MCUCR |= (1<<ISC01); //fallende Flanke, INT0 GICR |= (1<<INT0); //INT0 Freigabe Wenn ich eine negative Flanke auf den Eingang (INT0 / PD2) gebe, geht er in die ISR und schaltet die LED an, soweit so gut. Wenn die zweite negative Flanke kommt, sollte der Prozessor seine Arbeit nach dem sleep_mode() Befehl wieder aufnehmen und die LED ausschalten? Leider bleibt die LED dauerhaft an. Wo könnte das Problem liegen?
Und die Frage ist, warum geht die LED nicht beim sleep_mode() Befehl aus? Es scheint als geht der Controller nicht in den Schlaf Modus.
@ Martin (Gast) >Ich habe nun folgenden Quelltext versucht: Mit vielen Fehlern. In ISRs benutzt man KEINE Warteschleifen, schon gar nicht 1s. Auch wenn das hier nur ein Test ist, der Ansatz ist Murks. Ausserdem schaltet man in der IST nicht wieder in den Sleep Mode, das gibt aus verschiedenen Gründen Kuddelmuddel. Schau in den Artikel Sleep Mode, dort ist in einem Beispiel fast genau das drin, was du willst. >// Externer Interrupt 0 zum Ein- Ausschalten > MCUCR |= (1<<ISC01); //fallende Flanke, INT0 > GICR |= (1<<INT0); //INT0 Freigabe Und wenn du den Artikel so das Datenblatt deines ATmega8 mal lesen würdest, wäre dir aufgefallen, dass fallende FLANKE und Power Down nicht zusammenpasst. Hab ich nun schon zweimal geschrieben. MfG Falk
@ Frank Danke für deine Antwort. Ich bin noch blutiger Anfänger in dem Bereich, also verzeih mir bitte die unqualifizierten Fragen, aber ich möchte mich einarbeiten. ISR(INT0_vect) { if(aus == 0) aus = 1; else aus = 0; } //Im Hauptprogramm uint8_t aus = 0; if(aus == 1) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_mode(); // in den Schlafmodus wechseln aus=0; } Das Aus- und Anschalten funktioniert soweit. Bis das Hauptprogramm durchlaufen wird vergehen ca. 2 - 15 min (einstellbare Farbwechselgeschwindigkeit von RGB Led's). Das heißt, wenn ich im Hauptprogramm nur an einer Stelle if(aus == 1) abfrage und dann ausschalte, kann es im Extremfall bis zu 15 min dauern. Ich könnte die if Anweisung mehrfach kopieren und damit öffter abfragen, was wohl ziehmlicher Pfusch wäre. Gibt es eine andere Möglichkeit, damit der Controller sofort auschaltet? Und muss ich vor sleep_mode(); die LED's (alle Ausgänge) manuell ausschalten? Denn der Controller scheint dieß nicht automatisch zu machen.
Martin schrieb: > Bis das Hauptprogramm durchlaufen wird vergehen ca. 2 - 15 min > (einstellbare Farbwechselgeschwindigkeit von RGB Led's). Das heißt, wenn > ich im Hauptprogramm nur an einer Stelle if(aus == 1) abfrage und dann > ausschalte, kann es im Extremfall bis zu 15 min dauern. Das solltest Du ändern. Du hast warscheinlich 100kB Code per Copy&Paste hintereinander geklatscht, der fast immer was ähnliches macht. Sowas verbraucht nicht nur Unmengen an Code, es ist auch schwer verstehbar und erweiterbar. Du mußt Deinen Code in kleine Aufgaben aufteilen, die dann in einer Schleife aufgerufen werden. Dann kann man in der Schleife auch ne Taste abfragen und hat sofort ne Reaktion. Warscheinlich ist es nur eine einzige Aufgabe: für eine bestimmte Zeit bestimmte Werte als PWM ausgeben. Dann ist die Sache ganz einfach. Du legst alles in einer Tabelle (Array) ab und die Funktion holt sich alles aus der Tabelle. Dann wird der Tabellenindex hochgezählt und die Loop macht weiter. Peter
@ Martin (Gast) >@ Frank Who is this? >ISR(INT0_vect) >{ if(aus == 0) aus = 1; else aus = 0; } >//Im Hauptprogramm >uint8_t aus = 0; >if(aus == 1) >{ > set_sleep_mode(SLEEP_MODE_PWR_DOWN); > sleep_mode(); // in den Schlafmodus wechseln > aus=0; >} Das passt so nicht. Denn der uC macht folgendes. Er geht in den Sleep Mode. Der Low Level Interrupt weckt ihn auf. Er springt in den Low Level Interrupt, aus ist immer noch 1! aus wird in der ISR auf 0 gesetzt Er springt zurück zum Hauptprogramm und setzt aus=0, was aber dort sinnlos ist, auch wenn es keinen Schaden macht. >Das Aus- und Anschalten funktioniert soweit. Schön. >Bis das Hauptprogramm durchlaufen wird vergehen ca. 2 - 15 min >(einstellbare Farbwechselgeschwindigkeit von RGB Led's). Das heißt, wenn >ich im Hauptprogramm nur an einer Stelle if(aus == 1) abfrage und dann >ausschalte, kann es im Extremfall bis zu 15 min dauern. Falscher Ansatz. Richtig macht man es mit Multitasking. Klingt kompliziert, ist es aber nicht. Lies den Artikel und schau dir das Beispiel an. Dann ändere dein Programm. >Ich könnte die if Anweisung mehrfach kopieren und damit öffter abfragen, >was wohl ziehmlicher Pfusch wäre. Ja ;-) >Gibt es eine andere Möglichkeit, damit der Controller sofort auschaltet? Siehe Artikel Multitasking. >Und muss ich vor sleep_mode(); die LED's (alle Ausgänge) manuell >ausschalten? Wenn du Strom sparen willst. > Denn der Controller scheint dieß nicht automatisch zu >machen. Warum sollte er das? MFG Falk
Erstmal danke an Peter und Falk für euere Hilfe. Falk Brunner schrieb: > Richtig macht man es mit Multitasking. Wieder ein sehr guter Link. Ich habe das Kooperative Multitasking versucht umzusetzen, sprich alle Funktionen sind sehr kurz gehalten und damit klappt es sehr gut. Da ich festgestellt habe, dass mein "Programmierstil" bei weitem nicht ideal ist, würde ich mich freuen wenn ihr mal drüberfliegen könntet und mir Tips zu Verbesserung geben könntet. (C- File im Anhang) Eines Vorweg, das Programm funktioniert und erfüllt folgendes: - Ein- und Ausschalten über einen "Klatschschalter" an Int0 - Bei Neustart startet eine kurze Farb Demo der RGB Leiste - Danach werden zufällige Farbverläufe gestartet (Hauptaufgabe) - Die Geschwindigkeit der Farbverläufe ist über einen Poti einstellbar - steht der Poti auf "ganz langsamm" (Halt) wird der Farbverlauf gestoppt - beim ausschalten im Halte-Modus, wird die "Haltefarbe" gespeichert und beim Wiedereinschalten wieder geladen (falls der Poti noch auf "halten" steht) Interessant wäre noch eine automatische Abschaltung nach 2 Stunden. Mein Ansatz war, den Timer1 zu nutzen. Allerdings einfach eine Variable bis X hochzählen, damit bekommt man keine 2h hin. Was meint ihr? Vielen Dank für eure Geduld und Mühe.
@ Martin (Gast) >mir Tips zu Verbesserung geben könntet. (C- File im Anhang) Zuviele Leerzeilen, das zerreißt den Code. >Interessant wäre noch eine automatische Abschaltung nach 2 Stunden. >Mein Ansatz war, den Timer1 zu nutzen. Richtig. Du hast doch aber schon einen Timer für die PWM, denn kann man problemlos für mehrere Sachen gleichzeitig nutzen. > Allerdings einfach eine Variable > bis X hochzählen, damit bekommt man keine 2h hin. Was meint ihr? Wo ist das Problem? Dein jetztiger Timerinterrupt läuft mit 25,6kHz, macht 25.600 Zählschritte/s, bzw. 92.160.000 Schritte/h. Mit einer 32 Bit Variablen Null Problemo. Ansonsten sieht den Programm schon recht gut aus. MfG Falk
Falk Brunner schrieb: > Dein jetztiger Timerinterrupt läuft mit 25,6kHz, > macht 25.600 Zählschritte/s, bzw. 92.160.000 Schritte/h. Mit einer 32 > Bit Variablen Null Problemo. Du hast Recht, es funktioniert einwandfrei. Nun wollte ich das ganze noch mit #define machen: #define ausschaltzeit 1 //in Minuten #define off ( F_PWM*PWM_STEPS*60*ausschaltzeit ) //Berechenet die Standby Zeit in Systemtakte um Dummerweise scheint in dem Fall das "off" < 32 Bit zu sein, da der Compiler integer overflow anzeigt. Habe leider im Forum nichts in der Richtung gefunden. Besteht die Möglichkeit "größere Textzuweisungen" (define) zu machen?
@ Martin (Gast) >Dummerweise scheint in dem Fall das "off" < 32 Bit zu sein, da der >Compiler integer overflow anzeigt. Versuchs mal mit #define F_PWM 100L MFG Falk
Falk Brunner schrieb: > Versuchs mal mit > > #define F_PWM 100L Ich habe es soeben erfolgreich getestet - nur weiß ich leider nicht was das "L" bewirkt. Könntest du mir das bitte noch erklären?
> nur weiß ich leider nicht was das "L" bewirkt.
Die Konstante wird damit vermutlich im Format "Long" festgenagelt.
MfG
Falk Brunner schrieb: > http://www.mikrocontroller.net/articles/Bitmanipul... Alles klar, ich habs verstanden. Damit wäre mein erstes kleines Projekt erfolgreich umgesetzt. Hat zwar viel Zeit in Anspruch genommen aber ich hab einiges gelernt - auch Dank eurer Hilfe. Ich werde mich nun mal an ein LCD Display wagen. Ich hoffe ich kann auf euch zählen ;-) Vielen Dank. Martin
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.