Forum: Mikrocontroller und Digitale Elektronik C - Bit eines Bytes beschreiben


von Patrick E. (f4550tim)


Lesenswert?

Hallo,

x |= (Datenwert << 5) <-- Dass würde das 5te bit von x mit dem Wert 
"Datenwert beschreiben.

Könnt Ihr mir sagen, wie es einfacher geht.

Ich will nur ein bit in einem Byte, bzw in einem Integer beschreiben.

Aber soetwas wie

int Testvariable;


Testvariable.0 = 1;
Testvariable.1 = 0;
Testvariable.2 = 0;

Geht nicht. Könnt Ihr mir sagen wie ich es Syntax echt machen müsste ?



LG Tim

von Karl H. (kbuchegg)


Lesenswert?

Tim E. schrieb:
> Hallo,
>
> x |= (Datenwert << 5) <-- Dass würde das 5te bit von x mit dem Wert
> "Datenwert beschreiben.


Nicht wirklich.
Damit kannst du 1 Bit auf 1 setzen aber nicht auf 0. 'beschreiben' ist 
daher irgendwie das falsche Wort.


  x |= ( 1 << Bitnummer );   // Bit auf 1 setzen
  x &= ~( 1 << Bitnummer );  // Bit auf 0 setzen

> Könnt Ihr mir sagen, wie es einfacher geht.

Was gefällt dir daran nicht?

von Andreas B. (andreasb)


Lesenswert?

Das Stichwort ist Bitfelder und Union

sowas wie

union {
   int x;
   struct {
      char bit1:1;
      char bit2:1;
      char bit3:1;
   }
}

Beispiel, Syntaktisch nicht vollständig / korrekt.



mfg Andreas

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Tim E. schrieb:
> Dass würde das 5te bit von x mit dem Wert
> "Datenwert beschreiben.

Nein, da_s_ würde es nicht, beziehungsweise nur dann, wenn Datenwert 1 
ist.


Ein Bit setzen (mit dem Wert 1 beschreiben) geschieht so, wie von Dir 
beschrieben:

  Wert |= (1 << Bitnummer);

ein Bit löschen (mit dem Wert 0 beschreiben) aber geschieht so:

  Wert &= ~(1 << Bitnummer);


So und nur so wird das in C gemacht. "Einfacher" geht es nicht, aber 
"Einfacher" würde es auch durch die von Dir gewünschte Notation nicht 
werden.

Es gibt Krücken, beispielsweise die Kombination eines Bitfelds und eines 
Bytes in einer union, aber das bewirkt letztlich auch nichts anderes 
und hilft nur Leuten, das Erlernen herauszuzögern, wie man es richtig 
anstellt.

von Patrick E. (f4550tim)


Lesenswert?

Das es so lange und umständlich ist, wenn ich nicht weis ob es eine 0 
oder 1 ist, weil das unterschiedlich ist. Dann müsste ich immer ein If 
abfrage machen.

LG

von Karl H. (kbuchegg)


Lesenswert?

Tim E. schrieb:
> Das es so lange und umständlich ist, wenn ich nicht weis ob es eine 0
> oder 1 ist, weil das unterschiedlich ist. Dann müsste ich immer ein If
> abfrage machen.

Und?
Die C Mittel Makros und Funktionen, in denen man diese Details 
'verstecken' kann, wurden schon vor 40 Jahren erfunden. Du musst sie nur 
anwenden.

von Achim M. (minifloat)


Lesenswert?

Bitnummern kann man sich auch definieren. Ungefähr so...
1
#define BITF (1<<15)
2
...
3
...
4
#define BIT8 (1<<8)
5
#define BIT7 (1<<7)
6
#define BIT6 (1<<6)
7
...
8
...
9
#define BIT0 (1<<0)
...sieht das dann beim MSP430 aus, weil der ja eine 16Bit-Maschine ist.

Beispiel für Bit 3 und 4...
setzen:
1
foo |= BIT3 + BIT4;
löschen:
1
foo &= ~(BIT3 + BIT4);

mfg mf

von Thomas E. (thomase)


Lesenswert?

Tim E. schrieb:
> Dann müsste ich immer ein If abfrage machen.
Du musst das doch nur einmal eingeben. Machen tut das der Controller. 
Und dem ist egal, wie oft er das macht.

mfg.

von Patrick E. (f4550tim)


Lesenswert?

thx

von Achim M. (minifloat)


Lesenswert?

Tim E. schrieb:
> Das es so lange und umständlich ist, wenn ich nicht weis ob es eine 0
> oder 1 ist, weil das unterschiedlich ist. Dann müsste ich immer ein If
> abfrage machen.

