Forum: Compiler & IDEs Wakeup durch externen Interrupt


von Sacx (Gast)


Lesenswert?

Hallo zusammen

nach langer Zeit programmiere ich nun wieder was mit dem AVR Studio.
Bei meinem derzeitigen Projekt will ich meinen ATmega88 in den PowerDown 
versetzen, wenn die Leuchtstärke einer Fotodiode unter einen bestimmten 
Wert fällt. Die Leuchtstärke bestimme ich mittels eines A/D-Wandlers.
Befindet sich der uc nun im SleepMode soll er wieder aufwachen, wenn es 
hell wird.
Ich hab im Datenblatt auch gelesen, dass man die ext. Interrupts so 
definieren kann, dass sie entweder bei pos. Flag, neg. Flag, low level, 
logical change auslösen.
Desweiteren hab ich mir überlegt zwischen Sensor und ATmega eine Z-Diode 
zu schalten, das es aber einer bestimmten Spannung ein Durchbruch kommt 
und somit ein Signal an den ATmega kommt.

Welche Interrupteinstellung sollte ich denn in diesem Fall nehmen? Am 
besten das er bei pos. Flag aufwacht oder?

Kann die Interruptroutine überhaupt ausgeführt werden, wenn sich der uc 
im Powerdown befindet? Was muss ich dann beachten?

Hab irgendwo gelesen, dass ich dem Quarz eine Zeit zum Einschwingen 
lassen muss, damit keine Programmfehler auftreten.

Was passiert überhaupt im PowerDown Mode? Schläft da im Grunde alles?

So, jetzt ist erstmal genug mit Fragen :P

Danke schonmal im Voraus für eure Antworten ^^


Grüßle Alex

von Falk B. (falk)


Lesenswert?

@  Sacx (Gast)

>Wert fällt. Die Leuchtstärke bestimme ich mittels eines A/D-Wandlers.
>Befindet sich der uc nun im SleepMode soll er wieder aufwachen, wenn es
>hell wird.

Naja, dann darf er aber nicht zu fest schlafen. In allen wichtigen Sleep 
Modi ist der ADC tot.

>Ich hab im Datenblatt auch gelesen, dass man die ext. Interrupts so
>definieren kann, dass sie entweder bei pos. Flag, neg. Flag, low level,
>logical change auslösen.

Ja.

>Desweiteren hab ich mir überlegt zwischen Sensor und ATmega eine Z-Diode
>zu schalten, das es aber einer bestimmten Spannung ein Durchbruch kommt
>und somit ein Signal an den ATmega kommt.

Nicht sonderlich sinnvoll. Alles sehr ungenau und stromfressend.

>So, jetzt ist erstmal genug mit Fragen :P

Fast alle Antworten findest du im Artikel Sleep Mode.

MfG
Falk

von Sacx (Gast)


Lesenswert?

>>Desweiteren hab ich mir überlegt zwischen Sensor und ATmega eine Z-Diode
>>zu schalten, das es aber einer bestimmten Spannung ein Durchbruch kommt
>>und somit ein Signal an den ATmega kommt.
>
> Nicht sonderlich sinnvoll. Alles sehr ungenau und stromfressend.


Die Sache ist ja die... der Sensor sollte standardmäßig am A/D-Wandler 
hängen. Mit diesem messe ich die Leuchtstärke alle paar Minuten und 
bearbeite den Wert dann programmintern. Wenn der Sensor nun irgendwann 
einen zu geringen Wert liefert, möchte ich den PowerDown-Mode 
einschalten.

Davor muss ich ja noch den A/D-Wandler deaktivieren oder?

Wenn die Lichstärke nun wieder über einen Schwellenwert steigt, soll der 
Prozessor wieder aufwachen. Da die A/D-Wandlung ja deaktiviert ist, muss 
ich den Sensor gleichzeitig auch noch an INT0 oder INT1 (Eingang für 
ext. Int.) anschließen, damit der Prozessor wieder aufgeweckt wird.

Wenn ich nun nichts zwischen Sensor und uc schalte, könnte ja schon ein 
schwacher Lichteinfall für eine Flag sorgen oder? Deswegen hab ich mir 
überlegt was davorzuschalten, das wirklich erst aber einer bestimmten 
Lichtstärke ein Flag kommt.

Oder habt ihr eine Idee das iwie anders zu lösen?

von Bad U. (bad_urban)


Lesenswert?

Ich denke was Du brauchst ist ein Komparator mit Hysterese am Int-Pin. 
Damit kannst du Dir den Helligkeitswert einstellen und du bekommst auch 
ne gescheite Flanke.

Gruß
Bad Urban

von Peter D. (peda)


Lesenswert?

Du kannst den Watchdoginterrupt zum Aufwachen nehmen, z.B. alle 2s, dann 
ne Messung machen und wieder schlafen gehen.


Peter

von Falk B. (falk)


Lesenswert?

@  Sacx (Gast)

>hängen. Mit diesem messe ich die Leuchtstärke alle paar Minuten und

