while( ) >>> mit Bedingungen

OP #4433498
Lesenswert?

Hallo.
Möchte eine Endlosschleife durch eine Bedingung in der while-Schleife 
unterbrechen. Währe super einfach, ohne Interrupt und if().

Sobald Eingang/PB5 "1" ist, wird die Schleife gestoppt.
while((PINB & (1<<PB5)) == 0) // klappt nicht

umgekehrter Fall PB= 0= Stop
while(PINB & (1<<PB5)) // klappt auch nicht
Gast #4433571
Lesenswert?

Ein Buch... besorg dir bitte ein C-Buch!
Und nein, selbst wenn du eins haben solltest, dann hast du es nicht 
gelesen, auch wenn du jetzt was anderes behaupten magst.
Auch ausreden wie "Ich hab keine Zeit und/oder kein Geld", sind und 
bleiben ausreden.
Gast #4433592
Lesenswert?

Ulrich F. schrieb:
> mr. mo schrieb:
>> Was du willst ist folgendes:
>
> Eine Endlosschleife?
>
> Grundregel:
> Es darf nur eine geben!

Hehe :)

Ich bin davon ausgegangen, dass der TO ein wenig mit denkt und natürlich 
nicht meinen Pseudocode eins zu eins in sein Programm kopiert :).

Ist natürlich nur eine Anregung wie man vorgehen könnte, gibt wie sie 
oft viele Möglichkeiten.
#4433900
Lesenswert?

Ich denke Du willst in einer Funktion warten, bis der PINB5 auf 1 
gegangen ist.

while(!(PINB&0x10));           oder auch
while((PINB & (1<<PB5)) == 0); wie du schreibst sollte eigentlich 
funktionieren.

Hast Du schon mal überprüft, ob der Pin überhaupt als Eingang 
konfiguriert ist?

und lass solche sachen wie "if(..) break" in einer Schleife,
das ist schlechter stiel, und sollte genauso wie continue nicht 
verwendet werden. (MISRA)

sonst nimm
1
int abbruch = FALSE;
2

3
while(!abbruch)
4
{
5
...
6
   if(PINB & (1<<PB5))
7
   {
8
      abbruch = TRUE;
9
   }
10
...
11
}
dabei wird die Schleife zumindest noch zu Ende geführt.
Gast #4433938
Lesenswert?

Norbert H. schrieb:
> und lass solche sachen wie "if(..) break" in einer Schleife,
> das ist schlechter stiel, und sollte genauso wie continue nicht
> verwendet werden. (MISRA)

wie soll man das denn sonst machen wenn man ein einer liste etwas sucht? 
Goto?
1
while( interator != list.end() ) {
2
   if ( interator == gesucht ) {
3
      break;
4
    }
5
}

was ist daran anzusetzen?
Gast #4433945
Lesenswert?

Ein Seitenausstieg aus einer Schleife, oder auch aus einer Funktion ist 
schlechter Stil.
So wie die Verwendung von GOTO.

Es ist nicht verboten.
Es macht manchmal Sinn, wenn alles andere zu kompliziert wird.
Gast #4433964
Lesenswert?

mr. mo schrieb:
> Andreas B. schrieb:
>> while( interator != list.end() && !(( interator == gesucht )) )
>
> So einfach das man gar nicht dran denkt. Danke :)

Prima und wenn du dann mehrere Bedingungen hast, und Werte einzelner 
Bedingungen eventuell erst berechnet oder von Unterfunktionen geholt 
werden müssen?
Dann machst du eine while Bedingung, die 1000 Zeichen lang ist?
Gast #4433973
Lesenswert?

> while( interator != list.end() && !(( interator == gesucht )) )

Das ist deutlich schlechter lesbar und deswegen für mich schlechter 
Stil. Ein if () break; in einer übersichtlichen Funktion ist da deutlich 
besser in meinen Augen.

BTW: Warum einfach wenns auch kompliziert geht:

void Warte(uint16_t WarteMS)
{
  while(WarteMS)                  // Wartezeit
  {
    WarteMS--;                  // runter zählen
    _delay_ms(1);                // 1ms
  }
}
#4433975
Lesenswert?

Der Andere schrieb:
> Dann machst du eine while Bedingung, die 1000 Zeichen lang ist?

Ich (und andere auch) habe nicht behauptet, daß man nie mit break aus 
einer Shliefe gehen soll. Man versucht es nur zu vermeiden. In diesem 
Fall war es einfach.

Allerdings kann man auch in Deinem Fall die Bedingung "interator == 
gesucht" innerhalb der Schleife erzeugen. Das muß nicht in der while 
Bedingung geschehen.

Gruß
Andreas
#4433977
Lesenswert?

Der Andere schrieb:
> mr. mo schrieb:
>> Andreas B. schrieb:
>>> while( interator != list.end() && !(( interator == gesucht )) )
>>
>> So einfach das man gar nicht dran denkt. Danke :)
>
> Prima und wenn du dann mehrere Bedingungen hast, und Werte einzelner
> Bedingungen eventuell erst berechnet oder von Unterfunktionen geholt
> werden müssen?
> Dann machst du eine while Bedingung, die 1000 Zeichen lang ist?

Dann fasst man alle möglichen Abbruchbedingungen in einem Flag zusammen, 
welches man im Schleifenkopf abfragt.
#4433980
Lesenswert?

Gas_t schrieb:
> Das ist deutlich schlechter lesbar und deswegen für mich schlechter
> Stil. Ein if () break; in einer übersichtlichen Funktion ist da deutlich
> besser in meinen Augen.

Und die break Bedingung dann in der Schleife suchen?
Bei kurzen Schleifen vielleicht...

Kannst es auch so schreiben, wenn Dir das besser gefällt:
while( interator != list.end() &&
    !(( interator == gesucht )) )


Gruß
Andreas
#4433993
Lesenswert?

Mark B. schrieb:
>> Dann machst du eine while Bedingung, die 1000 Zeichen lang ist?
> Dann fasst man alle möglichen Abbruchbedingungen in einem Flag zusammen,
> welches man im Schleifenkopf abfragt.

Andreas B. schrieb:
> Und die break Bedingung dann in der Schleife suchen?

Naja, ob ich jetzt am Ende der Schleife weiß, dass "done == true" ist, 
oder ob irgendwo in der Schleife ein "break" gefeuert hat, macht jetzt 
keinen Unterschied.

Im Übrigen bin ich der Meinung, dass Kommentare bei soetwas hilfreich 
sind.
#4433995
Lesenswert?

Es gibt da durchaus zwei Ansätze:
1
char * SearchChar(char * String, char Char){
2
  while((*String != '\0) && (*String != Char)){
3
    String++;
4
  }
5
  return (*String == Char) ? String : NULL;
6
}
1
char * SearchChar(char * String, char Char){
2
  while(*String != '\0'){
3
    if(*String == Char){
4
      return String;
5
    }
6
    String++;
7
  }
8
  return NULL;
9
}

Ich bevorzuge die zweite Variante, obwohl das return innerhalb der 
Schleife ist (und somit einem break/goto entspricht) und ich sogar zwei 
davon habe.

Ich handhabe das meistens so:
Wenn es einfach und leserlich möglich ist, verwende ich die Bedingung im 
Schleifenkopf. Ist es hässlich, z.B. Flags über mehrere Ebenen, 
spendiere ich auch mal ein goto, das direkt hinter die Schleife springt. 
Zugegeben, dieser Fall tritt sehr selten auf, zumal ich für jeden 
Scheiss eine Funktion schreibe und dann meist ein return in der Schleife 
steht. Wenn ansonsten nichts in der Funktion gemacht wird (also reines 
Suchen), ist ein return in und eines nach der Schleife meiner Meinung 
nach kein schlechter Stil.

@TO: Warten in einer while-Schleife ist meist eine schlechte Idee, da 
dadurch der Controller auf unbestimmte Zeit blockiert ist. Besser ist 
es, nur auf eine Änderung der Eingangspins zu reagieren (pollen). Wenn 
die Bedingung nicht erfüllt ist, macht der Controller in der 
Zwischenzeit etwas anderes und prüft später nochmals.
Gast #4434002
Lesenswert?

Ulrich F. schrieb:
> Ein Seitenausstieg aus einer Schleife, oder auch aus einer Funktion ist
> schlechter Stil.
Finde ich auch nicht. Ein
1
if(Fehler aufgetreten)
2
    return 1;
finde ich schöner und sinnvoller als
1
if(Kein Fehler aufgetreten)
2
{
3
    Zeug();
4
    Mehr_Zeug();
5
    ...
6
    Anderes_Zeug();
7
    Fehlercode=0;
8
}
9
else  // Wo? welche Fehler war das? Achso, zwei Bildschirmseiten höher
10
{
11
    Fehlercode=-1;
12
}
13
return Fehlercode;
oder
1
if(Fehler aufgetreten)
2
    return -1;
3
else   //Sinnlos
4
{
5
    ...
6
}
Oder wie würdest du in dem Fall vorgehen?
Gast #4434034
Lesenswert?

Dussel schrieb:
> Oder wie würdest du in dem Fall vorgehen?
In dem Fall? KA, ist mir auch eigentlich recht egal...

Eben habe ich schon versucht zu sagen, dass es Trotz schlechtem Stil 
manchmal die einfachste Möglichkeit ist.

Bedenke:
Wer einmal begriffen hat, wie ein Hammer funktioniert, für den sieht 
plötzlich jedes Problem wie ein Nagel aus.


Alles, was die Lesbarkeit beeinträchtigt, ist schlechter Stil.
Und in der Regel gilt: Je mehr Ausstiegspunkte, desto unübersichtlicher.
Gast #4434038
Lesenswert?

Norbert H. schrieb:
> und lass solche sachen wie "if(..) break" in einer Schleife,
> das ist schlechter stiel, und sollte genauso wie continue nicht
> verwendet werden. (MISRA)

Eigentlich sagt MISRA , dass man pro Schleife maximal ein "break" 
verwenden soll (siehe MISRA 2004, Rule 14.6 bzw. Misra 2012, Rule 15.4). 
Ich verwende "break" ganz gerne um in kritischen Situationen sofort aus 
einer Schleife zu springen. Für die reguläre Iteration nutze ich aber 
auch die Prüfung im Schleifenkopf/-fuß.

Jedenfalls würde ich die Verwendung von "break" nicht generell 
verteufeln, es gibt durchaus Situationen wo es ganz nützlich sein kann 
und die Les- und Wartbarkeit des Codes erhöht.
Gast #4434042
Lesenswert?

Mark B. schrieb:
> Dann fasst man alle möglichen Abbruchbedingungen in einem Flag zusammen,
> welches man im Schleifenkopf abfragt.

Das ist dann aber eine andere Funktionalität, weil dann Code ausgeführt 
wird, der beim ersten brake nicht mehr ausgeführt worden wäre.
Einfaches Beispeil, es gehen mehrere Werte in eine Berechnung ein, aber 
einer davon ist 0 und durch den soll geteilt werden.
Also müsste man jede weitere Berechnung mit einem if (x !0 0) klammern.

Aber programmiert ruhig "stilistisch sauber" ich konzentriere mich auf 
fachlich korrekt und möglichst bugfrei :-)
#4434051
Lesenswert?

Ulrich F. schrieb:
> Alles, was die Lesbarkeit beeinträchtigt, ist schlechter Stil.
> Und in der Regel gilt: Je mehr Ausstiegspunkte, desto unübersichtlicher.

Bedingt. Folgendes Beispiel halte ich für leserlich:
1
int foo( /* ... */ ){
2
  if(BedingungA){
3
    return FehlerA;
4
  }
5
  if(BedingungB){
6
    return FehlerB;
7
  }
8
  if(BedingungC){
9
    return FehlerC;
10
  }
11
  
12
  /* eigentliche Funktion */
13
  
14
  return Result;
15
}

Aber grundsätzlich gebe ich dir Recht. Funktionen, die über zwei 
Bildschirmseiten ragen und mit returns gespickt sind, sind nicht 
wirklich übersichtlich. Was hälst du von Exceptions? Das sind im Prinzip 
auch returns, einfach ein wenig anders.
#4434247
Lesenswert?

mr. mo schrieb:
> Andreas B. schrieb:
>> while( interator != list.end() && !(( interator == gesucht )) )
>
> So einfach das man gar nicht dran denkt. Danke :)

Aber unsinnig.

Normalerweise will man ja mit dem gefundenen Element etwas machen (und 
das kann man nicht wenn es nicht gefunden wurde).
1
 while( interator != list.end() ) {
2
    if ( interator == gesucht ) {
3
       do_something(iterator) ;
4
       break;
5
     }
6
 }
geht dann nämlich schon nicht mehr mit Andreas seinem "Pattern".
#4434323
Lesenswert?

Michael B. schrieb:
> mr. mo schrieb:
>> Andreas B. schrieb:
>>> while( interator != list.end() && !(( interator == gesucht )) )
>>
>> So einfach das man gar nicht dran denkt. Danke :)
>
> Aber unsinnig.
...
> geht dann nämlich schon nicht mehr mit Andreas seinem "Pattern".

Das ist nicht das Problem mit dem Pattern. Abgesehen davon, dass 
list.end() C++ vermuten lässt, wobei std::find vorzuziehen währe, fällt 
anscheinend niemandem auf, dass man den Iterator in der Schleife erhöhen 
muss oder sonstwie auf das nächste Element setzen sollte.

In C könnte das so aussehen, wenn man es richtig macht:
1
#include <stdio.h>
2

3
int main(){
4

5
  int gesucht = 2;
6
  int list[] = {1,2,3};
7
  int*const list_end = list + sizeof(list) / sizeof(*list);
8

9
  int* it;
10
  for( it=list; it<list_end; it++ )
11
    if( *it == gesucht )
12
      break;
13

14
  if( it == list_end ){
15
    printf("Not found\n");
16
  }else{
17
    printf("Found %d at index %u\n",*it,(unsigned)(it-list));
18
  }
19

20
  return 0;
21
}
#4434478
Lesenswert?

Ich finde folgende Lösung deutlich angenehmer zu lesen. Kurz und 
knackig, und der Compiler warnt mich, wenn ich das Array überrenne.
1
#define LIST_SIZE 3
2
int list[LIST_SIZE] = {1, 2, 3};
3

4
for(size_t i = 0; i < LIST_SIZE; i++) {
5
  if(list[i] == gesucht) {
6
    /* tu was */
7
    break;
8
  }
9
}

Wenn im "nicht gefunden"-Fall noch eine spezielle Aktion dazu kommt, 
oder wenn ich wissen will, wie oft ich das Element gefunden habe, dann 
kommt ein Flag (oder Zähler) dazu.
#4434753
Lesenswert?

... wegen des originalen Problems des digitalen Eingangs auf PB5.

Jetzt kenne ich die Schaltung der Hardware nicht, aber lt. Programm 
solltest du entweder einen externen Pop-Up Widerstand an PB5 haben, oder 
den internen Pop-Up Widerstand einschalten.

mit
1
DDRB &= ~(1 << PB5);

schaltest du PB5 als Eingang, aber dieser Eingang hängt in der Luft und 
hat keinen definierten Zustand.

mit
1
DDRB &= ~(1 << PB5);
2
PORTB |= (1 << PB5);

schaltest du den internen Pop-Up Widerstand ein .

Gruß,
Ralph
OP #4435453
Lesenswert?

Ralph S. schrieb:
> ... wegen des originalen Problems des digitalen Eingangs auf PB5.
So sieht der Kopfbereich aus.
Hier soll das Programm stoppen, wenn PB5 auf Vcc liegt.

int main(void)
{
  DDRB &= ~(1<<PB5);  // Eingang, kein pull-up, via.100k auf Gnd

  while(1)
  {

    //while((PINB & (1<<PB5))==0);  //Versuch1, klappt nicht
    //while(!(PINB & (1<<PB5))==1);  //Versuch2, Stop, wenn PB5 low
    //while(!(PINB & (1<<PB5)));  //Versuch3, klappt nicht
    //while((PINB & (1<<PB5))!=1);  //Versuch4, klappt nicht
    //while((PINB & (1<<PB5))!=0);  //Versuch5, reagiert nicht
    //while((PINB & (1<<PB5))==1);  //Versuch6, Stop, wenn PB5 low
    while(PINB & (1<<PB5));    //Versuch7, Stop, wenn PB5 low
    ...

Ich verstehe nicht, dass die die Prüfung auf 0 (Versuch 6+7) 
funktioniert, die Invertierung aber nicht.
Scheint sich um ein generelles Verständnisproblem zu handeln - aber wo 
steck der Fehler?
Moderator (Firma: Titel) Persönliche Seite #4435480
Lesenswert?

__Son´s B. schrieb:
> aber wo steck der Fehler?
Was kommt bei PINB & (1<<PB5) raus?
1) wenn der Pin high ist: 0b00100000 = 0x20 = 32
und es gilt !0b00100000 = 0b00000000 = 0x00 = 0
2) wenn der Pin low ist:  0b00000000 = 0x00 = 0
hier gilt   !0b00000000 = 0b00000001 = 0x01 = 1

So, und jetzt trägst du das einfach mal in deine Abfragen ein:
Bei Eingang high
while(32==0)
while(0==1)
while(0)
while(32!=1)
while(32!=0)
while(32==1)
while(32)

Bei Eingang low
while(0==0)
while(0==1)
while(1)
while(0!=1)
while(0!=0)
while(0==1)
while(0)

Und dann überlegst du, ob die jeweilige Bedingung 0 (=false) ergibt. 
Falls die Bedingung falsch ist oder 0 ergibt, dann wird die Schleife 
abgebrochen. Ist sie ungleich 0 oder wahr, dann wird die Schleife 
ausgeführt. So einfach ist das. Da muss man nicht wirr herumstochern...


EDIT: Korrigiert entsprechend nachfolgendem Post...  :-/
OP #4436857
Lesenswert?

Lothar M. schrieb:
> Was kommt bei PINB & (1<<PB5) raus?
> 1) wenn der Pin high ist: 0b00100000 = 0x20 = 32
Folgendes funktioniert leider auch nicht. Habe noch kein Ausgabedisplay 
um interne Zustände sichtbar zu machen.
while((PINB&(1<<PB5))==32); // PB1=1 soll Schleife stoppen

Wie kann ich sicher sein, dass bei
PINB&(1<<PB5) = 0b00100000 = 32
alle Bits ausser PB5, garantiert 0 sind?

Müsste nicht erst einmal der PINB komplet ausgelesen und im Anschluss 
verglichen werden?
Moderator (Firma: Titel) Persönliche Seite #4436901
Lesenswert?

__Son´s B. schrieb:
> Wie kann ich sicher sein, dass bei
> PINB&(1<<PB5) = 0b00100000 = 32
> alle Bits ausser PB5, garantiert 0 sind?
Gar nicht, das ist für diese Abfrage auch uninteressant. Hier wird nur 
das Bit PB5 betrachtet (der Profi sagt "verUNDet" oder "ausmaskiert").
Wenn du abfragen willst, ob der gesamte Port genau den Wert 0b00100000 
hat, dann musst du so schreiben:
if (PINB = (1<<PB5)) ...

> Wie kann ich sicher sein, dass bei
> PINB&(1<<PB5) = 0b00100000 = 32
> alle Bits ausser PB5, garantiert 0 sind?
Mal angenommen, der PB wäre real 0b10101010, dann bleibt durch die UND 
Funktion mit (1<<PB5) also 0b00100000 noch genau 0b00100000 übrig.

__Son´s B. schrieb:
> while((PINB&(1<<PB5))==32); // PB1=1 soll Schleife stoppen
Der Compiler wertet nur den Code aus, nicht die Kommentare!
Im Code wird Pin 5 am Eingangsport B abgefragt...
#4436909
Lesenswert?

__Son´s B. schrieb:
> Wie kann ich sicher sein, dass bei
> PINB&(1<<PB5) = 0b00100000 = 32
> alle Bits ausser PB5, garantiert 0 sind?

Meinst du auf das Resultat von PINB & (1<<PB5) bezogen?
PB5 ist 5. 1<<PB5 ist 32 ist 0b00100000. Ein einzelnes '&' zeichen ist 
binär und. Es bleibt also so oder so nur das Bit von PB5 übrig:

