Arbeiten mit einzelnen Bits
Die wichtigsten Themen um mit Bit und Bytes zu arbeiten sind hier zusammengefasst. Arbeiten auf Bit-Ebene ist notwendig um mit Registern zur arbeiten oder um Datenströme zu senden oder zu empfangen.
- Bitvergleiche(& AND, | OR, ^ XOR, ~ NOT)
- Shiftoperationen (<<, >>)
- Funktionen um Bits und Bytes
- Binärzahlen Aus- und Eingeben
Bitvergleiche
UND (&) - Selektives Abfragen von Bits (maskieren) / Selektives Löschen von Bits
Der Bitoperator UND prüft, ob die beiden Operanden '1' sind. Ist das der Fall, dann ist das Ergebnis '1', sonst '0'.
0 & 0 = 0
1 & 0 = 0
0 & 1 = 0
1 & 1 = 1
Der Bitoperator UND wird oft benutzt um Bitwerte zu maskieren. Im Folgenden Beispiel soll nur die Stelle 2, 4, 6 und 8 übernommen werden. Der anderen Stellen bleiben unabhängig der vorherigen Werte auf '0'.
10011100
& 01010101
----------
= 00010100
ODER (|)- Selektives Setzen von Bits
Der Bitoperator ODER prüft, ob mindestens einer der beiden Operanden '1' ist. Wenn ja, dann ist das Ergebnis '1', sonst '0'.
0 | 0 = 0
1 | 0 = 1
0 | 1 = 1
1 | 1 = 1
OR wird oft verwendet, wenn man sicher gehen will, dass ein bestimmtes Bit unabhängig vom aktuellen Status auf '1' gesetzt wird. Hier sollen die Stellen 0 und 1 auf '1' gesetzt werden.
10011000
& 01000011
----------
= 01011011
XOR (^) - Selektives invertieren von Bits (toggeln)
Der Bitoperator XOR prüft, ob genau einer der beiden Operanden '1' ist. Wenn ja, ist das Ergebnis '1', sonst '0'. Im Gegensatz zum ODER liefert dieser Operator also auch dann '0', wenn beide Operanden '1' sind.
0 ^ 0 = 0
1 ^ 0 = 1
0 ^ 1 = 1
1 ^ 1 = 0
Der XOR Operator wird benutzt um bestimmte Stellen zu "toggeln" während andere so wie sie sind belassen werden. Hier im Beispiel werden die Stellen 0 und 1 getoggelt.
10011110
^ 00000011
----------
= 10011101
NICHT (~)
Der Bitoperator NICHT hat nur einen Operanden. NICHT kehrt den Wert um, aus '1' wird also '0' und umgekehrt.
~0 = 1
~1 = 0
Beispiel:
~ 10011100
----------
= 00100011
Bitschiebeoperator (Shiftoperator)
Beim Arduino bzw. in C++ gibt es zwei Schiebeoperatoren. LeftShift (<<) und RightShift (>>). Diese Operatoren bewirken, dass die Bits im linken Parameter um die Anzahl der Bits im rechten Parameter nach rechts oder links geschoben werden. (Gedanklich wird die Anzahl Nullen von links oder rechts eingeschoben).
byte a = 5; // binary: 00000101
byte b = a << 5; // binary: 10100000
byte c = b >> 3; // binary: 00010100
Fallen durch das Einschieben von Nullen auf der Gegenüberliegenden Seite die Daten heraus, sind diese unwiederbringlich verloren. Aufpassen muss man auch bei "signed Int" oder "signed long" Variablen. Diese Daten werden speziell gespeichert. Beispiel 4 = 00000100 und -4 = 11111100. (Negative Zahlen werden als Zweierkomplement gespeichert. Die positive Zahl wird invertiert und anschließend um 1 erhöht). Sobald dabei die erste Stelle eine '1' ist funktioniert das schieben nicht mehr wie erwartet. Daher am Besten für Bit Operationen zunächst in einen unsigned Wert umwandeln.
int a = -5; // binary: 1111111111111011
int b = x >> 2; // binary: 1111111111111110
int c = (unsigned int)x >> 4; // binary: 000011111111111110
Hinweis: Eine Verschiebung um x Stellen nach links entspricht dabei einer Multiplikation mit 2x. Eine Verschiebung um x Stellen nach rechts entspricht einer Division durch 2x (Bsp. 1 << 8 = 28 = 256 ).
Funktionen um Bits und Bytes
Ein Byte besteht aus 8 Bit. Die Position eines Bit innerhalb eines Bytes wird von rechts nach links gezählt
und beginnt mit der Position 0 ganz rechts.
Zwei Bytes zusammen ergeben ein Word. Das Highbyte steht dabei links, das Lowbyte rechts.
lowByte(vonZahl)
Ermittelt das niederwertige Byte einer längeren Variablen
int a = 0b111111110000000;
byte b = lowByte(a); // binary: 0000000
highByte(vonZahl)
Ermittelt den höherwertigen Byte eines Word, oder den zweitniedrigsten eines noch größeren Datentyps.
int a = 0b111111110000000;
byte b = highByte(a); // binary: 11111111
word (highByte, lowByte)
Setzt 2 einzelne Bytes zu einem gemeinsamen Word mit 16 Bits zusammen.
byte hb = 0b11111111;
byte lb = 0b11000011;
word = word(hb,lb); // binary: 1111111111000011
bitRead(vonZahl, stelleVonRechts)
Liest ein bestimmtes Bit einer Zahl an einer bestimmten Stelle. Beginnend ganz rechts mit der Stelle 0. Der Rückgabewert ist entweder 0 oder 1.
byte a = 0b00011110;
bool b = bitRead(a,2); // 1
bitWrite(inZahl, stelleVonRechts, Wert)
Schreibt ein bestimmtes Bit (Wert 0 oder 1) an eine bestimmten Stelle in einer numerischen Variable (also keine Strings). Die zu ändernden Stelle wird von rechts beginnend mit 0 gezählt.
byte a = 0b00011110;
bitWrite(a,2,0); // binary: 00011010
bitSet(inZahl,stelleVonRechts) und bitClear(inZahl,stelleVonRechts)
bitSet() setzt an eine bestimmte Stelle einer Zahl eine 1.
bitClear() löscht eine bestimmten Stelle einer Zahl (schreibt eine 0)
Die zu ändernden Stelle wird von rechts beginnend mit 0 gezählt.
byte a = 0b01000110;
b = bitClear(a,1); // binary: 01000100
c = bitSet(a,4); // binary: 01000110
bit(stelleVonRechts)
Ermittelt den Wert eines bestimmten Bits. Die entsprechende Stelle wird von rechts beginnend mit 0 gezählt.
a = bit(0); // 1
b = bit(4); // 16
b = bit(7); // 128
Binärzahlen Aus- und Eingeben
Eingabe von Binärwerten
Mit dem Prefix 0b kann man Zahlen binär eingeben (z.B. 0b0011110001010100).
Mit dem Prefix 0x werden sie hexadezimal angegeben(z.B. FF).
Binäre Werte bis zu der Größe von einem Byte lassen sich auch als Konstanten in Großbuchstaben eingen (z.B.
B00000101)
Ausgabe als String() oder auf dem seriellen Monitor
Zahlen sind als Variablen immer Binär gespeichert. Man kann diese Werte aber unterschiedlich anzeigen lassen.
Serial.print(75); // "75" (Standardeinstellung)
Serial.print(75, DEC); // "75" (75 in dezimal)
Serial.print(75, HEX); // "4B" (75 in hexadezimal)
Serial.print(75, BIN); // "1001011" (75 in Binärcode)
Ausgabe Binärwerte mit einer for-Schleife
Byte mit 8 Stellen ausgeben
void byteOut (byte wert) {
Serial.print("Binärwert: ");
for (int i = 7; i >= 0; i--) {
if (bitRead(wert, i)) Serial.print("1");
else Serial.print("0");
}
Serial.println();
}
Int mit 16 Stellen ausgeben
void intOut (unsigned int wert) {
Serial.print("Binärwert: ");
for (int i = 15; i >= 0; i--) {
if ( i == 7) Serial.print(" ");
if (bitRead(wert, i)) Serial.print("1");
else Serial.print("0");
}
Serial.println();
}