Interrupts während einer schleife

Gast #3573166
Lesenswert?

Hallo,

Ich habe 3 Fall unterscheidungen.
Wenn der UC angeht, ist er in Fall 1. per INT1 und INT0 erzeuge ich 
interrupts, die den fall ändern, entweder zu fall  oder fall 3.

Nun soll sobald ein Interrupt passiert ist der Fall sich sofort ändern. 
Wenn ich aber zb. eine längere schleife habe, springt er ja nach dem 
Interrupt an die letzte "arbeitsposition" und macht dort weiter, obwohl 
der fall gar nicht mehr aktuell ist.
1
while(1)
2
  {
3
          
4
          switch(fall)
5
          {
6
            case 1: PORTB |= (1<<PINB2);      //PB2
7
                PORTB &= ~(1<<PINB1);
8
                PORTB &= ~(1<<PINB7);
9
                _delay_ms(6000);
10
                break;
11
            case 2: PORTB |= (1<<PINB1);      //PB1
12
                PORTB &= ~(1<<PINB2);
13
                PORTB &= ~(1<<PINB7);
14
                _delay_ms(6000);            
15
                break;
16
            case 3: PORTB |= (1<<PINB7);      //PB7
17
                PORTB &= ~(1<<PINB1);
18
                PORTB &= ~(1<<PINB2);
19
                _delay_ms(6000); 
20
                break;
21
          }
22

23

24

25
  }
26

27
ISR(INT0_vect)
28
{
29
  fall=2;
30
}
31

32

33
ISR(INT1_vect)
34
{
35
  fall=3;
36
}

Wie kann ich das lösen, dass er direkt den alten Fall beendet und schaut 
welcher der neue Fall ist?

gruß
Gast #3573177
Lesenswert?

Dein _delay_ms(6000) wir immer fertig ausgefuehrt. Da musst Du 
eingreifen, z.b etwa wie
          switch(fall)
          {
            case 1: PORTB |= (1<<PINB2);      //PB2
                PORTB &= ~(1<<PINB1);
                PORTB &= ~(1<<PINB7);
                delay = 6000;
                while ((fall == 1) && delay) {
                     _delay_ms(1);
                     delay --;
                }
                break;
#3573183
Lesenswert?

Sascha712 schrieb:

> Nun soll sobald ein Interrupt passiert ist der Fall sich sofort ändern.
> Wenn ich aber zb. eine längere schleife habe,

schon falsch.
Dann darfst du eben keine längere Schleife haben.

konkret in deinem Programm: welchen Sinn haben denn die _delay_ms? 
Richtig. Gar keinen.

_delay_ms (insbesondere längere) sind selten die Lösung, aber oft das 
Problem.
Gast #3573188
Lesenswert?

Könnte ich das (fall == 1) nicht auch weglassen? wird doch schon durch 
case 1: bestimmt?

          switch(fall)
          {
            case 1: PORTB |= (1<<PINB2);      //PB2
                PORTB &= ~(1<<PINB1);
                PORTB &= ~(1<<PINB7);
                delay = 6000;
                while (delay) {
                     _delay_ms(1);
                     delay --;
                }
                break;
#3573193
Lesenswert?

Sascha712 schrieb:
> Könnte ich das (fall == 1) nicht auch weglassen?


In Uwes Version nicht

> wird doch schon durch
> case 1: bestimmt?

Du willst doch, dass die ganze Delay Sache sofort unterbrochen wird, 
sobald durch einen Interrupt ein anderer Fall eingestellt wird. Also ist 
eben nicht gewährleistet, dass fall ständig die ganze Zeit den Wert 1 
hat.

Das hier
1
   delay = 6000;
2
   while (delay) {
3
     _delay_ms(1);
4
   delay --;

bringt dir nichts. Da hättest du genausogut auch gleich
1
    _delay_ms( 6000 );
schreiben können.
Der ganze Witz in Uwes Lösung besteht ja darin, dass es hier
1
   delay = 6000;
2
   while ((fall == 1) && delay) {
3
     _delay_ms(1);
4
     delay --;
5
   }
2 Bedingungen gibt, unter denen die Wartezeit abgebrochen wird.
Einmal wenn die Wartezeit abgelaufen ist
und die zweite mögliche Bedingung besteht darin, dass ein Interrupt 
einen anderen fall eingestellt hat. Auch denn wird die Schleife 
spätestens 1ms später abgebrochen, weil dann fall eben nicht mehr 1 ist.

Aber tatsächlich ist die Lösung eher schlecht, denn du musst jeden delay 
einzeln pimpen. Das erledigt man anders, in dem man die Hauptschleife 
auf eine konstante Länge von zb 1ms bringt und dann einen Zähler 
installiert, der zb von einer eingestellten Wartezeit runterzählt.
Gast #3573484
Lesenswert?

Wie wär's mit:
1
uint8_t oldFall = ...;
2

3
....
4

5
while (1){
6
  uint8_t newFall = fall; //nur ein Zugriff auf fall, falls der Interrupt dies gerade ändert
7
  if (newfall != oldfall){
8
    oldfall = newfall;
9
    switch (newfall){
10
       //ohne delay !
11
    }
12
  }
13
}

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