In der Zeit in der du da rumprüfst, ob jetzt was getan werden muss, ist 
es besser, es wird gleich getan. Du gibst den Sollwert eines Bits an. 
Den nimmt es ein, egal was vorher war.

Wenn man alternierendes Verhalten haben will wie ein einrastender 
Druckknopf, dann gibt es noch toggeln:
1
int main(void)
2
{
3
   uint8_t foo = BIT1;
4
   
5
   while(1)
6
      foo ^= BIT1 + BIT6;
Bit1 und Bit6 spielen jetzt Polizeiauto mit Blaulicht...

mfg mf

PS: Beim Löschen schön drauf schaun, dass die "~" da ist.

von Thomas E. (thomase)


Lesenswert?

Mini Float schrieb:
> In der Zeit in der du da rumprüfst, ob jetzt was getan werden muss, ist
> es besser, es wird gleich getan. Du gibst den Sollwert eines Bits an.
> Den nimmt es ein, egal was vorher war.
Da sei dir man nicht so sicher. Das sieht in C geschrieben zwar kurz und 
knapp aus, aber guck' dir mal an, was der Compiler daraus macht.

Denn das prüfen auf "0" ist ein einziger Befehl, der in einem Takt 
ausgeführt wird. jz, breq oder wie auch immer.

mfg.

von Achim M. (minifloat)


Lesenswert?

eori, andi oder ori sind Einzeiler im Assemblercode. Die konstanten 
Werte hinter dem "=" werden als solche erkannt und in die Anweisung 
codiert.

Gerade bei ifs in C, wenn sie einen Vergleichsoperator haben, werfen 
manche compiler immer noch ein tst als expliziten Nullvergleich ein, 
obwohl es meist nicht sein muss.

mfg mf

von Thomas E. (thomase)


Lesenswert?

Na, wenn du meinst.

if (Datenwert) Testvariable |= (1 << 5); else Testvariable &= ~(1 << 5);
  9c:  80 91 6c 00   lds  r24, 0x006C
  a0:  88 23         and  r24, r24
  a2:  21 f0         breq  .+8        ; 0xac <main+0x10>
  a4:  80 91 6b 00   lds  r24, 0x006B
  a8:  80 62         ori  r24, 0x20  ; 32
  aa:  03 c0         rjmp  .+6        ; 0xb2 <main+0x16>
  ac:  80 91 6b 00   lds  r24, 0x006B
  b0:  8f 7d         andi  r24, 0xDF  ; 223
  b2:  80 93 6b 00   sts  0x006B, r24

Testvariable &= ~(1 << 5);
  b6:  80 91 6b 00   lds  r24, 0x006B
  ba:  8f 7d         andi  r24, 0xDF  ; 223
  bc:  80 93 6b 00   sts  0x006B, r24
Testvariable |= (Datenwert << 5);
  c0:  90 91 6b 00   lds  r25, 0x006B
  c4:  80 91 6c 00   lds  r24, 0x006C
  c8:  82 95         swap  r24
  ca:  88 0f         add  r24, r24
  cc:  80 7e         andi  r24, 0xE0  ; 224
  ce:  89 2b         or  r24, r25
  d0:  80 93 6b 00   sts  0x006B, r24

mfg.

von spess53 (Gast)


Lesenswert?

Hi

>eori, andi oder ori sind Einzeiler im Assemblercode.

eori gibt es nicht. Zumindest bei den Registern haben die GCC-Erfinder 
die Möglichkeiten des T-Flags völlig ignoriert.

  set
  bld Rxy,n

setzt Bit n (0...7) im Register xy

  clt
  bld Rxy,n

löscht Bit n (0...7) im Register xy

MfG Spess

von Achim M. (minifloat)


Lesenswert?

@Thomas Eckmann: Welche Optimierungsstufe nimmst du?

Ich optimiere immer, um Fehler zu finden wenn ich dem Compiler keine 
deutliche Anweisung gebe.
mfg mf

von Thomas E. (thomase)


Lesenswert?

Mini Float schrieb:
> Welche Optimierungsstufe nimmst du?
-Os

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Thomas Eckmann schrieb:
> Na, wenn du meinst.

Jetzt bist du aber unfair :-)

>
> if (Datenwert) Testvariable |= (1 << 5); else Testvariable &= ~(1 << 5);
>   9c:  80 91 6c 00   lds  r24, 0x006C
>   a0:  88 23         and  r24, r24
>   a2:  21 f0         breq  .+8        ; 0xac <main+0x10>
>   a4:  80 91 6b 00   lds  r24, 0x006B

hier
>   a8:  80 62         ori  r24, 0x20  ; 32
passiert das Bit setzen

>   aa:  03 c0         rjmp  .+6        ; 0xb2 <main+0x16>
>   ac:  80 91 6b 00   lds  r24, 0x006B

hier
>   b0:  8f 7d         andi  r24, 0xDF  ; 223
das Bit löschen

>   b2:  80 93 6b 00   sts  0x006B, r24

Das der Compiler den Inhalt der Variablen laden und Speichern muss, ist 
klar. Wenn du anstelle von Variablen Port-Register genommen hättest, 
wäre das nicht notwendig gewesen (insofern warst du unfair).

von Thomas E. (thomase)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Jetzt bist du aber unfair :-)
Wieso?
Es ging darum, ob eine If-Abfrage und dann entweder Löschen oder Setzen 
schneller ist, oder ob es günstiger ist, grundsätzlich zu löschen und 
dann zu setzen unabhängig vom Inhalt der Variable.

> Wenn du anstelle von Variablen Port-Register genommen hättest,
> wäre das nicht notwendig gewesen (insofern warst du unfair).
Das wollte ich auch erst, weil ich keine Lust hatte, noch zwei Variable 
hinzuschreiben. Aber dann habe ich gesehen, daß es oben um Variable 
ging.

mfg.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

spess53 schrieb:

> Zumindest bei den Registern haben die GCC-Erfinder
> die Möglichkeiten des T-Flags völlig ignoriert.

Nö.

Wie konnst du darauf?

von Karl H. (kbuchegg)


Lesenswert?

Thomas Eckmann schrieb:
> Karl Heinz Buchegger schrieb:
>> Jetzt bist du aber unfair :-)
> Wieso?
> Es ging darum, ob eine If-Abfrage und dann entweder Löschen oder Setzen
> schneller ist, oder ob es günstiger ist, grundsätzlich zu löschen und
> dann zu setzen unabhängig vom Inhalt der Variable.

OK.
Dann hab ich nicht mitgekriegt, warauf du hinaus wolltest. Und ich denke 
Mini-Float wollte seinen ursprünglichen Kommentar auch anders verstanden 
wissen.

von Thomas E. (thomase)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wenn du anstelle von Variablen Port-Register genommen hättest
Jetzt mal die Registervariante:

if (GPIOR1) GPIOR0 |= (1 << 5); else GPIOR0 &= ~(1 << 5);
  9c:  82 b3         in  r24, 0x12  ; 18
  9e:  88 23         and  r24, r24
  a0:  11 f0         breq  .+4        ; 0xa6 <main+0xa>
  a2:  8d 9a         sbi  0x11, 5  ; 17
  a4:  01 c0         rjmp  .+2        ; 0xa8 <main+0xc>
  a6:  8d 98         cbi  0x11, 5  ; 17

GPIOR0 &= ~(1 << 5);
  a8:  8d 98         cbi  0x11, 5  ; 17
GPIOR0 |= (GPIOR1 << 5);
  aa:  91 b3         in  r25, 0x11  ; 17
  ac:  82 b3         in  r24, 0x12  ; 18
  ae:  82 95         swap  r24
  b0:  88 0f         add  r24, r24
  b2:  80 7e         andi  r24, 0xE0  ; 224
  b4:  89 2b         or  r24, r25
  b6:  81 bb         out  0x11, r24  ; 17

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Ersetz doch mal das GPIOR1 durch eine Konstante.

Denn das wollte der TO ja wirklich machen und hat sich nur ungeschickt 
ausgedrückt


Zitat

> Also sowas wie
> int Testvariable;
>
>
> Testvariable.0 = 1;
> Testvariable.1 = 0;
> Testvariable.2 = 0;

Er weiß zur Compiletime, welches Bit er 0 oder 1 setzen will.

von Thomas E. (thomase)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Er weiß zur Compiletime, welches Bit er 0 oder 1 setzen will.
Das ist klar. Das sind dann im GPIO 2 Befehle.

Aber ich bin jetzt davon ausgegangen:
>x |= (Datenwert << 5) <-- Dass würde das 5te bit von x mit dem Wert
>"Datenwert beschreiben.
Naja, da hat er sich wohl wirklich unglücklich ausgedrückt. Oder ich 
hab' das unglücklich verstanden.

mfg.

von Karl H. (kbuchegg)


Lesenswert?

Egal.

So wie sein Programm aussieht
Beitrag "C Programm break vergessen ?"
hat er ganz andere Probleme.

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.