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 ...
Fritz schrieb: > hier im Anhang das Programm.
1 | void go_power_down( void ) |
2 | {
|
3 | ATOMIC_BLOCK(ATOMIC_FORCEON){ // = CLI |
4 | LED0 = LED_OFF; // switch off external loads |
5 | TIMSK = 0; // other interrupts off ! |
6 | |
7 | // GIMSK = 1<<PCIE; // awake interrupt on
|
8 | GICR |= 1<<INT1; |
9 | |
10 | 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 | void go_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.
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.