while-Schleife vorzeitig verlassen

#5756939
Lesenswert?

Mein Projekt befasst sich mit der Regelung der Temperatur mittels 
Thermostatventil.
Im Prinzip läuft die Regelung als PI-Regler schon nach meinen 
Vorstellungen.
Ein Problem  besteht allerdings darin, dass sich das Programm aufhängt, 
wenn das Ventil bis zur Endstellung fahren will, aber der Anschlag 
vorzeitig ereicht wird.
Verantwortlich mache ich die while schleife in der Funktion

void ventil_schliessen_regler(void)
{
ZU=1;           //zähler zählt herunter
while(hub >(ventilstellung_alt-umdrehung_zu ))
P3OUT &=~BIT0; // ZU-fahren
P3OUT |=BIT0;  // ZU-fahren HALT
ZU=0;

Zur Erklärung: Der hub entspricht der Anzahl der Umdrehungen eines 
Zahnrades des Getriebes.
Beim Schließen wird herunter gezählt.
Alle 8s wird die Hubstellung (ventilstellung_alt) abgefragt und über die 
Reglergleichung die Anzahl der Umdrehungen (umdrehung_zu) berechnet, die 
notwendig sind, um die neue Hubstellung anzufahren. Bisher alles gut.
Das Problem des Aufhängens tritt m. E. dann auf, wenn der Lauf durch 
Anschlag am Hubende  nicht bis zum Ende erfolgen kann.
Gibt es eine Möglichkeit, die Schleife vorzeitig zu verlassen, obwohl 
die errechnete Hubverstellung wegen Anschlag nicht erreichbar ist und 
deshalb die while-schleife nicht beendet wird.
Versuche mit Strommessungen waren bei mir  (programmiertechnisch)  nicht 
erfolgreich.
Aber vielleicht hat jemand eine Idee, wie das Aufhängen vermieden werden 
kann.
fragt ein Programmierlaie
Gast #5756956
Lesenswert?

Wolfgang schrieb:
> Eine while-Schleife wird genau dann unterbrochen, wenn die Bedingung
> nicht mehr erfüllt ist. Also schreibe die Abbruchbedingung mit rein.

Quatsch. Das sind Weicheierschleifen.

Männerschleifen werden SO geschrieben:
1
While(1) {
2
  if(Abbruchbedingung)
3
     {break;}
4
}


http://openbook.rheinwerk-verlag.de/c_von_a_bis_z/008_c_kontrollstrukturen_011.htm#mjd28218b0b10f4b2de0cf49a68ed3a79a
Gast #5756990
Lesenswert?

... schrieb:
> hub >(ventilstellung_alt-umdrehung_zu

Woher kommen die Variablen?

Prozessor Dokter Schmunz schrieb:
> Ganz einfach: Hier gibt es Antworter, die wissen noch weniger als der
> Frager ;)

Genau ;)
Im Moment kenne ich nur den Codeschnipsel.

Und wenn der TO wirklich in einer Schleife immer wieder ein Bit löscht, 
welches schon längst gelöscht ist, denke ich mir, dass es im restlichen 
Programm ähnlich ausieht.
Gast #5757003
Lesenswert?

... schrieb:
> Und wenn der TO wirklich in einer Schleife immer wieder ein Bit löscht,
> welches schon längst gelöscht ist, denke ich mir

Manche Ecken bestehen nur aus Fett. Aber nur Joseph Beuys konnte damit 
Geld machen. Es liegt also nicht am Fett, sondern am User.

Anderer Vorschlag, frei nach Beuys:
1
while(1) {
2
  if(Abbruchbedingung)
3
     {digitalWrite(PIN, 1);} // PIN ist ohne Widerstand mit Masse verbunden
4
}
Wenn die Abbruchbedingung erfüllt ist, wird ein Kurzschluss erzeugt. Der 
Prozessor raucht ab, und die Schleife gilt damit als verlassen. In 
meiner Funktion als Prozessor Dokter Schmunz darf ich das zwar nicht 
schreiben, aber Beuys, wäre er Programmierer, würde das tun. Kurz darauf 
würden das vermutlich alle tun.
#5757153
Lesenswert?

... schrieb:
> Im Moment kenne ich nur den Codeschnipsel.

deshalb als Anhang mal das gesamte Hauptprogramm, auch wenn es 
vielleicht nicht allen Anforderungen entsprechen sollte.
Es enthält zusammen mit *.h Dateien u.a.:
Aufzeichnung von Daten auf SD-Karte
Uhrzeit
Temperaturmessung
Anzeige auf Flüssigkristallanzeige

Vielleicht könnte jemand die Abruchbedingungen an der richtigen Stelle 
einfügen.

mit break
oder if (ADW_P6_3 > 24)... //steht für Stromstärke am Anschlag ZU
hatte ich es versucht --> Programm reagierte nicht mehr
deshalb mein Hilferuf
Angehängte Dateien:
#5757306
Lesenswert?

Tim T. schrieb:
> Wo kommt eigentlich hub her? Sehe dafür keine Deklaration... Und
> wenn
> sollte da ein volatile bei stehen.
Deklaration ist in DS10-g0107-LMK62-SD.h als volatile int  enthalten

Deinen Vorschlag habe ich wie folgt eingebaut:

void ventil_schliessen_regler(void)
      {
       ZU=1;  //zähler zählt herunter
       while(hub >(ventilstellung_alt-umdrehung_zu ))
       P3OUT &=~BIT0; // ZU-fahren
       if ( ADW_P6_3 > 24) break;      //hier Zeile 248
       P3OUT |=BIT0;  // ZU-fahren HALT
       ZU=0;
       }

Fehlermeldung: DS10-g0122-PID.c:248: break statement not within loop or 
switch
Gast #5757341
Lesenswert?

Mein Editor wuerde dein Codesnippet so editieren:
1
void ventil_schliessen_regler(void)
2
{
3
  ZU=1;  //zähler zählt herunter
4
  while(hub >(ventilstellung_alt-umdrehung_zu ))
5
    P3OUT &=~BIT0; // ZU-fahren
6
  if ( ADW_P6_3 > 24) break;      //hier Zeile 248
7
  P3OUT |=BIT0;  // ZU-fahren HALT
8
  ZU=0;
9
}

Faellt der was auf?
Formatier deinen Code, streich Duplikate usw.

HTH leo
Gast #5757363
Lesenswert?

Tim T. schrieb:
> Langsam wirds lächerlich:
>
>
1
>        while(hub >(ventilstellung_alt-umdrehung_zu ))
2
> {
3
>        P3OUT &=~BIT0; // ZU-fahren
4
>        if ( ADW_P6_3 > 24) break;      //hier Zeile 248
5
> }
6
>
>
> KLAMMERN!

Woher ADW_P6_3 den AKTUELLEN Wert hat, steht dann auch wieder in den 
Sternen. Wie kommt man eigentlich als so minderbegabt auf die Idee so 
ein Projekt zu machen? Dir fehlt es ja anscheinend an allem...
#5759554
Lesenswert?

Wahrscheinlich war ich diesmal zur falschen Zeit am falschen Ort, denn 
normalerweise wird hier im Forum zumeist konkret auf  Fragen 
eingegangen.
Unabhängig von seinen "sinnlosen Kommentaren" führten die 
Programmschnipsel von Tim T. letztendlich zum Erfolg.
Auch wenn es "nur" die Klammern waren.
So was sieht nun mal ein Laie nicht, auch wenn es "lächerlich" 
erscheinen soll.
Vielen Dank.
Hier die aus meiner Sicht geänderte entscheidende Funktion.

void ventil_schliessen_regler(void)
      {
       ZU=1;                      //zähler zählt herunter
       while(hub >(ventilstellung_alt-umdrehung_zu ))
       {
       ADW_lesen();               // Stromaufnahmemessung übernehmen
       if ( ADW_P6_3 > 80) break; // ADW_6_3=Kanal 6.3; Stromaufnahme
       // wird am Anschlag überschritten; while-Schleife wird verlassen
       P3OUT &=~BIT0;             // ZU-fahren
       }
       P3OUT |=BIT0;              // ZU-fahren HALT
       ZU=0;
       }
#5759617
Lesenswert?

äxl schrieb:
>> fragt ein Programmierlaie
>
> Ging ja wieder heiss her hier, gestern abend.
> Dafür, dass er 'n Laie ist auf dem Gebiet, geht das doch. Etwas holperig
> und ungelenk vielleicht.
> Aber trotzdem muss man hier nicht soo arrogant reagieren. Schade...

Ich stimme dir zu äxl. Es ist schade, traurig und dumm. Jeder ist Mal 
Laie und Mal Fachmann auf einem Gebiet. Mit etwas mehr Verständnis 
füreinander würd's hier glatt noch Spass machen ... . Wahrscheinlich zu 
gut für einige.
#5759674
Lesenswert?

Tim T. schrieb:
>Wobei aber ADW_P6_3 WÄHREND der Schleife nicht aktualisiert wird,

Hat das programmiertechnische Gründe oder liegt es an der Arbeitsweise 
des MSP430F1611?
Ich hatte eigentlich gedacht, dass der AD-wandler die Abtastung der 
Kanäle mit
ADC12CTL0 |= ADC12SC+ ENC;
ständig wiederholt  und dass mit
ADW_P6_3 = ADC12MEM3;
der Speicher ADC12MEM3 abgefragt wird und damit ADW_P6_3 auch beim 
Durchlaufen der while-Schleife aktuell ist.
Gast #5759704
Lesenswert?

Roland E. schrieb:
> Tim T. schrieb:
>> Wobei aber ADW_P6_3 WÄHREND der Schleife nicht aktualisiert wird, also
>> entweder ist die Stromaufnahme schon vor der Schleife zu hoch und damit
>> als Abbruchbedingung vorhanden oder es wirkt sich in der Schleife auch
>> nicht aus...
>
> Das aktualisieren passiert neben der Main() im interrupt.

Nö, ADW_P6_3 wird nur in der ADW_lesen() Funktion zugewiesen und die 
wird nirgends aufgerufen...
#5759736
Lesenswert?

Roland E. schrieb:
>Das aktualisieren passiert neben der Main() im interrupt.
Könnte das hier so gemeint sein? (aus  SLAU049E)

Repeat-Sequence-of-Channels Mode
A sequence of channels is sampled and converted repeatedly. The ADC
results are written to the conversion memories starting with the 
ADC12MEMx defined by the CSTARTADDx bits. The sequence ends after the 
measurement
of the channel with a set EOS bit and the next trigger signal re-starts 
the
sequence. Figure 17−9 shows the repeat-sequence-of-channels mode.

wolle g. schrieb:
>> ADW_P6_3 = ADC12MEM3;

>Das ist ne Zuweisung, mehr nicht. Und wann wird die in der Schleife
>gemacht? Richtig, garnicht.
Gibt es eine Lösung, um an den aktuellen Wert von ADW_P6_3  innerhalb 
der while-Schleife zu kommen?
Gast #5759756
Lesenswert?

> wolle g. schrieb:
> Gibt es eine Lösung, um an den aktuellen Wert von ADW_P6_3  innerhalb
> der while-Schleife zu kommen?

Argh, das ist echt so traurig.

ADW_P6_3 hat NATÜRLICH immer seinen aktuellen Wert, es ist ja nur ein 
verdammter int, geht auch garnicht anders, nur das ist überhaupt nicht 
was du willst!

Du willst nicht den aktuellen Wert von ADW_P6_3 wissen sondern den 
aktuellen Wert was bei der ADC Wandlung rausgekommen ist und jetzt 
Quizfrage, wo steht diese Information wohl?

Ob du den dann noch ADW_P6_3 zuweisen möchtest oder ob du ihn direkt 
nutzen willst ist dabei total egal...
#5759835
Lesenswert?

wolle g. schrieb:
> ... schrieb:
>> Im Moment kenne ich nur den Codeschnipsel.
>
> deshalb als Anhang mal das gesamte Hauptprogramm, auch wenn es
> vielleicht nicht allen Anforderungen entsprechen sollte.

Nein, das ist nicht das gesamte Programm.
* Was verbirgt die includierte C-Datei namens "DS10-gP12-SD_MAINTI.c" ?
* Sind da vielleciht die Funktionen temp_messung_starten() und 
FKA_einrichten() definiert?

Ausserdem: Die pauseX() Funktionen werden wenn du Glück oder Pech hast, 
vom Compiler komplett wegoptimiert und bewirken allen das gleich, 
nämlich NIX. Du hast einen Timer - benutzt den!
Gast #5759996
Lesenswert?

max123 schrieb:
> Hallo,
>
> Das alte Pferd
>
> XXX:
> goto
>
> läuft noch. Und sogar in der Bibel (K&R) wird es für tief
> verschachtelten Schleifen empfohlen.
> ( Gültig für C/C++ und Arduino)

Praktisch um dem toten Pferd den Rest zu geben? Gotos sind fast immer 
Unsinn, das einzige wofür ich die z.B. benutze ist um bei Treiber 
initialisierungen Stufenweise zu deinitialisieren wenn was schief läuft. 
Hier haben sie jedenfalls garnix zu suchen.
#5760135
Lesenswert?

Eric B. schrieb:
> Ausserdem: Die pauseX() Funktionen werden wenn du Glück oder Pech hast,
> vom Compiler komplett wegoptimiert und bewirken allen das gleich,
> nämlich NIX. Du hast einen Timer - benutzt den!

Das hat aber nichts mit dem Thema while ... zu tun.
Aber wenn man evtl. mein Programm verbessern möchte, dann bitte mit 
konkreten Zeilen (einschließlich Klammern usw.)

>Du hast einen Timer - benutzt den!
Damit kann ich z.B. in diesem Fall gar nichts anfangen.

Nach der oben gezeigten Korrektur läuft man Programm, wobei jetzt noch 
offen ist, welcher Wert der Stromaufnahme für den Abbruch der Schleife 
verwendet wird. Während des Lauf der while-Schleife oder vor Beginn der 
Schleife.
M.M. nach müsste es der ADW_P6_3 Wert sein, der während des 
Schleifenlaufs vom AD_Wandler (ADCM12EM3) gemessen wird.
Gast #5760160
Lesenswert?

wolle g. schrieb:
> M.M. nach müsste es der ADW_P6_3 Wert sein, der während des
> Schleifenlaufs vom AD_Wandler (ADCM12EM3) gemessen wird.

-.-

ADW_P6_3 ist einfach nur eine Variable vom Typ int, die überhaupt nichts 
selber macht, der musst du, damit du irgendwas sinnvolles damit machen 
kannst, schon einen entsprechenden Wert zuweisen.
ADCM12EM3 ist ein Ergebnisregister wo die ADC-Einheit nach jedem 
Messvorgang ein Ergebniswert rein schreibt, komplett unabhängig von 
deinem sonstigen Programmablauf. Du machst die ganze Zeit den Fehler, 
dass du aus irgendwelchen Gründen erwartest, dass die Variable ADW_P6_3, 
warum auch immer, den gleichen Wert wie das Messergebnis im Register 
ADCM12EM3 besitzt. Die VARIABLE ADW_P6_3 muss der Wert aus dem REGISTER 
ADCM12EM3 zugewisen werden ( ADW_P6_3 = ADCM12EM3 ) und das musst du vor 
jeder Prüfung innerhalb der Schleife machen, sonst testest du jeweils 
nur gegen den alten Wert der Variablen ADW_P6_3. Wobei sich da natürlich 
dann die Frage stellt, warum du nicht direkt das REGISTER ADCM12EM3 
testest (z.B. if ( ADCM12EM3 > 80 ) break;) !?

Und jetzt hab ich keine Lust mehr...
#5760247
Lesenswert?

Tim T. schrieb:
>Und jetzt hab ich keine Lust mehr...
Nicht so schnell aufgeben!

> Die VARIABLE ADW_P6_3 muss der Wert aus dem REGISTER
> ADCM12EM3 zugewiesen werden ( ADW_P6_3 = ADCM12EM3 )

Wahrscheinlich hast Du es übersehen.
In der Funktion:    int ADW_lesen(void)
werden  die ADW-Register gelesen.
Das soll jetzt kein Vorwurf sein, denn mein Programm lädt vermutlich 
nicht zum Studium ein.

