Forum: Mikrocontroller und Digitale Elektronik Komm mit der while Anweisung net klar


von Bastler (Gast)


Lesenswert?

Hallo zusammen,

kann mir bitte mal jemand genau die folgende Anweisung bit für bit 
erklären.
while (!(UCSR1A & (1<<UDRE1)))
Blick das mit den Opreatoren noch nicht so ganz... :-(

von Johannes M. (johnny-m)


Lesenswert?

Der Inhalt der Schleife wird ausgeführt, solange die bitweise 
UND-Verknüpfung des Registers UCSR1A mit dem Ausdruck (1 << UDRE) nicht 
wahr ist.

von Bastler (Gast)


Lesenswert?

Ich blick das nicht ganz,

weil UCSR1A ist ja ein ganzes Register, also 8 bit.
bsp. 00100000 Wenn wir mal annehmen das die 1 UDRE1 ist

jetz verunde ich zusätzlich noch UDRE damit???
Was kommt dann in diesem bsp raus??

von Johannes M. (johnny-m)


Lesenswert?

UDRE ist ein Makro, das in der Header-Datei definiert ist. Wenn UDRE das 
Bit mit der Nummer 1 ist, dann steht in der Header-Datei
1
#define UDRE 1
Wenn man jetzt eine "1" (binär 00000001) um "UDRE" Stellen (also um eine 
Stelle) nach links schiebt, dann erhält man 00000010. Und damit wird das 
UCSR1A jetzt verknüpft. Der Rest steht in jedem C-Buch und -Tutorial.

EDIT:
Sorry, muss natürlich "UDRE1" heißen und nicht "UDRE"...

von ARM-Fan (Gast)


Lesenswert?

Es wird hier UCSR1A mit einer um den Wert von UDRE1 nach links
geschobenen "1" verundet.

UDRE1 wird irgendwo in einem Header als Zahl zwischen 0..7 definiert
sein. Also als das n-te Bit.

1 << 0 = 1
1 << 1 = 2
1 << 2 = 4
1 << 3 = 8
usw.

1 << UDRE1 = ?

Klar?

von Hagen R. (hagen)


Lesenswert?

>kann mir bitte mal jemand genau die folgende Anweisung bit für bit
>erklären.
>while (!(UCSR1A & (1<<UDRE1)))
>Blick das mit den Opreatoren noch nicht so ganz... :-(


entweder ein Wert von 0 oder 00100000. Durch die UND Maske kann es nur 
diese 2 Zustände geben.

Normaleweise denkt man so

while ((UCSR1A & BitMaske) <> 0)

oder

while ((UCSR1A & BitMaske) == 0)


Nun gilt aber im C

1.) != statt <>
2.) kann man diese Schreibweise abkürzen durch Weglassen des 
Vergleiches, und das ist sau doofe C Syntax

Also es wird dann so

while (UCSR1A & BitMaske) do

solange in UCSR1A and Bitmaske <> 0 ist mache das


while (!(UCSR1A & BitMaske)) do

solange NICHT in USCR1A and Bitmaske <> 0 ist mache das, also
solange in USCR1A ad Bitmaske == 0 ist mache das

Das ist eben C Syntax, und in moderneren Sprache kommt man wieder zurück 
zu der expliziten Schreibweise. Also das was man denkt und liest 
schreibt man auch explizit hin.

Bitte Leute, keine Diskussionen ob diese Syntax schlecht oder gut ist. 
Ich weiß nur das meine Lehrlinge exakt damit immer Probleme hatten.

Gruß Hagen

von Johannes M. (johnny-m)


Lesenswert?

Hagen Re wrote:
> Bitte Leute, keine Diskussionen ob diese Syntax schlecht oder gut ist.
> Ich weiß nur das meine Lehrlinge exakt damit immer Probleme hatten.
Nee, nicht "gut" oder "schlecht", das ist tatsächlich Geschmackssache. 
Aber Spock würde korrekterweise anmerken: "Faszinierend, die Syntax ist 
logisch..."

Man muss einfach daran denken, dass in solchen Anweisungen 
Wahrheitswerte ausgewertet werden, und ein Wahrheitswert kann nunmal nur 
zwei Zustände annehmen, nämlich wahr oder falsch. Und man sollte 
wenigstens versuchen, seinen Lehrlingen/Studenten/Wasauchimmer das 
Denken in logischen Operationen nahezubringen. Klar, es gibt immer 
Leute, die sich damit schwerer tun als andere, aber: Es ist 
logisch...;-)

von Bastler (Gast)


Lesenswert?

Ok dann hier nochmal ob ich es verstanden habe....

UCSR1A ist im Moment wenn ich in die while schleife eintrete so
00100000 wobei die 1 gerade UDRE1 ist.

So nun kommt meine Anweisung

while (!(UCSR1A & (1<<UDRE1)))

Die Schleife dürfte jetzt nicht durchlaufen werden, da

00100000
&
00100000

wieder

00100000
ergeben und das doch wahr ist???
Bin ich doof, ich blick das nicht HILFE....... ;-(
Lehrling.de

von Hagen R. (hagen)


Lesenswert?

@Johannes, das bestreite ich nicht. Aber es soll Menschen geben die 
Logik anderst sprechen und denken als das was die C Entwickler darunter 
cerstanden als sie die C Syntax erschafften ;)

Da ich ebenfalls Logik anderst beigebracht bekommen habe, so wie man es 
eben spricht, muß ich ebenfalls bei komplexeren C Abfrage immer noch im 
Kopf umformulieren.

Gruß Hagen

von Johannes M. (johnny-m)


Lesenswert?

