Forum: Mikrocontroller und Digitale Elektronik Beenden eine while(1)-schleife in einer Interruptroutine


von Karl (Gast)


Lesenswert?

hallo Leute
ich bin dabei eine C funktion zu  implementieren
Das Programm ist in mehrere Routine aufgeteilt.
Die erste Routine soll abfaufen bis Zeichen  zur Übergang zur nächte 
kommt.
ich habe mir gedach in der Erste Routine eine while(1) schleife zu 
setzen und eine Interrupt für die nächste Routine zu implementieren.
Nun  so weiß ich nicht wie  oder ob es machbar eine while schleife 
innerhalb einer Interruptfunktion zu unterbrechen  und in die nächte 
einzuspringen.

Hat jemand eine Idee  wie diese machbar ist  ?  oder eine andere 
Möglichkeit vorzuschlagen?

Ich wäre für jeden Beitrag bankbar.
Karl

von Agro_ (Gast)


Lesenswert?

So macht man es sicher nicht, warum setzt du nicht in deiner ISR einen 
Merker und wechselst daraufhin zur nächsten Routine. ISRs sollte man 
immer so kurz wie möglich halten.

von Karl (Gast)


Lesenswert?

wie eine Merker???
ich verstehe nicht. kannst du mal eine kurze beispiel zeigen

von Mandrake (Gast)


Lesenswert?

Bau ein Switch-Case in deine while(TRUE)-Schleife und schalte in deiner 
ISR einfach die switch-variable um. So einfach ist das...


Gruß

Mandrake

von heinz (Gast)


Lesenswert?

Schau dir mal das Konzept von "Finite State Machines" (fsm, oder in dt. 
Endliche Automaten) an.

br
heinz

von karl (Gast)


Lesenswert?

Ja    aber ich  möchte diese auf Sofware-basis realisieren.


danke

von Gast (Gast)


Lesenswert?

So macht man das für gewöhnlich:
1
ISR (WHATEVER) {
2
  marker++;
3
}
4
5
main:
6
7
while (1) {
8
  switch(marker) {
9
    case 1: bla; break;
10
    case 2: bla2; break;
11
    case 3: bla3; break;
12
    default: break;
13
}

von Gast (Gast)


Lesenswert?

} nach dem switch vergessen.

von Falk B. (falk)


Lesenswert?

Siehe Interrupt

von karl (Gast)


Lesenswert?

Die Interrups laufen nicht über die selbe Taste  deswegen  kann schlecht 
unter Switsch   gemach werden.

Jede interrupt hat sein Erzeuger(taste).

so meine  ich :


void Einspritzen(void)

{
  while(1)
  {
    // do many things
  }

}

void vorbereitung(void)
{
  while(1)
  {
   //do many things
   }

}


int main()
{
vorbereitung();
einspritzen();
.
.
.

}

von Karl (Gast)


Lesenswert?

we  soll dann  zum beispiel eine Interrup  sein, die die 
Vorbereitungsfunktion beendet und die Einspritzungsfunktion startet 
aussehen.

danke.

von Falk B. (falk)


Lesenswert?

1
void Einspritzen(void)
2
3
{
4
  while(1)
5
  {
6
    // do many things
7
    if (flag_end_einprizen) break;
8
  }
9
10
}
11
12
void vorbereitung(void)
13
{
14
  while(1)
15
  {
16
   //do many things
17
   if (flag_end_vorbereitung) break;
18
   }
19
20
}
21
22
//globale variable
23
24
char flag_end_vorbereitung;
25
char flag_end_einprizen;
26
27
int main()
28
{
29
vorbereitung();
30
einspritzen();
31
.
32
.
33
.
34
35
}
36
37
ISR (whatever)
38
(
39
     if (bedingung) flag_end_vorbereitung =1;
40
)

von Hans Fanic (Gast)


Lesenswert?

Hallo,

aus einer while(1) Schleife kommst Du nur noch über die brutalo Methode 
"gehe zurück zu Los, ziehe keine 4.000" ein. Los ist in diesem Fall 
RESET.

Wenn Du aus einer Schleife wieder rauskommen willst must Du schon als 
Abruchbedingung eine Variable setzen.

Hans

von Karl H. (kbuchegg)


Lesenswert?

Was du da hast ist doch Unsinn.
Da benutzt mn doch keine Endlos-while Schleifen nur um sie dann mit 
Gewalt abzuschiessen.

Dafür benutzt man Schleifen, die von einer Bedingung abhängen. Welche 
das sind musst du entscheiden.
Aber im Grunde

