Forum: Mikrocontroller und Digitale Elektronik Kurzschreibweise


von Christoph B. (brandneraut)


Lesenswert?

Hallo liebes µC-Forum,

ich taste mich gerade an die digitalen Eingänge am ELEGOO Uno R3, einem 
Arduino-Nachbau, an. Ich programmiere den Arduino mit der 
Programmiersprache C, da ich gehört habe, dass sehr viele MCUs mit C 
programmiert werden.
Jetzt zu meiner Frage: Wieso kann ich bei der Abfrage, ob der Taster 
gedrückt ist, den Ausdruck
1
if ((PIND & (1<<3)) == 0b00001000)
 durch
1
if (PIND & (1<<3))
 ersetzen?

Mit freundlichen Grüßen
BrandnerAUT

von Stefan F. (Gast)


Lesenswert?

Christoph B. schrieb:
> Wieso kann ich bei der Abfrage, ob der Taster
> gedrückt ist, den Ausdruck ersetzen?

Weil in C alles was nicht 0 ist, wahr ist.

> PIND & (1<<3)

Liefert eine Zahl ungleich Null wenn der Pin High ist. Dann ist der 
if-Ausdruck wahr.

Mehr is Detail:

Genau genommen erwartet if() keinen booleschen wahr/falsch Ausdruck, 
sondern einen numerischen Wert der gleich oder ungleich 0 ist. Das 
kannst du sehen, wenn du dir den generierten Assembler-Code anschaust.

von Thomas E. (thomase)


Lesenswert?

Die obere Abfrage vergleicht den eingelesenen und verknüpften 
Integerwert des Portstatus mit einer Integer-Konstante. Das Ergebnis 
eines Vergleiches ist normalerweise ein Boolean mit true oder false. 
Entsprechend wird die if-Anweisung dann ausgeführt.

So etwas kompliziertes gibt es in C aber gar nicht, sondern C kennt nur 
Integer, wobei 0 immer false und alles andere true ist.

Die logische Verknüpfung von den zwei Integerwerten unten liefert als 
Ergebnis auch 0 oder was anderes. Was als if-Bedingung wieder wie ein 
Boolean mit false oder true betrachtet werden kann.

Andere Programmiersprachen lassen das nicht zu, sondern bestehen im 
unteren Fall auf eine explizite Typumwandlung bzw. auf die obere Form. C 
ist da nicht so pingelig. Und die Programmierer sind es auch nicht. Wenn 
du darauf bestehst, es in C immer wie oben zu schreiben, was zwar 
vollkommen richtig ist, wirst du irgendwann geteert und gefedert.

von Wolfgang (Gast)


Lesenswert?

Christoph B. schrieb:
> Jetzt zu meiner Frage: Wieso kann ich bei der Abfrage, ob der Taster
> gedrückt ist, den Ausdruckif ((PIND & (1<<3)) == 0b00001000)

Diese Formulierung ist ausgesprochen tückisch: Du verwendest dort zwei 
Konstanten in verschiedenen Schreibweisen, deren Wert identisch sein 
muss.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

(1<<3) ist schon deine Maske auf die du den Registerinhalt prüfst.

Das heißt, wenn du dich beim tippen von
1
0b00001000
nicht in der Bitstelle vertan hast, was tückisch sein kann, dann muss 
der Wert von (PIND & (1<<3)) bei Gültigkeit sowieso gleich dem Wert 
0b00001000 sein. Du hättest im dümmsten Fall nur eine überflüssige 
Fehlerquelle ohne Nutzen.

Die Abfrage sagt glasklar aus das du nur auf die Gültigkeit des 3. Bits 
abfragst.
1
if (PIND & (1<<3))

Die Alternative wäre
1
if (PIND & 0b00001000)
Was dir aber wohl niemand so richtig empfehlen wird, weil die 
Schreibweise tückisch ist.

Die Alternative zu oben wäre noch
1
if (PIND & _BV(3))

: Bearbeitet durch User
von dfIas (Gast)


Lesenswert?

Wolfgang schrieb:
> Diese Formulierung ist ausgesprochen tückisch: Du verwendest dort zwei
> Konstanten in verschiedenen Schreibweisen, deren Wert identisch sein
> muss.
Muss nicht. Dann kommt entweder immer true oder false heraus. Ein guter 
Compiler würde das erkennen und warnen. Oder die Maske enthält mehr Bits 
als das abgefragte Muster:
1
 if (PIND & 0b00110000 == 0b0001000)
Machte durchaus Sinn.
Üblicherweise setzt man Masken und Muster z.B. mit Defines oder 
Enumerations. Vereinfachen sollte man selbst aber nichts, das kann der 
Optimizer. Und es bleibt lesbar:
1
 if (PIND & NAME_DER_MASKE == NAME_DES_MUSTERS)

von dfIas (Gast)


Lesenswert?

1
if (PIND.bitfeldname == NAME_DES_MUSTERS)
Der geht übrigens auch, wenn das PIND als eine Struktur mit 
vordefinierten Bitfeldern (Records) angelegt wurde. Ist m. E. die 
übersichtlichste Methode.

von Lutz (Gast)


Lesenswert?

Aber auch die Langsamste.

von Lutz (Gast)


Lesenswert?

dfIas schrieb:
> Oder die Maske enthält mehr Bits als das abgefragte Muster:
>  if (PIND & 0b00110000 == 0b0001000)

