Ich habe ein 8-Bit-Register und ich möchte die Bits 4,5 und 6 ändern, ohne die anderen Bits zu ändern. Dieses Bit kann Werte von 000
bis 111
annehmen (unabhängig von ihrem vorherigen Zustand). Gibt es eine Methode, um sie in einem Schritt zu ändern oder muss ich sie einzeln ändern?Ändern von mehr als einem Bit in einem Register
Antwort
Sie benötigen eine Maske, die angeforderten Bits in einem Zustand bekannt zu setzen, 0 ist die bequemer als je meine Programmiergewohnheiten, legen Sie dann die Bits, die Sie mit einer oder Betrieb zu 1 und schreiben wollen zurück:
#define mask 0x70 // 01110000b bit 4, 5 & 6 set
reg = (reg & ~mask) | (newVal & mask);
Wir haben die invertierte Maske verwenden, um 0 die Bits zu setzen und die unveränderte Maske zu ändern setze auf 0 die Bits, die wir nicht wollen stört den neuen Wert.
Wenn Sie sicher sind, dass die unerwünschten Bits des neuen Wertes 0 sind immer können Sie vereinfachen:
#define mask 0x8f // 10001111b bit 4, 5 & 6 reset
reg = (reg & mask) | newVal; //newVal must have always bits 7, 3, 2, 1 & 0 reset.
Sie können es tun, indem bitweise Operation, dh zuerst die 3 Bits löschen, und dann setzen sie:
unsigned char value = 0x70;
unsigned char r = 0xFF;
r = (r & 0x8F) | value;
Ich denke du meinst bitweise oder '|'? – Unimportant
ah, in der Tat, ja, behoben, danke @ user1320881 – fluter
Sie bit-field innerhalb einer Struktur verwenden können:
typedef struct{
unsigned char b0_3 : 4;
unsigned char b4_6 : 3;
unsigned char b7 : 1;
}your_reg_type;
your_reg_type my_register;
//modify only the bits you need
my_register.b4_6 = 0x02;
Überprüfen Sie, wie Ihr Compiler Befehl, die Bits in der Struktur vor dem Versuch und order your bit-field accordingly
Diese Antwort ist nicht (unbedingt) korrekt, da es in C keine Garantie gibt, dass das erste Bit Bit 7 ist. Es kann Bit 0 sein. – user3629249
Deshalb habe ich gesagt "check out the endianess of the target ..." – simpego81
Bei einem einzelnen Byte geht es nicht um Endianess, sondern um Compilerimplementierung. Tatsächlich ist es sogar für Multi-Bytes immer noch nicht eine Frage der Endianess - Endianess ist über die Byte-Reihenfolge nicht Bit-Reihenfolge. Der Compiler kann unabhängig von der Byte-Reihenfolge Bits von MSB oder LSB packen. Überprüfen Sie also die Dokumentation Ihres Compilers und nicht die Endlichkeit des Ziels. Beachten Sie, dass sich dies bei verschiedenen Compilern für dasselbe Ziel ändern kann. – Clifford
Eine Reihe von Lösungen und Variationen sind möglich (und wurden bereits vorgeschlagen), aber wenn der Wert der drei aufeinander folgenden Bits Bedeutung an sich hat (dh . es ist ein Wert von 0 bis 7 und nicht einfach eine Sammlung von unabhängigen Flag- oder Steuerbits), es kann nützlich sein, den Wert als einen einfachen numerischen Bereich von 0 bis 7 zu halten, anstatt direkt Details der Bitposition innerhalb des Wertes zu codieren. In diesem Fall:
assert(val <= 7) ; // During debug (when NDEBUG not defined) the
// assert trap will catch out-of-range inputs
reg = (reg & mask) | (val << 4) ;
Natürlich gibt es einige klein Kosten für die Vereinfachung der Schnittstelle auf diese Weise zu zahlen (durch einen Schichtbetrieb Zugabe), aber der Vorteil ist, dass das Wissen über die Einzelheiten der Registerfelds Layout auf einen Ort beschränkt.
Ich sehe nicht, wie '0' ist bequemer als' 1' für den bekannten Zustand. Es ist nur eine Frage, ob Sie im nächsten Schritt die gewünschten Bits einschalten (mit einer '|' -Operation), oder die gewünschten Bits ausschalten (mit einer '&' -Operation). –
@ JohnBollinger, halte ich die 0 bequemer, weil, um die gewünschten Bits zu setzen, wie Sie sagten, Sie brauchen nur ein 'oder' zwischen Werten, um sie zurückzusetzen, müssen Sie 'und' den Registerwert mit ** der invertierten ** eingegebener Wert. Sie benötigen 2 Operationen. –
Nein, die Alternative kann genau so komplex sein wie Ihr Beispiel, und es ist nicht notwendig, die Eingabe zu invertieren: 'reg = (reg | mask) & (newVal | ~ mask)'. –