void vorbereiten()
{
  while( !vorbereitung abgeschlossen )
    mache vorbereitungsarbeit
}

Jetzt bist du drann. Woran kann man erkennen, dass die Vorbereitung 
abgeschlossen ist?
(Selbiges auch für die anderen Funktionen)

von Karl (Gast)


Lesenswert?

jetzt  ist  mir was aus verschiedene Posten aufgefallen. ich mache eine 
While mit Bedingung.  und in der ISR setze ich die Bedingung zu 1.  Dann 
brich die Whileschleife ab und läuft normal weiter in die andere 
Funktion.


Ich denke so geht.

von Karl (Gast)


Lesenswert?

so  habe ich mir das nun vorgestellt:




ISR (einsptz)
(
     arbeit_ende=1;
)


ISR (vorber)
(
     wasser=1;
)


void vorbereitung(void)
{
  while(arbeit_ende)
  {
   //do many things

   }

}


void Einspritzen(void)

{
  while(wasser)
  {
    // do many things

  }

}

.
.
.


Was meint ihr .  ich kann  das nun   nicht debuggen , aber ist plausibel 
oder ??


lg
Karl

von Karl H. (kbuchegg)


Lesenswert?

Karl schrieb:

> Was meint ihr .  ich kann  das nun   nicht debuggen ,

Warum nicht?

von Gast (Gast)


Lesenswert?

Wo wird arbeit_ende = 0 gesetzt, damit es nicht weiter ausgeführt wird 
wenn wasser = 1?

Kannst Du bitte mal deine Leertaste entprellen.   Das ist fürchterlich 
mit den  vielen   Leerzeichen  .

von Karl (Gast)


Lesenswert?

ach nööön ich habe ein Fehler gemacht

Verzeihung ich meinte in der ISR die variablen zu Null(Wasser=0 und 
arbeits_ende=0) setzen damit die whilen abbrechen.

>Kannst Du bitte mal deine Leertaste entprellen.   Das ist fürchterlich
>mit den  vielen   Leerzeichen  .

Ok ich bemühe mich die Leezeichen in griff zu bekommen.

lg
Karl

von Roland P. (pram)


Lesenswert?

noch wichtig, die Variablen im Interrupt und in der Schleife müssen als 
"volatile" deklariert werden

Gruß
Roland

von stefan Konrad (Gast)


Lesenswert?

Hi Leute

mir ist was änhliches am brennen.

in der Schleife , die ich abbrechen will, warte ich auf 3 daten per 
Pollin der UART  (receive).
d h bei einem drduck an dem Taster würde ich zwar die ISR laufen lassen 
aber das Programm wird beim Rückker auf das Ursprungliche warten zurück 
kommen und ewig verhaaren.

ich schliesse mich als Beispiel an dem Code von Karl
1
 
2
volatile unsigned int arbeit_ende=0;
3
volatile unsigned int wasser=0;
4
ISR (einsptz)
5
(
6
     arbeit_ende=1;
7
)
8
 
9
 
10
ISR (vorber)
11
(
12
     wasser=1;
13
)
14
 
15
 
16
void vorbereitung(void)
17
{
18
  while(!arbeit_ende)
19
  {
20
   while ( !(UCSR0A & (1<<RXC0)) );
21
/* Get and return received data from buffer */
22
x=UDR0;
23
   while ( !(UCSR0A & (1<<RXC0)) );
24
/* Get and return received data from buffer */
25
y=UDR0;
26
   while ( !(UCSR0A & (1<<RXC0)) );
27
/* Get and return received data from buffer */
28
z=UDR0;
29
 
30
   }
31
 
32
}
33
 
34
 
35
void Einspritzen(void)
36
 
37
{
38
  while(!wasser)
39
  {
40
    // do many things
41
 
42
  }
43
 
44
}
45
 
46
 
47
int main()
48
{
49
while(1)
50
{
51
vorbereitung();
52
 
53
Einspritzen();
54
 
55
}
56
 
57
}

Aber das möchte, dass es nach dem Interrupt zu der Funtion Einspritzen() 
springt und die Kommunikation wieder initialisiert so dass es auf keine 
Zeichen mehr wartet.

vieleicht hat eine ein Idee.

Danke

von I. E. (anfaenger69)


Lesenswert?

Du kannst nicht in einen While bereich hinein springen. Machs mit Goto:

beginn:
.
.
.

schleife1:
    tuh irgendwas;
    if (taster2) goto schleife2;
goto schleife1;

.
.
.

