Hallo,
Aus einem Attiny13 soll ein Würfel entstehen.
Ein problem ist jedoch noch das INT0 nur 1 mal auslöst.
Zunächst wartet der Controller auf den 1. Tastendurck,
dann wird ISR(INT0_vect) ausgeführt.
Soweit ist alles Ok,
Nun bekommt der Timer er seine Energie:
PRR&=~(1<<PRTIM0); //Power to The Timer!
nun wird der Timer Interrupt zugellassen
TIMSK0|=(1<<TOIE0);
Danach wird der Timer gestartet,
TCCR0B|=((1<<CS02)|(1<<CS00)); //Prescaler=1024, Timer-Start
Da der Controller mit 128KHz läuft sollte er jede Sec um 128 Hochzählen
Folglich sollte er bei Normalem betrieb nach 2Sec überlaufen.
Nun Leuchten die LEDs.
Nach ca 2 Sec werden sie abgeschaltet.
Problem ist nun dass der Controller nie mehr aufwacht.
Ich sehe keinen Grund warum es kein 2. mal möglich sein sollte.
INT0 ist doch Low-Level Interrupt?
Kann mich jemand aufklären?
Uwe S. schrieb:> Du produzierst ein Dead-Lock über die INT0 AnweisungGIMSK&=~(1<<INT0); ,> siehe Datenblatt "7.1 Sleep Modes".>> Ist das klar ?
Ne ich verstehs nicht,
"
Bit 6 – INT0: External Interrupt Request 0 Enable
When the INT0 bit is set (one) and the I-bit in the Status Register
(SREG) is set (one), the external
pin interrupt is enabled. The Interrupt Sense Control0 bits 1/0 (ISC01
and ISC00) in the MCU
Control Register (MCUCR) define whether the external interrupt is
activated on rising and/or falling
edge of the INT0 pin or level sensed. Activity on the pin will cause an
interrupt request even
if INT0 is configured as an output. The corresponding interrupt of
External Interrupt Request 0 is
executed from the INT0 Interrupt Vector."
Ich Disable ihn doch nur.
Nach dem Timerüberlauf wird er wieder Enabled
Hab es nun Mehrfach durchgelesen, sehe in 7.1 keinen Grund für das
Problem.
Das Bit INT0 in GIMSK dient zum Enablen/Disablen des Extreren
Interrupts.
Wenn ich es rücksetze ist der Interrupt disabled, beim Setzen wird er
Enabled.
Ich kann mir das Deaht-Lock nicht vorstellen, aber es scheint
aufzutreten.
Auch wenn ich auf Enable/Disable INT0 verzichte löst er kein 2. mal aus.
Matze schrieb:> Ne ich verstehs nicht,
Ich auch nicht.
Uwe S. schrieb:> und genau diese Annahme>> Nach dem Timerüberlauf wird er wieder Enabled> ist falsch. Bitte lese das im Datenblatt nach.
Und was ist daran falsch?
mfg.
setzt die Bits im Regster MCUCR SM[1:0]=10 und SE=1, dann gilt in der
Tabelle 7.1 die markierte Zeile.
Und die wichtigste Info aus der Tabelle und dem erklärendem Text ist,
dass es nur ZWEI Quelle für die Beendigung gibt und der Clock
abgeschaltet ist.
Sprichwort "Wo kein Clock, da auch kein Timer!"
So genau sollte man das Datenblatt dann doch lesen können.
Uwe S. schrieb:> Sprichwort "Wo kein Clock, da auch kein Timer!"
Ich verstehe nicht, das Problem ist dass der INT0 des Externen Pins INT0
(PB1) der im Normalfall als LOW-Level-Interrupt konfiguriert ist nicht
ausgelöst wird.
In der ROT mirkierten Zeile der Tabelle wird der Externe INT0 als
Interruptquelle im Power-Down-Modus genannt.
Der Timer läuft, nach 2 Sec werden die LEDs abgeschaltet.
Wo soll da dass Problem sein?
Matze, mit dem gezeigten Code aus dem ersten Post, läuft der Timer
nicht.
Warum habe ich erläutert, wenn das nicht verständlich ist, könnte jemand
Anderes das Problem "Dead-Lock" evtl. besser beschreiben ?
Mein Tip:
Komplett wegschmeißen und neu machen.
Der Mainloop ist furchtbar.
Die Interrupt-Routine macht viel zu viel. Auch gruselig.
Meckern ist immer einfach, deshalb auch ein paar anregungen.
Versuche es dann mal so:
- Timer einrichten und eine Variable für den Sleep hochzählen (INT).
- Im Main die Taste abfragen und darauf reagieren.
- Wird die Taste gedrückt, den Sleep-Zähler zurücksetzten.
- Im Main auch den Sleep-Zähler prüfen und gegebenenfalls "einschlafen".
- Tasten-Interrupt einrichten der nur das Aufwachen auslöst.
- Tasten-Interrupt-Routine muss vorhanden sein, kann aber leer bleiben.
- Nach den Aufwachen (direkt nach dem SLEEP Aufruf) nicht vergessen den
Sleep-Zähler zurückzusetzen.
- Und vor dem SLEEP nicht vergessen die LEDs abzuschalten.
Versuche es mal. Ich unterstütze dich gern auf den Weg dahin. Habe auch
schon mehrere ATtiny13 Würfel selbst gechrieben.
Uwe S. schrieb:> Matze, mit dem gezeigten Code aus dem ersten Post, läuft der Timer> nicht.> Warum habe ich erläutert, wenn das nicht verständlich ist, könnte jemand> Anderes das Problem "Dead-Lock" evtl. besser beschreiben ?
Ja, dass ist mir selbst schon aufgefallen.
Matze schrieb:> Stopp, hier stimmt was nicht: set_sleep_mode(SLEEP_MODE_PWR_DOWN);> sleep_mode();> Steht nicht in Main, sondern in am Ende des ISR(TIM0_OVF_vect).
Ursprünglich war der SLEEP-MODE auch schon im Timer-ISR, ich hatte es
auf der Suche nur mal umgestellt, und bemerkt dass es keinen Sinn macht
:)
Ich dachte du beschreibst den Grund für das einmalige Auslösen des INT0.
Uwe S. schrieb:> Hi,>> Du produzierst ein Dead-Lock über die INT0 AnweisungGIMSK&=~(1<<INT0); ,> siehe Datenblatt "7.1 Sleep Modes".>> Ist das klar ?
Aber selbst in dem Zusammenhang versteh ich es nun noch nicht,
Dass disablen des EXT-INT (an sich) stoppt doch den doch Timer nicht?
Uwe K,
das ist auch noch ein Fehler in deiner Programmskitze.
Der INT0 ist ein LEVEL Interrupt, man kann also nicht
> Tasten-Interrupt-Routine muss, kann aber leer bleiben.
Denn wir sofort nach dem verlassen der Interrupt-Routine, diese wieder
aufgerufen.
Also, entweder INT0 Interrupt sperren, oder auf eine Flankenwechsel
warten.
Man,
Der Timer läuft nicht! da es in diesem Sleepmode keinen Takt gibt und
dieser nicht als "Aufwach Quelle" angegeben ist, wie sollte er auch; er
funktioniert jetzt gerade nicht.
Matze schrieb:> Aber selbst in dem Zusammenhang versteh ich es nun noch nicht,> Dass disablen des EXT-INT (an sich) stoppt doch den doch Timer nicht?
Hallo,
ich sehe dein Verständnis Problem. Durch dieses Haupt-Programm
1
while(1)
2
{
3
//Nun 30Sec Warten...
4
//Nun in Power Down-Mode
5
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
6
sleep_mode();
7
}
verweilt der Atmel µC fast Immer im Power Down Schlafmodus und kann nur
durch den INT0 = GND aufwachen.
Dann führt er einmalig den Code in der INT0 Interrupt-Routine aus. Diese
schaltet den INT0 Level-Interrupt aus, alles weitere ist nicht wichtig
für die weitere Betrachtung.
Bei Verlassen der INT0 Interrupt-Routine verfällt er sofort wieder in
den Power Down Schlafmodus aus dem er nie wieder aufwachen kann.
Da hilft nur noch ein Reset - den Reset-Pin = GND.
Uwe S. schrieb:> Uwe K,>> das ist auch noch ein Fehler in deiner Programmskitze.>> Der INT0 ist ein LEVEL Interrupt, man kann also nicht>> Tasten-Interrupt-Routine muss, kann aber leer bleiben.> Denn wir sofort nach dem verlassen der Interrupt-Routine, diese wieder> aufgerufen.>> Also, entweder INT0 Interrupt sperren, oder auf eine Flankenwechsel> warten.
Was ist schon Perfekt. Noch besser den PCINT1 verwenden.
Vor dem Schlafen einschalten, danach wieder ausschalten.
Uwe S. schrieb:> verweilt der Atmel µC fast Immer im Power Down Schlafmodus und kann nur> durch den INT0 = GND aufwachen.> Dann führt er einmalig den Code in der INT0 Interrupt-Routine. Diese> schaltet dann den INT0 Level-Interrupt aus.> Bei verlassen der INT0 Interrupt-Routine verfällt er sofort wieder in> den Power Down Schlafmodus aus dem er nie wieder aufwachen kann.> Da hilft nur noch ein Reset - das Reset-Pin = GND.
Du hast schon recht, der Timer läuft im Oben angegebenen Programm nicht,
es sollte so aussehen.
Dies ändert am Problem aber garnichts, der Timer läuft.
Dies zeigt sich durch das Rücksetzen der LEDs, nur aufwachen tut er nie
wieder.
Uwe K. schrieb:> Versuche es mal. Ich unterstütze dich gern auf den Weg dahin. Habe auch> schon mehrere ATtiny13 Würfel selbst gechrieben.
Danke, finde es so wie es ist schon sinvoll, du würdest also statt der
Timer-ISR, das Timer-Interrupt-Flag abfragen?
Habe eine Aufgabe nochnie so unterschätzt.
Uwe S. schrieb:> Du produzierst ein Dead-Lock über die INT0 AnweisungGIMSK&=~(1<<INT0);
Nö, sondern anders.
Wenn der INT0_vect endet, geht er zur Mainloop zurück und die macht
sleep. Damit stoppt der Timer und Du kriegst nie nen Timerinterrupt.
Uwe S. schrieb:> Bei Verlassen der INT0 Interrupt-Routine verfällt er sofort wieder in> den Power Down Schlafmodus aus dem er nie wieder aufwachen kann.> Da hilft nur noch ein Reset - den Reset-Pin = GND.
Ja. jetzt sehe ich es auch.
Matze schrieb:> ISR(TIM0_OVF_vect)> {> TCCR0B&=~((1<<CS02)|(1<<CS00)); //Timer-Stop> PORTB&=~ ((1<<PB0)|(1<<PB2)|(1<<PB3)|(1<<PB4)); //Löchen> TCNT0=0x00; //Timer-Register zurück> PRR|=(1<<PRTIM0); //Timer Aus> // GIMSK|=(1<<INT0); //INT0 Interrupt enable> set_sleep_mode(SLEEP_MODE_PWR_DOWN);> sleep_mode();> }
Was soll das denn? Wie willst du da wieder rauskommen? In der ISR sind
die Interrupts abgeschaltet. Da gibt es keinen INT0.
mfg.
Thomas Eckmann schrieb:> Was soll das denn? Wie willst du da wieder rauskommen? In der ISR sind> die Interrupts abgeschaltet. Da gibt es keinen INT0.>> mfg.
Ja, das ist die Idee, natütlich springt er nicht zwischen 2 gleich
Priorisierten Interrupts!
Nutze nun eine globale volatile variable in ihn nur in den Sleep-Modus
zu schicken wenn der Timer abgelaufen ist.
So funktioniert es.
Der Controller selbst braucht beim Würfeln 100uA,
während der Timer läuft 30uA, im Power-Down nur 100nA.
Schön sparsam :)
Danke an Euch.
Hi Matze,
Du hast noch einen Designfehler, solange der Zustand des Eingangs INT0
aktiv low ist, wird die Interrupt-Service-Routine INT0_vect auch
angesprungen.
Entweder auf einen Flankenwechsel per Software triggern oder den INT0
Interrupt sperren.