Nur ein Bit ändern
Dafür gibt es bit-Operationen:
Code: Alles auswählen
ist = 0b10100110
soll = ist & ~(1 << 7)Was möchte ich überhaupt machen.
Ich bekomme ein Hex der zum Beispiel "C9" ist
Diesen kann ich wenn nötig direkt auf Int umwandeln ... wäre 201.
Diese beiden Ergebnisse stellen dann eigentlich meine Binärzahl 11001001 dar, welche den Aufbau und Funktion eines Datenfeldes im Speicher wiedergeben.
Möchte ich das Datenfeld aus dem Speicher löschen, so wird nur das 7.bit auf 0 gesetzt. der Rest bleibt im Speicher als "unsichtbar" bestehen.
Alles andere ist erst einmal unwichtig.
Sehe ich es richtig, das ein reines 11001001 nicht funktioniert? Es benötigt immer das 0b vor meiner Binärzahl bei bin() benötigt?
Error: unsupported operand type(s) for &: 'str' and 'int'
Ich bekomme ein Hex der zum Beispiel "C9" ist
Diesen kann ich wenn nötig direkt auf Int umwandeln ... wäre 201.
Diese beiden Ergebnisse stellen dann eigentlich meine Binärzahl 11001001 dar, welche den Aufbau und Funktion eines Datenfeldes im Speicher wiedergeben.
Möchte ich das Datenfeld aus dem Speicher löschen, so wird nur das 7.bit auf 0 gesetzt. der Rest bleibt im Speicher als "unsichtbar" bestehen.
Alles andere ist erst einmal unwichtig.
Sehe ich es richtig, das ein reines 11001001 nicht funktioniert? Es benötigt immer das 0b vor meiner Binärzahl bei bin() benötigt?
Code: Alles auswählen
df_status_int = 201
df_status_bin = bin(df_status_int)#[2:].zfill(8)
print(df_status_bin)
df_status_bin = df_status_bin & ~(1 << 7)
print(df_status_bin)
Error: unsupported operand type(s) for &: 'str' and 'int'
- __blackjack__
- User
- Beiträge: 14336
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@kiaralle: Ein ”reines” 11001001 ist die Dezimalzahl elf Millionen und eintausend und eins. 0b11001001 ist die Dezimalzahl 201. `bin()` liefert eine Zeichenkette und keine Zahl und mit Zeichenketten kann keine Bitoperationen durchführen. Das macht also keinen Sinn die 201 in eine Zeichenkette in Binärdarstellung zu wandeln. Rechnen und Bitoperationen macht man mit Zahlen, nicht mit Zeichenketten. In eine Zeichenkette würde man das vielleicht zur Anzeige umwandeln wenn der Benutzer oder der Programmierer das gerne mal in Binärdarstellung sehen möchte. Ansonsten ist das 201 und nach dem löschen des Bits 73 dezimal (oder C9 und 49 hexadezimal, oder 311 und 111 oktal, …). Das sind ja alles nur verschiedene Darstellungen der selben beiden Zahlen als Zeichenketten.
„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
So, meine doch etwas andere Lösung. Warum nicht gleich mit Hex rechnen.
Ich bekomme den Status meines Datenfeldes gemeldet..... Hex C8
Ich weiß , dass ich immer 10.000.000 abziehen muss um das Datenfeld abzuschalten..... Hex 80
C8 = 11001000
- 80 = 10000000
48 = 01001000
Also rechnen wir,
Damit kann ich den Datensatz löschen.
Jetzt muss ich an das erstellen des neuen Datenfeldes gehen, den ich wieder als Hex schreiben kann.
bit
7 Datenfeld aktiv
6 beschreibbar
5/4 Passwort 0-3
3 Passwort aktiv
2/1/0 Speichergröße 16/32/64.....
Es bleibt wie immer spannend
Danke noch mal in die Runde.
Ich bekomme den Status meines Datenfeldes gemeldet..... Hex C8
Ich weiß , dass ich immer 10.000.000 abziehen muss um das Datenfeld abzuschalten..... Hex 80
C8 = 11001000
- 80 = 10000000
48 = 01001000
Also rechnen wir,
Code: Alles auswählen
hex_a ="C8"
hex_b = "80"
hex_c = hex(int(hex_a,16) - int(hex_b,16))[2:]
print(hex_c)
Ergebniss = 48
Jetzt muss ich an das erstellen des neuen Datenfeldes gehen, den ich wieder als Hex schreiben kann.
bit
7 Datenfeld aktiv
6 beschreibbar
5/4 Passwort 0-3
3 Passwort aktiv
2/1/0 Speichergröße 16/32/64.....
Es bleibt wie immer spannend
Danke noch mal in die Runde.
@kiaralle: Wenn Du Zahlen hast, dann solltest Du auch mit Zahlen rechnen und nicht immer alles in Strings umwandeln. Natürlich kann man dann für die Ausgabe ein passendes Ausgabeformat wählen.
Auch den Input wirst Du ja in irgendeiner binären Form erhalten und nicht als Hexadezimaldarstellung.
Minus zu benutzen hat das Problem, falls das Bit gar nicht gesetzt war, dass dann ein komisches Ergebnis rauskommt. Das ist beim binären UND nicht der Fall.
Besser man benutzt statt kryptischer Zahlen IntFlags:
Auch den Input wirst Du ja in irgendeiner binären Form erhalten und nicht als Hexadezimaldarstellung.
Minus zu benutzen hat das Problem, falls das Bit gar nicht gesetzt war, dass dann ein komisches Ergebnis rauskommt. Das ist beim binären UND nicht der Fall.
Code: Alles auswählen
eingabe = 0xC8
ergebnis = eingabe & 0x7F
print(f"{ergebnis:02x}")Code: Alles auswählen
import enum
class AccessBits(enum.IntFlag):
ACTIVE = 0x80
WRITEABLE = 0x40
PASSWORD = 0x30
PASSWORD_ENABLED = 0x08
SIZE = 0x07
value = 0xC8
value &= ~AccessBits.ACTIVEDanke für deine Hilfe und Hinweise.
Ich erhalte den Input wirklich als Hex.
Deshalb war es für mich logisch und mit meine Wissensstand kann ich nur so vorzugehen.
Hier habe ich vorher die Anzahl der Datenfelder abgefragt.
Dann lese ich den Aufbau der Datenfelder aus.
Ich wandle den response der als Hex kommt in Bin um und kann so schön die Info der einzelnen Positionen auswerten.
Das funktioniert. Deinen Weg muss ich erst verstehen und werde es dann versuchen umzusetzen.
Ich erhalte den Input wirklich als Hex.
Deshalb war es für mich logisch und mit meine Wissensstand kann ich nur so vorzugehen.
Hier habe ich vorher die Anzahl der Datenfelder abgefragt.
Dann lese ich den Aufbau der Datenfelder aus.
Ich wandle den response der als Hex kommt in Bin um und kann so schön die Info der einzelnen Positionen auswerten.
Das funktioniert. Deinen Weg muss ich erst verstehen und werde es dann versuchen umzusetzen.
Code: Alles auswählen
i= 0
while i <= number_of_datafields -1:
df = "{:02x}".format(i)
data = bytearray.fromhex("FF 4C" + df)
data.append(ChecksumXor8.calc(data))
try:
serial_interface.reset_input_buffer()
serial_interface.reset_output_buffer()#flush output buffer, aborting current output
time.sleep(0.010) #give the serial port sometime to receive the data
serial_interface.write(data)
time.sleep(0.01)
response = serial_interface.read(7)
if response.hex()[2:4] == "50" or ChecksumXor8.calc(response) != 0:
self.info_error["text"] = sick_error.srm_errors(response.hex()[4:6])
else:
datenfeld_int=int.from_bytes(response[3:4],'big',signed=False)
datenfeld_bin =bin(datenfeld_int)[2:].zfill(8)
df_mem =str((int(datenfeld_bin[5:])+1) *16)
df_nummer = "\n" + str(i) + " \t"
i+=1
if int(datenfeld_bin[0:1]) == 0:
df_enable = "nein\t"
else:
df_enable = "ja\t"
if int(datenfeld_bin[1:2]) == 0:
df_writable = "nein\t"
else:
df_writable = "ja\t"
df_password = str(int(datenfeld_bin[2:4])) +"\t"
if int(datenfeld_bin[4:5]) == 0:
df_password_aktiv = "nein\t"
else:
df_password_aktiv = "ja\t"
data = df_nummer + df_enable + df_writable + df_password + df_password_aktiv + df_mem
self.datenfeld_info.insert('end',data)
except Exception as e1:
print ("error communicating...: " + str(e1))
self.datenfeld_info.config(state='disabled')
Also, Du wandelst ein `i` in Hex um, um es gleich danach wieder über bytearray.fromhex in Bytes umzuwandeln. Dann liest Du sieben Bytes und wandelst diese in Hex um.
Oder `datenfeld_int in eine Binärdarstellung um diese dann als Dezimalzahl zu interpretieren.
Also: Nein, Du bekommst keine Hex- oder Binärdaten, sondern bist selbst dafür verantwortlich, dass das alles so kompliziert ist.
Deine while-Schleife sollte eine for-Schleife sein und statt auf einer String-Repräsentation Deiner Zahlen solltest Du direkt mit den Zahlen selbst arbeiten:
Oder `datenfeld_int in eine Binärdarstellung um diese dann als Dezimalzahl zu interpretieren.
Also: Nein, Du bekommst keine Hex- oder Binärdaten, sondern bist selbst dafür verantwortlich, dass das alles so kompliziert ist.
Deine while-Schleife sollte eine for-Schleife sein und statt auf einer String-Repräsentation Deiner Zahlen solltest Du direkt mit den Zahlen selbst arbeiten:
Code: Alles auswählen
for i in range(number_of_datafields):
data = bytearray([0xff, 0x4c, i])
data.append(ChecksumXor8.calc(data))
try:
# flush output buffer, aborting current output
serial_interface.reset_input_buffer()
serial_interface.reset_output_buffer()
time.sleep(0.010)
serial_interface.write(data)
# give the serial port sometime to receive the data
time.sleep(0.01)
response = serial_interface.read(7)
if response[0] == 0x50 or ChecksumXor8.calc(response) != 0:
self.info_error["text"] = sick_error.srm_errors(hex(response[1]))
else:
datenfeld = response[3]
mem = datenfeld & AccessBits.SIZE
enabled = "ja" if datenfeld & AccessBits.ACTIVE else "nein"
writeable = "ja" if datenfeld & AccessBits.WRITEABLE else "nein"
password = datenfeld & AccessBits.PASSWORD
password_active = "ja" if datenfeld & AccessBits.PASSWORD_ENABLED else "nein"
info = f"\n{i}\t{enabled}\t{writeable}\t{password}\t{password_active}\t{mem}"
self.datenfeld_info.insert('end', info)
except Exception as error:
print(f"error communicating...: {error}")
self.datenfeld_info.config(state='disabled')@Sirius
Du zeigst mir gerade neue Wege auf.
Das scheint ja wirklich einfacher zu sein als mein Weg.
Mein Code hat jetzt zwar ca. 1000 Zeilen aber ich habe keinen Zeitdruck und ich werde deine Tipps annehmen und den Code umschreiben.
Schön das du mir den Weg zeigst.
Mein Programm funktioniert zu 90% und ich kann es zur Montage von Gebern am Servomotor bereits verwenden.
Aber ich lerne gern was dazu.
Bin halt doch nur ein Schlosser
Aber das wird...
Danke
Du zeigst mir gerade neue Wege auf.
Das scheint ja wirklich einfacher zu sein als mein Weg.
Mein Code hat jetzt zwar ca. 1000 Zeilen aber ich habe keinen Zeitdruck und ich werde deine Tipps annehmen und den Code umschreiben.
Schön das du mir den Weg zeigst.
Mein Programm funktioniert zu 90% und ich kann es zur Montage von Gebern am Servomotor bereits verwenden.
Aber ich lerne gern was dazu.
Bin halt doch nur ein Schlosser
Danke
Noch mal ich,
ich habe mal deinen Code als Versuch genommen.
Die Variable "datenfeld" zeigt mir jetzt 200 an.
Damit kann ich ja so nichts anfangen. Ich benötige wieder die 11001000 um zu schauen welches bit wie gesetzt ist.
Oder hab ich es noch nicht ganz verstanden?
Wie kommt man sonnst an AccessBits.SIZE.... ?
1
ich habe mal deinen Code als Versuch genommen.
Die Variable "datenfeld" zeigt mir jetzt 200 an.
Damit kann ich ja so nichts anfangen. Ich benötige wieder die 11001000 um zu schauen welches bit wie gesetzt ist.
Oder hab ich es noch nicht ganz verstanden?
Wie kommt man sonnst an AccessBits.SIZE.... ?
Code: Alles auswählen
mem = bin(datenfeld)[2:][0:1]
print(mem)data = bytearray([0xff, 0x4c, 0x01])
data.append(ChecksumXor8.calc(data))
try:
serial_interface.reset_input_buffer()
serial_interface.reset_output_buffer()
time.sleep(0.010)
serial_interface.write(data)
time.sleep(0.01)
response = serial_interface.read(7)
if response[0] == 0x50 or ChecksumXor8.calc(response) != 0:
print(sick_error.srm_errors(hex(response[1])))
else:
datenfeld = response[3]
"""
mem = datenfeld & AccessBits.SIZE
enabled = "ja" if datenfeld & AccessBits.ACTIVE else "nein"
writeable = "ja" if datenfeld & AccessBits.WRITEABLE else "nein"
password = datenfeld & AccessBits.PASSWORD
password_active = "ja" if datenfeld & AccessBits.PASSWORD_ENABLED else "nein"
"""
print(datenfeld) # 200
except Exception as error:
print(f"error communicating...: {error}")
- __blackjack__
- User
- Beiträge: 14336
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@kiaralle: Da kommt man dran in dem man alle anderen Bits ausmaskiert. Du musst Dir wirklich mal diese Operationen anschauen was die machen. Bei 200 hat ”size” den Wert 0:
Code: Alles auswählen
In [448]: 200 & 0b111
Out[448]: 0„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
- DeaD_EyE
- User
- Beiträge: 1329
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Code: Alles auswählen
def set_bit(data: int, bit: int, value: bool):
"""
Set or clear a bit of given data and return it.
Look here: https://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching
"""
return data ^ (-value ^ data) & (1 << bit)
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
- DeaD_EyE
- User
- Beiträge: 1329
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Ja, ich würde es aber so nicht im Quelltext verwenden.
Man muss wissen, dass ein bool(0) immer False ergibt und alle andere Zahlen (auch negativ) ein bool(x) == True.
Die if-Anweisung fragt den boolschen Wert eines Objektes ab und bool ist von int vererbt.
Noch einfacher ist es sich eine Funktion zu schreiben:
Und falls du mehrere Bits auf einmal prüfen möchtest:
oder als Dict zurückgeben:
Oder wenn z.B. nur ein True zurückgegeben werden soll, wenn mehrere Bits gleichzeitig gesetzt sind.
PS: Die Typehints sind nicht notwendig. Das kannst auch wieder entfernen, da es keinen Einfluss auf das Programm hat. Das macht nur Sinn, wenn man konsistent Typehints nutzt oder eine Bibliothek schreibt.
Code: Alles auswählen
BIT6 = 1 << 6
value = 255
if BIT6 & value:
print("Bit 6 ist gesetzt")
Die if-Anweisung fragt den boolschen Wert eines Objektes ab und bool ist von int vererbt.
Noch einfacher ist es sich eine Funktion zu schreiben:
Code: Alles auswählen
def get_bit(value: int, bit: int) -> bool:
return bool(value & 1 << bit)
Code: Alles auswählen
from typing import Iterable
def get_bits(value: int, bits: Iterable[int]) -> list[bool]:
return [bool(value & 1 << bit) for bit in bits]
Code: Alles auswählen
def get_bits(value: int, bits: Iterable[int]) -> list[bool]:
return {bit: bool(value & 1 << bit) for bit in bits}
Code: Alles auswählen
def is_set(value: int, bits: Iterable[int]) -> list[bool]:
mask = sum(1 << bit for bit in bits)
return value & mask == mask
PS: Die Typehints sind nicht notwendig. Das kannst auch wieder entfernen, da es keinen Einfluss auf das Programm hat. Das macht nur Sinn, wenn man konsistent Typehints nutzt oder eine Bibliothek schreibt.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
- DeaD_EyE
- User
- Beiträge: 1329
- Registriert: Sonntag 19. September 2010, 13:45
- Wohnort: Hagen
- Kontaktdaten:
Das kann man auch machen, aber dann lernt man nichts über Bit-Manipulation und spätestens wenn Datenblätter verstehen muss, hat man ein Problem das Protokoll zu verstehen.Sirius3 hat geschrieben: Montag 23. Februar 2026, 23:01 @DeaD_EyE: oder man nimmt, wie ich ja schon gezeigt habe, ein enum.IntFlag, denn dann hat man sprechende Namen, statt irgendwelcher Bit-Werte.
Nehmen wir z.B. das Modul, mit dem ich mich gerade beschäftige. Es geht um die Ansteuerung von Dosierpumpen einer VT-Anlage: Technologiemodul TM Pulse 2x24V
Siemens war so nett, Datentypen bereitzustellen, aber in vielen Fällen muss man das auch selbst machen.
D.h. wenn man z.B. später im Beruf SPS programmieren will, muss man die Bit-Manipulation verstehen. Wenn man jedes Mal Nachlesen muss, kommt man nicht weit.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Ich teste das heute Abend.
Ich sehe jetzt Licht am Ende des Tunnels.
Aber, wie Werte ich zum Beispiel drei Bits aus.
Bit 0-2 zeigen mir die Speichergröße an.
Bit 0-2 = 000 = (1 +bit) x 16 = 16
001 = (1+ bit) x16 = 32
....
Geht das auch auf diesen Wege?
Ich sehe jetzt Licht am Ende des Tunnels.
Aber, wie Werte ich zum Beispiel drei Bits aus.
Bit 0-2 zeigen mir die Speichergröße an.
Bit 0-2 = 000 = (1 +bit) x 16 = 16
001 = (1+ bit) x16 = 32
....
Geht das auch auf diesen Wege?
- __blackjack__
- User
- Beiträge: 14336
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@kiaralle: Das hatte ich doch schon gezeigt. Wenn man die letzten drei Bits haben möchte, dann muss man die anderen einfach alle ausmaskieren mit ``&`` und 0b111 oder 0x07 oder 0o007 oder 7. Das sind ja alles nur verschiedene Schreibweisen für den gleichen Wert. Also:
Code: Alles auswählen
memory_size = (1 + (byte_value & 0b0000_0111)) * 16„Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.“ — Brian W. Kernighan
