Tiny45 Interrupt wird in ISR nicht wieder eingeschaltet

Gast #825352
Lesenswert?
• ▲
▼
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?
Gast #825466
Lesenswert?
• ▲
▼
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
Gast #825530
Lesenswert?
• ▲
▼
> 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.
Gast #825550
Lesenswert?
• ▲
▼
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
Gast #825584
Lesenswert?
• ▲
▼
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.
Gast #825625
Lesenswert?
• ▲
▼
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.
Gast #825795
Lesenswert?
• ▲
▼
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?
Gast #826370
Lesenswert?
• ▲
▼
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.
Gast #826398
Lesenswert?
• ▲
▼
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren