Dieser Thread ist schon etwas aelter, aber hier dennoch mein Loesungsansatz :
Um Bits innerhalb eines Bytes zu manipulieren ist "bitwise" Manipulation mit log. Operatoren und Bit-Masken sinnvoll.
Die fokussierten Register des MCP23017 muessen also bei jedem i2c-write komplett gesetzt werden. Dabei sind die vorherigen Zustaende der nicht betrachteten Bits, zusammen mit den gaenderten Bits als ein neues Byte in das betroffene Register zu schreiben.
Beispiele zum Testen in Python:
1.) Ausgabe von dez 228 im Binaerformat
2.) Bit1 auf 1 setzen, ohne die restlichen Bits im Ausgangswert zu aendern
- Ausgangszustand: der dezimale Wert 228, entspricht binaer 11100100 und ist gegeben
- Absicht: Bit1 auf 1 setzen ohne Bit0 sowie Bit2-Bit7 zu aendern
- Lösung: gegebenen Wert binaer ueber "log. ODER" mit der Bit-Maske der zu setzenden Bits verknuepfen
- Vorgehen: Bit-Maske efinieren ... fuer Bit1 = 1 ergibt sich Bit-Maske 00000010 = dezimal 2
- 11100100 ODER 00000010 = 11100110; Python-Operator fuer "log. ODER" = "|"
3.) Bit1 auf 0 setzen, ohne die restlichen Bits im Ausgangszustand zu aendern
- Ausgangszustand: der dezimale Wert 230, entspricht binaer 11100110 und ist gegeben
- Absicht: Bit1 auf 0 setzen ohne Bit0 sowie Bit2-Bit7 zu aendern
- Lösung: gegebenen Wert binaer ueber "log. UND" mit der negierten Bit-Maske der zu setzenden Bits verknuepfen
- Vorgehen: Bit-Maske definieren ... fuer Bit1 = 1 ergibt sich Bit-Maske 00000010 = dezimal 2
- 11100110 UND (NICHT(00000010)) = 11100100; Python-Operator fuer "log. UND" = "&", fuer "NICHT" = "~"
4.) Multiple Bits in einem Durchgang aendern ...
>>> print('{:08b}'.format(228 | 3)) # gegeben: dez 228; bin 11100100; Bit0 und Bit1 setzen; Bit-Maske 00000011 entspricht dez 3
11100111
>>> print('{:08b}'.format(231 & ~3)) # gegeben: dez 231; bin 11100111; Bit0 und Bit1 löschen; Bit-Maske 00000011 entspricht dez 3
11100100
Skript-Beispiel (unter Verwendung des SMBUS-I2C-Moduls):
#!/usr/bin/python3
#coding=utf-8
import smbus
#### i2c ####
bus = smbus.SMBus(1) # Raspberry Pi 1 model B ... Pin3 (SDA), Pin5 (SCL)
address = 0x20 # Basis-Adresse des MCP23017, mit A0, A1, A2 auf Masse
def get(register):
read = bus.read_byte_data(address, register)
return read
def set(register, data):
write = bus.write_byte_data(address, register, data)
return
#### Main ####
set(0x00,0x00) # MCP23017 Bank A (alle Pins) auf Ausgang setzen
CtrlByte = get(0x14) # OLATA auslesen
set(0x14,CtrlByte | 5) # nur Bits 0 und 2 auf 1 setzen (Maske 00000101 = dez. 5) ... Ergebnis: XXXXX1X1 in OLATA; "X" = beliebig
CtrlByte = get(0x14) # OLATA auslesen
set(0x14,CtrlByte & ~12) # nur Bits 2 und 3 auf 0 setzen (Maske 00001100 = dez. 12) .... Ergebnis: XXXX00X1 in OLATA; "X" = beliebig
Display More
SMBUS kommt mit Hex-Werten im Format 0x00 und Dez-Werten im Integerformat, auch gemischt, zurecht.
Das Integerformat funktioniert in diesem Zusammenhang, bis jetzt, sehr gut.
Die Bit-Masken lassen sich recht gut und schnell mit Integer-Werten festlegen.
TIP: Etwas Ordnung bei der Zuweisung / Verschaltung der General Purpose Pins am MCP23017 erspart heftigste Kopfschmerzen
Ein Problem, mit dem ich in diesem Zusammenhang, noch kaempfe:
Jeder Veränderung der MCP23017-Register-Bits muss ein Auslesen des betroffenen Registers vorweg gehen, um eine Ausgangsbasis zur Bit-Manipulation zu schaffen.
Unnötige I2C-Transfer (z.B.: Register auslesen) ist aber unschoen, besonders wenn rel. viele Daten transferriert werden muessen.
Ich ueberlege daher, die Register-Werte nicht immer aus dem MCP23017 auszulesen, sondern groesstenteils innerhalb des Programms in Variablen zu fuehren bzw. zu aendern. Wenn die Variablen aber nicht mehr die aktuellen Werten habe, wird ggf. das ganze Programm inkonsistent. Eine gute Mischung zwischen Auslesen und in Fuehren in separaten Variablen muss gefunden werden ... :s