Hallo,
ich möchte gerne mit einem Taster den AtMega32 schlafen legen, und auch
wieder wecken.
habe dazu folgendes Programm von Peter Dannegger verwendet:
Beitrag "AVR-GCC Power-Down Tutorial"
Und verwende den INT1 mit PD3 als Low aktiven Interrupt.
Ich habe nur folgendes Phänomen:
In meinem INT1_vect Interrupt wird, wie bei Peter Dannegger, der INT1
deaktiviert, danach schalte ich LEDs an ( zum testen ).
Wenn ich nun meinen µC anschalte, und die Taste drücke, gehen die LEDs
an, und der µC geht schlafen. Ich kann ihn auch wieder wecken mit der
Taste.
Aber, wieso gehen die LEDs an? Meines erachtens sollte er doch nur
schlafen gehen, und erst nach dem aufwecken, den Interrupt ausführen und
die LEDs angehen oder?
Bzw. wieso funktioniert das aufwecken überhaupt, wenn er den Interrupt
ausführt in dem der INT1 deaktiviert wird?
Danke
Fritz schrieb:> habe dazu folgendes Programm von Peter Dannegger verwendet:> Beitrag "AVR-GCC Power-Down Tutorial"
Verweise nicht auf das Original, sondern zeige deine Version, exakt so,
wie du sie verwendest.
Es muss ein Fehler darin sein.
Fritz schrieb:> habe dazu folgendes Programm von Peter Dannegger verwendet:> Beitrag "AVR-GCC Power-Down Tutorial"
Das Original ist für den ATTiny13 geschrieben - Du hast wohl einen
Fehler in der Umsetzung auf den ATMega32.
Zeigen - dann kann Dir geholfen werden ...
set_sleep_mode(SLEEP_MODE_PWR_DOWN);// prepare power down
11
12
}// = SEI
13
#ifdef USE_SLEEP_MODE
14
// use never sleep_mode()
15
sleep_mode();// under no circumstances
16
17
// its always dangerous !!!
18
#else
19
20
sleep_cpu();// do SLEEP instruction only !
21
22
#endif
23
TIMSK=1<<TOIE0;// enable other interrupts again
24
}
OMG. Ein schönes Beispiel dafür, wie saukompliziert die Verwendung von C
als Sprache eine absolut simple Sache machen kann...
Aber wenn man sich diesen Scheissdreck schon antut, dann muss man es
halt trotzdem einfach nur richtig machen. Also etwa so:
1
voidgo_power_down(void)
2
{
3
ATOMIC_BLOCK(ATOMIC_FORCEON)
4
{
5
LED0=LED_OFF;
6
GICR|=1<<INT1;
7
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
8
GIFR=1<<INTF1;
9
}
10
sleep_cpu();
11
}
Wenn dieser Schrottcompiler jetzt wirklich die schließende Klammer des
Atomic-Blocks zu einer sei-Instruction übersetzt und das sleep_cpu() zu
einer sleep-Instraction und nix weiter dazwischenballert, dann ist die
Sache safe.
In Asm schreibt man das einfach so hin, dass es safe ist und muss sich
nicht auf Ratespiele einlassen, wie der Compiler den Scheiss nun genau
übersetzen wird...
Fritz schrieb:> Aber, wieso gehen die LEDs an?
Weil Du die "falsch" herum angeschlossen hast.
Was Du da bezweckst
1
DDRB=0xFF;
2
PORTB|=0x10;
3
PORTB&=~(0x20);
weiß ich nicht so recht. Aber die PWM-LED geht an (wenn Du in den
Sleep-Mode gehst) weil Du es so definiert
1
#define LED_OFF 1
2
#define LED_ON 0
hast. Entweder die Definition umkehren oder die LED anders herum
anchliessen.
Das Aufwecken erfolgt rein durch das Auslösen des Interrupts - den
könntest Du auch leer lassen, aber dann hätte das Debouncing ein
Problem, weil der Interrupt dann x-mal aufgerufen wird, in der Zeit in
welcher Du die Taste drückst und der Timer-Interrupt (für das
Debouncing) nicht zum Zuge kommt.
@c-hater:
danke, leider schafft aber auch das keine Abhilfe.
Ich werde mal das ganze "frisch" Programmieren und nicht das komplette
Programm übernehmen, sondern erstmal debouncing, und dann Sleep
Funktionen. Vielleicht klappt es dann.
Dieter F. schrieb:> Fritz schrieb:>> Aber, wieso gehen die LEDs an?>> Weil Du die "falsch" herum angeschlossen hast.
Nein, ich habe an PORTB 8 LEDs dran. Die 1. wird gefaded, alle anderen
sollen nur zeigen, ob er aufgewacht ist.
> Was Du da bezweckst> DDRB = 0xFF;> PORTB |= 0x10;> PORTB &= ~(0x20);>> weiß ich nicht so recht. Aber die PWM-LED geht an (wenn Du in den> Sleep-Mode gehst) weil Du es so definiert> #define LED_OFF 1> #define LED_ON 0>> hast. Entweder die Definition umkehren oder die LED anders herum> anchliessen.>> Das Aufwecken erfolgt rein durch das Auslösen des Interrupts - den> könntest Du auch leer lassen, aber dann hätte das Debouncing ein> Problem, weil der Interrupt dann x-mal aufgerufen wird, in der Zeit in> welcher Du die Taste drückst und der Timer-Interrupt (für das> Debouncing) nicht zum Zuge kommt.
Fritz schrieb:> danke, leider schafft aber auch das keine Abhilfe.
Hast du auch kontrolliert, dass der Compiler das Richtige daraus gemacht
hat?
Der springende Punkt ist, dass zwischen dem "sei" und dem "sleep" keine
weiteren Instruktionen liegen dürfen. AUSSCHLIESSLICH unter dieser
Bedingung ist die Sache wirklich prinzipiell sicher.
Diese prinzipielle Sicherheit bedeutet allerdings noch lange nicht, dass
es auch wie gewünscht funktioniert. Dazu muss natürlich dann auch noch
der Rest des Programmes an den richtigen Stellen das Richtige tun.
Das heisst übrigens u.a.: Die ISR des Wakeup-Interrupts darf eigentlich
nichts anderes machen, als eben diesen Interrupt zu deaktivieren.
Abweichungen von diesem Grundsatz sind möglich, erfordern aber im
Minimum ein vollständiges Verständnis des Sleep-Mechanismus und der zum
Aufwachen benutzten Hardware.
Hallo,
nein, das habe ich nicht, muss mir ansehen, wie ich mir die Ausgabe in
asm ansehen kann, mache ich gleich! Danke
Aber das Problem dürfte folgendes sein, ich muss einen Low Level
Interrupt verwenden, da der Atmega32 mit einem falling Edge Interrupt
nicht aufwachen kann.
Drücke ich nun meine Taste, geht er in den Sleep Modus, die Taste ist
noch gedrückt, es kommt sofort ein Interrupt zum aufwachen, in der main
sieht er aber, die Taste ist gedrückt, er legt sich gleich wieder
schlafen, und das in einer Schleife...
Kann es sein, dass es mit einem Low Level Interrupt einfach nicht
funktioniert, das heißt mit einem atmega32 in der Art nicht Möglich ist?
Fritz schrieb:> in der main> sieht er aber, die Taste ist gedrückt, er legt sich gleich wieder> schlafen,
Dann Ändere die Tastenabfrage in main, so dass sie nur auf Flanken
Reagiert, üblich ist das Loslassen des Tasters.
Geht zusammen mit der Entprellung in Software sehr einfach.
Fritz schrieb:> Nein, ich habe an PORTB 8 LEDs dran. Die 1. wird gefaded, alle anderen> sollen nur zeigen, ob er aufgewacht ist.
Wie hast Du die denn angeschlossen? Welche Vorwiderstände?
Also das Coding funktioniert ohne die x LED's wunderbar auf meinem
ATMega32 - mit dem Unterschied, dass ich PINB3 für die LED nutze - aber
das kann es nicht sein.
Hallo,
läuft auf einem STK500, also low active LEDs.
Naja mehr oder weniger funktioniert es ja, aber wenn man eben im
Interrupt die LEDs toggelt sieht man extrem, wie er in der Schleife
läuft. Im Endeffekt kommt er zwar ins Sleep, aber finde es nicht so
wirklich toll, wenn er ständig aufwächt, schlafen geht, solange bis ich
von der Taste runtergehe.
Hast dus schonmal versucht in dem Interrupt LEDs toggeln zu lassen, oder
einfach auf einem PIN ausgeben und mit Oszi ansehen? Ich denke bei dir
wirds dann auch in einer Schleife toggeln, sonst wär das tatsächlich
irgendwie komisch !?
Werde aber wahrscheinlich ohnehin auf einen neueren Atmega umsteigen,
mit Pin Change Interrupts, da funktionierts besser ;).
Fritz schrieb:> aber finde es nicht so> wirklich toll, wenn er ständig aufwächt, schlafen geht, solange bis ich> von der Taste runtergehe.
Na dann geh eben erst in Power-Down, nachdem der Pin wieder high ist.
c-hater schrieb:> Wenn dieser Schrottcompiler jetzt wirklich die schließende Klammer des> Atomic-Blocks zu einer sei-Instruction übersetzt und das sleep_cpu() zu> einer sleep-Instraction und nix weiter dazwischenballert, dann ist die> Sache safe.
Was soll denn eine "sei-Instrucion" sein? sei() macht nix anderes als
das asm-sei auch macht: Das Global Interrupt Flag setzen.
Probleme hat man eigentlich nur wenn z.B. die Tastatur kaputt ist und
man statt GICR GIFR schreibt oder statt INT0 INTF0...Aber ich bin mir
sicher, dann hat man auch in ASM ein Problem, nicht nur in C. Der
Compiler kann dafür nix, der rät nicht was eigentlich damit gemeint war.