Nur ein Bit ändern

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
kiaralle
User
Beiträge: 176
Registriert: Donnerstag 19. August 2021, 19:11

Hallo,

wie kann ich bei einem 8bit das 7. bit ändern?

Aufbau bit 7 ....... bit 0

Ist 10100110
Soll 00100110

Gruß Ralf
Sirius3
User
Beiträge: 18372
Registriert: Sonntag 21. Oktober 2012, 17:20

Dafür gibt es bit-Operationen:

Code: Alles auswählen

ist = 0b10100110
soll = ist & ~(1 << 7)
kiaralle
User
Beiträge: 176
Registriert: Donnerstag 19. August 2021, 19:11

Danke, ich hatte auch was gefunden aber das war nicht so schön erklärt.
nezzcarth
User
Beiträge: 1799
Registriert: Samstag 16. April 2011, 12:47

kiaralle hat geschrieben: Sonntag 22. Februar 2026, 08:56 Danke, ich hatte auch was gefunden aber das war nicht so schön erklärt.
"Bitmaske" ist hier der Fachbegriff für die weitere Suche.
kiaralle
User
Beiträge: 176
Registriert: Donnerstag 19. August 2021, 19:11

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?

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'
Benutzeravatar
__blackjack__
User
Beiträge: 14328
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
kiaralle
User
Beiträge: 176
Registriert: Donnerstag 19. August 2021, 19:11

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,

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
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 :lol:

Danke noch mal in die Runde.
Sirius3
User
Beiträge: 18372
Registriert: Sonntag 21. Oktober 2012, 17:20

@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.

Code: Alles auswählen

eingabe = 0xC8
ergebnis = eingabe & 0x7F
print(f"{ergebnis:02x}")
Besser man benutzt statt kryptischer Zahlen IntFlags:

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.ACTIVE
kiaralle
User
Beiträge: 176
Registriert: Donnerstag 19. August 2021, 19:11

Danke 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. :D

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')

Sirius3
User
Beiträge: 18372
Registriert: Sonntag 21. Oktober 2012, 17:20

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:

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')
Antworten