Forum: Mikrocontroller und Digitale Elektronik Interrupts während einer schleife


von Sascha712 (Gast)


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ß

von Uwe Bonnes (Gast)


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;

von Karl H. (kbuchegg)


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.

: Bearbeitet durch User
von Sascha712 (Gast)


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;

von Sascha712 (Gast)


Lesenswert?

Die delays sind da grad nur, damit ich das auf meinem steckbrett sehen 
kann, das der interrupt eingreift. Später wird das anders sein und ich 
werd auch höchstens delays von 17ms haben.

von Karl H. (kbuchegg)


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.

: Bearbeitet durch User
von Sascha712 (Gast)


Lesenswert?

Dazu müsste ich aber auch wissen wieviele Takte er pro schelife den 
abarbeitet ^^ Hab aber kein debug tool um das iwie zu messen oder so.
Danke für die Erklärung :)

von Flohzirkus (Gast)


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
}

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
Noch kein Account? Hier anmelden.