Wieder ein Problem Grob das Programm: TIMSK = 1<<OCIE0A; MCUCR = 0; GIMSK = 1<<PCIE; PCMSK = 1<<PCINT2; set_sleep_mode(SLEEP_MODE_PWR_DOWN); sei(); sleep_mode(); die main loop ist leer. Taste gedrückt. ISR(PCINT0_vect) { GIMSK &= ~(1<<PCIE); } Dann nudelt das Programm, in einer Timer-ISR ist dann Schluss GIMSK |= (1<<PCIE); sleep_mode(); Aber der PCInterrupt wird anschließend nicht mehr ausgeführt. Gibt es da irgendwelche Einschränkungen, dass man das Register nicht aus einer ISR schreiben kann oder so?
Hi, Du solltest Dich nochmal mit der Funktionsweise von Interruptroutinen beschäftigen! Während einer Interruptroutine sind alle weiteren Interrupts gesperrt und werden erst wieder beim Verlassen freigegeben (RETI in ASM). Wenn Du also deinen Controller innerhalb der Interruptroutine schlafen legst hast Du verloren. Schmeiß das "sleep_mode();" aus Deinem Timerinterrupt und verschiebe selbiges aus main in die Endlosschleife. CU
Oder mach es manuell, ich glaube STI oder so ähnlich heißt der Befehl. Die Lösung von FBI ist aber die bessere.
> Oder mach es manuell, ich glaube STI oder so ähnlich heißt der Befehl.
Du meinst vermutlich sei(), aber innerhalb einer Interrupt-Routine
sollte man keine Interrupts einschalten, wenn's nicht unbedingt nötig
ist bzw. man ich über die Auswirkungen nicht 100% im Klaren ist.
Hi concept, Deine Frage kann ich nicht gut mit dem Code in Verbindung bringen. Du fragst, warum der PC-Interrupt nicht ausgelöst wird. Anhand des geposteteten Codes würde ich sagen, weil Du PCMSK für PCINT2 initialisierst ( PCMSK = 1<<PCINT2; ), aber keine entsprechende ISR, sondern nur eine für PCINT0 ( ISR(PCINT0_vect) ) verwendest. Um Deine Verwendung von "sleep()" im Power-Down Modus zur verstehen, brauchte man mehr vom Programm. Aber vielleicht findest Du mit meiner obigen Anmerkung das eigentliche Problem. Lass doch zunächst mal alle "sleep()" usw. Befehle weg. Gruß Fred
ARGH! > Während einer Interruptroutine sind alle weiteren Interrupts gesperrt > und werden erst wieder beim Verlassen freigegeben (RETI in ASM). Wenn Du > also deinen Controller innerhalb der Interruptroutine schlafen legst > hast Du verloren. Danke! @Fred Dieser Interrupt kann von mehreren Pins ausgelöst werden.
Leider gibt es noch ein Problem, wahrscheinlich übersehe ich wieder sowas Blödes :-) TIMSK = 1<<OCIE0A; MCUCR = 0; GIMSK = 1<<PCIE; PCMSK = 1<<PCINT2; set_sleep_mode(SLEEP_MODE_PWR_DOWN); sei(); for (;;) { sleep_mode(); } ISR(PCINT0_vect) { GIMSK &= ~(1<<PCIE); set_sleep_mode(SLEEP_MODE_IDLE); } ISR(TIM0_COMPA_vect) { GIMSK = (1<<PCIE); set_sleep_mode(SLEEP_MODE_PWR_DOWN); } Das ist auch so in etwa der Ablauf. Die Timer-ISR wird nicht mehr aufgerufen, daher gehe ich davon aus, dass er wirklich im PWR_DOWN ist. Leider greift der Interrupt nicht, und er schläft immer weiter. Sehr viel später passiert allerdings irgendetwas und er wacht wieder auf Knopfdruck auf. Ich kann leider nicht nachvollziehen, was das ist (reset?). Aber wenn es prinzipiell so funktionieren sollte, weiß ich, dass ich den Fehler woanders suchen kann.
Wird bei meinem Gefasel nicht so ganz klar: einmal nach dem Einschalten funktioniert das Ganze.
Der Timer wird nirgends gestartet. Aber mal abgesehen davon: Woher weißt du eigentlich, daß die Timer-ISR nicht aufgerufen wird?
Hi, der Timer wird vor den Codeausschnitten gestartet, und läuft mit 32kHz. Im Timerinterrupt schalte ich einen Pin ein und aus. Ich habe mittlerweile das Programm komplett leergemacht, die Beschaltung sicherheitshalber entkoppelt, die Schaltung aus einer Batterie (3.2V) versorgt. Interner Takt mit 8MHz.
1 | #include <avr/io.h> |
2 | #include <stdint.h> |
3 | #include <stdlib.h> |
4 | #include <avr/sleep.h> |
5 | #include <avr/interrupt.h> |
6 | #include <avr/pgmspace.h> |
7 | |
8 | ISR(TIM0_COMPA_vect) |
9 | {
|
10 | PORTB |= 1<<PB0; |
11 | GIMSK = (1<<PCIE); |
12 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); |
13 | PORTB &= ~(1<<PB0); |
14 | }
|
15 | |
16 | ISR(PCINT0_vect) |
17 | {
|
18 | GIMSK &= ~(1<<PCIE); |
19 | set_sleep_mode(SLEEP_MODE_IDLE); |
20 | }
|
21 | |
22 | int main( void ) |
23 | {
|
24 | |
25 | OSCCAL = 0x55; |
26 | |
27 | PORTB = 1<<PB2; |
28 | DDRB = 1<<PB0; |
29 | |
30 | ACSR = 1<<ACD; |
31 | |
32 | TCCR0A = 1<<WGM01; |
33 | TCCR0B = 1 << CS00; |
34 | OCR0A = 250; |
35 | TCCR1 = 1<<PWM1A | 1<<CS10 | 1<<COM1A1; |
36 | OCR1A = 0; |
37 | |
38 | TIMSK = 1<<OCIE0A; |
39 | MCUCR = 0; |
40 | GIMSK = 1<<PCIE; |
41 | PCMSK = 1<<PCINT2; |
42 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); |
43 | sei(); |
44 | for (;;) |
45 | {
|
46 | sleep_mode(); |
47 | }
|
48 | }
|
Nach Anlegen der Versorgung messe ich an PB0 erwartungsgemäß je einen High-Impuls beim Drücken/Loslassen von PB2. Das Ganze funktioniert sogar mehrmals hintereinander, aber irgendwann ist dann Schluß - warum?
Tja, nachdem ich den AVR ausgetauscht habe (kein Unterschied) habe ich noch die überflüssigen Includes gelöscht - jetzt geht's. Der Impuls bei einem Tastendruck ist ca. 1,2µs lang.
1 | #include <avr/io.h> |
2 | #include <stdint.h> |
3 | |
4 | #include <avr/sleep.h> |
5 | #include <avr/interrupt.h> |
6 | |
7 | ISR(TIM0_COMPA_vect) |
8 | {
|
9 | PORTB |= 1<<PB0; |
10 | GIMSK |= 1<<PCIE; |
11 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); |
12 | PORTB &= ~(1<<PB0); |
13 | }
|
14 | |
15 | ISR(PCINT0_vect) |
16 | {
|
17 | GIMSK &= ~(1<<PCIE); |
18 | set_sleep_mode(SLEEP_MODE_IDLE); |
19 | }
|
20 | |
21 | int main( void ) |
22 | {
|
23 | |
24 | PORTB = 1<<PB2; |
25 | DDRB = 1<<PB0; |
26 | |
27 | TCCR0A = 1<<WGM01; // CTC MODE |
28 | TCCR0B = 1<<CS00; // 8MHz |
29 | OCR0A = 250; // 32000Hz |
30 | |
31 | TIMSK = 1<<OCIE0A; |
32 | |
33 | GIMSK = 1<<PCIE; |
34 | PCMSK = 1<<PCINT2; |
35 | |
36 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); |
37 | sei(); |
38 | |
39 | for (;;) |
40 | {
|
41 | sleep_mode(); |
42 | }
|
43 | }
|
Dann Versuch ich jetzt mal, das Programm wieder zum Laufen zu kriegen.
Zu früh gefreut. Es geht ein paar (3-15) Tastendrücke, aber irgendwann nicht mehr. Kann mir jemand vielleicht auf die Sprünge helfen, das Problem weiter einzugrenzen? Fuses: BOD 2.0V Int. Osc. 8MHz + 4ms
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.