Bastler wrote:
> Ok dann hier nochmal ob ich es verstanden habe....
>
> UCSR1A ist im Moment wenn ich in die while schleife eintrete so
> 00100000 wobei die 1 gerade UDRE1 ist.
>
> So nun kommt meine Anweisung
>
> while (!(UCSR1A & (1<<UDRE1)))
>
> Die Schleife dürfte jetzt nicht durchlaufen werden, da
>
> 00100000
> &
> 00100000
>
> wieder
>
> 00100000
> ergeben und das doch wahr ist???
> Bin ich doof, ich blick das nicht HILFE....... ;-(
> Lehrling.de
Wenn UDRE1 im Header als "5" definiert ist, dann hast Du das richtig 
verstanden. Dann steht da im Klartext
1
while (!(UCSR1A & (1<<5)))
und "1 << 5" ist 00100000. Das mit dem UCSR1A bitweise verUNDet gibt 
00100000 zurück (wobei es sogar egal ist, welchen Zustand die anderen 
Bits im UCSR1A haben, denn 00100000 & XX1XXXXX gibt das selbe zurück). 
00100000 wird jetzt mit dem logischen (!) Negierungsoperator "!" 
verarbeitet. Dieser gibt genau dann eine 1 zurück, wenn der Operand 0 
ist. Der ist aber nicht 0, sondern 00100000, was ungleich Null und 
deshalb wahr ist. "!" gibt also eine 0 zurück. Dann steht da "while(0)". 
Demnach wird nicht in die Schleife hineingesprungen.

von Hagen R. (hagen)


Lesenswert?

@Bastler:

nochmal, in jeder Abfrage von IF und WHILE muß es zu einer Boolschen 
Formel kommen. Also immer nur JA oder NEIN.

Jede der kompakten, vereinfacht geschriebenen Abfragen in C kann man 
auch anders schreiben, nämlich so


while (X != 0)  <- ungleich, <>

oder eben

while (X == 0)

Das lässt sich dann kürzer schreiben

while (X)

oder

while (!(X))  <- solange NICHT (X ungleich 0)

Viele Profi-C'ler verkürzen es auf diese Weise, einerseits weil man es 
in der Mathematik der Boolschen Abfragen auch so schreibt, und 
andererseit weil man so zeigen kann das man Profi "ist".


0 ist also immer bool'sch FALSCH, und alles was nicht 0 ist ist bool'sch 
gesehen WAHR.

Gruß Hagen

von Karl H. (kbuchegg)


Lesenswert?

2 Dinge:

* In C hat praktisch jeder Ausdruck einen Ergebnis-Wert.
  Auch eine Zuweisung hat einen Wert, nämlich den Wert der
  zugewiesen wurde. Das macht Dinge wie  i = j = 5; möglich.
  Auch ein Vergleich ist nichts anderes als ein Ausdruck, der
  einen Wert liefert: i == 5 liefert 0 (FALSCH) oder 1 (WAHR)
  je nachdem, ob i eben 5 ist oder nicht. Dies macht Dinge
  wie j = ( i == 5 ); möglich, wo das Ergebnis eines Vergleiches
  in einer Variablen abgespeichert wird. Ein Vergleich ist
  auch nichts anderes als ein 'arithmetischer Ausdruck'
  (im Englischen: eine Expression) so wie 2 + 3 auch.
  Während 2 + 3 als Ergebnis 5 liefert, so liefert halt
  der Ausdruck 5 == 7 eine 0 als Ergebnis.

* Wahrheitswerte sind nichts anderes als ganze Zahlen, wobei
  0 die Bedeutung von FALSCH (FALSE) besitzt und alles was
  nicht 0 ist, die Bedeutung WAHR (TRUE) besitzt.

In C gibt es keine expliziten boolschen Datentypen, man nimmt
einfach obige Konvention her und benutzt einen Ganzzahltyp.
Bolsche Werte sind also auch nur Zahlen und auch umgekehrt:
jede Zahl kann auch als boolscher Wert fungieren, wobei das
allerdings beim while gar nicht zum tragen kommt.
In C prüft eine while Schleife eiegentlich gar nicht, ob der
angegebene Ausdruck nun TRUE oder FALSE ergibt, sondern es wird
(in Ermangelung eines expliziten Boolschen Typen) geprüft, ob
der Ausdruck 0 oder eben nicht 0 (in Übereinstimmung mit der
Konvention für boolsche Auswertung, siehe Punkt 2 da oben) ist.

Das ist alles, was man wissen muss um zu verstehen, warum
while (!(UCSR1A & (1<<UDRE1)))
so ausgewertet wird, wie es wird. Entweder der Ausdruck
!(UCSR1A & (1<<UDRE1)) ergibt 0 oder ergibt nicht 0.

von Peter D. (peda)


Lesenswert?

Hagen Re wrote:
> @Johannes, das bestreite ich nicht. Aber es soll Menschen geben die
> Logik anderst sprechen und denken als das was die C Entwickler darunter
> cerstanden als sie die C Syntax erschafften ;)
>
> Da ich ebenfalls Logik anderst beigebracht bekommen habe, so wie man es
> eben spricht, muß ich ebenfalls bei komplexeren C Abfrage immer noch im
> Kopf umformulieren.

Ich glaube nicht, daß das nur ein C-Problem ist.

Wer MCs programmieren will, muß einfach wissen, wie Binärzahlen 
aufgebaut sind und wie bitweise Operatoren (~,&,|,^) funktionieren. Das 
sind Grundlagen, da kommt keiner drumrum.


Es ist schon richtig, daß C auch logische Operatoren (!,&&,||) kennt, 
damit kann man komplexe if,else-Ketten besser lesbar darstellen.

Aber warum zum Teufel gibts kein ^^ ?


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger wrote:

> Aber warum zum Teufel gibts kein ^^ ?

Das gibt's, das heißt aber !=.
1
  if ((a > b) ^^ (b < c)) {
2
    ...
3
  }

wäre dasselbe wie
1
  if ((a > b) != (b < c)) {
2
    ...
3
  }

Wenn's dir besser gefällt, kannst du also

#define ^^ !=

schreiben. ;-)  (Obiges trifft natürlich nur zu, wenn auf beiden
Seiten echte Wahrheitswerte stehen, also nur 0 und 1 zugelassen
sind.)

von Karl H. (kbuchegg)


Lesenswert?

Jörg Wunsch wrote:
> Peter Dannegger wrote:
>
>> Aber warum zum Teufel gibts kein ^^ ?
>
> Das gibt's, das heißt aber !=.