schleife2:
    tuh irgendwas;
    if (taster1) goto schleife1;
goto schleife2;

.
.
.

goto beginn;

von Klaus (Gast)


Lesenswert?

NEEEEEIIIIIIIIIN!
Es geht auch ohne ver***** goto!!!

von I. E. (anfaenger69)


Lesenswert?

Warum einfach, wenns auch kompliziert geht :c)

von Karl H. (kbuchegg)


Lesenswert?

Das sieht nur auf den ersten Blick einfach aus.
Oft verwandelt sich diese 'Einfachheit' ganz schnell in einen Bumerang, 
der auf einen zurückschlägt.

Das Beispiel hier schreit doch schon förmlich danach, dass man die in 
der ISR gesetzten Flags benutzt!

von gastlich (Gast)


Lesenswert?

Goto in einem c-programm ???

leute, leute ... das geht unter "ganz böse", sollte mann vermeiden ...

wegen den zeichen an der UART:

warum empfängst du die zeichen nicht auch per interrupt? dannn 
bräuchtest du die while() nicht.

innerhalb der uart_rx ISR in einen buffer schreiben und diesen zu den 
richtigen zeiten entweder auswerten oder löschen ...

gruss Claudio

von uart (Gast)


Angehängte Dateien:

Lesenswert?

ich hab da mal was vorbereitet:
1
#define maxstrlen 10
2
...
3
volatile char string[maxstrlen+1];
4
volatile uint8_t str_complete;
5
volatile uint8_t str_count;
6
...
7
ISR(USART_RXC_vect)
8
{
9
    unsigned char buffer;
10
11
    // Daten aus dem Puffer lesen
12
    buffer = UDR;
13
  // Daten werden erst in string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
14
    if (buffer!='\n' && buffer!='\r' && str_count<maxstrlen-1){ //&& str_complete!=0) {
15
    string[str_count]=buffer;
16
    str_count++;
17
  } else {
18
    if (buffer!='\n' && buffer!='\r'){
19
      string[str_count]=buffer;
20
      str_count++;
21
    }
22
    string[str_count]='\0';
23
    str_complete=1;
24
  }
25
}

Im Hauptprogramm fragst du einfach zyklisch ab ob str_complete=1 ist und 
holst dir die Zeichenkette aus string. Du darfst natürlich das 
Rücksetzen der Variablen nicht vergessen.

PS an alle Nörgler: das ist nur ein Vorschlag

von I. E. (anfaenger69)


Lesenswert?

Da haben sich schon zwei gegen da "goto" ausgesprochen. Was ist so 
schlimm daran? Im Assembler heisst der Befehl JMP oder RJMP und und wird 
sehr häufig verwendet... Klärt mich mal auf... so als Neben-Topic...

von Falk B. (falk)


Lesenswert?

@  Igor Ebner (anfaenger69)

>Da haben sich schon zwei gegen da "goto" ausgesprochen. Was ist so
>schlimm daran?

Es führt meist zu Sphagetticode. Und es ist in C praktisch unnötig, von 
gaaaaaaaanz wenige Ausnahmen mal abgesehen, wo man es als Vereinfachung 
nutzen KÖNNTE!
Wird aber praktisch nie gemacht, denn man kann jeden Programmablauf 
sauber duch die normalen Konstrukte if, for, while, Switch abbilden.

> Im Assembler heisst der Befehl JMP oder RJMP und und wird
>sehr häufig verwendet...

Auch der Compiler nutzt die, ist auch OK. Aber sinnvollerweise nur, um 
eben die oben genannten Konstrukte zu generieren, welche dann sauber 
sind. Gleiches sollte man auch von hand in Assembler tun und solche 
sauberen Konstruktionen schreiben. Wilde Sprünge quer durch die Botanik 
gibt es auch nicht in einem sauberen Assemblerprogramm!

MfG
Falk

von I. E. (anfaenger69)


Lesenswert?

Ahhhh, OK... danke Dir... back to topic :c)

von Karl H. (kbuchegg)


Lesenswert?

Igor Ebner schrieb:
> Da haben sich schon zwei gegen da "goto" ausgesprochen. Was ist so
> schlimm daran?

Eine Analogie:
Man kann seine Kabel einfach zusammenknüdeln und in eine Kiste 
schmeissen. Man kann aber auch die Kabel vorher sauber aufrollen und die 
Rollen so sichern, dass sich in der Kabellade keine Rolle mit einer 
anderen verheddert.

von stefan Konrad (Gast)


Lesenswert?

ok danke für Anrregungen.

