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?
@ 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?
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