Alle paar Minuten? Da kann der uC ja 1.000.000mal dazwischen schlafen 
gehen.

>bearbeite den Wert dann programmintern. Wenn der Sensor nun irgendwann
>einen zu geringen Wert liefert, möchte ich den PowerDown-Mode
>einschalten.

Viel zu spät, siehe Sleep Mode.

>Davor muss ich ja noch den A/D-Wandler deaktivieren oder?

Wenn du Strom sparen willst.

>Wenn die Lichstärke nun wieder über einen Schwellenwert steigt, soll der
>Prozessor wieder aufwachen. Da die A/D-Wandlung ja deaktiviert ist, muss
>ich den Sensor gleichzeitig auch noch an INT0 oder INT1 (Eingang für
>ext. Int.) anschließen, damit der Prozessor wieder aufgeweckt wird.

kann man machen, ist hier aber wahrscheinlich nicht sinnvoll. Schick 
deinen uC in den Power Save Mode und miss alle paar Minuten das Signal, 
so wie sonst auch. Das spart genug Strom.

>Wenn ich nun nichts zwischen Sensor und uc schalte, könnte ja schon ein
>schwacher Lichteinfall für eine Flag sorgen oder? Deswegen hab ich mir
>überlegt was davorzuschalten, das wirklich erst aber einer bestimmten
>Lichtstärke ein Flag kommt.

???
Licht macht erstmal gar kein Flag, sondern bestenfalls eine Spannung an 
deinem Sensor. Die kann man per ADC oder Komparator auswerten. Die 
Software macht dann ggf. ein Flag draus.

MFG
Falk

von Sacx (Gast)


Lesenswert?

Vielen Dank für eure Antworten.

Ich ziehe es jetzt glaub vor einen Power Save Mode zu benutzen. Dieser 
wird ja über den Timer2 Interrupt aufgeweckt.

Nun könnte ich mit einem 32,768khz Quarz das Auftreten eines Interrupt 
alle 8Sekunden erreichen. Was für meinen Fall ausreichend ist. Der uc 
sollte nämlich die ganze Nacht "schlafen" bis ihn morgens die ersten 
Sonnenstrahlen komplett aus dem Schlaf reißen ^^

Wenn ich nun bei einem bestimmten Ereignis (z.b. das Verfahren eines 
Motors) die Interruptzeit für ein paar Sekunden auf 125ms setzen will, 
was muss ich dann machen? Muss ich in diesem Fall dann die Interrupts 
ausschalten, den Timer2 neu definieren, die Interrupts einschalten... 
warten bist der Motor verfahren ist, dann wieder ausschalten, alten Wert 
einstellen und wieder einschalten? würde das so in etwas funktionieren? 
oder gäbe es da noch einfachere Möglichkeiten?

von Falk B. (falk)


Lesenswert?

@  Sacx (Gast)

>Wenn ich nun bei einem bestimmten Ereignis (z.b. das Verfahren eines
>Motors) die Interruptzeit für ein paar Sekunden auf 125ms setzen will,
>was muss ich dann machen?

Man könnte den Presclaer von Timer 2 ändern. Wenn man den nicht als 
Zeitbasis braucht, ist das OK. Einfacher und besser, weil dann nämlich 
Timer 2 normal mit konstanter Frequenz weiterläuft, ist die Nutzung 
eines anderen Timers, z.B, Timer 0. Für die paar Sekunden schickt man 
den uC auch nicht mehr in den Sleep Mode, sonder arbeitet erst die 
"schnellen" Aufgaben ab.

> Muss ich in diesem Fall dann die Interrupts
>ausschalten, den Timer2 neu definieren, die Interrupts einschalten...
>warten bist der Motor verfahren ist, dann wieder ausschalten, alten Wert
>einstellen und wieder einschalten? würde das so in etwas funktionieren?

Ja, ist aber unnötig kompliziert und fehleranfällig.

MFG
Falk

von Sacx (Gast)


Lesenswert?

Okay das klingt vernünftig :)

Soweit ich das mitbekommen habe wird der Sleep Mode ja ständig neu in 
der Hauptschleife (while(1)) aufgerufen oder?

Die Konfiguration des Timers2 mache ich schon davor. Genauso wie die 
Ausschaltung des ADC Wandlers, weil dieser anscheinend einiges an Strom 
zieht.

Wenn nun der Timer2 überläuft, wird der Interrupt ausgeführt und ich 
wollte i inkrementieren lassen, damit ab nem bestimmten Zeitpunkt (ein 
paar Minuten) eine ADC Messung durchgeführt wird.

Beispiel:
1
ISR(TIMER2_OVF_VECT)  //mit Prescaler auf 4s pro OVF eingestellt
2
3
{
4
i++;
5
6
if(i==150)            //d.h nach 600s sprich 10min eine Messung
7
8
   {
9
   LDR_Messung();     //Unterprogramm zur Messung von 4LDRs und Vergleich
10
   }                  //der Werte. In diesem Unterprogramm müsste ich ja 
11
}                     //zu Beginn den ADC aktivieren und nach der Messung
12
                      //wieder deaktivieren oder?