Unw welchen Sinn macht die Maske dann noch?

von Wolfgang (Gast)


Lesenswert?

dfIas schrieb:
> Oder die Maske enthält mehr Bits
> als das abgefragte Muster: if (PIND & 0b00110000 == 0b0001000)
> Machte durchaus Sinn.

Deine Konstruktion macht so bestimmt keinen Sinn und liefert immer 
false.

von Veit D. (devil-elec)


Lesenswert?

dfIas schrieb:
> Oder die Maske enthält mehr Bits
> als das abgefragte Muster:
>
1
 if (PIND & 0b00110000 == 0b0001000)
> Machte durchaus Sinn.
> Üblicherweise setzt man Masken und Muster z.B. mit Defines oder
> Enumerations. Vereinfachen sollte man selbst aber nichts, das kann der
> Optimizer. Und es bleibt lesbar:
>
1
 if (PIND & NAME_DER_MASKE == NAME_DES_MUSTERS)

Das ist ja genau das was wir dem TO nicht empfehlen. Doppelt gemoppelt. 
Eine zusätzliche Fehlerquelle ohne Nutzen und zudem falsch. Du nennst 
das eine Maske und das andere Muster. Ist aber jeweils das Selbe. Eins 
davon muss weg. Und eigentlich sollte man keine defines mehr verwenden, 
sondern konstante Variablen.

: Bearbeitet durch User
von dfIas (Gast)


Lesenswert?

Veit D. schrieb:
> Das ist ja genau das was wir dem TO nicht empfehlen. Doppelt gemoppelt.
> Eine zusätzliche Fehlerquelle ohne Nutzen und zudem falsch. Du nennst
> das eine Maske und das andere Muster. Ist aber jeweils das Selbe. Eins
> davon muss weg. Und eigentlich sollte man keine defines mehr verwenden,
> sondern konstante Variablen.
Nichts doppelt gemoppelt - genau so sollte man es machen. Kürzen bitte 
ausschließlich dem Compiler/Optimizer überlassen, sonst ist die Source 
unvollständig.
Die Maske spannt sich über alle Bits auf, das Muster hat innerhalb der 
Maske Nullen oder Einsen, außerhab don't-cares. Sind also nicht per se 
gleich. Es gibt aber zu jeder Maske auch ein Muster, das der Maske 
entspricht.
Dass die Maske aus nur einem Bit besteht, ist ein Sonderfall. Und auch 
zu einer Maske mit nur einem Bit gibt es 2^n Muster, also zwei Muster - 
eines mit Null, eines mit Eins.
Bei meinem Beispiel hatte sich ein Typo eingeschlichen, hinten fehlte 
beim Muster eine 0. Das hätte man erkennen können. Hier noch mal 
korrigiert:
1
if (PIND & 0b00110000 == 0b0001000*0*)
Maske und Muster sind allgemein nicht gleich. Sie sind nur gleich, wenn 
man ein einzelnes Bit auf Eins abfragt.
Zur Maske 0b00*11*0000 gäbe es die vier abzufragenden Muster 
0b00*00*0000, 0b00*01*0000, 0b00*10*0000 und 0b00*11*0000.
Wie gesagt, ein angelegter Record (Schreibweise mit Doppelpunkt) räumt 
mit diesen Konstrukten gänzlich auf. Man muss sich dann auch bei den 
abgefragten Mustern nicht mehr ums Schieben kümmern.

von dfIas (Gast)


Lesenswert?

Aha, bold geht nicht im Code-Segement - ager egal.

von Yalu X. (yalu) (Moderator)


Lesenswert?

dfIas schrieb:
> if (PIND & 0b00110000 == 0b0001000*0*)

Vorsicht: Den folgenden Code
1
  if (PIND & 0b00110000 == 0b00010000) [
2
    mach_dies();
3
    mach_das();
4
    // ... und viel weiterer code
5
  }

optimiert GCC zu einem simplen
1
  PIND;

;-)

Wenn – wie im Beispiel des TE – nur ein einzelnes Bit abgefragt werden
soll, würde ich das "== irgendwas" generell weglassen, da es mehr zur
Verwirrung als zur Verständlichkeit beiträgt.

: Bearbeitet durch Moderator
von Veit D. (devil-elec)


Lesenswert?

Hallo,

habe nochmal nachgedacht. Ich war immer auf einen EIN-Bit Vergleich aus. 
Du möchtest 2 Bit vergleichen. Okay, dass ist was anderes.  :-)
Ich würde bzw. muss noch eine Klammer drumherum schreiben, ansonsten 
meckert mein Compiler.
1
if ( (PIND & 0b00110000) == 0b00010000 )
2
{
3
}

Von meiner Seite her ist alles geklärt.  :-)

von Christoph B. (brandneraut)


Lesenswert?

dfIas schrieb:
> Der geht übrigens auch, wenn das PIND als eine Struktur mit
> vordefinierten Bitfeldern (Records) angelegt wurde. Ist m. E. die
> übersichtlichste Methode.

Ein Bitfeld? Davon höre ich zum ersten Mal. Was kann ein Bitfeld?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Christoph B. schrieb:
> Was kann ein Bitfeld?
Du hast das im falschen Browserfenster eingetippt. So wäre das richtig 
gewesen:
https://www.google.com/search?q=Was+kann+ein+Bitfeld

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.