Ich denke, Peter meinte mit ^^ das Potenzieren.

von Bastler (Gast)


Lesenswert?

Ok vielen Dank an euch alle, ich denke jetzt hab ich es auch kappiert.
Bitte streitet euch jetzt nicht ob C gut oder schlecht ist. Könnte ich 
schon so gut programmieren wie ihr, würde ich es für gut ansehen :-)

Danke nochmal
Gruß
Azubi

von Peter D. (peda)


Lesenswert?

Jörg Wunsch wrote:

> Wenn's dir besser gefällt, kannst du also
>
> #define ^^ !=
>
> schreiben. ;-)  (Obiges trifft natürlich nur zu, wenn auf beiden
> Seiten echte Wahrheitswerte stehen, also nur 0 und 1 zugelassen
> sind.)

Leider.

Man kann dann nicht schreiben:
1
if((x & 0x01) ^^ (y & 0x80))


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Peter Dannegger wrote:

> Man kann dann nicht schreiben:
>
>
1
> if((x & 0x01) ^^ (y & 0x80))
2
>
1
#define BOOL(x) ((x) != 0)
2
3
...
4
5
  if (BOOL(x & 0x01) ^^ BOOL(y & 0x80)) {
6
    ...
7
  }

von Karl H. (kbuchegg)


Lesenswert?

Bastler wrote:
> Bitte streitet euch jetzt nicht ob C gut oder schlecht ist.

Hier geht es nicht um gut oder schlecht.
In einigen Bereichen von C hat man sich überlegt, ob man die
überhaupt braucht. So zb. bei boolschen Dingen
Und man ist zu den Schluss gekommen: Nein, eigentlich brauchen
wir die ja gar nicht. Mann muss nur seine Sichtweise der Dinge
etwas verändern.

Während in vielen anderen Sprachen die Syntax (vereinfacht)
so aussieht

   if  Ausdruck Vergleichsoperator Ausdruck  then

hat man sich überlegt: Was wäre, wenn so ein Vergleichsoperator
auf einer Stufe mit den anderen arithmetischen Operatoren wie
+ - * / stehen würde, also einfach auch nur seine beiden
Operanden miteinander verknüpft und ein arithmetisches Ergebnis
liefern würde.

Und man ist zu dem Schluss gekommen, das das durchaus geht, dass
man also die Syntax von if, while vereinfachen kann zu

  if  Ausdruck  then

Natürlich braucht man noch eine Konvention dafür, wie denn das
Ergebnis des Ausdruckes sein muss, damit der then Zweig genommen
wird, aber das ist eine Frage von Konventionen und man entschied
sich für die 0 - nicht 0 Regel.
Aber: Durch den Wegfall eines expliziten bool Typen konnte man
die Sprache einfacher halten ohne das es zu Einbussen gekommen
wäre, ganz im Gegenteil, man erhielt neue Freiheiten.
So kann man in C schreiben:

  i = ( j == 5 ) * a + 3 * ( k < 8 );

Ein Vergleichsoperator liefert ja 1 wenn der Vergleich zutrifft
und 0 wenn er nicht zutrifft. Dementsprechen ist das Ergebnis
von  ( j == 5 ) * a, genau dann a wenn j gleich 5 ist (weil ja
1 * a wieder a ergibt, während 0 * a immer 0 ist).

In Langform ist obiges also

  if( j == 5 )
    i = a;
  else
    i = 0;

  if( k < 8 )
    i = i + 3;

ok. zugegeben. Die kompremierte Syntax ist für den Anfang etwas
schwer zu lesen. Wenn man sich aber mal dran gewöhnt hat, dann
kommt sie einem relativ natürlich vor. Und klarerweise benutzt
man sowas eher selten (da es meist relativ sinnlos ist). Aber
man kann zb das hier machen:

  foo( a, b, i == 5 );

anstelle von

  if( i ==  5)
    foo( a, b, 1 );
  else
    foo( a, b, 0 );

und das sieht man schon etwas häufiger.

von Hagen R. (hagen)


Lesenswert?