Falls diese zwei von diesen vier Werten nicht "annähernd" 
übereinstimmen, soll der Motor gestartet werden und die Sensoreinheit 
wieder in Position bringen, weshalb dabei auch viele Messungen 
aufeinander folgen sollen um den Motor richtig zu verfahren.

Ich würde im Falle einer Abweichung also in ein weiteres Unterprogramm 
springen in dem dann, solange der Motor verfährt, mehrere Messungen 
durchgeführt werden. Dies könnte ich ja entweder mit dem Timer0 machen, 
den ich dann zu Beginn der Messung initialisieren müsste oder was ich 
mir grad überlegt habe einfach eine if-Schleife zu nehmen, die wenn alle 
4 Messwerte ungefähr den gleichen Wert liefern, den Motor stoppt und das 
Programm wieder in die while-Schleife lässt, wo das System wieder in den 
Power Save Mode gelangt.

Könnte das ungefähr so hinkommen?

Noch ne Frage:
Wenn nun der OVF-Interrupt ausgelöst wird und er meine Unterprogramme 
abarbeitet, läuft dann im Hintergrund der OVF weiter, also könnte 
während des einen Interrupts ein weiterer auftreten? Wenn ja, kann ich 
das ganze dann mit den Befehlen cli(); (Interrupts deaktivieren) zu 
Beginn der LDR Messung und sei(); (Interrupts aktivieren) am Ende der 
Messung bzw des Verfahrens des Motors unterbinden?

Grüße sacx

von Jan (Gast)


Lesenswert?

Ich finde da könnte man schon einen kleinen Zustandsautomaten draus 
machen:

Zustand 1: Schalfen
Der Microcontroller legt sich schlafen und wird über einen 
Timerinterrupt mit langsamer Zeitbasis gelegentlich geweckt um dann alle 
2 min (oder so ähnlich) in den Zustand 2 zu wechseln.

Zustand 2: Kontrollmessung
es wird eine ADC durchgeführt, Timerinterrupt kann dafür ja deaktiviert 
sein. Je nachdem ob der Schwellwert erreicht wird oder nicht, wird 
danach zurück in den Zustand 1 gewechselt, oder der Zustand 3 
aufgerufen.

Zustand 3: Ausrichten
Hier wird abwechselnd das Verfahrprogramm und ein Messprogramm 
aufgerufen. Hier muß die Zeitbasis schneller sein als in Zustand 1, un 
das ist meine ich der Vorteil der Statemachine - Abhänging vom zustand 
werden z.B. die Timer anders eingestellt.
Ist das Ausrichten zufridenstellend abgeschlossen, wird wieder in 
Zustand 1 gewechselt.

Gruß, Jan

von Falk B. (falk)


Lesenswert?

@  Sacx (Gast)

>Soweit ich das mitbekommen habe wird der Sleep Mode ja ständig neu in
>der Hauptschleife (while(1)) aufgerufen oder?

Ja.

>Die Konfiguration des Timers2 mache ich schon davor.

Ja.

> Genauso wie die Ausschaltung des ADC Wandlers, weil dieser anscheinend einiges 
an Strom
>zieht.

Nein, der wird IN der Hauptschleife an- und ausgeschaltet, natürlich 
gesteuert duch Bedingungen.

>   {
>   LDR_Messung();     //Unterprogramm zur Messung von 4LDRs und Vergleich
>   }                  //der Werte. In diesem Unterprogramm müsste ich ja
>}                     //zu Beginn den ADC aktivieren und nach der Messung
                      //wieder deaktivieren oder?

Nicht gut. Solche Sachen gehören nicht in einen Interrupt, das macht 
man in der Hauptschleife. Steht alles im Artikel.

>4 Messwerte ungefähr den gleichen Wert liefern, den Motor stoppt und das
>Programm wieder in die while-Schleife lässt,

Das Programm läuft fast immer in der Hauptschleife. Im Interrupt wird 
nur minimal Arbeit verrichtet und Flags gesetzt.

>Könnte das ungefähr so hinkommen?

Grob ja, im Detail nein. Siehe oben.

>Wenn nun der OVF-Interrupt ausgelöst wird und er meine Unterprogramme
>abarbeitet, läuft dann im Hintergrund der OVF weiter, also könnte
Ywährend des einen Interrupts ein weiterer auftreten?

Ja, wenn dein Unterprogramme zu lange dauern. Deshalb macht man das 
nicht so.

> Wenn ja, kann ich
>das ganze dann mit den Befehlen cli(); (Interrupts deaktivieren) zu
>Beginn der LDR Messung und sei(); (Interrupts aktivieren) am Ende der
>Messung bzw des Verfahrens des Motors unterbinden?

Unsinning, im Interrupt sind diese beim AVR sowieso gesperrt. Lies den 
Artikel Interrupt.

MFG
Falk

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.