PINB    a b c d e f g h
1<<PB5  0 0 1 0 0 0 0 0
-----------------------
Result  0 0 c 0 0 0 0 0

Falls du aber wissen willst, ob keines der Bits von PINB ohne PB5 
gesetzt ist, dann wäre dass so: !( PINB & ~(1<<PB5) )

PINB       a b c d e f g h
~(1<<PB5)  1 1 0 1 1 1 1 1
---------------------------
           a b 0 d e f g h

Lothar M. schrieb:
> Wenn du abfragen willst, ob der gesamte Port genau den Wert 0b00100000
> hat, dann musst du so schreiben:
> if (PINB = (1<<PB5))

c'mon, da müssen 2 gleich hin: if (PINB == (1<<PB5))
OP #4436958
Lesenswert?

Daniel A. schrieb:
> Meinst du auf das Resultat von PINB & (1<<PB5) bezogen?
Ja, es geht mir nur(!) um den Status von PB5! Daher ist die Maskierung 
richtig.

Ich möchte folgendes;
wenn an PB5 ein high anliegt, soll die Schleife durch while(...); 
gestoppt/angehalten werden. Aber nur dann!

DDRB &= ~(1<<PB5);  // ATTiny85

--Bsp.1--
Wenn also 0b0010 0000 anliegt, sollte der Vergleich
((PINB&(1<<PB5))==32)
"wahr", oder "1" sein!?

--Bsp.2--
Genau so, wenn 0b0010 0000 anliegt, müsste der Vergleich
((PINB&(1<<PB5))!=0)
gneauso "wahr" oder "1" sein!?

Warum klappt das nicht bei mir?
Moderator (Firma: Titel) Persönliche Seite #4436975
Lesenswert?

__Son´s B. schrieb:
> soll die Schleife durch while(...); gestoppt/angehalten werden.
Eine kleine Wiederholung: eine Schleife wird nicht "angehalten" oder 
"gestoppt". Sie wird "beendet", denn der Prozessor läuft mit Vollgas 
weiter...

> Wenn also 0b0010 0000 anliegt, sollte der Vergleich
> ((PINB&(1<<PB5))==32)
> "wahr", oder "1" sein!?
Richtig. Und dann läuft die Schleife noch einmal durch. Es reicht aber 
auch aus, auf
if  (PINB&(1<<PB5)) ...
abzufragen, denn dann ist das bei einem High am Pin B5 gleich wie
if (32) ...
und 32 ist ungleich 0 und damit wird die Schleife nochmal durchlaufen.

> Warum klappt das nicht bei mir?
Sehr wahrscheinlich, weil du noch was anderes falsch machst. Gern werden 
z.B. Taster mit Pullups nach GND geschaltet, und dann ist der Eingang 
natürlich '0', wenn die Taste gedrückt ist....
#4436979
Lesenswert?

Was spricht eigentlich gegen die Verwendung der Makros "bit_is_set" bzw. 
"bit_is_clear"?
1
bit_is_set(PINB, PB5)

Könnte doch einige Verwirrung vermeiden. Und wenn man partout den 
Programmablauf unterbrechen will gibt es "loop_until_bit_is_set" bzw. 
"loop_until_bit_is_set".
OP #4437036
Lesenswert?

Lothar M. schrieb:
> Richtig. Und dann läuft die Schleife noch einmal durch. Es reicht aber
> auch aus, auf
> if  (PINB&(1<<PB5)) ...
Genau hier setzt mein Verstehen aus, diese Befehlt, egal ob if() oder 
while() funktioniert bei mir nicht. Egal ob 1 oder 0 an PB5, Schleife 
wird nicht ausgeführt.

Lothar M. schrieb:
> Sehr wahrscheinlich, weil du noch was anderes falsch machst. Gern werden
> z.B. Taster mit Pullups nach GND geschaltet, und dann ist der Eingang
> natürlich '0', wenn die Taste gedrückt ist....
Kein Pull-up eingeschaltet.
Externer Pull-down über 100k auf Gnd!

J.-u. G. schrieb:
> bit_is_set(PINB, PB5)
Danke, aber ich möchte erst einmal die Bit-Manipulation und deren 
Vergleiche vollständig verstehen.

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