gibt es nicht eine Möglichkeit es zu machen ohne ein ISR bei RX-Uart zu 
nutzen?
Denn mommentan habe ich das gesamte Programm übernommen und es ist 
überrall mit Pollin implementiert.

Und wenn ich es mit ISR machen sollte(aufwendig den gesamten Code zu 
fummeln, na ja wenn nicht anders geht...), die Daten sind keine Strings 
sondern Bytes-Pakette  genauso wie ich es oben in meiner Vorgehensweise 
dargestellt habe.   Wie soll dann nun ihr ISR aussehen?

danke

von Karl H. (kbuchegg)


Lesenswert?

Man könnte zb
1
void vorbereitung(void)
2
{
3
  while(!arbeit_ende)
4
  {
5
    while ( !arbeit_ende && !(UCSR0A & (1<<RXC0)) )
6
     ;
7
    /* Get and return received data from buffer */
8
    x=UDR0;
9
10
    while ( !arbeit_ende && !(UCSR0A & (1<<RXC0)) )
11
      ;
12
    /* Get and return received data from buffer */
13
    y=UDR0;
14
15
    while ( !arbeit_ende && !(UCSR0A & (1<<RXC0)) )
16
      ;
17
    /* Get and return received data from buffer */
18
    z=UDR0;
19
  }
20
}


Man könnte aber auch den immer gleichen Teil in eine eigene Funktion 
rausziehen und so auf einfache Art die Fehlbelegung von y oder z 
verhindern.
1
uint8_t readValue( uint8_t * pVal )
2
{
3
  while ( !arbeit_ende && !(UCSR0A & (1<<RXC0)) )
4
    ;
5
6
  if( arbeit_ende )
7
    return FALSE;
8
9
  *pVal = UDR0;
10
  return TRUE;
11
}
12
13
void vorbereitung(void)
14
{
15
  while(!arbeit_ende)
16
  {
17
    if( !readValue( &x ) )
18
      return;
19
20
    if( !readValue( &y ) )
21
      return;
22
23
    if( !readValue( &z ) )
24
      return;
25
  }
26
}

Möglichkeiten gibt es genug, ohne auf einen goto ausweichen zu müssen. 
Was in der jeweiligen Situation vernünftig ist und was nicht, hängt zwar 
immer von den Umständen ab, aber ein goto ist selten vernünftig (und 
wenn dann nur in ganz bestimmten Situationen die hier aber nicht 
vorliegen).

von stefan Konrad (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Man könnte zb

1
C-Code
2
3
while(!arbeit_ende)
4
  {
5
    while ( !arbeit_ende && !(UCSR0A & (1<<RXC0)) )
6
     ;
7
    /* Get and return received data from buffer */
8
    x=UDR0;



danke Karl,
diese Vorgehensweise habe ich auch versucht und es kalpptauch nicht.
Auch die Simulation auf dem Board hat nicht geklappt. an der Schleife 
bleibt es bei der simulation hängen und es kann keine Pins mehr gesetzt 
werden.

Bei dem Test auf dem wirklichen System läuft das Programm nicht weiter.
Ich habe schon alle mögliche Kombination durchgeführt, aber ohne erfolgt
•
1
while(!arbeit_ende)
2
  {
3
    while ( !arbeit_ende && !(UCSR0A & (1<<RXC0)) )
4
     ;
5
    /* Get and return received data from buffer */
6
    x=UDR0;
7
.
8
.
9
.
10
11
//-------kombination 2-------------------------
12
while(!arbeit_ende)
13
  {
14
    while ( !arbeit_ende & !(UCSR0A & (1<<RXC0)) )
15
     ;
16
    /* Get and return received data from buffer */
17
    x=UDR0;
18
.
19
.
20
.
21
//----------kombination 3----------------------------------
22
23
while(!arbeit_ende)
24
  {
25
    while ( (!arbeit_ende) && (!(UCSR0A & (1<<RXC0))) )
26
     ;
27
    /* Get and return received data from buffer */
28
    x=UDR0;
29
.
30
.
31
.


der Schlüsselname ist diese "arbeit_ende". weiss nur nicht wie ich es am 
besten gleichzeitig mit deAbfrage des Empfangsdatens verknüpfen kann.

danke

von freak (Gast)


Lesenswert?

ich muss mir das   offline debugen

von stefan Konrad (Gast)


Lesenswert?

übrigens

arbeits_ende ist in der main.c  als globalvariable und volatile 
deklariert. in der anderen ".c" wo es verwendet wird, wird er als : 
extern volatile ... arbeits_ende.

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.