>Wobei sich da natürlich dann die Frage stellt, warum du nicht direkt das 
>REGISTER ADCM12EM3 testest (z.B. if ( ADCM12EM3 > 80 ) break;) !?
Die Frage ist berechtigt. Hier bin ich dem Holzweg gelandet. Vor 
gewisser Zeit hatte ich etwas zur Funktionsweise des AD-Wandlers falsch 
gedeutet.
Gast #5760265
Lesenswert?

wolle g. schrieb:
> Wahrscheinlich hast Du es übersehen.
> In der Funktion:    int ADW_lesen(void)
> werden  die ADW-Register gelesen.
> Das soll jetzt kein Vorwurf sein, denn mein Programm lädt vermutlich
> nicht zum Studium ein.

Nein, wenn du mal weiter oben genau gelesen hättest, wäre dir 
aufgefallen das ich die schon gefunden hab, aber sie wird nirgendwo 
aufgerufen, was ich aber auch oben geschrieben hab.
Jetzt bin ich aber wirklich raus, ist müßig wenn nichtmal der ganze Text 
gelesen wird...
#5760293
Lesenswert?

Prozessor Dokter Schmunz schrieb:
> Quatsch. Das sind Weicheierschleifen.
>
> Männerschleifen werden SO geschrieben:While(1) {
>   if(Abbruchbedingung)
>      {break;}
> }

Echt lustig, dass du Männerschleifen und Rheinwerk (Jürgen Wolf) in 
einem Beitrag gemeins erwähnst.

Ich sage nicht, dass du falsch liegst, aber es kommt auf das Problem 
drauf an, man kann vieles nicht einfach über ein Kamm scheren.
Manchmal ist es Sinnvoller beides oder doch nur das eine zu 
machen...oder vllt. doch eine

do
{
/* */
} while (x);

Deine while(1) ist nämlich in deinem Link nicht zu finden...
DORT steht die Abbruchbedingung auch im Kopf der while().

Naja, sei es drum.

Und nun geht es seid 2 Tagen und hab in allen Beiträgen keine Anständige 
Antwort gesehen, die dem TO als Lösung dienen könnte...
#5760311
Lesenswert?

wolle g. schrieb:
> Wie kommst Du darauf? Mit Hilfe von Tim T. wurde das Problem im Prinzip
> gelöst.
> siehe meinen Beitrag 05.03.2019 13:48

Ja OK,

Ich bin davon ausgegangen, dass du die Klammern nicht gesetzt hast, da 
du wolltest das die while nur die nächste Anweisung einbezieht.
( Hatte den geposteten C Code nicht gesehen) lediglich dein ersten 
Code-Schnipsel.
#5760806
Lesenswert?

Tim T. schrieb:
>aber sie wird nirgendwo aufgerufen,

Ich denke, im Programmschnipsel vom 05.03.2019 13:48 wird mit
ADW_lesen();  ADC12MEM3 abgerufen.

void ventil_schliessen_regler(void)
      {
       ZU=1;                      //zähler zählt herunter
       while(hub >(ventilstellung_alt-umdrehung_zu ))
       {
       ADW_lesen();               // Stromaufnahmemessung übernehmen
       if ( ADW_P6_3 > 80) break; // ADW_6_3=Kanal 6.3; Stromaufnahme
       // wird am Anschlag überschritten; while-Schleife wird verlassen
       P3OUT &=~BIT0;             // ZU-fahren
       }
       P3OUT |=BIT0;              // ZU-fahren HALT
       ZU=0;
       }


Mit  ADW_P6_3 = ADC12MEM3;
enthält m. E. ADW_P6_3 das Messergebnis, welches in ADC12MEM3 aktuell 
steht.

>Jetzt bin ich aber wirklich raus,

Nee, nee; Das ist erst möglich, wenn Du mich überzeugt hast.
Gast #5760848
Lesenswert?

Ach ja, Variablen dürfen auf längere sprechende Namen haben, welche die 
genaue Funktion beschreiben.
1
stromaufnahme = stromaufnahme_stellmotor();
2
if (stromaufname > 80) break;

oder auch gleich
1
if (stromaufnahme_stellmotor() > 80) break;

hört sich schon besser an als
1
ADW_lesen();               // Stromaufnahmemessung übernehmen
2
if ( ADW_P6_3 > 80) break;

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