Das führte aber zwangsläufig dazu das sich die Syntaxgrenzen zwischen 
den einzelnen Sprachelementen verwischten. Also Zuweisung und Boolsche 
Abfragen in einem einzigsten Konstrukt. Und das wäre mein 
Hauptkritikpunkt an C. Andere Sprache reduzierten absichtlich diese 
Möglichkeiten der sehr flexiblen Schreibweisen für den gleichen 
Sachverhalt, die restriktiven Sprachen. Solche erlernt man viel leichter 
und intuitiver als C.

Wichtig ist aber letzendlich nur eines: Hat man sich in C rein-"gequält" 
wird es immer mehr Spaß machen. Ein Vorteil ist eben auch das wenn man C 
kann wird  man die einfacheren restriktiven Sprachen leichter erlernen.

Ich kann eben bestätigen das gerade bei diesen Syntaxkonstrukten die 
Lehrlinge die meisten Probleme haben und Fehler machen. Bevor das nicht 
sitzt braucht man die Pointerarithmetiken garnicht anfangen.

Gruß Hagen

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nun ist C auch nicht dazu gedacht, als Lehr- oder Unterrichtssprache 
genutzt zu werden, sondern primär als Werkzeug. Und das hat halt auch 
Eigenschaften, die es dem, der es kennt, sehr einfach machen, sie zu 
nutzen, die aber dem, der es nicht kennt, nur sehr schwer zu vermitteln 
sind.
C ist nicht Pädagogik. Programmieren ist auch nicht Pädagogik.

Pädagogik im Sinne einiger mehr oder weniger brauchbarer Lehr- und 
Unterrichtssprachen kommt aus dem Hause Wirth*.


*) Niklaus Wirth, Pascal, Modula(2), Oberon ...

von Hagen R. (hagen)


Lesenswert?

Eines sollte aber das Andere nicht ausschließen. Wenn es einen Job gibt 
bei dem man nie auslernt dann wohl Programmierung, oder ?

Gruß Hagen

von Karl H. (kbuchegg)


Lesenswert?

Hagen Re wrote:
> Wichtig ist aber letzendlich nur eines: Hat man sich in C rein-"gequält"
> wird es immer mehr Spaß machen.

Das sicherlich.
Wenn ich jemanden in die Grundzüge von C einführe, fang ich auch nicht
mit diesen Kurzschreibweisen an, sondern achte darauf, dass er
die Langformen benutzt

   if( i == 0 )

   if( ptr == NULL )

Irgendwann studiert er dann auch mal andere Programme und dann kann
man ihn langsam an die "Wahrheit" heranführen und schrittweise in
die Geheimnisse der Kurzschreibweisen einführen. Die ersten davon
werden sicherlich ++, --, +=, -= usw. sein.

>
> Ich kann eben bestätigen das gerade bei diesen Syntaxkonstrukten die
> Lehrlinge die meisten Probleme haben und Fehler machen.

Das glaub ich gerne.

> Bevor das nicht
> sitzt braucht man die Pointerarithmetiken garnicht anfangen.

:-) Die nächste große Hürde.
Danach kommt noch der Übergang von 1-Stern Programmierung zu
2-Stern Programmierung, der erstaunlicherweise (obwohl völlig
logisch) auch immer wieder zu Problemen führt

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl heinz Buchegger wrote:

> Danach kommt noch der Übergang von 1-Stern Programmierung zu
> 2-Stern Programmierung, der erstaunlicherweise (obwohl völlig
> logisch) auch immer wieder zu Problemen führt

Wenn sie dann endlich denken, sie hätten C schon verstanden, kann
man sie noch mit dem ternären operator (?:) überraschen.
Anschließend kommt als Prüfungsaufgabe das Schreiben einer
Funktion, die einen Zeiger auf den Typ ihrer selbst übernimmt
und einen ebensolchen zurück gibt, und zwar ohne Benutzung
von typedef. :-))

Schließlich und endlich blieben noch geschachtelte obskure
Präprozessorkonstrukte übrig, in denen es von # und ## nur so
wimmelt. ;-)

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.